@adonis-agora/flags 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/README.md +15 -2
- package/dist/assets/spa/assets/index-DdmFo7xr.js +12 -0
- package/dist/assets/spa/assets/index-DdmFo7xr.js.map +1 -0
- package/dist/assets/spa/assets/index-DhkcP3Cw.css +2 -0
- package/dist/assets/spa/index.html +26 -0
- package/dist/commands/flags_list.d.ts +9 -0
- package/dist/commands/flags_list.d.ts.map +1 -0
- package/dist/commands/flags_list.js +51 -0
- package/dist/commands/flags_list.js.map +1 -0
- package/dist/commands/flags_ops.d.ts +60 -0
- package/dist/commands/flags_ops.d.ts.map +1 -0
- package/dist/commands/flags_ops.js +253 -0
- package/dist/commands/flags_ops.js.map +1 -0
- package/dist/commands/flags_refs.d.ts +15 -0
- package/dist/commands/flags_refs.d.ts.map +1 -0
- package/dist/commands/flags_refs.js +90 -0
- package/dist/commands/flags_refs.js.map +1 -0
- package/dist/commands/flags_set.d.ts +19 -0
- package/dist/commands/flags_set.d.ts.map +1 -0
- package/dist/commands/flags_set.js +97 -0
- package/dist/commands/flags_set.js.map +1 -0
- package/dist/commands/flags_types.d.ts +18 -0
- package/dist/commands/flags_types.d.ts.map +1 -0
- package/dist/commands/flags_types.js +94 -0
- package/dist/commands/flags_types.js.map +1 -0
- package/dist/commands/flags_work.d.ts +16 -0
- package/dist/commands/flags_work.d.ts.map +1 -0
- package/dist/commands/flags_work.js +71 -0
- package/dist/commands/flags_work.js.map +1 -0
- package/dist/commands/main.d.ts +15 -0
- package/dist/commands/main.d.ts.map +1 -0
- package/dist/commands/main.js +30 -0
- package/dist/commands/main.js.map +1 -0
- package/dist/commands/shared.d.ts +21 -0
- package/dist/commands/shared.d.ts.map +1 -0
- package/dist/commands/shared.js +70 -0
- package/dist/commands/shared.js.map +1 -0
- package/dist/configure.d.ts +11 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +32 -0
- package/dist/configure.js.map +1 -0
- package/dist/providers/dashboard_provider.d.ts +65 -0
- package/dist/providers/dashboard_provider.d.ts.map +1 -0
- package/dist/providers/dashboard_provider.js +340 -0
- package/dist/providers/dashboard_provider.js.map +1 -0
- package/dist/providers/flags_provider.d.ts +30 -0
- package/dist/providers/flags_provider.d.ts.map +1 -0
- package/dist/providers/flags_provider.js +184 -0
- package/dist/providers/flags_provider.js.map +1 -0
- package/dist/services/main.d.ts +17 -0
- package/dist/services/main.d.ts.map +1 -0
- package/dist/services/main.js +20 -0
- package/dist/services/main.js.map +1 -0
- package/dist/src/admin.d.ts +189 -0
- package/dist/src/admin.d.ts.map +1 -0
- package/dist/src/admin.js +539 -0
- package/dist/src/admin.js.map +1 -0
- package/dist/src/analytics/backend.d.ts +18 -0
- package/dist/src/analytics/backend.d.ts.map +1 -0
- package/dist/src/analytics/backend.js +25 -0
- package/dist/src/analytics/backend.js.map +1 -0
- package/dist/src/analytics/clickhouse_backend.d.ts +16 -0
- package/dist/src/analytics/clickhouse_backend.d.ts.map +1 -0
- package/dist/src/analytics/clickhouse_backend.js +48 -0
- package/dist/src/analytics/clickhouse_backend.js.map +1 -0
- package/dist/src/analytics/duckdb.d.ts +39 -0
- package/dist/src/analytics/duckdb.d.ts.map +1 -0
- package/dist/src/analytics/duckdb.js +117 -0
- package/dist/src/analytics/duckdb.js.map +1 -0
- package/dist/src/analytics/lucid_backend.d.ts +16 -0
- package/dist/src/analytics/lucid_backend.d.ts.map +1 -0
- package/dist/src/analytics/lucid_backend.js +45 -0
- package/dist/src/analytics/lucid_backend.js.map +1 -0
- package/dist/src/analytics/metrics.d.ts +50 -0
- package/dist/src/analytics/metrics.d.ts.map +1 -0
- package/dist/src/analytics/metrics.js +42 -0
- package/dist/src/analytics/metrics.js.map +1 -0
- package/dist/src/analytics/results.d.ts +80 -0
- package/dist/src/analytics/results.d.ts.map +1 -0
- package/dist/src/analytics/results.js +143 -0
- package/dist/src/analytics/results.js.map +1 -0
- package/dist/src/dashboard/access_denied_page.d.ts +100 -0
- package/dist/src/dashboard/access_denied_page.d.ts.map +1 -0
- package/dist/src/dashboard/access_denied_page.js +262 -0
- package/dist/src/dashboard/access_denied_page.js.map +1 -0
- package/dist/src/dashboard/actor.d.ts +12 -0
- package/dist/src/dashboard/actor.d.ts.map +1 -0
- package/dist/src/dashboard/actor.js +33 -0
- package/dist/src/dashboard/actor.js.map +1 -0
- package/dist/src/dashboard/authorize_decision.d.ts +48 -0
- package/dist/src/dashboard/authorize_decision.d.ts.map +1 -0
- package/dist/src/dashboard/authorize_decision.js +44 -0
- package/dist/src/dashboard/authorize_decision.js.map +1 -0
- package/dist/src/dashboard/console_authorize.d.ts +77 -0
- package/dist/src/dashboard/console_authorize.d.ts.map +1 -0
- package/dist/src/dashboard/console_authorize.js +104 -0
- package/dist/src/dashboard/console_authorize.js.map +1 -0
- package/dist/src/dashboard/define_config.d.ts +71 -0
- package/dist/src/dashboard/define_config.d.ts.map +1 -0
- package/dist/src/dashboard/define_config.js +18 -0
- package/dist/src/dashboard/define_config.js.map +1 -0
- package/dist/src/dashboard/handlers.d.ts +172 -0
- package/dist/src/dashboard/handlers.d.ts.map +1 -0
- package/dist/src/dashboard/handlers.js +949 -0
- package/dist/src/dashboard/handlers.js.map +1 -0
- package/dist/src/dashboard/index.d.ts +15 -0
- package/dist/src/dashboard/index.d.ts.map +1 -0
- package/dist/src/dashboard/index.js +10 -0
- package/dist/src/dashboard/index.js.map +1 -0
- package/dist/src/dashboard/shape.d.ts +12 -0
- package/dist/src/dashboard/shape.d.ts.map +1 -0
- package/dist/src/dashboard/shape.js +232 -0
- package/dist/src/dashboard/shape.js.map +1 -0
- package/dist/src/dashboard/spa.d.ts +34 -0
- package/dist/src/dashboard/spa.d.ts.map +1 -0
- package/dist/src/dashboard/spa.js +50 -0
- package/dist/src/dashboard/spa.js.map +1 -0
- package/dist/src/declare.d.ts +85 -0
- package/dist/src/declare.d.ts.map +1 -0
- package/dist/src/declare.js +62 -0
- package/dist/src/declare.js.map +1 -0
- package/dist/src/define_config.d.ts +256 -0
- package/dist/src/define_config.d.ts.map +1 -0
- package/dist/src/define_config.js +90 -0
- package/dist/src/define_config.js.map +1 -0
- package/dist/src/durable.d.ts +29 -0
- package/dist/src/durable.d.ts.map +1 -0
- package/dist/src/durable.js +55 -0
- package/dist/src/durable.js.map +1 -0
- package/dist/src/enrichers.d.ts +51 -0
- package/dist/src/enrichers.d.ts.map +1 -0
- package/dist/src/enrichers.js +105 -0
- package/dist/src/enrichers.js.map +1 -0
- package/dist/src/events/buffer.d.ts +38 -0
- package/dist/src/events/buffer.d.ts.map +1 -0
- package/dist/src/events/buffer.js +86 -0
- package/dist/src/events/buffer.js.map +1 -0
- package/dist/src/events/event.d.ts +42 -0
- package/dist/src/events/event.d.ts.map +1 -0
- package/dist/src/events/event.js +82 -0
- package/dist/src/events/event.js.map +1 -0
- package/dist/src/http/browser.d.ts +33 -0
- package/dist/src/http/browser.d.ts.map +1 -0
- package/dist/src/http/browser.js +81 -0
- package/dist/src/http/browser.js.map +1 -0
- package/dist/src/http/browser_api.d.ts +48 -0
- package/dist/src/http/browser_api.d.ts.map +1 -0
- package/dist/src/http/browser_api.js +273 -0
- package/dist/src/http/browser_api.js.map +1 -0
- package/dist/src/http/browser_tokens.d.ts +27 -0
- package/dist/src/http/browser_tokens.d.ts.map +1 -0
- package/dist/src/http/browser_tokens.js +48 -0
- package/dist/src/http/browser_tokens.js.map +1 -0
- package/dist/src/http/control_plane.d.ts +58 -0
- package/dist/src/http/control_plane.d.ts.map +1 -0
- package/dist/src/http/control_plane.js +318 -0
- package/dist/src/http/control_plane.js.map +1 -0
- package/dist/src/http/csrf.d.ts +22 -0
- package/dist/src/http/csrf.d.ts.map +1 -0
- package/dist/src/http/csrf.js +24 -0
- package/dist/src/http/csrf.js.map +1 -0
- package/dist/src/http/edge_tag.d.ts +55 -0
- package/dist/src/http/edge_tag.d.ts.map +1 -0
- package/dist/src/http/edge_tag.js +45 -0
- package/dist/src/http/edge_tag.js.map +1 -0
- package/dist/src/http/flag_middleware.d.ts +27 -0
- package/dist/src/http/flag_middleware.d.ts.map +1 -0
- package/dist/src/http/flag_middleware.js +30 -0
- package/dist/src/http/flag_middleware.js.map +1 -0
- package/dist/src/http/flags_middleware.d.ts +20 -0
- package/dist/src/http/flags_middleware.d.ts.map +1 -0
- package/dist/src/http/flags_middleware.js +20 -0
- package/dist/src/http/flags_middleware.js.map +1 -0
- package/dist/src/http/subject_resolver.d.ts +45 -0
- package/dist/src/http/subject_resolver.d.ts.map +1 -0
- package/dist/src/http/subject_resolver.js +93 -0
- package/dist/src/http/subject_resolver.js.map +1 -0
- package/dist/src/identity.d.ts +82 -0
- package/dist/src/identity.d.ts.map +1 -0
- package/dist/src/identity.js +100 -0
- package/dist/src/identity.js.map +1 -0
- package/dist/src/index.d.ts +41 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +34 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/manager.d.ts +154 -0
- package/dist/src/manager.d.ts.map +1 -0
- package/dist/src/manager.js +333 -0
- package/dist/src/manager.js.map +1 -0
- package/dist/src/openfeature/provider.d.ts +36 -0
- package/dist/src/openfeature/provider.d.ts.map +1 -0
- package/dist/src/openfeature/provider.js +82 -0
- package/dist/src/openfeature/provider.js.map +1 -0
- package/dist/src/relay/relay.d.ts +36 -0
- package/dist/src/relay/relay.d.ts.map +1 -0
- package/dist/src/relay/relay.js +73 -0
- package/dist/src/relay/relay.js.map +1 -0
- package/dist/src/relay/results_cache.d.ts +20 -0
- package/dist/src/relay/results_cache.d.ts.map +1 -0
- package/dist/src/relay/results_cache.js +31 -0
- package/dist/src/relay/results_cache.js.map +1 -0
- package/dist/src/relay/worker.d.ts +66 -0
- package/dist/src/relay/worker.d.ts.map +1 -0
- package/dist/src/relay/worker.js +177 -0
- package/dist/src/relay/worker.js.map +1 -0
- package/dist/src/ruleset_source.d.ts +73 -0
- package/dist/src/ruleset_source.d.ts.map +1 -0
- package/dist/src/ruleset_source.js +128 -0
- package/dist/src/ruleset_source.js.map +1 -0
- package/dist/src/runtime.d.ts +70 -0
- package/dist/src/runtime.d.ts.map +1 -0
- package/dist/src/runtime.js +301 -0
- package/dist/src/runtime.js.map +1 -0
- package/dist/src/schema.d.ts +39 -0
- package/dist/src/schema.d.ts.map +1 -0
- package/dist/src/schema.js +311 -0
- package/dist/src/schema.js.map +1 -0
- package/dist/src/services/accessor.d.ts +5 -0
- package/dist/src/services/accessor.d.ts.map +1 -0
- package/dist/src/services/accessor.js +20 -0
- package/dist/src/services/accessor.js.map +1 -0
- package/dist/src/sinks/clickhouse.d.ts +41 -0
- package/dist/src/sinks/clickhouse.d.ts.map +1 -0
- package/dist/src/sinks/clickhouse.js +117 -0
- package/dist/src/sinks/clickhouse.js.map +1 -0
- package/dist/src/sinks/lucid_sink.d.ts +25 -0
- package/dist/src/sinks/lucid_sink.d.ts.map +1 -0
- package/dist/src/sinks/lucid_sink.js +87 -0
- package/dist/src/sinks/lucid_sink.js.map +1 -0
- package/dist/src/sinks/parquet_sink.d.ts +41 -0
- package/dist/src/sinks/parquet_sink.d.ts.map +1 -0
- package/dist/src/sinks/parquet_sink.js +140 -0
- package/dist/src/sinks/parquet_sink.js.map +1 -0
- package/dist/src/sinks/posthog_sink.d.ts +29 -0
- package/dist/src/sinks/posthog_sink.d.ts.map +1 -0
- package/dist/src/sinks/posthog_sink.js +65 -0
- package/dist/src/sinks/posthog_sink.js.map +1 -0
- package/dist/src/sinks/sink.d.ts +36 -0
- package/dist/src/sinks/sink.d.ts.map +1 -0
- package/dist/src/sinks/sink.js +36 -0
- package/dist/src/sinks/sink.js.map +1 -0
- package/dist/src/sql.d.ts +33 -0
- package/dist/src/sql.d.ts.map +1 -0
- package/dist/src/sql.js +66 -0
- package/dist/src/sql.js.map +1 -0
- package/dist/src/stores/lucid_store.d.ts +55 -0
- package/dist/src/stores/lucid_store.d.ts.map +1 -0
- package/dist/src/stores/lucid_store.js +412 -0
- package/dist/src/stores/lucid_store.js.map +1 -0
- package/dist/src/stores/memory_store.d.ts +38 -0
- package/dist/src/stores/memory_store.d.ts.map +1 -0
- package/dist/src/stores/memory_store.js +166 -0
- package/dist/src/stores/memory_store.js.map +1 -0
- package/dist/src/stores/store.d.ts +166 -0
- package/dist/src/stores/store.d.ts.map +1 -0
- package/dist/src/stores/store.js +67 -0
- package/dist/src/stores/store.js.map +1 -0
- package/dist/src/subject.d.ts +25 -0
- package/dist/src/subject.d.ts.map +1 -0
- package/dist/src/subject.js +30 -0
- package/dist/src/subject.js.map +1 -0
- package/dist/src/testing/index.d.ts +31 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +60 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/topology/browser_token.d.ts +48 -0
- package/dist/src/topology/browser_token.d.ts.map +1 -0
- package/dist/src/topology/browser_token.js +128 -0
- package/dist/src/topology/browser_token.js.map +1 -0
- package/dist/src/topology/remote_source.d.ts +39 -0
- package/dist/src/topology/remote_source.d.ts.map +1 -0
- package/dist/src/topology/remote_source.js +184 -0
- package/dist/src/topology/remote_source.js.map +1 -0
- package/dist/src/topology/token.d.ts +36 -0
- package/dist/src/topology/token.d.ts.map +1 -0
- package/dist/src/topology/token.js +68 -0
- package/dist/src/topology/token.js.map +1 -0
- package/dist/src/topology/verify.d.ts +88 -0
- package/dist/src/topology/verify.d.ts.map +1 -0
- package/dist/src/topology/verify.js +128 -0
- package/dist/src/topology/verify.js.map +1 -0
- package/dist/src/transports/db_transport.d.ts +55 -0
- package/dist/src/transports/db_transport.d.ts.map +1 -0
- package/dist/src/transports/db_transport.js +202 -0
- package/dist/src/transports/db_transport.js.map +1 -0
- package/dist/src/transports/http_transport.d.ts +30 -0
- package/dist/src/transports/http_transport.d.ts.map +1 -0
- package/dist/src/transports/http_transport.js +51 -0
- package/dist/src/transports/http_transport.js.map +1 -0
- package/dist/src/transports/memory_transport.d.ts +29 -0
- package/dist/src/transports/memory_transport.d.ts.map +1 -0
- package/dist/src/transports/memory_transport.js +91 -0
- package/dist/src/transports/memory_transport.js.map +1 -0
- package/dist/src/transports/redis_transport.d.ts +50 -0
- package/dist/src/transports/redis_transport.d.ts.map +1 -0
- package/dist/src/transports/redis_transport.js +107 -0
- package/dist/src/transports/redis_transport.js.map +1 -0
- package/dist/src/transports/transport.d.ts +62 -0
- package/dist/src/transports/transport.d.ts.map +1 -0
- package/dist/src/transports/transport.js +2 -0
- package/dist/src/transports/transport.js.map +1 -0
- package/dist/src/types.d.ts +30 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/usage.d.ts +18 -0
- package/dist/src/usage.d.ts.map +1 -0
- package/dist/src/usage.js +52 -0
- package/dist/src/usage.js.map +1 -0
- package/dist/stubs/config/flags.stub +50 -0
- package/dist/stubs/config/flags_dashboard.stub +35 -0
- package/dist/stubs/database/migrations/create_flags_tables.stub +27 -0
- package/dist/stubs/main.d.ts +3 -0
- package/dist/stubs/main.d.ts.map +1 -0
- package/dist/stubs/main.js +9 -0
- package/dist/stubs/main.js.map +1 -0
- package/package.json +178 -3
- package/skills/flags-basics/SKILL.md +142 -0
- package/skills/flags-deployment/SKILL.md +125 -0
- package/skills/flags-experiments/SKILL.md +99 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { evaluate, } from '@adonis-agora/flags-core';
|
|
2
|
+
import { HOLDOUT_VARIANT } from './analytics/results.js';
|
|
3
|
+
import { effectiveDeclarations } from './declare.js';
|
|
4
|
+
import { runEnrichers } from './enrichers.js';
|
|
5
|
+
import { EVENT_SCHEMA_VERSION, exposureId, uuidv7 } from './events/event.js';
|
|
6
|
+
import { toContext, toSubject } from './subject.js';
|
|
7
|
+
/**
|
|
8
|
+
* The entry point: `flags.for(user).enabled('new_player')`. Evaluation is in memory against the
|
|
9
|
+
* ruleset the source keeps fresh; nothing here waits on the database except an opt-in sticky lookup
|
|
10
|
+
* (once per scope).
|
|
11
|
+
*/
|
|
12
|
+
export class FlagsManager {
|
|
13
|
+
deps;
|
|
14
|
+
#fakes;
|
|
15
|
+
#warnedTransactional = false;
|
|
16
|
+
constructor(deps) {
|
|
17
|
+
this.deps = deps;
|
|
18
|
+
}
|
|
19
|
+
get environment() {
|
|
20
|
+
return this.deps.environment;
|
|
21
|
+
}
|
|
22
|
+
get app() {
|
|
23
|
+
return this.deps.app;
|
|
24
|
+
}
|
|
25
|
+
get admin() {
|
|
26
|
+
if (!this.deps.admin) {
|
|
27
|
+
throw new Error('flags admin is not available here (a tenant edits flags on its control-plane)');
|
|
28
|
+
}
|
|
29
|
+
return this.deps.admin;
|
|
30
|
+
}
|
|
31
|
+
/** Flags declared in code. */
|
|
32
|
+
get declarations() {
|
|
33
|
+
return this.deps.declarations;
|
|
34
|
+
}
|
|
35
|
+
/** Every known flag: declared in code or created in the console (code wins). */
|
|
36
|
+
effectiveDeclarations() {
|
|
37
|
+
return effectiveDeclarations(this.deps.declarations, this.ruleset());
|
|
38
|
+
}
|
|
39
|
+
/** The ruleset this process evaluates against. */
|
|
40
|
+
ruleset() {
|
|
41
|
+
return this.deps.source.current();
|
|
42
|
+
}
|
|
43
|
+
status() {
|
|
44
|
+
return {
|
|
45
|
+
app: this.deps.app,
|
|
46
|
+
environment: this.deps.environment,
|
|
47
|
+
source: this.deps.source.status(),
|
|
48
|
+
buffer: this.deps.buffer
|
|
49
|
+
? {
|
|
50
|
+
pending: this.deps.buffer.pending,
|
|
51
|
+
published: this.deps.buffer.published,
|
|
52
|
+
dropped: this.deps.buffer.dropped,
|
|
53
|
+
}
|
|
54
|
+
: null,
|
|
55
|
+
transport: this.deps.transport
|
|
56
|
+
? { name: this.deps.transport.name, ...this.deps.transport.capabilities }
|
|
57
|
+
: null,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Reloads the ruleset now (after an edit in this process, or from a command). */
|
|
61
|
+
refresh() {
|
|
62
|
+
return this.deps.source.refresh();
|
|
63
|
+
}
|
|
64
|
+
/** A scope for one subject. In HTTP handlers prefer `ctx.flags`, which the middleware builds. */
|
|
65
|
+
for(subject, attributes = {}) {
|
|
66
|
+
return new FlagsScope(this, toSubject(subject), attributes);
|
|
67
|
+
}
|
|
68
|
+
/** A scope whose subject is resolved on the first flag read. */
|
|
69
|
+
forLazy(resolve, attributes = {}) {
|
|
70
|
+
return new FlagsScope(this, resolve, attributes);
|
|
71
|
+
}
|
|
72
|
+
/** The declared default: from code, else from the console declaration in the ruleset. */
|
|
73
|
+
declaredDefault(key) {
|
|
74
|
+
return this.deps.declarations[key]?.default ?? this.ruleset().flags[key]?.declaration?.default;
|
|
75
|
+
}
|
|
76
|
+
/** @internal Evaluation with fakes, usage counting and enrichers. */
|
|
77
|
+
evaluateFor(key, fallback, context, options) {
|
|
78
|
+
this.deps.usage?.hit(key);
|
|
79
|
+
const fake = this.#fakes;
|
|
80
|
+
let details;
|
|
81
|
+
if (fake?.has(key)) {
|
|
82
|
+
details = {
|
|
83
|
+
flagKey: key,
|
|
84
|
+
value: fake.get(key),
|
|
85
|
+
variant: String(fake.get(key)),
|
|
86
|
+
reason: 'STATIC',
|
|
87
|
+
flagMetadata: { faked: true },
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
details = evaluate(this.ruleset(), key, fallback, context, options);
|
|
92
|
+
if (details.errorCode === 'FLAG_NOT_FOUND' && key in this.deps.declarations) {
|
|
93
|
+
// Declared in code, not configured yet: serving the declared default is the normal state,
|
|
94
|
+
// not an error (alerts on reason ERROR would fire for every new flag).
|
|
95
|
+
details = {
|
|
96
|
+
flagKey: key,
|
|
97
|
+
value: details.value,
|
|
98
|
+
reason: 'DEFAULT',
|
|
99
|
+
flagMetadata: { ...details.flagMetadata, configured: false },
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (details.errorCode && details.errorCode !== 'FLAG_NOT_FOUND') {
|
|
104
|
+
this.deps.logger?.warn(`[flags] ${key}: ${details.errorCode} ${details.errorMessage ?? ''}`.trim());
|
|
105
|
+
}
|
|
106
|
+
const enrichers = this.deps.enrichers ?? [];
|
|
107
|
+
runEnrichers(enrichers, (e) => e.onEvaluation?.(details, context));
|
|
108
|
+
return details;
|
|
109
|
+
}
|
|
110
|
+
/** @internal Records an exposure for an experiment assignment. */
|
|
111
|
+
expose(subject, details) {
|
|
112
|
+
const experiment = details.flagMetadata.experiment;
|
|
113
|
+
if (typeof experiment !== 'string' || details.variant === undefined)
|
|
114
|
+
return;
|
|
115
|
+
const holdout = details.flagMetadata.holdout === true;
|
|
116
|
+
if (details.reason !== 'SPLIT' && !holdout)
|
|
117
|
+
return;
|
|
118
|
+
const subjectId = String(subject.id);
|
|
119
|
+
const event = {
|
|
120
|
+
id: exposureId(this.deps.app, this.deps.environment, experiment, subjectId),
|
|
121
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
122
|
+
app: this.deps.app,
|
|
123
|
+
environment: this.deps.environment,
|
|
124
|
+
type: 'exposure',
|
|
125
|
+
flag: details.flagKey,
|
|
126
|
+
experiment,
|
|
127
|
+
variant: holdout ? HOLDOUT_VARIANT : details.variant,
|
|
128
|
+
subject: subjectId,
|
|
129
|
+
subjectType: subject.type ?? 'user',
|
|
130
|
+
...(holdout ? { props: { holdout: true } } : {}),
|
|
131
|
+
ts: Date.now(),
|
|
132
|
+
};
|
|
133
|
+
if (this.deps.buffer?.push(event)) {
|
|
134
|
+
runEnrichers(this.deps.enrichers ?? [], (e) => e.onEvent?.(event));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** Records a tracked event (a conversion) for a subject. */
|
|
138
|
+
async track(subject, name, options = {}) {
|
|
139
|
+
const normalized = toSubject(subject);
|
|
140
|
+
if (!normalized)
|
|
141
|
+
throw new Error('flags.track() needs a subject');
|
|
142
|
+
if (this.#fakes)
|
|
143
|
+
return;
|
|
144
|
+
const event = {
|
|
145
|
+
id: uuidv7(),
|
|
146
|
+
schemaVersion: EVENT_SCHEMA_VERSION,
|
|
147
|
+
app: this.deps.app,
|
|
148
|
+
environment: this.deps.environment,
|
|
149
|
+
type: 'track',
|
|
150
|
+
name,
|
|
151
|
+
subject: String(normalized.id),
|
|
152
|
+
subjectType: normalized.type ?? 'user',
|
|
153
|
+
...(options.value !== undefined ? { value: options.value } : {}),
|
|
154
|
+
...(options.props !== undefined ? { props: options.props } : {}),
|
|
155
|
+
ts: Date.now(),
|
|
156
|
+
};
|
|
157
|
+
runEnrichers(this.deps.enrichers ?? [], (e) => e.onEvent?.(event));
|
|
158
|
+
const transport = this.deps.transport;
|
|
159
|
+
if (options.client && transport) {
|
|
160
|
+
if (transport.capabilities.transactional) {
|
|
161
|
+
await transport.publish([event], { client: options.client });
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (!this.#warnedTransactional) {
|
|
165
|
+
this.#warnedTransactional = true;
|
|
166
|
+
this.deps.logger?.warn(`[flags] the "${transport.name}" transport is not transactional: tracked events are sent after commit, and are lost if the process dies in between`);
|
|
167
|
+
}
|
|
168
|
+
if (options.client.after) {
|
|
169
|
+
options.client.after('commit', () => {
|
|
170
|
+
this.deps.buffer?.push(event);
|
|
171
|
+
});
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
this.deps.buffer?.push(event);
|
|
176
|
+
}
|
|
177
|
+
/** Experiment results as last computed by the worker (or `null`), for this process's environment by default. */
|
|
178
|
+
results(experiment, environment) {
|
|
179
|
+
return this.deps.results ? this.deps.results(experiment, environment) : Promise.resolve(null);
|
|
180
|
+
}
|
|
181
|
+
/** Deletes everything stored about a subject in every sink that supports it. */
|
|
182
|
+
async forget(subject) {
|
|
183
|
+
const normalized = toSubject(subject);
|
|
184
|
+
if (!normalized)
|
|
185
|
+
return;
|
|
186
|
+
await this.deps.forget?.(String(normalized.id));
|
|
187
|
+
}
|
|
188
|
+
/** @internal */
|
|
189
|
+
async attributesFor(subject) {
|
|
190
|
+
if (!subject || !this.deps.attributes)
|
|
191
|
+
return {};
|
|
192
|
+
return this.deps.attributes(subject);
|
|
193
|
+
}
|
|
194
|
+
/** @internal */
|
|
195
|
+
stickyFor(subject) {
|
|
196
|
+
if (!subject || !this.deps.sticky)
|
|
197
|
+
return undefined;
|
|
198
|
+
return this.deps.sticky(String(subject.id));
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Replaces flag values for the duration of a test. Every evaluation of a faked key returns the
|
|
202
|
+
* given value; tracked events are dropped. Returns a function that restores real evaluation.
|
|
203
|
+
*
|
|
204
|
+
* ```ts
|
|
205
|
+
* const restore = flags.fake({ checkout_v2: 'b' })
|
|
206
|
+
* // …
|
|
207
|
+
* restore()
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
fake(values) {
|
|
211
|
+
this.#fakes = new Map(Object.entries(values));
|
|
212
|
+
return () => this.restore();
|
|
213
|
+
}
|
|
214
|
+
restore() {
|
|
215
|
+
this.#fakes = undefined;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Flags for one subject. Results are memoized for the life of the scope (one request), so a flag
|
|
220
|
+
* cannot change value halfway through rendering a page. The subject may be given directly or as a
|
|
221
|
+
* resolver that runs on the first read (what `ctx.flags` uses).
|
|
222
|
+
*/
|
|
223
|
+
export class FlagsScope {
|
|
224
|
+
manager;
|
|
225
|
+
attributes;
|
|
226
|
+
#memo = new Map();
|
|
227
|
+
#subject;
|
|
228
|
+
#context;
|
|
229
|
+
#sticky;
|
|
230
|
+
#resolver;
|
|
231
|
+
#resolved;
|
|
232
|
+
constructor(manager, subject, attributes = {}) {
|
|
233
|
+
this.manager = manager;
|
|
234
|
+
this.attributes = attributes;
|
|
235
|
+
if (typeof subject === 'function') {
|
|
236
|
+
const resolve = subject;
|
|
237
|
+
this.#resolver = async () => toSubject(await resolve());
|
|
238
|
+
this.#subject = Promise.resolve(undefined);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
this.#subject = Promise.resolve(subject);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/** The subject this scope evaluates for (resolved on first use). */
|
|
245
|
+
subject() {
|
|
246
|
+
if (!this.#resolver)
|
|
247
|
+
return this.#subject;
|
|
248
|
+
this.#resolved ??= this.#resolver();
|
|
249
|
+
return this.#resolved;
|
|
250
|
+
}
|
|
251
|
+
#ctx() {
|
|
252
|
+
this.#context ??= this.subject().then(async (subject) => {
|
|
253
|
+
const resolved = await this.manager.attributesFor(subject);
|
|
254
|
+
return toContext(subject, { ...resolved, ...this.attributes });
|
|
255
|
+
});
|
|
256
|
+
return this.#context;
|
|
257
|
+
}
|
|
258
|
+
async #options(key) {
|
|
259
|
+
const flag = this.manager.ruleset().flags[key];
|
|
260
|
+
if (!flag?.experiment)
|
|
261
|
+
return {};
|
|
262
|
+
this.#sticky ??= this.subject().then((subject) => this.manager.stickyFor(subject)?.catch(() => ({})) ?? {});
|
|
263
|
+
return { sticky: await this.#sticky };
|
|
264
|
+
}
|
|
265
|
+
async #evaluate(key) {
|
|
266
|
+
const cached = this.#memo.get(key);
|
|
267
|
+
if (cached)
|
|
268
|
+
return cached;
|
|
269
|
+
const fallback = (this.manager.declaredDefault(key) ?? null);
|
|
270
|
+
const details = this.manager.evaluateFor(key, fallback, await this.#ctx(), await this.#options(key));
|
|
271
|
+
this.#memo.set(key, details);
|
|
272
|
+
return details;
|
|
273
|
+
}
|
|
274
|
+
/** Full evaluation details (value, variant, reason, error). Records an exposure for experiments. */
|
|
275
|
+
async details(key) {
|
|
276
|
+
const details = await this.#evaluate(key);
|
|
277
|
+
const subject = await this.subject();
|
|
278
|
+
if (subject)
|
|
279
|
+
this.manager.expose(subject, details);
|
|
280
|
+
return details;
|
|
281
|
+
}
|
|
282
|
+
/** The flag's value. */
|
|
283
|
+
async value(key) {
|
|
284
|
+
return (await this.details(key)).value;
|
|
285
|
+
}
|
|
286
|
+
/** Whether a boolean flag is on. */
|
|
287
|
+
async enabled(key) {
|
|
288
|
+
return (await this.details(key)).value === true;
|
|
289
|
+
}
|
|
290
|
+
async disabled(key) {
|
|
291
|
+
return !(await this.enabled(key));
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* `true` when a boolean flag is on, or — given variants — when the flag serves one of them.
|
|
295
|
+
* What the Edge `@flag` tag compiles to.
|
|
296
|
+
*/
|
|
297
|
+
async matches(key, ...variants) {
|
|
298
|
+
const details = await this.details(key);
|
|
299
|
+
if (variants.length === 0)
|
|
300
|
+
return details.value === true;
|
|
301
|
+
return variants.includes(details.variant ?? String(details.value));
|
|
302
|
+
}
|
|
303
|
+
/** The variant name served (experiments). Falls back to the value as a string. */
|
|
304
|
+
async variant(key) {
|
|
305
|
+
const details = await this.details(key);
|
|
306
|
+
return details.variant ?? String(details.value);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Values of several flags at once — for the frontend. Without `keys`, only flags declared with
|
|
310
|
+
* `client: true` are included, so internal flag names never reach the browser by accident.
|
|
311
|
+
* Experiment exposures are NOT recorded here unless `expose: true`: values sent to a page are not
|
|
312
|
+
* necessarily seen.
|
|
313
|
+
*/
|
|
314
|
+
async all(keys, options = {}) {
|
|
315
|
+
const declarations = this.manager.effectiveDeclarations();
|
|
316
|
+
const list = keys ?? Object.keys(declarations).filter((key) => declarations[key]?.client);
|
|
317
|
+
const out = {};
|
|
318
|
+
for (const key of list) {
|
|
319
|
+
out[key] = options.expose
|
|
320
|
+
? (await this.details(key)).value
|
|
321
|
+
: (await this.#evaluate(key)).value;
|
|
322
|
+
}
|
|
323
|
+
return out;
|
|
324
|
+
}
|
|
325
|
+
/** Records a tracked event for this scope's subject. */
|
|
326
|
+
async track(name, options = {}) {
|
|
327
|
+
const subject = await this.subject();
|
|
328
|
+
if (!subject)
|
|
329
|
+
throw new Error('cannot track for an anonymous subject');
|
|
330
|
+
return this.manager.track(subject, name, options);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { EvaluationContext, JsonValue as OFJsonValue, Provider, ResolutionDetails, TrackingEventDetails } from '@openfeature/server-sdk';
|
|
2
|
+
import type { FlagsManager } from '../manager.js';
|
|
3
|
+
/**
|
|
4
|
+
* An OpenFeature provider backed by the same engine as `flags.for()`: same ruleset, same buckets,
|
|
5
|
+
* same exposures. Use it when your code talks to `@openfeature/server-sdk` (to stay vendor-neutral
|
|
6
|
+
* or to share code with services in other stacks).
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { OpenFeature } from '@openfeature/server-sdk'
|
|
10
|
+
* import { AgoraFlagsProvider } from '@adonis-agora/flags/openfeature'
|
|
11
|
+
*
|
|
12
|
+
* await OpenFeature.setProviderAndWait(new AgoraFlagsProvider())
|
|
13
|
+
* const client = OpenFeature.getClient()
|
|
14
|
+
* await client.getBooleanValue('new_player', false, { targetingKey: user.id })
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* The context's `targetingKey` is the subject id; `subjectType` sets the subject type; every other
|
|
18
|
+
* attribute is a targeting attribute. Tracking is OpenFeature's experimental `track()`.
|
|
19
|
+
*/
|
|
20
|
+
export declare class AgoraFlagsProvider implements Provider {
|
|
21
|
+
#private;
|
|
22
|
+
private readonly manager?;
|
|
23
|
+
readonly metadata: {
|
|
24
|
+
readonly name: '@adonis-agora/flags';
|
|
25
|
+
};
|
|
26
|
+
readonly runsOn: 'server';
|
|
27
|
+
readonly hooks: never[];
|
|
28
|
+
/** Pass a manager explicitly, or let it resolve the booted one. */
|
|
29
|
+
constructor(manager?: FlagsManager | undefined);
|
|
30
|
+
resolveBooleanEvaluation(flagKey: string, defaultValue: boolean, context: EvaluationContext): Promise<ResolutionDetails<boolean>>;
|
|
31
|
+
resolveStringEvaluation(flagKey: string, defaultValue: string, context: EvaluationContext): Promise<ResolutionDetails<string>>;
|
|
32
|
+
resolveNumberEvaluation(flagKey: string, defaultValue: number, context: EvaluationContext): Promise<ResolutionDetails<number>>;
|
|
33
|
+
resolveObjectEvaluation<T extends OFJsonValue>(flagKey: string, defaultValue: T, context: EvaluationContext): Promise<ResolutionDetails<T>>;
|
|
34
|
+
track(trackingEventName: string, context: EvaluationContext, details?: TrackingEventDetails): void;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/openfeature/provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EACjB,SAAS,IAAI,WAAW,EACxB,QAAQ,EACR,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAIlD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,kBAAmB,YAAW,QAAQ;;IAMrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IALrC,QAAQ,CAAC,QAAQ;iBAAK,IAAI,EAAE,qBAAqB;MAAY;IAC7D,QAAQ,CAAC,MAAM,EAAG,QAAQ,CAAU;IACpC,QAAQ,CAAC,KAAK,UAAM;IAEpB,mEAAmE;IACnE,YAA6B,OAAO,CAAC,EAAE,YAAY,YAAA,EAAI;IA2CjD,wBAAwB,CAC5B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,OAAO,EACrB,OAAO,EAAE,iBAAiB,uCAG3B;IAEK,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,sCAE9F;IAEK,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,sCAE9F;IAEK,uBAAuB,CAAC,CAAC,SAAS,WAAW,EACjD,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,CAAC,EACf,OAAO,EAAE,iBAAiB,iCAO3B;IAED,KAAK,CACH,iBAAiB,EAAE,MAAM,EACzB,OAAO,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE,oBAAoB,GAC7B,IAAI,CAQN;CACF"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { getRuntime } from '../services/accessor.js';
|
|
2
|
+
/**
|
|
3
|
+
* An OpenFeature provider backed by the same engine as `flags.for()`: same ruleset, same buckets,
|
|
4
|
+
* same exposures. Use it when your code talks to `@openfeature/server-sdk` (to stay vendor-neutral
|
|
5
|
+
* or to share code with services in other stacks).
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { OpenFeature } from '@openfeature/server-sdk'
|
|
9
|
+
* import { AgoraFlagsProvider } from '@adonis-agora/flags/openfeature'
|
|
10
|
+
*
|
|
11
|
+
* await OpenFeature.setProviderAndWait(new AgoraFlagsProvider())
|
|
12
|
+
* const client = OpenFeature.getClient()
|
|
13
|
+
* await client.getBooleanValue('new_player', false, { targetingKey: user.id })
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* The context's `targetingKey` is the subject id; `subjectType` sets the subject type; every other
|
|
17
|
+
* attribute is a targeting attribute. Tracking is OpenFeature's experimental `track()`.
|
|
18
|
+
*/
|
|
19
|
+
export class AgoraFlagsProvider {
|
|
20
|
+
manager;
|
|
21
|
+
metadata = { name: '@adonis-agora/flags' };
|
|
22
|
+
runsOn = 'server';
|
|
23
|
+
hooks = [];
|
|
24
|
+
/** Pass a manager explicitly, or let it resolve the booted one. */
|
|
25
|
+
constructor(manager) {
|
|
26
|
+
this.manager = manager;
|
|
27
|
+
}
|
|
28
|
+
get #manager() {
|
|
29
|
+
return this.manager ?? getRuntime().manager;
|
|
30
|
+
}
|
|
31
|
+
#subject(context) {
|
|
32
|
+
const key = context.targetingKey;
|
|
33
|
+
if (key === undefined || key === '')
|
|
34
|
+
return undefined;
|
|
35
|
+
return {
|
|
36
|
+
id: key,
|
|
37
|
+
...(typeof context.subjectType === 'string' ? { type: context.subjectType } : {}),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
#resolve(flagKey, defaultValue, context) {
|
|
41
|
+
const manager = this.#manager;
|
|
42
|
+
const { targetingKey: _key, ...attributes } = context;
|
|
43
|
+
const details = manager.evaluateFor(flagKey, defaultValue, {
|
|
44
|
+
...attributes,
|
|
45
|
+
...(context.targetingKey ? { targetingKey: context.targetingKey } : {}),
|
|
46
|
+
}, {});
|
|
47
|
+
const subject = this.#subject(context);
|
|
48
|
+
if (subject)
|
|
49
|
+
manager.expose(subject, details);
|
|
50
|
+
return {
|
|
51
|
+
value: details.value,
|
|
52
|
+
reason: details.reason,
|
|
53
|
+
...(details.variant !== undefined ? { variant: details.variant } : {}),
|
|
54
|
+
...(details.errorCode ? { errorCode: details.errorCode } : {}),
|
|
55
|
+
...(details.errorMessage ? { errorMessage: details.errorMessage } : {}),
|
|
56
|
+
flagMetadata: details.flagMetadata,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async resolveBooleanEvaluation(flagKey, defaultValue, context) {
|
|
60
|
+
return this.#resolve(flagKey, defaultValue, context);
|
|
61
|
+
}
|
|
62
|
+
async resolveStringEvaluation(flagKey, defaultValue, context) {
|
|
63
|
+
return this.#resolve(flagKey, defaultValue, context);
|
|
64
|
+
}
|
|
65
|
+
async resolveNumberEvaluation(flagKey, defaultValue, context) {
|
|
66
|
+
return this.#resolve(flagKey, defaultValue, context);
|
|
67
|
+
}
|
|
68
|
+
async resolveObjectEvaluation(flagKey, defaultValue, context) {
|
|
69
|
+
return this.#resolve(flagKey, defaultValue, context);
|
|
70
|
+
}
|
|
71
|
+
track(trackingEventName, context, details) {
|
|
72
|
+
const subject = this.#subject(context);
|
|
73
|
+
if (!subject)
|
|
74
|
+
return;
|
|
75
|
+
const { value, ...props } = details ?? {};
|
|
76
|
+
void this.#manager.track(subject, trackingEventName, {
|
|
77
|
+
...(typeof value === 'number' ? { value } : {}),
|
|
78
|
+
...(Object.keys(props).length > 0 ? { props: props } : {}),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../src/openfeature/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Sink } from '../sinks/sink.js';
|
|
2
|
+
import type { Transport } from '../transports/transport.js';
|
|
3
|
+
export interface RelayOptions {
|
|
4
|
+
/** Events per batch. Default 1000 (a sink can ask for its own). */
|
|
5
|
+
batchSize?: number;
|
|
6
|
+
/** How long a lease lasts (ms) before another process may take over. Default 60000. */
|
|
7
|
+
leaseMs?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface DrainResult {
|
|
10
|
+
sink: string;
|
|
11
|
+
delivered: number;
|
|
12
|
+
batches: number;
|
|
13
|
+
/** Another process holds the lease. */
|
|
14
|
+
busy: boolean;
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
/** A process-unique owner id for leases. */
|
|
18
|
+
export declare function relayOwner(): string;
|
|
19
|
+
/**
|
|
20
|
+
* Moves events from the transport to one sink: lease, read a batch, write it, ack (which moves the
|
|
21
|
+
* cursor). Errors leave the cursor where it was, so the batch is retried next time. The lease makes
|
|
22
|
+
* it safe for every replica to run the relay: one of them delivers per sink at a time.
|
|
23
|
+
*/
|
|
24
|
+
export declare class Relay {
|
|
25
|
+
private readonly transport;
|
|
26
|
+
private readonly sinks;
|
|
27
|
+
private readonly options;
|
|
28
|
+
readonly owner: string;
|
|
29
|
+
constructor(transport: Transport, sinks: Map<string, Sink>, options?: RelayOptions, owner?: string);
|
|
30
|
+
get sinkNames(): string[];
|
|
31
|
+
sink(name: string): Sink | undefined;
|
|
32
|
+
/** Delivers up to `maxBatches` batches to `name`. */
|
|
33
|
+
drain(name: string, maxBatches?: number): Promise<DrainResult>;
|
|
34
|
+
drainAll(maxBatches?: number): Promise<DrainResult[]>;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=relay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../../../src/relay/relay.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,4CAA4C;AAC5C,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;;;GAIG;AACH,qBAAa,KAAK;IAId,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAL1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,YACmB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,EACxB,OAAO,GAAE,YAAiB,EAC3C,KAAK,CAAC,EAAE,MAAM,EAQf;IAED,IAAI,SAAS,IAAI,MAAM,EAAE,CAExB;IAED,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAEnC;IAED,qDAAqD;IAC/C,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,SAAK,GAAG,OAAO,CAAC,WAAW,CAAC,CA8B/D;IAEK,QAAQ,CAAC,UAAU,SAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAItD;CACF"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { hostname } from 'node:os';
|
|
3
|
+
/** A process-unique owner id for leases. */
|
|
4
|
+
export function relayOwner() {
|
|
5
|
+
return `${hostname()}:${process.pid}:${randomUUID().slice(0, 8)}`;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Moves events from the transport to one sink: lease, read a batch, write it, ack (which moves the
|
|
9
|
+
* cursor). Errors leave the cursor where it was, so the batch is retried next time. The lease makes
|
|
10
|
+
* it safe for every replica to run the relay: one of them delivers per sink at a time.
|
|
11
|
+
*/
|
|
12
|
+
export class Relay {
|
|
13
|
+
transport;
|
|
14
|
+
sinks;
|
|
15
|
+
options;
|
|
16
|
+
owner;
|
|
17
|
+
constructor(transport, sinks, options = {}, owner) {
|
|
18
|
+
this.transport = transport;
|
|
19
|
+
this.sinks = sinks;
|
|
20
|
+
this.options = options;
|
|
21
|
+
this.owner = owner ?? relayOwner();
|
|
22
|
+
if (!transport.consume) {
|
|
23
|
+
throw new Error(`the "${transport.name}" transport has no consumer side; there is nothing to relay here`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
get sinkNames() {
|
|
27
|
+
return [...this.sinks.keys()];
|
|
28
|
+
}
|
|
29
|
+
sink(name) {
|
|
30
|
+
return this.sinks.get(name);
|
|
31
|
+
}
|
|
32
|
+
/** Delivers up to `maxBatches` batches to `name`. */
|
|
33
|
+
async drain(name, maxBatches = 20) {
|
|
34
|
+
const sink = this.sinks.get(name);
|
|
35
|
+
if (!sink)
|
|
36
|
+
throw new Error(`unknown sink "${name}"`);
|
|
37
|
+
const result = { sink: name, delivered: 0, batches: 0, busy: false };
|
|
38
|
+
for (let i = 0; i < maxBatches; i++) {
|
|
39
|
+
const delivery = await this.transport.consume(name, {
|
|
40
|
+
batchSize: sink.batchSize ?? this.options.batchSize ?? 1000,
|
|
41
|
+
leaseMs: this.options.leaseMs ?? 60_000,
|
|
42
|
+
owner: this.owner,
|
|
43
|
+
});
|
|
44
|
+
if (!delivery) {
|
|
45
|
+
result.busy = result.batches === 0;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
if (delivery.events.length === 0) {
|
|
49
|
+
await delivery.release();
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
await sink.write(delivery.events);
|
|
54
|
+
await delivery.ack();
|
|
55
|
+
result.delivered += delivery.events.length;
|
|
56
|
+
result.batches++;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
await delivery.fail(error);
|
|
60
|
+
result.error = error instanceof Error ? error.message : String(error);
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
async drainAll(maxBatches = 20) {
|
|
67
|
+
const out = [];
|
|
68
|
+
for (const name of this.sinks.keys())
|
|
69
|
+
out.push(await this.drain(name, maxBatches));
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=relay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay.js","sourceRoot":"","sources":["../../../src/relay/relay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ExperimentResults } from '../analytics/results.js';
|
|
2
|
+
import { type SqlDatabase } from '../sql.js';
|
|
3
|
+
/** Last computed experiment results: the console reads these instead of scanning events. */
|
|
4
|
+
export interface ResultsCache {
|
|
5
|
+
get(environment: string, experiment: string): Promise<ExperimentResults | null>;
|
|
6
|
+
set(environment: string, experiment: string, results: ExperimentResults): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export declare class MemoryResultsCache implements ResultsCache {
|
|
9
|
+
#private;
|
|
10
|
+
get(environment: string, experiment: string): Promise<ExperimentResults | null>;
|
|
11
|
+
set(environment: string, experiment: string, results: ExperimentResults): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
/** `flags_results`, shared by every replica. */
|
|
14
|
+
export declare class LucidResultsCache implements ResultsCache {
|
|
15
|
+
private readonly db;
|
|
16
|
+
constructor(db: SqlDatabase);
|
|
17
|
+
get(environment: string, experiment: string): Promise<ExperimentResults | null>;
|
|
18
|
+
set(environment: string, experiment: string, results: ExperimentResults): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=results_cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"results_cache.d.ts","sourceRoot":"","sources":["../../../src/relay/results_cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAA+B,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAE1E,4FAA4F;AAC5F,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAChF,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzF;AAED,qBAAa,kBAAmB,YAAW,YAAY;;IAE/C,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,qCAEhD;IACK,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,iBAE5E;CACF;AAED,gDAAgD;AAChD,qBAAa,iBAAkB,YAAW,YAAY;IACxC,OAAO,CAAC,QAAQ,CAAC,EAAE;IAA/B,YAA6B,EAAE,EAAE,WAAW,EAAI;IAE1C,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAOpF;IAEK,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAW5F;CACF"}
|