@happyvertical/smrt-features 0.51.13 → 0.51.15

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/AGENTS.md CHANGED
@@ -20,6 +20,7 @@ Code-first feature flag system with global, app-level, and tenant-hierarchy reso
20
20
 
21
21
  - Feature keys should be namespaced by package or domain, e.g. `commerce.invoice.draft-mode`, `content.editor.ai-suggestions`
22
22
  - Definitions are code-owned. Don't write `FeatureDefinition` rows directly — use `FeatureSyncService.syncDefinitions()` at startup with the manifest of expected features
23
+ - Neither object exposes generated REST routes, MCP tools, or CLI commands (`api: false`, `mcp: false`, `cli: false`, #3013): override rows can target any scope and the object is not tenant-scoped, so a generated authentication-only surface would let any signed-in principal set another tenant's flag. Hosts write overrides server-side with `FeatureOverrideService` (which requires an explicit authorizer for every write) or `FeatureOverrideCollection.setOverride()` / `removeOverride()` only after their own authorization decision.
23
24
  - Overrides are write-time validated against the matching definition (effect must be a known `FeatureOverrideEffect`, scope must be valid for the definition's `allowedScopes`)
24
25
  - Tenant-hierarchy resolution is an optional integration wired by dependency injection (`FeatureTenantHierarchyProvider`), not a static dependency — `smrt-features` never imports `@happyvertical/smrt-users`. Without a configured provider, tenant-hierarchy resolution falls back to a flat tenant scope. (The consumer that wants hierarchy installs `smrt-users` itself and supplies the provider; `smrt-users` is a dev-only dependency here for tests.)
25
26
 
package/README.md CHANGED
@@ -53,6 +53,23 @@ The first match wins.
53
53
  - `_smrt_feature_definitions` — code-owned feature shape (default effect, allowed scopes, metadata)
54
54
  - `_smrt_feature_overrides` — runtime overrides at any scope level
55
55
 
56
+ ## Generated surfaces
57
+
58
+ `FeatureDefinition` and `FeatureOverride` ship with generated REST routes,
59
+ MCP tools, and CLI commands closed (`api: false`, `mcp: false`,
60
+ `cli: false`). Override rows are authorization state for every scope, so
61
+ write them only from server code through `FeatureOverrideService`, which
62
+ asks an authorizer you bind to the current caller before every write and
63
+ fails closed:
64
+
65
+ ```typescript
66
+ const service = new FeatureOverrideService(overrides, (request) =>
67
+ request.scopeType === 'tenant' && request.scopeId === session.tenantId &&
68
+ session.permissions.has('features.manage'),
69
+ );
70
+ await service.setOverride(key, 'tenant', session.tenantId, FeatureOverrideEffect.ENABLE);
71
+ ```
72
+
56
73
  ## Documentation
57
74
 
58
75
  - See [`AGENTS.md`](./AGENTS.md) for package-internal patterns
package/dist/index.d.ts CHANGED
@@ -75,6 +75,20 @@ export declare class FeatureOverride extends SmrtObject {
75
75
  isDisabled(): boolean;
76
76
  }
77
77
 
78
+ /** Thrown when the authorizer does not return `true`. Nothing is written. */
79
+ export declare class FeatureOverrideAuthorizationError extends Error {
80
+ readonly request: FeatureOverrideWriteRequest;
81
+ readonly status = 403;
82
+ constructor(request: FeatureOverrideWriteRequest);
83
+ }
84
+
85
+ /**
86
+ * The host's explicit authorization decision for one override write. Return
87
+ * `true` only when the current caller may write that exact scope; anything
88
+ * else denies.
89
+ */
90
+ export declare type FeatureOverrideAuthorizer = (request: FeatureOverrideWriteRequest) => boolean | Promise<boolean>;
91
+
78
92
  export declare class FeatureOverrideCollection extends SmrtCollection<FeatureOverride> {
79
93
  static readonly _itemClass: typeof FeatureOverride;
80
94
  findByFeatureKey(featureKey: string): Promise<FeatureOverride[]>;
@@ -104,6 +118,33 @@ export declare interface FeatureOverrideOptions {
104
118
  updatedAt?: Date;
105
119
  }
106
120
 
121
+ /**
122
+ * Authorized write path for feature overrides (#3013). Override rows are
123
+ * authorization state for every scope and `FeatureOverride` is not
124
+ * tenant-scoped, so generated surfaces are closed. Hosts that let callers
125
+ * change flags construct this service with an authorizer bound to the
126
+ * current caller and write through it; every write asks the authorizer
127
+ * first and fails closed.
128
+ */
129
+ export declare class FeatureOverrideService {
130
+ private readonly overrides;
131
+ private readonly authorize;
132
+ constructor(overrides: FeatureOverrideCollection, authorize: FeatureOverrideAuthorizer);
133
+ setOverride(featureKey: string, scopeType: FeatureScopeType, scopeId: string, effect: FeatureOverrideEffect): Promise<FeatureOverride>;
134
+ removeOverride(featureKey: string, scopeType: FeatureScopeType, scopeId: string): Promise<boolean>;
135
+ private require;
136
+ }
137
+
138
+ /** One override write the host must authorize before it runs (#3013). */
139
+ export declare interface FeatureOverrideWriteRequest {
140
+ operation: 'set' | 'remove';
141
+ featureKey: string;
142
+ scopeType: FeatureScopeType;
143
+ scopeId: string;
144
+ /** Present for `set`. */
145
+ effect?: FeatureOverrideEffect;
146
+ }
147
+
107
148
  export declare interface FeatureResolutionContext {
108
149
  tenantId?: string;
109
150
  }
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { FeatureOverrideEffect, GLOBAL_FEATURE_SCOPE_ID } from "./types.js";
2
2
  import { ObjectRegistry, SmrtCollection, SmrtObject, createQualifiedName, isQualifiedName, parseQualifiedName, smrt } from "@happyvertical/smrt-core";
3
3
  import { importWorkspaceModule } from "@happyvertical/smrt-core/utils/import-workspace-module";
4
4
  //#region src/__smrt-register__.ts
5
- ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-features\",\"packageVersion\":\"0.51.13\",\"objects\":{\"@happyvertical/smrt-features:FeatureDefinition\":{\"name\":\"featuredefinition\",\"className\":\"FeatureDefinition\",\"qualifiedName\":\"@happyvertical/smrt-features:FeatureDefinition\",\"collection\":\"featuredefinitions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/features/src/feature-definition.ts\",\"packageName\":\"@happyvertical/smrt-features\",\"fields\":{\"featureKey\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"packageName\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"qualifiedClassName\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"className\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"localId\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"defaultEnabled\":{\"type\":\"boolean\",\"required\":false,\"default\":false},\"label\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"description\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"metadata\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"visibility\":{\"type\":\"text\",\"required\":false,\"default\":\"public\"}},\"methods\":{\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"FeatureMetadata\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"FeatureMetadata | null\",\"optional\":false,\"unionBranches\":[{\"type\":\"FeatureMetadata\"},{\"type\":\"null\"}]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"_smrt_feature_definitions\",\"api\":{\"include\":[\"list\",\"get\"]},\"cli\":{\"include\":[\"list\",\"get\"],\"exclude\":[\"getMetadata\",\"setMetadata\"]},\"mcp\":{\"include\":[\"list\",\"get\"],\"exclude\":[\"getMetadata\",\"setMetadata\"]},\"conflictColumns\":[\"feature_key\"]},\"extends\":\"SmrtObject\",\"exportName\":\"FeatureDefinition\",\"collectionExportName\":\"FeatureDefinitionCollection\",\"schema\":{\"tableName\":\"_smrt_feature_definitions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"_smrt_feature_definitions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"feature_key\\\" TEXT DEFAULT '',\\n \\\"package_name\\\" TEXT DEFAULT '',\\n \\\"qualified_class_name\\\" TEXT DEFAULT '',\\n \\\"class_name\\\" TEXT DEFAULT '',\\n \\\"local_id\\\" TEXT DEFAULT '',\\n \\\"default_enabled\\\" BOOLEAN DEFAULT FALSE,\\n \\\"label\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"metadata\\\" TEXT DEFAULT '',\\n \\\"visibility\\\" TEXT DEFAULT 'public'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"feature_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"package_name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"qualified_class_name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"class_name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"local_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"default_enabled\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":false},\"label\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"visibility\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"public\"}},\"indexes\":[{\"name\":\"_smrt_feature_definitions_feature_key_idx\",\"columns\":[\"feature_key\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"_smrt_feature_definitions_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"_smrt_feature_definitions_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"8813204c\"},\"importPath\":\"@happyvertical/smrt-features\"},\"@happyvertical/smrt-features:FeatureDefinitionCollection\":{\"name\":\"featuredefinitioncollection\",\"className\":\"FeatureDefinitionCollection\",\"qualifiedName\":\"@happyvertical/smrt-features:FeatureDefinitionCollection\",\"collection\":\"featuredefinitions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/features/src/feature-definitions.ts\",\"packageName\":\"@happyvertical/smrt-features\",\"fields\":{},\"methods\":{\"findByFeatureKey\":{\"name\":\"findByFeatureKey\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<FeatureDefinition | null>\",\"isStatic\":false,\"isPublic\":true},\"findByPackageName\":{\"name\":\"findByPackageName\",\"async\":true,\"parameters\":[{\"name\":\"packageName\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<FeatureDefinition[]>\",\"isStatic\":false,\"isPublic\":true},\"upsertDefinition\":{\"name\":\"upsertDefinition\",\"async\":true,\"parameters\":[{\"name\":\"seed\",\"type\":\"FeatureDefinitionSeed\",\"optional\":false}],\"returnType\":\"Promise<object>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"_smrt_feature_definitions\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"FeatureDefinition\",\"exportName\":\"FeatureDefinitionCollection\",\"collectionExportName\":\"FeatureDefinitionCollectionCollection\",\"schema\":{\"tableName\":\"_smrt_feature_definitions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"_smrt_feature_definitions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"feature_key\\\" TEXT DEFAULT '',\\n \\\"package_name\\\" TEXT DEFAULT '',\\n \\\"qualified_class_name\\\" TEXT DEFAULT '',\\n \\\"class_name\\\" TEXT DEFAULT '',\\n \\\"local_id\\\" TEXT DEFAULT '',\\n \\\"default_enabled\\\" BOOLEAN DEFAULT FALSE,\\n \\\"label\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"metadata\\\" TEXT DEFAULT '',\\n \\\"visibility\\\" TEXT DEFAULT 'public'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"feature_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"package_name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"qualified_class_name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"class_name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"local_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"default_enabled\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":false},\"label\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"visibility\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"public\"}},\"indexes\":[{\"name\":\"_smrt_feature_definitions_feature_key_idx\",\"columns\":[\"feature_key\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"_smrt_feature_definitions_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"_smrt_feature_definitions_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"8813204c\"},\"importPath\":\"@happyvertical/smrt-features\"},\"@happyvertical/smrt-features:FeatureOverride\":{\"name\":\"featureoverride\",\"className\":\"FeatureOverride\",\"qualifiedName\":\"@happyvertical/smrt-features:FeatureOverride\",\"collection\":\"featureoverrides\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/features/src/feature-override.ts\",\"packageName\":\"@happyvertical/smrt-features\",\"fields\":{\"featureKey\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"scopeType\":{\"type\":\"text\",\"required\":false,\"default\":\"global\"},\"scopeId\":{\"type\":\"text\",\"required\":false},\"effect\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"isInherit\":{\"name\":\"isInherit\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isEnabled\":{\"name\":\"isEnabled\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isDisabled\":{\"name\":\"isDisabled\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"_smrt_feature_overrides\",\"api\":{\"include\":[\"list\",\"get\",\"create\",\"update\",\"delete\"]},\"cli\":{\"exclude\":[\"isInherit\",\"isEnabled\",\"isDisabled\"]},\"mcp\":{\"exclude\":[\"isInherit\",\"isEnabled\",\"isDisabled\"]},\"conflictColumns\":[\"feature_key\",\"scope_type\",\"scope_id\"]},\"extends\":\"SmrtObject\",\"exportName\":\"FeatureOverride\",\"collectionExportName\":\"FeatureOverrideCollection\",\"schema\":{\"tableName\":\"_smrt_feature_overrides\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"_smrt_feature_overrides\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"feature_key\\\" TEXT DEFAULT '',\\n \\\"scope_type\\\" TEXT DEFAULT 'global',\\n \\\"scope_id\\\" TEXT,\\n \\\"effect\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"feature_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"scope_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"global\"},\"scope_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"effect\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"_smrt_feature_overrides_feature_key_scope_type_idx\",\"columns\":[\"feature_key\",\"scope_type\",\"scope_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"_smrt_feature_overrides_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"_smrt_feature_overrides_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"d61cf901\"},\"importPath\":\"@happyvertical/smrt-features\"},\"@happyvertical/smrt-features:FeatureOverrideCollection\":{\"name\":\"featureoverridecollection\",\"className\":\"FeatureOverrideCollection\",\"qualifiedName\":\"@happyvertical/smrt-features:FeatureOverrideCollection\",\"collection\":\"featureoverrides\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/features/src/feature-overrides.ts\",\"packageName\":\"@happyvertical/smrt-features\",\"fields\":{},\"methods\":{\"findByFeatureKey\":{\"name\":\"findByFeatureKey\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride[]>\",\"isStatic\":false,\"isPublic\":true},\"findByFeatureAndScope\":{\"name\":\"findByFeatureAndScope\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"scopeType\",\"type\":\"FeatureScopeType\",\"optional\":false},{\"name\":\"scopeId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride | null>\",\"isStatic\":false,\"isPublic\":true},\"getGlobalOverride\":{\"name\":\"getGlobalOverride\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride | null>\",\"isStatic\":false,\"isPublic\":true},\"getTenantOverride\":{\"name\":\"getTenantOverride\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride | null>\",\"isStatic\":false,\"isPublic\":true},\"getOverrideMap\":{\"name\":\"getOverrideMap\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"scopeType\",\"type\":\"FeatureScopeType\",\"optional\":false},{\"name\":\"scopeIds\",\"type\":\"string[]\",\"optional\":false}],\"returnType\":\"Promise<Map<string, FeatureOverride>>\",\"isStatic\":false,\"isPublic\":true},\"setOverride\":{\"name\":\"setOverride\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"scopeType\",\"type\":\"FeatureScopeType\",\"optional\":false},{\"name\":\"scopeId\",\"type\":\"string\",\"optional\":false},{\"name\":\"effect\",\"type\":\"FeatureOverrideEffect\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride>\",\"isStatic\":false,\"isPublic\":true},\"setGlobalOverride\":{\"name\":\"setGlobalOverride\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"effect\",\"type\":\"FeatureOverrideEffect\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride>\",\"isStatic\":false,\"isPublic\":true},\"setTenantOverride\":{\"name\":\"setTenantOverride\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"effect\",\"type\":\"FeatureOverrideEffect\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride>\",\"isStatic\":false,\"isPublic\":true},\"removeOverride\":{\"name\":\"removeOverride\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"scopeType\",\"type\":\"FeatureScopeType\",\"optional\":false},{\"name\":\"scopeId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"_smrt_feature_overrides\"},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"FeatureOverride\",\"exportName\":\"FeatureOverrideCollection\",\"collectionExportName\":\"FeatureOverrideCollectionCollection\",\"schema\":{\"tableName\":\"_smrt_feature_overrides\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"_smrt_feature_overrides\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"feature_key\\\" TEXT DEFAULT '',\\n \\\"scope_type\\\" TEXT DEFAULT 'global',\\n \\\"scope_id\\\" TEXT,\\n \\\"effect\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"feature_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"scope_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"global\"},\"scope_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"effect\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"_smrt_feature_overrides_feature_key_scope_type_idx\",\"columns\":[\"feature_key\",\"scope_type\",\"scope_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"_smrt_feature_overrides_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"_smrt_feature_overrides_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"d61cf901\"},\"importPath\":\"@happyvertical/smrt-features\"}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-core\",\"@happyvertical/smrt-users\"]}"));
5
+ ObjectRegistry.registerPackageManifest(JSON.parse("{\"version\":\"1.0.0\",\"timestamp\":0,\"packageName\":\"@happyvertical/smrt-features\",\"packageVersion\":\"0.51.15\",\"objects\":{\"@happyvertical/smrt-features:FeatureDefinition\":{\"name\":\"featuredefinition\",\"className\":\"FeatureDefinition\",\"qualifiedName\":\"@happyvertical/smrt-features:FeatureDefinition\",\"collection\":\"featuredefinitions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/features/src/feature-definition.ts\",\"packageName\":\"@happyvertical/smrt-features\",\"fields\":{\"featureKey\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"packageName\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"qualifiedClassName\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"className\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"localId\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"defaultEnabled\":{\"type\":\"boolean\",\"required\":false,\"default\":false},\"label\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"description\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"metadata\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"visibility\":{\"type\":\"text\",\"required\":false,\"default\":\"public\"}},\"methods\":{\"getMetadata\":{\"name\":\"getMetadata\",\"async\":false,\"parameters\":[],\"returnType\":\"FeatureMetadata\",\"isStatic\":false,\"isPublic\":true},\"setMetadata\":{\"name\":\"setMetadata\",\"async\":false,\"parameters\":[{\"name\":\"metadata\",\"type\":\"FeatureMetadata | null\",\"optional\":false,\"unionBranches\":[{\"type\":\"FeatureMetadata\"},{\"type\":\"null\"}]}],\"returnType\":\"void\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"_smrt_feature_definitions\",\"api\":false,\"cli\":false,\"mcp\":false,\"conflictColumns\":[\"feature_key\"]},\"extends\":\"SmrtObject\",\"exportName\":\"FeatureDefinition\",\"collectionExportName\":\"FeatureDefinitionCollection\",\"schema\":{\"tableName\":\"_smrt_feature_definitions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"_smrt_feature_definitions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"feature_key\\\" TEXT DEFAULT '',\\n \\\"package_name\\\" TEXT DEFAULT '',\\n \\\"qualified_class_name\\\" TEXT DEFAULT '',\\n \\\"class_name\\\" TEXT DEFAULT '',\\n \\\"local_id\\\" TEXT DEFAULT '',\\n \\\"default_enabled\\\" BOOLEAN DEFAULT FALSE,\\n \\\"label\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"metadata\\\" TEXT DEFAULT '',\\n \\\"visibility\\\" TEXT DEFAULT 'public'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"feature_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"package_name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"qualified_class_name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"class_name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"local_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"default_enabled\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":false},\"label\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"visibility\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"public\"}},\"indexes\":[{\"name\":\"_smrt_feature_definitions_feature_key_idx\",\"columns\":[\"feature_key\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"_smrt_feature_definitions_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"_smrt_feature_definitions_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"8813204c\"},\"importPath\":\"@happyvertical/smrt-features\"},\"@happyvertical/smrt-features:FeatureDefinitionCollection\":{\"name\":\"featuredefinitioncollection\",\"className\":\"FeatureDefinitionCollection\",\"qualifiedName\":\"@happyvertical/smrt-features:FeatureDefinitionCollection\",\"collection\":\"featuredefinitions\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/features/src/feature-definitions.ts\",\"packageName\":\"@happyvertical/smrt-features\",\"fields\":{},\"methods\":{\"findByFeatureKey\":{\"name\":\"findByFeatureKey\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<FeatureDefinition | null>\",\"isStatic\":false,\"isPublic\":true},\"findByPackageName\":{\"name\":\"findByPackageName\",\"async\":true,\"parameters\":[{\"name\":\"packageName\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<FeatureDefinition[]>\",\"isStatic\":false,\"isPublic\":true},\"upsertDefinition\":{\"name\":\"upsertDefinition\",\"async\":true,\"parameters\":[{\"name\":\"seed\",\"type\":\"FeatureDefinitionSeed\",\"optional\":false}],\"returnType\":\"Promise<object>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"_smrt_feature_definitions\",\"api\":false,\"mcp\":false,\"cli\":false},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"FeatureDefinition\",\"exportName\":\"FeatureDefinitionCollection\",\"collectionExportName\":\"FeatureDefinitionCollectionCollection\",\"schema\":{\"tableName\":\"_smrt_feature_definitions\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"_smrt_feature_definitions\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"feature_key\\\" TEXT DEFAULT '',\\n \\\"package_name\\\" TEXT DEFAULT '',\\n \\\"qualified_class_name\\\" TEXT DEFAULT '',\\n \\\"class_name\\\" TEXT DEFAULT '',\\n \\\"local_id\\\" TEXT DEFAULT '',\\n \\\"default_enabled\\\" BOOLEAN DEFAULT FALSE,\\n \\\"label\\\" TEXT DEFAULT '',\\n \\\"description\\\" TEXT DEFAULT '',\\n \\\"metadata\\\" TEXT DEFAULT '',\\n \\\"visibility\\\" TEXT DEFAULT 'public'\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"feature_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"package_name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"qualified_class_name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"class_name\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"local_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"default_enabled\":{\"type\":\"BOOLEAN\",\"notNull\":false,\"unique\":false,\"default\":false},\"label\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"description\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"metadata\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"visibility\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"public\"}},\"indexes\":[{\"name\":\"_smrt_feature_definitions_feature_key_idx\",\"columns\":[\"feature_key\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"_smrt_feature_definitions_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"_smrt_feature_definitions_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"8813204c\"},\"importPath\":\"@happyvertical/smrt-features\"},\"@happyvertical/smrt-features:FeatureOverride\":{\"name\":\"featureoverride\",\"className\":\"FeatureOverride\",\"qualifiedName\":\"@happyvertical/smrt-features:FeatureOverride\",\"collection\":\"featureoverrides\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/features/src/feature-override.ts\",\"packageName\":\"@happyvertical/smrt-features\",\"fields\":{\"featureKey\":{\"type\":\"text\",\"required\":false,\"default\":\"\"},\"scopeType\":{\"type\":\"text\",\"required\":false,\"default\":\"global\"},\"scopeId\":{\"type\":\"text\",\"required\":false},\"effect\":{\"type\":\"text\",\"required\":false}},\"methods\":{\"isInherit\":{\"name\":\"isInherit\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isEnabled\":{\"name\":\"isEnabled\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true},\"isDisabled\":{\"name\":\"isDisabled\",\"async\":false,\"parameters\":[],\"returnType\":\"boolean\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"_smrt_feature_overrides\",\"api\":false,\"cli\":false,\"mcp\":false,\"conflictColumns\":[\"feature_key\",\"scope_type\",\"scope_id\"]},\"extends\":\"SmrtObject\",\"exportName\":\"FeatureOverride\",\"collectionExportName\":\"FeatureOverrideCollection\",\"schema\":{\"tableName\":\"_smrt_feature_overrides\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"_smrt_feature_overrides\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"feature_key\\\" TEXT DEFAULT '',\\n \\\"scope_type\\\" TEXT DEFAULT 'global',\\n \\\"scope_id\\\" TEXT,\\n \\\"effect\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"feature_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"scope_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"global\"},\"scope_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"effect\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"_smrt_feature_overrides_feature_key_scope_type_idx\",\"columns\":[\"feature_key\",\"scope_type\",\"scope_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"_smrt_feature_overrides_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"_smrt_feature_overrides_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"d61cf901\"},\"importPath\":\"@happyvertical/smrt-features\"},\"@happyvertical/smrt-features:FeatureOverrideCollection\":{\"name\":\"featureoverridecollection\",\"className\":\"FeatureOverrideCollection\",\"qualifiedName\":\"@happyvertical/smrt-features:FeatureOverrideCollection\",\"collection\":\"featureoverrides\",\"filePath\":\"/home/runner/work/smrt/smrt/packages/features/src/feature-overrides.ts\",\"packageName\":\"@happyvertical/smrt-features\",\"fields\":{},\"methods\":{\"findByFeatureKey\":{\"name\":\"findByFeatureKey\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride[]>\",\"isStatic\":false,\"isPublic\":true},\"findByFeatureAndScope\":{\"name\":\"findByFeatureAndScope\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"scopeType\",\"type\":\"FeatureScopeType\",\"optional\":false},{\"name\":\"scopeId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride | null>\",\"isStatic\":false,\"isPublic\":true},\"getGlobalOverride\":{\"name\":\"getGlobalOverride\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride | null>\",\"isStatic\":false,\"isPublic\":true},\"getTenantOverride\":{\"name\":\"getTenantOverride\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride | null>\",\"isStatic\":false,\"isPublic\":true},\"getOverrideMap\":{\"name\":\"getOverrideMap\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"scopeType\",\"type\":\"FeatureScopeType\",\"optional\":false},{\"name\":\"scopeIds\",\"type\":\"string[]\",\"optional\":false}],\"returnType\":\"Promise<Map<string, FeatureOverride>>\",\"isStatic\":false,\"isPublic\":true},\"setOverride\":{\"name\":\"setOverride\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"scopeType\",\"type\":\"FeatureScopeType\",\"optional\":false},{\"name\":\"scopeId\",\"type\":\"string\",\"optional\":false},{\"name\":\"effect\",\"type\":\"FeatureOverrideEffect\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride>\",\"isStatic\":false,\"isPublic\":true},\"setGlobalOverride\":{\"name\":\"setGlobalOverride\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"effect\",\"type\":\"FeatureOverrideEffect\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride>\",\"isStatic\":false,\"isPublic\":true},\"setTenantOverride\":{\"name\":\"setTenantOverride\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"tenantId\",\"type\":\"string\",\"optional\":false},{\"name\":\"effect\",\"type\":\"FeatureOverrideEffect\",\"optional\":false}],\"returnType\":\"Promise<FeatureOverride>\",\"isStatic\":false,\"isPublic\":true},\"removeOverride\":{\"name\":\"removeOverride\",\"async\":true,\"parameters\":[{\"name\":\"featureKey\",\"type\":\"string\",\"optional\":false},{\"name\":\"scopeType\",\"type\":\"FeatureScopeType\",\"optional\":false},{\"name\":\"scopeId\",\"type\":\"string\",\"optional\":false}],\"returnType\":\"Promise<boolean>\",\"isStatic\":false,\"isPublic\":true}},\"decoratorConfig\":{\"tableName\":\"_smrt_feature_overrides\",\"api\":false,\"mcp\":false,\"cli\":false},\"extends\":\"SmrtCollection\",\"extendsTypeArg\":\"FeatureOverride\",\"exportName\":\"FeatureOverrideCollection\",\"collectionExportName\":\"FeatureOverrideCollectionCollection\",\"schema\":{\"tableName\":\"_smrt_feature_overrides\",\"ddl\":\"CREATE TABLE IF NOT EXISTS \\\"_smrt_feature_overrides\\\" (\\n \\\"id\\\" UUID PRIMARY KEY NOT NULL,\\n \\\"slug\\\" TEXT NOT NULL,\\n \\\"context\\\" TEXT NOT NULL DEFAULT '',\\n \\\"created_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"updated_at\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\\"feature_key\\\" TEXT DEFAULT '',\\n \\\"scope_type\\\" TEXT DEFAULT 'global',\\n \\\"scope_id\\\" TEXT,\\n \\\"effect\\\" TEXT\\n);\",\"columns\":{\"id\":{\"type\":\"UUID\",\"primaryKey\":true,\"referenceKind\":\"id\",\"notNull\":true},\"slug\":{\"type\":\"TEXT\",\"notNull\":true},\"context\":{\"type\":\"TEXT\",\"notNull\":true,\"default\":\"\"},\"created_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"updated_at\":{\"type\":\"TIMESTAMP\",\"notNull\":true,\"default\":\"current_timestamp\"},\"feature_key\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"\"},\"scope_type\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false,\"default\":\"global\"},\"scope_id\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false},\"effect\":{\"type\":\"TEXT\",\"notNull\":false,\"unique\":false}},\"indexes\":[{\"name\":\"_smrt_feature_overrides_feature_key_scope_type_idx\",\"columns\":[\"feature_key\",\"scope_type\",\"scope_id\"],\"unique\":true,\"nullsNotDistinct\":true},{\"name\":\"_smrt_feature_overrides_slug_context_idx\",\"columns\":[\"slug\",\"context\"]},{\"name\":\"_smrt_feature_overrides_created_at_idx\",\"columns\":[\"created_at\"]}],\"version\":\"d61cf901\"},\"importPath\":\"@happyvertical/smrt-features\"}},\"moduleType\":\"smrt\",\"smrtDependencies\":[\"@happyvertical/smrt-core\",\"@happyvertical/smrt-users\"]}"));
6
6
  //#endregion
7
7
  //#region src/utils.ts
8
8
  function createFeatureKey(qualifiedClassName, localId) {
@@ -190,15 +190,9 @@ var FeatureDefinition = class extends SmrtObject {
190
190
  };
191
191
  FeatureDefinition = __decorateClass$1([smrt({
192
192
  tableName: "_smrt_feature_definitions",
193
- api: { include: ["list", "get"] },
194
- cli: {
195
- include: ["list", "get"],
196
- exclude: ["getMetadata", "setMetadata"]
197
- },
198
- mcp: {
199
- include: ["list", "get"],
200
- exclude: ["getMetadata", "setMetadata"]
201
- },
193
+ api: false,
194
+ cli: false,
195
+ mcp: false,
202
196
  conflictColumns: ["feature_key"]
203
197
  })], FeatureDefinition);
204
198
  //#endregion
@@ -282,23 +276,9 @@ var FeatureOverride = class extends SmrtObject {
282
276
  };
283
277
  FeatureOverride = __decorateClass([smrt({
284
278
  tableName: "_smrt_feature_overrides",
285
- api: { include: [
286
- "list",
287
- "get",
288
- "create",
289
- "update",
290
- "delete"
291
- ] },
292
- cli: { exclude: [
293
- "isInherit",
294
- "isEnabled",
295
- "isDisabled"
296
- ] },
297
- mcp: { exclude: [
298
- "isInherit",
299
- "isEnabled",
300
- "isDisabled"
301
- ] },
279
+ api: false,
280
+ cli: false,
281
+ mcp: false,
302
282
  conflictColumns: [
303
283
  "feature_key",
304
284
  "scope_type",
@@ -306,6 +286,53 @@ FeatureOverride = __decorateClass([smrt({
306
286
  ]
307
287
  })], FeatureOverride);
308
288
  //#endregion
289
+ //#region src/feature-override-service.ts
290
+ var FeatureOverrideAuthorizationError = class extends Error {
291
+ constructor(request) {
292
+ super(`Feature override ${request.operation} denied for ${request.scopeType} scope`);
293
+ this.request = request;
294
+ this.name = "FeatureOverrideAuthorizationError";
295
+ }
296
+ request;
297
+ status = 403;
298
+ };
299
+ var FeatureOverrideService = class {
300
+ constructor(overrides, authorize) {
301
+ this.overrides = overrides;
302
+ this.authorize = authorize;
303
+ }
304
+ overrides;
305
+ authorize;
306
+ async setOverride(featureKey, scopeType, scopeId, effect) {
307
+ await this.require({
308
+ operation: "set",
309
+ featureKey,
310
+ scopeType,
311
+ scopeId,
312
+ effect
313
+ });
314
+ return this.overrides.setOverride(featureKey, scopeType, scopeId, effect);
315
+ }
316
+ async removeOverride(featureKey, scopeType, scopeId) {
317
+ await this.require({
318
+ operation: "remove",
319
+ featureKey,
320
+ scopeType,
321
+ scopeId
322
+ });
323
+ return this.overrides.removeOverride(featureKey, scopeType, scopeId);
324
+ }
325
+ async require(request) {
326
+ let allowed = false;
327
+ try {
328
+ allowed = await this.authorize(request) === true;
329
+ } catch {
330
+ allowed = false;
331
+ }
332
+ if (!allowed) throw new FeatureOverrideAuthorizationError(request);
333
+ }
334
+ };
335
+ //#endregion
309
336
  //#region src/feature-overrides.ts
310
337
  var FeatureOverrideCollection = class extends SmrtCollection {
311
338
  static _itemClass = FeatureOverride;
@@ -554,6 +581,6 @@ var FeatureSyncService = class {
554
581
  }
555
582
  };
556
583
  //#endregion
557
- export { FeatureDefinition, FeatureDefinitionCollection, FeatureOverride, FeatureOverrideCollection, FeatureOverrideEffect, FeatureResolver, FeatureSyncService, GLOBAL_FEATURE_SCOPE_ID, createFeatureKey, findFeatureDefaultInRegistry, parseFeatureKey, resolveFeatureKeyForTarget };
584
+ export { FeatureDefinition, FeatureDefinitionCollection, FeatureOverride, FeatureOverrideAuthorizationError, FeatureOverrideCollection, FeatureOverrideEffect, FeatureOverrideService, FeatureResolver, FeatureSyncService, GLOBAL_FEATURE_SCOPE_ID, createFeatureKey, findFeatureDefaultInRegistry, parseFeatureKey, resolveFeatureKeyForTarget };
558
585
 
559
586
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/__smrt-register__.ts","../src/utils.ts","../src/feature-definition.ts","../src/feature-definitions.ts","../src/feature-override.ts","../src/feature-overrides.ts","../src/feature-resolver.ts","../src/feature-sync.ts"],"sourcesContent":["/**\n * Self-registers this package's build-time manifest before any @smrt() decorator\n * in the package fires. Fixes issue #1132: in consumer runtimes (tsx, SvelteKit\n * SSR, plain `vite dev`) the decorator's synchronous manifest lookup previously\n * missed because no step populated the global manifest cache — classes got\n * registered with zero fields and `save()` / `toJSON()` silently dropped every\n * declared property.\n *\n * Import this module as the first statement in `src/index.ts` so its top-level\n * side effect runs ahead of any class module's @smrt() decorator.\n *\n * Silent no-op in dev/test, where the vitest plugin already populates manifests\n * via a different path. Only needs to succeed in the published dist output.\n *\n * @see https://github.com/happyvertical/smrt/issues/1132\n */\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n// During library builds, smrtPlugin replaces this entire module with generated\n// code that embeds the scanned manifest inline (#1506/#1507) — published dists\n// never resolve this URL, so downstream bundlers cannot break registration by\n// relocating the compiled module away from dist/manifest.json. The runtime\n// lookup below is the fallback for source-mode runs without that transform.\nObjectRegistry.registerPackageManifest(\n new URL('./manifest.json', import.meta.url),\n);\n","import {\n createQualifiedName,\n isQualifiedName,\n ObjectRegistry,\n parseQualifiedName,\n type SmartObjectConfig,\n} from '@happyvertical/smrt-core';\nimport type {\n SmartObjectDefinition,\n SmartObjectManifest,\n} from '@happyvertical/smrt-core/manifest';\nimport type {\n FeatureDefinitionSeed,\n FeatureMetadata,\n FeatureTargetConstructor,\n} from './types.js';\n\nexport type RegistryEntryLike = {\n name: string;\n qualifiedName?: string;\n packageName?: string;\n config: SmartObjectConfig;\n visibility?: string;\n};\n\nexport function createFeatureKey(\n qualifiedClassName: string,\n localId: string,\n): string {\n if (!isQualifiedName(qualifiedClassName)) {\n throw new Error(\n `Feature keys require a qualified class name. Received \"${qualifiedClassName}\".`,\n );\n }\n\n if (!localId) {\n throw new Error('Feature localId is required.');\n }\n\n if (localId.includes('#')) {\n throw new Error(\n `Feature localId \"${localId}\" cannot contain \"#\". This character is reserved for canonical feature keys.`,\n );\n }\n\n return `${qualifiedClassName}#${localId}`;\n}\n\nexport function parseFeatureKey(featureKey: string): {\n qualifiedClassName: string;\n localId: string;\n} {\n const separatorIndex = featureKey.lastIndexOf('#');\n if (separatorIndex <= 0 || separatorIndex === featureKey.length - 1) {\n throw new Error(\n `Invalid feature key \"${featureKey}\". Expected format \"<qualifiedClassName>#<localId>\".`,\n );\n }\n\n const qualifiedClassName = featureKey.slice(0, separatorIndex);\n const localId = featureKey.slice(separatorIndex + 1);\n\n if (!isQualifiedName(qualifiedClassName)) {\n throw new Error(\n `Invalid feature key \"${featureKey}\". \"${qualifiedClassName}\" is not a qualified class name.`,\n );\n }\n\n return { qualifiedClassName, localId };\n}\n\nexport function serializeFeatureMetadata(\n metadata: FeatureMetadata | string | null | undefined,\n): string {\n if (!metadata) {\n return '';\n }\n\n if (typeof metadata === 'string') {\n const parsed = parseFeatureMetadataString(metadata);\n return JSON.stringify(parsed);\n }\n\n if (!isFeatureMetadataRecord(metadata)) {\n throw new Error(\n 'Feature metadata must be a plain object or a JSON string representing a plain object.',\n );\n }\n\n return JSON.stringify(metadata);\n}\n\nexport function parseFeatureMetadata(\n metadata: string | null | undefined,\n): FeatureMetadata {\n if (!metadata) {\n return {};\n }\n\n try {\n return parseFeatureMetadataString(metadata);\n } catch {\n return {};\n }\n}\n\nfunction parseFeatureMetadataString(metadata: string): FeatureMetadata {\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(metadata);\n } catch (error) {\n throw new Error(\n 'Feature metadata must be a plain object or a JSON string representing a plain object.',\n { cause: error },\n );\n }\n\n if (!isFeatureMetadataRecord(parsed)) {\n throw new Error(\n 'Feature metadata must be a plain object or a JSON string representing a plain object.',\n );\n }\n\n return parsed;\n}\n\nfunction isFeatureMetadataRecord(value: unknown): value is FeatureMetadata {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nexport function getQualifiedClassNameFromRegistry(\n registration: RegistryEntryLike,\n): string | null {\n if (\n registration.qualifiedName &&\n isQualifiedName(registration.qualifiedName)\n ) {\n return registration.qualifiedName;\n }\n\n if (registration.packageName) {\n return createQualifiedName(registration.packageName, registration.name);\n }\n\n return null;\n}\n\nexport function getPackageNameFromRegistry(\n registration: RegistryEntryLike,\n): string | null {\n if (registration.packageName) {\n return registration.packageName;\n }\n\n const qualifiedClassName = getQualifiedClassNameFromRegistry(registration);\n if (!qualifiedClassName) {\n return null;\n }\n\n return parseQualifiedName(qualifiedClassName).packageName;\n}\n\nexport function extractFeatureSeedsFromRegistryEntry(\n registration: RegistryEntryLike,\n): FeatureDefinitionSeed[] {\n if (registration.visibility === 'test') {\n return [];\n }\n\n const qualifiedClassName = getQualifiedClassNameFromRegistry(registration);\n if (!qualifiedClassName) {\n return [];\n }\n\n const featureConfig = registration.config.features;\n if (!featureConfig) {\n return [];\n }\n\n const packageName =\n registration.packageName ||\n parseQualifiedName(qualifiedClassName).packageName;\n\n return Object.entries(featureConfig).map(([localId, feature]) => ({\n featureKey: createFeatureKey(qualifiedClassName, localId),\n packageName,\n qualifiedClassName,\n className: registration.name,\n localId,\n defaultEnabled: feature.defaultEnabled,\n label: feature.label,\n description: feature.description,\n metadata: feature.metadata,\n visibility: registration.visibility,\n }));\n}\n\nexport function extractFeatureSeedsFromManifest(\n manifest: SmartObjectManifest,\n): FeatureDefinitionSeed[] {\n const seeds: FeatureDefinitionSeed[] = [];\n\n for (const [objectKey, objectDef] of Object.entries(manifest.objects)) {\n seeds.push(...extractFeatureSeedsFromManifestObject(objectKey, objectDef));\n }\n\n return seeds;\n}\n\nexport function extractTouchedPackagesFromManifest(\n manifest: SmartObjectManifest,\n): Set<string> {\n const packages = new Set<string>();\n\n if (manifest.packageName) {\n packages.add(manifest.packageName);\n }\n\n for (const [objectKey, objectDef] of Object.entries(manifest.objects)) {\n if (objectDef.visibility === 'test') {\n continue;\n }\n\n if (objectDef.packageName) {\n packages.add(objectDef.packageName);\n continue;\n }\n\n const qualifiedClassName = resolveManifestQualifiedClassName(\n objectKey,\n objectDef,\n );\n if (qualifiedClassName) {\n packages.add(parseQualifiedName(qualifiedClassName).packageName);\n }\n }\n\n return packages;\n}\n\nfunction extractFeatureSeedsFromManifestObject(\n objectKey: string,\n objectDef: SmartObjectDefinition,\n): FeatureDefinitionSeed[] {\n if (objectDef.visibility === 'test') {\n return [];\n }\n\n const features = objectDef.decoratorConfig.features;\n if (!features) {\n return [];\n }\n\n const qualifiedClassName = resolveManifestQualifiedClassName(\n objectKey,\n objectDef,\n );\n if (!qualifiedClassName) {\n return [];\n }\n\n const packageName =\n objectDef.packageName || parseQualifiedName(qualifiedClassName).packageName;\n\n return Object.entries(features).map(([localId, feature]) => ({\n featureKey: createFeatureKey(qualifiedClassName, localId),\n packageName,\n qualifiedClassName,\n className: objectDef.className,\n localId,\n defaultEnabled: feature.defaultEnabled,\n label: feature.label,\n description: feature.description,\n metadata:\n feature.metadata && typeof feature.metadata === 'object'\n ? (feature.metadata as FeatureMetadata)\n : undefined,\n visibility: objectDef.visibility,\n }));\n}\n\nfunction resolveManifestQualifiedClassName(\n objectKey: string,\n objectDef: SmartObjectDefinition,\n): string | null {\n if (objectDef.qualifiedName && isQualifiedName(objectDef.qualifiedName)) {\n return objectDef.qualifiedName;\n }\n\n if (isQualifiedName(objectKey)) {\n return objectKey;\n }\n\n if (objectDef.packageName) {\n return createQualifiedName(objectDef.packageName, objectDef.className);\n }\n\n return null;\n}\n\nexport function resolveFeatureKeyForTarget(\n classOrInstance: object | FeatureTargetConstructor,\n localId: string,\n): {\n featureKey: string;\n defaultEnabled: boolean;\n} {\n const ctor: FeatureTargetConstructor =\n typeof classOrInstance === 'function'\n ? (classOrInstance as FeatureTargetConstructor)\n : (classOrInstance.constructor as FeatureTargetConstructor);\n\n const registration = ObjectRegistry.getClassByConstructor(ctor);\n if (!registration) {\n throw new Error(\n `Cannot resolve feature \"${localId}\" because ${ctor?.name || 'the target class'} is not registered with @smrt().`,\n );\n }\n\n const qualifiedClassName = getQualifiedClassNameFromRegistry(registration);\n if (!qualifiedClassName) {\n throw new Error(\n `Cannot resolve feature \"${localId}\" for ${registration.name} because the class has no qualified package identity.`,\n );\n }\n\n const feature = registration.config.features?.[localId];\n if (!feature) {\n throw new Error(\n `Feature \"${localId}\" is not declared on ${qualifiedClassName}.`,\n );\n }\n\n return {\n featureKey: createFeatureKey(qualifiedClassName, localId),\n defaultEnabled: feature.defaultEnabled,\n };\n}\n\nexport function findFeatureDefaultInRegistry(\n featureKey: string,\n): boolean | undefined {\n const { qualifiedClassName, localId } = parseFeatureKey(featureKey);\n const registration =\n ObjectRegistry.getClassByQualifiedName(qualifiedClassName) ||\n ObjectRegistry.getClass(qualifiedClassName);\n\n const feature = registration?.config.features?.[localId];\n return feature?.defaultEnabled;\n}\n","import { SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport type { FeatureDefinitionOptions, FeatureMetadata } from './types.js';\nimport { parseFeatureMetadata, serializeFeatureMetadata } from './utils.js';\n\n@smrt({\n tableName: '_smrt_feature_definitions',\n api: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'], exclude: ['getMetadata', 'setMetadata'] },\n mcp: { include: ['list', 'get'], exclude: ['getMetadata', 'setMetadata'] },\n conflictColumns: ['feature_key'],\n})\nexport class FeatureDefinition extends SmrtObject {\n featureKey: string = '';\n packageName: string = '';\n qualifiedClassName: string = '';\n className: string = '';\n localId: string = '';\n defaultEnabled: boolean = false;\n label: string = '';\n description: string = '';\n metadata: string = '';\n visibility: string = 'public';\n\n constructor(options: FeatureDefinitionOptions = {}) {\n super(options);\n\n if (options.featureKey !== undefined) this.featureKey = options.featureKey;\n if (options.packageName !== undefined)\n this.packageName = options.packageName;\n if (options.qualifiedClassName !== undefined) {\n this.qualifiedClassName = options.qualifiedClassName;\n }\n if (options.className !== undefined) this.className = options.className;\n if (options.localId !== undefined) this.localId = options.localId;\n if (options.defaultEnabled !== undefined) {\n this.defaultEnabled = options.defaultEnabled;\n }\n if (options.label !== undefined) this.label = options.label;\n if (options.description !== undefined)\n this.description = options.description;\n if (options.visibility !== undefined) this.visibility = options.visibility;\n if (options.metadata !== undefined) {\n this.metadata = serializeFeatureMetadata(options.metadata);\n }\n }\n\n getMetadata(): FeatureMetadata {\n return parseFeatureMetadata(this.metadata);\n }\n\n setMetadata(metadata: FeatureMetadata | null): void {\n this.metadata = serializeFeatureMetadata(metadata);\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { FeatureDefinition } from './feature-definition.js';\nimport type { FeatureDefinitionSeed } from './types.js';\nimport { serializeFeatureMetadata } from './utils.js';\n\nexport class FeatureDefinitionCollection extends SmrtCollection<FeatureDefinition> {\n static readonly _itemClass = FeatureDefinition;\n\n async findByFeatureKey(\n featureKey: string,\n ): Promise<FeatureDefinition | null> {\n const results = await this.list({\n where: { featureKey },\n limit: 1,\n });\n return results[0] ?? null;\n }\n\n async findByPackageName(packageName: string): Promise<FeatureDefinition[]> {\n return this.list({\n where: { packageName },\n });\n }\n\n async upsertDefinition(seed: FeatureDefinitionSeed): Promise<{\n definition: FeatureDefinition;\n status: 'created' | 'updated' | 'unchanged';\n }> {\n const existing = await this.findByFeatureKey(seed.featureKey);\n\n if (!existing) {\n const created = await this.create({\n ...seed,\n metadata: serializeFeatureMetadata(seed.metadata),\n });\n await created.save();\n return { definition: created, status: 'created' };\n }\n\n const nextMetadata = serializeFeatureMetadata(seed.metadata);\n const changed =\n existing.packageName !== seed.packageName ||\n existing.qualifiedClassName !== seed.qualifiedClassName ||\n existing.className !== seed.className ||\n existing.localId !== seed.localId ||\n existing.defaultEnabled !== seed.defaultEnabled ||\n existing.label !== (seed.label ?? '') ||\n existing.description !== (seed.description ?? '') ||\n existing.metadata !== nextMetadata ||\n existing.visibility !== (seed.visibility ?? 'public');\n\n if (!changed) {\n return { definition: existing, status: 'unchanged' };\n }\n\n existing.packageName = seed.packageName;\n existing.qualifiedClassName = seed.qualifiedClassName;\n existing.className = seed.className;\n existing.localId = seed.localId;\n existing.defaultEnabled = seed.defaultEnabled;\n existing.label = seed.label ?? '';\n existing.description = seed.description ?? '';\n existing.metadata = nextMetadata;\n existing.visibility = seed.visibility ?? 'public';\n await existing.save();\n\n return { definition: existing, status: 'updated' };\n }\n}\n","import { SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport {\n FeatureOverrideEffect,\n type FeatureOverrideOptions,\n type FeatureScopeType,\n GLOBAL_FEATURE_SCOPE_ID,\n} from './types.js';\n\n@smrt({\n tableName: '_smrt_feature_overrides',\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n cli: {\n exclude: ['isInherit', 'isEnabled', 'isDisabled'],\n },\n mcp: {\n exclude: ['isInherit', 'isEnabled', 'isDisabled'],\n },\n conflictColumns: ['feature_key', 'scope_type', 'scope_id'],\n})\nexport class FeatureOverride extends SmrtObject {\n featureKey: string = '';\n scopeType: FeatureScopeType = 'global';\n scopeId: string = GLOBAL_FEATURE_SCOPE_ID;\n effect: FeatureOverrideEffect = FeatureOverrideEffect.INHERIT;\n\n constructor(options: FeatureOverrideOptions = {}) {\n super(options);\n\n if (options.featureKey !== undefined) this.featureKey = options.featureKey;\n if (options.scopeType !== undefined) this.scopeType = options.scopeType;\n if (options.scopeId !== undefined) this.scopeId = options.scopeId;\n if (options.effect !== undefined) this.effect = options.effect;\n }\n\n isInherit(): boolean {\n return this.effect === FeatureOverrideEffect.INHERIT;\n }\n\n isEnabled(): boolean {\n return this.effect === FeatureOverrideEffect.ENABLE;\n }\n\n isDisabled(): boolean {\n return this.effect === FeatureOverrideEffect.DISABLE;\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { FeatureOverride } from './feature-override.js';\nimport {\n type FeatureOverrideEffect,\n type FeatureScopeType,\n GLOBAL_FEATURE_SCOPE_ID,\n} from './types.js';\n\nexport class FeatureOverrideCollection extends SmrtCollection<FeatureOverride> {\n static readonly _itemClass = FeatureOverride;\n\n async findByFeatureKey(featureKey: string): Promise<FeatureOverride[]> {\n return this.list({\n where: { featureKey },\n });\n }\n\n async findByFeatureAndScope(\n featureKey: string,\n scopeType: FeatureScopeType,\n scopeId: string,\n ): Promise<FeatureOverride | null> {\n const results = await this.list({\n where: { featureKey, scopeType, scopeId },\n limit: 1,\n });\n return results[0] ?? null;\n }\n\n async getGlobalOverride(featureKey: string): Promise<FeatureOverride | null> {\n return this.findByFeatureAndScope(\n featureKey,\n 'global',\n GLOBAL_FEATURE_SCOPE_ID,\n );\n }\n\n async getTenantOverride(\n featureKey: string,\n tenantId: string,\n ): Promise<FeatureOverride | null> {\n return this.findByFeatureAndScope(featureKey, 'tenant', tenantId);\n }\n\n async getOverrideMap(\n featureKey: string,\n scopeType: FeatureScopeType,\n scopeIds: string[],\n ): Promise<Map<string, FeatureOverride>> {\n const result = new Map<string, FeatureOverride>();\n if (scopeIds.length === 0) {\n return result;\n }\n\n const overrides = await this.list({\n where: { featureKey, scopeType, scopeId: scopeIds },\n });\n\n for (const override of overrides) {\n result.set(override.scopeId, override);\n }\n\n return result;\n }\n\n async setOverride(\n featureKey: string,\n scopeType: FeatureScopeType,\n scopeId: string,\n effect: FeatureOverrideEffect,\n ): Promise<FeatureOverride> {\n const existing = await this.findByFeatureAndScope(\n featureKey,\n scopeType,\n scopeId,\n );\n\n if (existing) {\n existing.effect = effect;\n await existing.save();\n return existing;\n }\n\n const created = await this.create({\n featureKey,\n scopeType,\n scopeId,\n effect,\n });\n await created.save();\n return created;\n }\n\n async setGlobalOverride(\n featureKey: string,\n effect: FeatureOverrideEffect,\n ): Promise<FeatureOverride> {\n return this.setOverride(\n featureKey,\n 'global',\n GLOBAL_FEATURE_SCOPE_ID,\n effect,\n );\n }\n\n async setTenantOverride(\n featureKey: string,\n tenantId: string,\n effect: FeatureOverrideEffect,\n ): Promise<FeatureOverride> {\n return this.setOverride(featureKey, 'tenant', tenantId, effect);\n }\n\n async removeOverride(\n featureKey: string,\n scopeType: FeatureScopeType,\n scopeId: string,\n ): Promise<boolean> {\n const existing = await this.findByFeatureAndScope(\n featureKey,\n scopeType,\n scopeId,\n );\n\n if (!existing) {\n return false;\n }\n\n await existing.delete();\n return true;\n }\n}\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport { importWorkspaceModule } from '@happyvertical/smrt-core/utils/import-workspace-module';\nimport { FeatureDefinitionCollection } from './feature-definitions.js';\nimport { FeatureOverrideCollection } from './feature-overrides.js';\nimport {\n FeatureOverrideEffect,\n type FeatureResolutionContext,\n type FeatureResolverOptions,\n type FeatureTargetConstructor,\n type FeatureTenantHierarchyProvider,\n type FeatureTenantNode,\n type FeatureUsersModule,\n} from './types.js';\nimport {\n findFeatureDefaultInRegistry,\n resolveFeatureKeyForTarget,\n} from './utils.js';\n\nexport class FeatureResolver {\n private readonly options: SmrtClassOptions;\n private readonly resolverOptions: FeatureResolverOptions;\n private featureDefinitions!: FeatureDefinitionCollection;\n private featureOverrides!: FeatureOverrideCollection;\n private initializationPromise: Promise<void> | null = null;\n private tenantHierarchyPromise: Promise<FeatureTenantHierarchyProvider | null> | null =\n null;\n\n constructor(\n options: SmrtClassOptions = {},\n resolverOptions: FeatureResolverOptions = {},\n ) {\n this.options = options;\n this.resolverOptions = resolverOptions;\n }\n\n async isEnabled(\n featureKey: string,\n context: FeatureResolutionContext = {},\n ): Promise<boolean> {\n await this.ensureInitialized();\n\n const baseState = await this.resolveBaseState(featureKey);\n const globalOverride =\n await this.featureOverrides.getGlobalOverride(featureKey);\n const globalState = this.applyOverride(baseState, globalOverride?.effect);\n\n if (!context.tenantId) {\n return globalState;\n }\n\n const tenantHierarchy = await this.getTenantHierarchy();\n if (!tenantHierarchy) {\n const directOverride = await this.featureOverrides.getTenantOverride(\n featureKey,\n context.tenantId,\n );\n return this.applyOverride(globalState, directOverride?.effect);\n }\n\n const chain = await tenantHierarchy.getChain(context.tenantId);\n if (chain.length === 0) {\n const directOverride = await this.featureOverrides.getTenantOverride(\n featureKey,\n context.tenantId,\n );\n return this.applyOverride(globalState, directOverride?.effect);\n }\n\n const overrides = await this.featureOverrides.getOverrideMap(\n featureKey,\n 'tenant',\n chain.map((node) => node.id),\n );\n\n let inheritedState = globalState;\n\n for (let index = 0; index < chain.length; index++) {\n const current = chain[index];\n const previous = index > 0 ? chain[index - 1] : null;\n const shouldInherit =\n index === 0 ||\n (!!previous?.cascadePermissions && current.inheritPermissions);\n\n const baseline = shouldInherit ? inheritedState : globalState;\n const override = overrides.get(current.id);\n inheritedState = this.applyOverride(baseline, override?.effect);\n }\n\n return inheritedState;\n }\n\n async isEnabledFor(\n classOrInstance: object | FeatureTargetConstructor,\n localId: string,\n context: FeatureResolutionContext = {},\n ): Promise<boolean> {\n const { featureKey } = resolveFeatureKeyForTarget(classOrInstance, localId);\n return this.isEnabled(featureKey, context);\n }\n\n private async ensureInitialized(): Promise<void> {\n if (!this.initializationPromise) {\n this.initializationPromise = (async () => {\n this.featureDefinitions = await FeatureDefinitionCollection.create(\n this.options,\n );\n this.featureOverrides = await FeatureOverrideCollection.create(\n this.options,\n );\n })();\n }\n\n await this.initializationPromise;\n }\n\n private async resolveBaseState(featureKey: string): Promise<boolean> {\n const registryDefault = findFeatureDefaultInRegistry(featureKey);\n if (registryDefault !== undefined) {\n return registryDefault;\n }\n\n const definition =\n await this.featureDefinitions.findByFeatureKey(featureKey);\n if (!definition) {\n throw new Error(\n `Feature \"${featureKey}\" is not declared in the registry or synced feature definitions.`,\n );\n }\n\n return definition.defaultEnabled;\n }\n\n private applyOverride(\n currentState: boolean,\n effect: FeatureOverrideEffect | undefined,\n ): boolean {\n switch (effect) {\n case FeatureOverrideEffect.ENABLE:\n return true;\n case FeatureOverrideEffect.DISABLE:\n return false;\n default:\n return currentState;\n }\n }\n\n private async getTenantHierarchy(): Promise<FeatureTenantHierarchyProvider | null> {\n if (!this.tenantHierarchyPromise) {\n const loader =\n this.resolverOptions.tenantHierarchyLoader ||\n defaultTenantHierarchyLoader;\n this.tenantHierarchyPromise = loader(this.options);\n }\n\n return this.tenantHierarchyPromise;\n }\n}\n\nasync function defaultTenantHierarchyLoader(\n options: SmrtClassOptions,\n): Promise<FeatureTenantHierarchyProvider | null> {\n try {\n const usersModule = await importWorkspaceModule<FeatureUsersModule>({\n packageName: '@happyvertical/smrt-users',\n sourceEntry: 'packages/users/src/collections/index.ts',\n purpose: 'tenant-aware feature flag resolution',\n });\n\n const tenantCollection = await usersModule.TenantCollection.create(options);\n return {\n async getChain(tenantId: string): Promise<FeatureTenantNode[]> {\n const tenant = await tenantCollection.get({ id: tenantId });\n if (!tenant) {\n return [];\n }\n\n const ancestors = await tenantCollection.getAncestorsFromRoot(tenantId);\n return [...ancestors, tenant].map((node) => ({\n id: String(node.id),\n inheritPermissions: Boolean(node.inheritPermissions),\n cascadePermissions: Boolean(node.cascadePermissions),\n }));\n },\n };\n } catch (error) {\n if (isMissingUsersDependency(error)) {\n return null;\n }\n throw error;\n }\n}\n\nfunction isMissingUsersDependency(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n\n const causeMessage =\n error.cause instanceof Error ? ` ${error.cause.message}` : '';\n const text = `${error.message}${causeMessage}`;\n\n return (\n text.includes('@happyvertical/smrt-users') &&\n (text.includes('Cannot find module') ||\n text.includes('Failed to load') ||\n text.includes('could not find'))\n );\n}\n","import {\n ObjectRegistry,\n type SmrtClassOptions,\n} from '@happyvertical/smrt-core';\nimport type { SmartObjectManifest } from '@happyvertical/smrt-core/manifest';\nimport { FeatureDefinitionCollection } from './feature-definitions.js';\nimport type {\n FeatureDefinitionSeed,\n FeatureSyncResult,\n SyncDefinitionsOptions,\n SyncManifestOptions,\n} from './types.js';\nimport {\n extractFeatureSeedsFromManifest,\n extractFeatureSeedsFromRegistryEntry,\n extractTouchedPackagesFromManifest,\n getPackageNameFromRegistry,\n type RegistryEntryLike,\n} from './utils.js';\n\nexport class FeatureSyncService {\n private readonly options: SmrtClassOptions;\n private featureDefinitions!: FeatureDefinitionCollection;\n private initializationPromise: Promise<void> | null = null;\n\n constructor(options: SmrtClassOptions = {}) {\n this.options = options;\n }\n\n async syncDefinitions(\n options: SyncDefinitionsOptions = {},\n ): Promise<FeatureSyncResult> {\n await this.ensureInitialized();\n const registrations = this.collectRegistrations(options);\n const definitions = this.collectDefinitionsFromRegistrations(registrations);\n const touchedPackages =\n this.collectTouchedPackagesFromRegistrations(registrations);\n const isFilteredSync =\n Boolean(options.classNames?.length) ||\n Boolean(options.constructors?.length);\n const pruneStale = isFilteredSync ? false : (options.pruneStale ?? true);\n\n return this.applyDefinitions(definitions, touchedPackages, pruneStale);\n }\n\n async syncManifest(\n manifest: SmartObjectManifest,\n options: SyncManifestOptions = {},\n ): Promise<FeatureSyncResult> {\n await this.ensureInitialized();\n const definitions = extractFeatureSeedsFromManifest(manifest);\n const touchedPackages = extractTouchedPackagesFromManifest(manifest);\n return this.applyDefinitions(\n definitions,\n touchedPackages,\n options.pruneStale ?? true,\n );\n }\n\n private async ensureInitialized(): Promise<void> {\n if (!this.initializationPromise) {\n this.initializationPromise = (async () => {\n this.featureDefinitions = await FeatureDefinitionCollection.create(\n this.options,\n );\n })();\n }\n\n await this.initializationPromise;\n }\n\n private collectDefinitionsFromRegistrations(\n registrations: RegistryEntryLike[],\n ): FeatureDefinitionSeed[] {\n const definitions: FeatureDefinitionSeed[] = [];\n\n for (const registration of registrations) {\n definitions.push(...extractFeatureSeedsFromRegistryEntry(registration));\n }\n\n return definitions;\n }\n\n private collectTouchedPackagesFromRegistrations(\n registrations: RegistryEntryLike[],\n ): Set<string> {\n const packages = new Set<string>();\n\n for (const registration of registrations) {\n if (registration.visibility === 'test') {\n continue;\n }\n\n const packageName = getPackageNameFromRegistry(registration);\n if (packageName) {\n packages.add(packageName);\n }\n }\n\n return packages;\n }\n\n private collectRegistrations(\n options: SyncDefinitionsOptions,\n ): RegistryEntryLike[] {\n if (options.classNames?.length) {\n return options.classNames\n .map((name) => ObjectRegistry.getClass(name))\n .filter((value): value is NonNullable<typeof value> => !!value);\n }\n\n if (options.constructors?.length) {\n return options.constructors\n .map((ctor) => ObjectRegistry.getClassByConstructor(ctor))\n .filter((value): value is NonNullable<typeof value> => !!value);\n }\n\n const registrations: RegistryEntryLike[] = [];\n const seen = new Set<RegistryEntryLike>();\n\n for (const registration of ObjectRegistry.getAllClasses().values()) {\n if (seen.has(registration)) {\n continue;\n }\n seen.add(registration);\n registrations.push(registration);\n }\n\n return registrations;\n }\n\n private async applyDefinitions(\n definitions: FeatureDefinitionSeed[],\n touchedPackages: Set<string>,\n pruneStale: boolean,\n ): Promise<FeatureSyncResult> {\n const deduped = new Map<string, FeatureDefinitionSeed>();\n for (const definition of definitions) {\n deduped.set(definition.featureKey, definition);\n }\n\n let created = 0;\n let updated = 0;\n let unchanged = 0;\n let deleted = 0;\n\n const dedupedDefinitions = Array.from(deduped.values());\n const currentKeys = new Set(\n dedupedDefinitions.map((definition) => definition.featureKey),\n );\n const upsertResults = await Promise.all(\n dedupedDefinitions.map((definition) =>\n this.featureDefinitions.upsertDefinition(definition),\n ),\n );\n for (const result of upsertResults) {\n if (result.status === 'created') created++;\n if (result.status === 'updated') updated++;\n if (result.status === 'unchanged') unchanged++;\n }\n\n if (pruneStale) {\n const existingByPackage = await Promise.all(\n Array.from(touchedPackages, (packageName) =>\n this.featureDefinitions.findByPackageName(packageName),\n ),\n );\n\n const staleDefinitions = existingByPackage.flatMap((existing) =>\n existing.filter(\n (definition) => !currentKeys.has(definition.featureKey),\n ),\n );\n\n await Promise.all(\n staleDefinitions.map((definition) => definition.delete()),\n );\n deleted = staleDefinitions.length;\n }\n\n return {\n total: deduped.size,\n created,\n updated,\n unchanged,\n deleted,\n featureKeys: Array.from(currentKeys).sort(),\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/__smrt-register__.ts","../src/utils.ts","../src/feature-definition.ts","../src/feature-definitions.ts","../src/feature-override.ts","../src/feature-override-service.ts","../src/feature-overrides.ts","../src/feature-resolver.ts","../src/feature-sync.ts"],"sourcesContent":["/**\n * Self-registers this package's build-time manifest before any @smrt() decorator\n * in the package fires. Fixes issue #1132: in consumer runtimes (tsx, SvelteKit\n * SSR, plain `vite dev`) the decorator's synchronous manifest lookup previously\n * missed because no step populated the global manifest cache — classes got\n * registered with zero fields and `save()` / `toJSON()` silently dropped every\n * declared property.\n *\n * Import this module as the first statement in `src/index.ts` so its top-level\n * side effect runs ahead of any class module's @smrt() decorator.\n *\n * Silent no-op in dev/test, where the vitest plugin already populates manifests\n * via a different path. Only needs to succeed in the published dist output.\n *\n * @see https://github.com/happyvertical/smrt/issues/1132\n */\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\n// During library builds, smrtPlugin replaces this entire module with generated\n// code that embeds the scanned manifest inline (#1506/#1507) — published dists\n// never resolve this URL, so downstream bundlers cannot break registration by\n// relocating the compiled module away from dist/manifest.json. The runtime\n// lookup below is the fallback for source-mode runs without that transform.\nObjectRegistry.registerPackageManifest(\n new URL('./manifest.json', import.meta.url),\n);\n","import {\n createQualifiedName,\n isQualifiedName,\n ObjectRegistry,\n parseQualifiedName,\n type SmartObjectConfig,\n} from '@happyvertical/smrt-core';\nimport type {\n SmartObjectDefinition,\n SmartObjectManifest,\n} from '@happyvertical/smrt-core/manifest';\nimport type {\n FeatureDefinitionSeed,\n FeatureMetadata,\n FeatureTargetConstructor,\n} from './types.js';\n\nexport type RegistryEntryLike = {\n name: string;\n qualifiedName?: string;\n packageName?: string;\n config: SmartObjectConfig;\n visibility?: string;\n};\n\nexport function createFeatureKey(\n qualifiedClassName: string,\n localId: string,\n): string {\n if (!isQualifiedName(qualifiedClassName)) {\n throw new Error(\n `Feature keys require a qualified class name. Received \"${qualifiedClassName}\".`,\n );\n }\n\n if (!localId) {\n throw new Error('Feature localId is required.');\n }\n\n if (localId.includes('#')) {\n throw new Error(\n `Feature localId \"${localId}\" cannot contain \"#\". This character is reserved for canonical feature keys.`,\n );\n }\n\n return `${qualifiedClassName}#${localId}`;\n}\n\nexport function parseFeatureKey(featureKey: string): {\n qualifiedClassName: string;\n localId: string;\n} {\n const separatorIndex = featureKey.lastIndexOf('#');\n if (separatorIndex <= 0 || separatorIndex === featureKey.length - 1) {\n throw new Error(\n `Invalid feature key \"${featureKey}\". Expected format \"<qualifiedClassName>#<localId>\".`,\n );\n }\n\n const qualifiedClassName = featureKey.slice(0, separatorIndex);\n const localId = featureKey.slice(separatorIndex + 1);\n\n if (!isQualifiedName(qualifiedClassName)) {\n throw new Error(\n `Invalid feature key \"${featureKey}\". \"${qualifiedClassName}\" is not a qualified class name.`,\n );\n }\n\n return { qualifiedClassName, localId };\n}\n\nexport function serializeFeatureMetadata(\n metadata: FeatureMetadata | string | null | undefined,\n): string {\n if (!metadata) {\n return '';\n }\n\n if (typeof metadata === 'string') {\n const parsed = parseFeatureMetadataString(metadata);\n return JSON.stringify(parsed);\n }\n\n if (!isFeatureMetadataRecord(metadata)) {\n throw new Error(\n 'Feature metadata must be a plain object or a JSON string representing a plain object.',\n );\n }\n\n return JSON.stringify(metadata);\n}\n\nexport function parseFeatureMetadata(\n metadata: string | null | undefined,\n): FeatureMetadata {\n if (!metadata) {\n return {};\n }\n\n try {\n return parseFeatureMetadataString(metadata);\n } catch {\n return {};\n }\n}\n\nfunction parseFeatureMetadataString(metadata: string): FeatureMetadata {\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(metadata);\n } catch (error) {\n throw new Error(\n 'Feature metadata must be a plain object or a JSON string representing a plain object.',\n { cause: error },\n );\n }\n\n if (!isFeatureMetadataRecord(parsed)) {\n throw new Error(\n 'Feature metadata must be a plain object or a JSON string representing a plain object.',\n );\n }\n\n return parsed;\n}\n\nfunction isFeatureMetadataRecord(value: unknown): value is FeatureMetadata {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nexport function getQualifiedClassNameFromRegistry(\n registration: RegistryEntryLike,\n): string | null {\n if (\n registration.qualifiedName &&\n isQualifiedName(registration.qualifiedName)\n ) {\n return registration.qualifiedName;\n }\n\n if (registration.packageName) {\n return createQualifiedName(registration.packageName, registration.name);\n }\n\n return null;\n}\n\nexport function getPackageNameFromRegistry(\n registration: RegistryEntryLike,\n): string | null {\n if (registration.packageName) {\n return registration.packageName;\n }\n\n const qualifiedClassName = getQualifiedClassNameFromRegistry(registration);\n if (!qualifiedClassName) {\n return null;\n }\n\n return parseQualifiedName(qualifiedClassName).packageName;\n}\n\nexport function extractFeatureSeedsFromRegistryEntry(\n registration: RegistryEntryLike,\n): FeatureDefinitionSeed[] {\n if (registration.visibility === 'test') {\n return [];\n }\n\n const qualifiedClassName = getQualifiedClassNameFromRegistry(registration);\n if (!qualifiedClassName) {\n return [];\n }\n\n const featureConfig = registration.config.features;\n if (!featureConfig) {\n return [];\n }\n\n const packageName =\n registration.packageName ||\n parseQualifiedName(qualifiedClassName).packageName;\n\n return Object.entries(featureConfig).map(([localId, feature]) => ({\n featureKey: createFeatureKey(qualifiedClassName, localId),\n packageName,\n qualifiedClassName,\n className: registration.name,\n localId,\n defaultEnabled: feature.defaultEnabled,\n label: feature.label,\n description: feature.description,\n metadata: feature.metadata,\n visibility: registration.visibility,\n }));\n}\n\nexport function extractFeatureSeedsFromManifest(\n manifest: SmartObjectManifest,\n): FeatureDefinitionSeed[] {\n const seeds: FeatureDefinitionSeed[] = [];\n\n for (const [objectKey, objectDef] of Object.entries(manifest.objects)) {\n seeds.push(...extractFeatureSeedsFromManifestObject(objectKey, objectDef));\n }\n\n return seeds;\n}\n\nexport function extractTouchedPackagesFromManifest(\n manifest: SmartObjectManifest,\n): Set<string> {\n const packages = new Set<string>();\n\n if (manifest.packageName) {\n packages.add(manifest.packageName);\n }\n\n for (const [objectKey, objectDef] of Object.entries(manifest.objects)) {\n if (objectDef.visibility === 'test') {\n continue;\n }\n\n if (objectDef.packageName) {\n packages.add(objectDef.packageName);\n continue;\n }\n\n const qualifiedClassName = resolveManifestQualifiedClassName(\n objectKey,\n objectDef,\n );\n if (qualifiedClassName) {\n packages.add(parseQualifiedName(qualifiedClassName).packageName);\n }\n }\n\n return packages;\n}\n\nfunction extractFeatureSeedsFromManifestObject(\n objectKey: string,\n objectDef: SmartObjectDefinition,\n): FeatureDefinitionSeed[] {\n if (objectDef.visibility === 'test') {\n return [];\n }\n\n const features = objectDef.decoratorConfig.features;\n if (!features) {\n return [];\n }\n\n const qualifiedClassName = resolveManifestQualifiedClassName(\n objectKey,\n objectDef,\n );\n if (!qualifiedClassName) {\n return [];\n }\n\n const packageName =\n objectDef.packageName || parseQualifiedName(qualifiedClassName).packageName;\n\n return Object.entries(features).map(([localId, feature]) => ({\n featureKey: createFeatureKey(qualifiedClassName, localId),\n packageName,\n qualifiedClassName,\n className: objectDef.className,\n localId,\n defaultEnabled: feature.defaultEnabled,\n label: feature.label,\n description: feature.description,\n metadata:\n feature.metadata && typeof feature.metadata === 'object'\n ? (feature.metadata as FeatureMetadata)\n : undefined,\n visibility: objectDef.visibility,\n }));\n}\n\nfunction resolveManifestQualifiedClassName(\n objectKey: string,\n objectDef: SmartObjectDefinition,\n): string | null {\n if (objectDef.qualifiedName && isQualifiedName(objectDef.qualifiedName)) {\n return objectDef.qualifiedName;\n }\n\n if (isQualifiedName(objectKey)) {\n return objectKey;\n }\n\n if (objectDef.packageName) {\n return createQualifiedName(objectDef.packageName, objectDef.className);\n }\n\n return null;\n}\n\nexport function resolveFeatureKeyForTarget(\n classOrInstance: object | FeatureTargetConstructor,\n localId: string,\n): {\n featureKey: string;\n defaultEnabled: boolean;\n} {\n const ctor: FeatureTargetConstructor =\n typeof classOrInstance === 'function'\n ? (classOrInstance as FeatureTargetConstructor)\n : (classOrInstance.constructor as FeatureTargetConstructor);\n\n const registration = ObjectRegistry.getClassByConstructor(ctor);\n if (!registration) {\n throw new Error(\n `Cannot resolve feature \"${localId}\" because ${ctor?.name || 'the target class'} is not registered with @smrt().`,\n );\n }\n\n const qualifiedClassName = getQualifiedClassNameFromRegistry(registration);\n if (!qualifiedClassName) {\n throw new Error(\n `Cannot resolve feature \"${localId}\" for ${registration.name} because the class has no qualified package identity.`,\n );\n }\n\n const feature = registration.config.features?.[localId];\n if (!feature) {\n throw new Error(\n `Feature \"${localId}\" is not declared on ${qualifiedClassName}.`,\n );\n }\n\n return {\n featureKey: createFeatureKey(qualifiedClassName, localId),\n defaultEnabled: feature.defaultEnabled,\n };\n}\n\nexport function findFeatureDefaultInRegistry(\n featureKey: string,\n): boolean | undefined {\n const { qualifiedClassName, localId } = parseFeatureKey(featureKey);\n const registration =\n ObjectRegistry.getClassByQualifiedName(qualifiedClassName) ||\n ObjectRegistry.getClass(qualifiedClassName);\n\n const feature = registration?.config.features?.[localId];\n return feature?.defaultEnabled;\n}\n","import { SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport type { FeatureDefinitionOptions, FeatureMetadata } from './types.js';\nimport { parseFeatureMetadata, serializeFeatureMetadata } from './utils.js';\n\n@smrt({\n tableName: '_smrt_feature_definitions',\n // Closed by default like FeatureOverride (#3013): the catalog is framework\n // state synced from manifests, not a tenant resource.\n api: false,\n cli: false,\n mcp: false,\n conflictColumns: ['feature_key'],\n})\nexport class FeatureDefinition extends SmrtObject {\n featureKey: string = '';\n packageName: string = '';\n qualifiedClassName: string = '';\n className: string = '';\n localId: string = '';\n defaultEnabled: boolean = false;\n label: string = '';\n description: string = '';\n metadata: string = '';\n visibility: string = 'public';\n\n constructor(options: FeatureDefinitionOptions = {}) {\n super(options);\n\n if (options.featureKey !== undefined) this.featureKey = options.featureKey;\n if (options.packageName !== undefined)\n this.packageName = options.packageName;\n if (options.qualifiedClassName !== undefined) {\n this.qualifiedClassName = options.qualifiedClassName;\n }\n if (options.className !== undefined) this.className = options.className;\n if (options.localId !== undefined) this.localId = options.localId;\n if (options.defaultEnabled !== undefined) {\n this.defaultEnabled = options.defaultEnabled;\n }\n if (options.label !== undefined) this.label = options.label;\n if (options.description !== undefined)\n this.description = options.description;\n if (options.visibility !== undefined) this.visibility = options.visibility;\n if (options.metadata !== undefined) {\n this.metadata = serializeFeatureMetadata(options.metadata);\n }\n }\n\n getMetadata(): FeatureMetadata {\n return parseFeatureMetadata(this.metadata);\n }\n\n setMetadata(metadata: FeatureMetadata | null): void {\n this.metadata = serializeFeatureMetadata(metadata);\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { FeatureDefinition } from './feature-definition.js';\nimport type { FeatureDefinitionSeed } from './types.js';\nimport { serializeFeatureMetadata } from './utils.js';\n\nexport class FeatureDefinitionCollection extends SmrtCollection<FeatureDefinition> {\n static readonly _itemClass = FeatureDefinition;\n\n async findByFeatureKey(\n featureKey: string,\n ): Promise<FeatureDefinition | null> {\n const results = await this.list({\n where: { featureKey },\n limit: 1,\n });\n return results[0] ?? null;\n }\n\n async findByPackageName(packageName: string): Promise<FeatureDefinition[]> {\n return this.list({\n where: { packageName },\n });\n }\n\n async upsertDefinition(seed: FeatureDefinitionSeed): Promise<{\n definition: FeatureDefinition;\n status: 'created' | 'updated' | 'unchanged';\n }> {\n const existing = await this.findByFeatureKey(seed.featureKey);\n\n if (!existing) {\n const created = await this.create({\n ...seed,\n metadata: serializeFeatureMetadata(seed.metadata),\n });\n await created.save();\n return { definition: created, status: 'created' };\n }\n\n const nextMetadata = serializeFeatureMetadata(seed.metadata);\n const changed =\n existing.packageName !== seed.packageName ||\n existing.qualifiedClassName !== seed.qualifiedClassName ||\n existing.className !== seed.className ||\n existing.localId !== seed.localId ||\n existing.defaultEnabled !== seed.defaultEnabled ||\n existing.label !== (seed.label ?? '') ||\n existing.description !== (seed.description ?? '') ||\n existing.metadata !== nextMetadata ||\n existing.visibility !== (seed.visibility ?? 'public');\n\n if (!changed) {\n return { definition: existing, status: 'unchanged' };\n }\n\n existing.packageName = seed.packageName;\n existing.qualifiedClassName = seed.qualifiedClassName;\n existing.className = seed.className;\n existing.localId = seed.localId;\n existing.defaultEnabled = seed.defaultEnabled;\n existing.label = seed.label ?? '';\n existing.description = seed.description ?? '';\n existing.metadata = nextMetadata;\n existing.visibility = seed.visibility ?? 'public';\n await existing.save();\n\n return { definition: existing, status: 'updated' };\n }\n}\n","import { SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport {\n FeatureOverrideEffect,\n type FeatureOverrideOptions,\n type FeatureScopeType,\n GLOBAL_FEATURE_SCOPE_ID,\n} from './types.js';\n\n// Override rows are authorization state: any scope (global, another tenant,\n// another user) can be written, and the object is not tenant-scoped. Generated\n// REST routes and MCP tools only check authentication, so they are closed\n// (#3013). Hosts write overrides server-side through\n// `FeatureOverrideService`, which requires an explicit authorizer for every\n// write (or the collection's `setOverride()` / `removeOverride()` after their\n// own authorization decision). The CLI is closed too: generated CLI commands\n// dispatch through the generated API.\n@smrt({\n tableName: '_smrt_feature_overrides',\n api: false,\n cli: false,\n mcp: false,\n conflictColumns: ['feature_key', 'scope_type', 'scope_id'],\n})\nexport class FeatureOverride extends SmrtObject {\n featureKey: string = '';\n scopeType: FeatureScopeType = 'global';\n scopeId: string = GLOBAL_FEATURE_SCOPE_ID;\n effect: FeatureOverrideEffect = FeatureOverrideEffect.INHERIT;\n\n constructor(options: FeatureOverrideOptions = {}) {\n super(options);\n\n if (options.featureKey !== undefined) this.featureKey = options.featureKey;\n if (options.scopeType !== undefined) this.scopeType = options.scopeType;\n if (options.scopeId !== undefined) this.scopeId = options.scopeId;\n if (options.effect !== undefined) this.effect = options.effect;\n }\n\n isInherit(): boolean {\n return this.effect === FeatureOverrideEffect.INHERIT;\n }\n\n isEnabled(): boolean {\n return this.effect === FeatureOverrideEffect.ENABLE;\n }\n\n isDisabled(): boolean {\n return this.effect === FeatureOverrideEffect.DISABLE;\n }\n}\n","import type { FeatureOverride } from './feature-override.js';\nimport type { FeatureOverrideCollection } from './feature-overrides.js';\nimport type { FeatureOverrideEffect, FeatureScopeType } from './types.js';\n\n/** One override write the host must authorize before it runs (#3013). */\nexport interface FeatureOverrideWriteRequest {\n operation: 'set' | 'remove';\n featureKey: string;\n scopeType: FeatureScopeType;\n scopeId: string;\n /** Present for `set`. */\n effect?: FeatureOverrideEffect;\n}\n\n/**\n * The host's explicit authorization decision for one override write. Return\n * `true` only when the current caller may write that exact scope; anything\n * else denies.\n */\nexport type FeatureOverrideAuthorizer = (\n request: FeatureOverrideWriteRequest,\n) => boolean | Promise<boolean>;\n\n/** Thrown when the authorizer does not return `true`. Nothing is written. */\nexport class FeatureOverrideAuthorizationError extends Error {\n readonly status = 403;\n constructor(readonly request: FeatureOverrideWriteRequest) {\n super(\n `Feature override ${request.operation} denied for ${request.scopeType} scope`,\n );\n this.name = 'FeatureOverrideAuthorizationError';\n }\n}\n\n/**\n * Authorized write path for feature overrides (#3013). Override rows are\n * authorization state for every scope and `FeatureOverride` is not\n * tenant-scoped, so generated surfaces are closed. Hosts that let callers\n * change flags construct this service with an authorizer bound to the\n * current caller and write through it; every write asks the authorizer\n * first and fails closed.\n */\nexport class FeatureOverrideService {\n constructor(\n private readonly overrides: FeatureOverrideCollection,\n private readonly authorize: FeatureOverrideAuthorizer,\n ) {}\n\n async setOverride(\n featureKey: string,\n scopeType: FeatureScopeType,\n scopeId: string,\n effect: FeatureOverrideEffect,\n ): Promise<FeatureOverride> {\n await this.require({\n operation: 'set',\n featureKey,\n scopeType,\n scopeId,\n effect,\n });\n return this.overrides.setOverride(featureKey, scopeType, scopeId, effect);\n }\n\n async removeOverride(\n featureKey: string,\n scopeType: FeatureScopeType,\n scopeId: string,\n ): Promise<boolean> {\n await this.require({ operation: 'remove', featureKey, scopeType, scopeId });\n return this.overrides.removeOverride(featureKey, scopeType, scopeId);\n }\n\n private async require(request: FeatureOverrideWriteRequest): Promise<void> {\n let allowed = false;\n try {\n allowed = (await this.authorize(request)) === true;\n } catch {\n allowed = false;\n }\n if (!allowed) throw new FeatureOverrideAuthorizationError(request);\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { FeatureOverride } from './feature-override.js';\nimport {\n type FeatureOverrideEffect,\n type FeatureScopeType,\n GLOBAL_FEATURE_SCOPE_ID,\n} from './types.js';\n\nexport class FeatureOverrideCollection extends SmrtCollection<FeatureOverride> {\n static readonly _itemClass = FeatureOverride;\n\n async findByFeatureKey(featureKey: string): Promise<FeatureOverride[]> {\n return this.list({\n where: { featureKey },\n });\n }\n\n async findByFeatureAndScope(\n featureKey: string,\n scopeType: FeatureScopeType,\n scopeId: string,\n ): Promise<FeatureOverride | null> {\n const results = await this.list({\n where: { featureKey, scopeType, scopeId },\n limit: 1,\n });\n return results[0] ?? null;\n }\n\n async getGlobalOverride(featureKey: string): Promise<FeatureOverride | null> {\n return this.findByFeatureAndScope(\n featureKey,\n 'global',\n GLOBAL_FEATURE_SCOPE_ID,\n );\n }\n\n async getTenantOverride(\n featureKey: string,\n tenantId: string,\n ): Promise<FeatureOverride | null> {\n return this.findByFeatureAndScope(featureKey, 'tenant', tenantId);\n }\n\n async getOverrideMap(\n featureKey: string,\n scopeType: FeatureScopeType,\n scopeIds: string[],\n ): Promise<Map<string, FeatureOverride>> {\n const result = new Map<string, FeatureOverride>();\n if (scopeIds.length === 0) {\n return result;\n }\n\n const overrides = await this.list({\n where: { featureKey, scopeType, scopeId: scopeIds },\n });\n\n for (const override of overrides) {\n result.set(override.scopeId, override);\n }\n\n return result;\n }\n\n async setOverride(\n featureKey: string,\n scopeType: FeatureScopeType,\n scopeId: string,\n effect: FeatureOverrideEffect,\n ): Promise<FeatureOverride> {\n const existing = await this.findByFeatureAndScope(\n featureKey,\n scopeType,\n scopeId,\n );\n\n if (existing) {\n existing.effect = effect;\n await existing.save();\n return existing;\n }\n\n const created = await this.create({\n featureKey,\n scopeType,\n scopeId,\n effect,\n });\n await created.save();\n return created;\n }\n\n async setGlobalOverride(\n featureKey: string,\n effect: FeatureOverrideEffect,\n ): Promise<FeatureOverride> {\n return this.setOverride(\n featureKey,\n 'global',\n GLOBAL_FEATURE_SCOPE_ID,\n effect,\n );\n }\n\n async setTenantOverride(\n featureKey: string,\n tenantId: string,\n effect: FeatureOverrideEffect,\n ): Promise<FeatureOverride> {\n return this.setOverride(featureKey, 'tenant', tenantId, effect);\n }\n\n async removeOverride(\n featureKey: string,\n scopeType: FeatureScopeType,\n scopeId: string,\n ): Promise<boolean> {\n const existing = await this.findByFeatureAndScope(\n featureKey,\n scopeType,\n scopeId,\n );\n\n if (!existing) {\n return false;\n }\n\n await existing.delete();\n return true;\n }\n}\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport { importWorkspaceModule } from '@happyvertical/smrt-core/utils/import-workspace-module';\nimport { FeatureDefinitionCollection } from './feature-definitions.js';\nimport { FeatureOverrideCollection } from './feature-overrides.js';\nimport {\n FeatureOverrideEffect,\n type FeatureResolutionContext,\n type FeatureResolverOptions,\n type FeatureTargetConstructor,\n type FeatureTenantHierarchyProvider,\n type FeatureTenantNode,\n type FeatureUsersModule,\n} from './types.js';\nimport {\n findFeatureDefaultInRegistry,\n resolveFeatureKeyForTarget,\n} from './utils.js';\n\nexport class FeatureResolver {\n private readonly options: SmrtClassOptions;\n private readonly resolverOptions: FeatureResolverOptions;\n private featureDefinitions!: FeatureDefinitionCollection;\n private featureOverrides!: FeatureOverrideCollection;\n private initializationPromise: Promise<void> | null = null;\n private tenantHierarchyPromise: Promise<FeatureTenantHierarchyProvider | null> | null =\n null;\n\n constructor(\n options: SmrtClassOptions = {},\n resolverOptions: FeatureResolverOptions = {},\n ) {\n this.options = options;\n this.resolverOptions = resolverOptions;\n }\n\n async isEnabled(\n featureKey: string,\n context: FeatureResolutionContext = {},\n ): Promise<boolean> {\n await this.ensureInitialized();\n\n const baseState = await this.resolveBaseState(featureKey);\n const globalOverride =\n await this.featureOverrides.getGlobalOverride(featureKey);\n const globalState = this.applyOverride(baseState, globalOverride?.effect);\n\n if (!context.tenantId) {\n return globalState;\n }\n\n const tenantHierarchy = await this.getTenantHierarchy();\n if (!tenantHierarchy) {\n const directOverride = await this.featureOverrides.getTenantOverride(\n featureKey,\n context.tenantId,\n );\n return this.applyOverride(globalState, directOverride?.effect);\n }\n\n const chain = await tenantHierarchy.getChain(context.tenantId);\n if (chain.length === 0) {\n const directOverride = await this.featureOverrides.getTenantOverride(\n featureKey,\n context.tenantId,\n );\n return this.applyOverride(globalState, directOverride?.effect);\n }\n\n const overrides = await this.featureOverrides.getOverrideMap(\n featureKey,\n 'tenant',\n chain.map((node) => node.id),\n );\n\n let inheritedState = globalState;\n\n for (let index = 0; index < chain.length; index++) {\n const current = chain[index];\n const previous = index > 0 ? chain[index - 1] : null;\n const shouldInherit =\n index === 0 ||\n (!!previous?.cascadePermissions && current.inheritPermissions);\n\n const baseline = shouldInherit ? inheritedState : globalState;\n const override = overrides.get(current.id);\n inheritedState = this.applyOverride(baseline, override?.effect);\n }\n\n return inheritedState;\n }\n\n async isEnabledFor(\n classOrInstance: object | FeatureTargetConstructor,\n localId: string,\n context: FeatureResolutionContext = {},\n ): Promise<boolean> {\n const { featureKey } = resolveFeatureKeyForTarget(classOrInstance, localId);\n return this.isEnabled(featureKey, context);\n }\n\n private async ensureInitialized(): Promise<void> {\n if (!this.initializationPromise) {\n this.initializationPromise = (async () => {\n this.featureDefinitions = await FeatureDefinitionCollection.create(\n this.options,\n );\n this.featureOverrides = await FeatureOverrideCollection.create(\n this.options,\n );\n })();\n }\n\n await this.initializationPromise;\n }\n\n private async resolveBaseState(featureKey: string): Promise<boolean> {\n const registryDefault = findFeatureDefaultInRegistry(featureKey);\n if (registryDefault !== undefined) {\n return registryDefault;\n }\n\n const definition =\n await this.featureDefinitions.findByFeatureKey(featureKey);\n if (!definition) {\n throw new Error(\n `Feature \"${featureKey}\" is not declared in the registry or synced feature definitions.`,\n );\n }\n\n return definition.defaultEnabled;\n }\n\n private applyOverride(\n currentState: boolean,\n effect: FeatureOverrideEffect | undefined,\n ): boolean {\n switch (effect) {\n case FeatureOverrideEffect.ENABLE:\n return true;\n case FeatureOverrideEffect.DISABLE:\n return false;\n default:\n return currentState;\n }\n }\n\n private async getTenantHierarchy(): Promise<FeatureTenantHierarchyProvider | null> {\n if (!this.tenantHierarchyPromise) {\n const loader =\n this.resolverOptions.tenantHierarchyLoader ||\n defaultTenantHierarchyLoader;\n this.tenantHierarchyPromise = loader(this.options);\n }\n\n return this.tenantHierarchyPromise;\n }\n}\n\nasync function defaultTenantHierarchyLoader(\n options: SmrtClassOptions,\n): Promise<FeatureTenantHierarchyProvider | null> {\n try {\n const usersModule = await importWorkspaceModule<FeatureUsersModule>({\n packageName: '@happyvertical/smrt-users',\n sourceEntry: 'packages/users/src/collections/index.ts',\n purpose: 'tenant-aware feature flag resolution',\n });\n\n const tenantCollection = await usersModule.TenantCollection.create(options);\n return {\n async getChain(tenantId: string): Promise<FeatureTenantNode[]> {\n const tenant = await tenantCollection.get({ id: tenantId });\n if (!tenant) {\n return [];\n }\n\n const ancestors = await tenantCollection.getAncestorsFromRoot(tenantId);\n return [...ancestors, tenant].map((node) => ({\n id: String(node.id),\n inheritPermissions: Boolean(node.inheritPermissions),\n cascadePermissions: Boolean(node.cascadePermissions),\n }));\n },\n };\n } catch (error) {\n if (isMissingUsersDependency(error)) {\n return null;\n }\n throw error;\n }\n}\n\nfunction isMissingUsersDependency(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n\n const causeMessage =\n error.cause instanceof Error ? ` ${error.cause.message}` : '';\n const text = `${error.message}${causeMessage}`;\n\n return (\n text.includes('@happyvertical/smrt-users') &&\n (text.includes('Cannot find module') ||\n text.includes('Failed to load') ||\n text.includes('could not find'))\n );\n}\n","import {\n ObjectRegistry,\n type SmrtClassOptions,\n} from '@happyvertical/smrt-core';\nimport type { SmartObjectManifest } from '@happyvertical/smrt-core/manifest';\nimport { FeatureDefinitionCollection } from './feature-definitions.js';\nimport type {\n FeatureDefinitionSeed,\n FeatureSyncResult,\n SyncDefinitionsOptions,\n SyncManifestOptions,\n} from './types.js';\nimport {\n extractFeatureSeedsFromManifest,\n extractFeatureSeedsFromRegistryEntry,\n extractTouchedPackagesFromManifest,\n getPackageNameFromRegistry,\n type RegistryEntryLike,\n} from './utils.js';\n\nexport class FeatureSyncService {\n private readonly options: SmrtClassOptions;\n private featureDefinitions!: FeatureDefinitionCollection;\n private initializationPromise: Promise<void> | null = null;\n\n constructor(options: SmrtClassOptions = {}) {\n this.options = options;\n }\n\n async syncDefinitions(\n options: SyncDefinitionsOptions = {},\n ): Promise<FeatureSyncResult> {\n await this.ensureInitialized();\n const registrations = this.collectRegistrations(options);\n const definitions = this.collectDefinitionsFromRegistrations(registrations);\n const touchedPackages =\n this.collectTouchedPackagesFromRegistrations(registrations);\n const isFilteredSync =\n Boolean(options.classNames?.length) ||\n Boolean(options.constructors?.length);\n const pruneStale = isFilteredSync ? false : (options.pruneStale ?? true);\n\n return this.applyDefinitions(definitions, touchedPackages, pruneStale);\n }\n\n async syncManifest(\n manifest: SmartObjectManifest,\n options: SyncManifestOptions = {},\n ): Promise<FeatureSyncResult> {\n await this.ensureInitialized();\n const definitions = extractFeatureSeedsFromManifest(manifest);\n const touchedPackages = extractTouchedPackagesFromManifest(manifest);\n return this.applyDefinitions(\n definitions,\n touchedPackages,\n options.pruneStale ?? true,\n );\n }\n\n private async ensureInitialized(): Promise<void> {\n if (!this.initializationPromise) {\n this.initializationPromise = (async () => {\n this.featureDefinitions = await FeatureDefinitionCollection.create(\n this.options,\n );\n })();\n }\n\n await this.initializationPromise;\n }\n\n private collectDefinitionsFromRegistrations(\n registrations: RegistryEntryLike[],\n ): FeatureDefinitionSeed[] {\n const definitions: FeatureDefinitionSeed[] = [];\n\n for (const registration of registrations) {\n definitions.push(...extractFeatureSeedsFromRegistryEntry(registration));\n }\n\n return definitions;\n }\n\n private collectTouchedPackagesFromRegistrations(\n registrations: RegistryEntryLike[],\n ): Set<string> {\n const packages = new Set<string>();\n\n for (const registration of registrations) {\n if (registration.visibility === 'test') {\n continue;\n }\n\n const packageName = getPackageNameFromRegistry(registration);\n if (packageName) {\n packages.add(packageName);\n }\n }\n\n return packages;\n }\n\n private collectRegistrations(\n options: SyncDefinitionsOptions,\n ): RegistryEntryLike[] {\n if (options.classNames?.length) {\n return options.classNames\n .map((name) => ObjectRegistry.getClass(name))\n .filter((value): value is NonNullable<typeof value> => !!value);\n }\n\n if (options.constructors?.length) {\n return options.constructors\n .map((ctor) => ObjectRegistry.getClassByConstructor(ctor))\n .filter((value): value is NonNullable<typeof value> => !!value);\n }\n\n const registrations: RegistryEntryLike[] = [];\n const seen = new Set<RegistryEntryLike>();\n\n for (const registration of ObjectRegistry.getAllClasses().values()) {\n if (seen.has(registration)) {\n continue;\n }\n seen.add(registration);\n registrations.push(registration);\n }\n\n return registrations;\n }\n\n private async applyDefinitions(\n definitions: FeatureDefinitionSeed[],\n touchedPackages: Set<string>,\n pruneStale: boolean,\n ): Promise<FeatureSyncResult> {\n const deduped = new Map<string, FeatureDefinitionSeed>();\n for (const definition of definitions) {\n deduped.set(definition.featureKey, definition);\n }\n\n let created = 0;\n let updated = 0;\n let unchanged = 0;\n let deleted = 0;\n\n const dedupedDefinitions = Array.from(deduped.values());\n const currentKeys = new Set(\n dedupedDefinitions.map((definition) => definition.featureKey),\n );\n const upsertResults = await Promise.all(\n dedupedDefinitions.map((definition) =>\n this.featureDefinitions.upsertDefinition(definition),\n ),\n );\n for (const result of upsertResults) {\n if (result.status === 'created') created++;\n if (result.status === 'updated') updated++;\n if (result.status === 'unchanged') unchanged++;\n }\n\n if (pruneStale) {\n const existingByPackage = await Promise.all(\n Array.from(touchedPackages, (packageName) =>\n this.featureDefinitions.findByPackageName(packageName),\n ),\n );\n\n const staleDefinitions = existingByPackage.flatMap((existing) =>\n existing.filter(\n (definition) => !currentKeys.has(definition.featureKey),\n ),\n );\n\n await Promise.all(\n staleDefinitions.map((definition) => definition.delete()),\n );\n deleted = staleDefinitions.length;\n }\n\n return {\n total: deduped.size,\n created,\n updated,\n unchanged,\n deleted,\n featureKeys: Array.from(currentKeys).sort(),\n };\n }\n}\n"],"mappings":";;;;;;;ACyBO,SAAS,iBACd,oBACA,SACQ;CACR,IAAI,CAAC,gBAAgB,kBAAkB,GACrC,MAAM,IAAI,MACR,0DAA0D,mBAAkB,GAC9E;CAGF,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,8BAA8B;CAGhD,IAAI,QAAQ,SAAS,GAAG,GACtB,MAAM,IAAI,MACR,oBAAoB,QAAO,6EAC7B;CAGF,OAAO,GAAG,mBAAkB,GAAI;AAClC;AAEO,SAAS,gBAAgB,YAG9B;CACA,MAAM,iBAAiB,WAAW,YAAY,GAAG;CACjD,IAAI,kBAAkB,KAAK,mBAAmB,WAAW,SAAS,GAChE,MAAM,IAAI,MACR,wBAAwB,WAAU,qDACpC;CAGF,MAAM,qBAAqB,WAAW,MAAM,GAAG,cAAc;CAC7D,MAAM,UAAU,WAAW,MAAM,iBAAiB,CAAC;CAEnD,IAAI,CAAC,gBAAgB,kBAAkB,GACrC,MAAM,IAAI,MACR,wBAAwB,WAAU,MAAO,mBAAkB,iCAC7D;CAGF,OAAO;EAAE;EAAoB;CAAQ;AACvC;AAEO,SAAS,yBACd,UACQ;CACR,IAAI,CAAC,UACH,OAAO;CAGT,IAAI,OAAO,aAAa,UAAU;EAChC,MAAM,SAAS,2BAA2B,QAAQ;EAClD,OAAO,KAAK,UAAU,MAAM;CAC9B;CAEA,IAAI,CAAC,wBAAwB,QAAQ,GACnC,MAAM,IAAI,MACR,uFACF;CAGF,OAAO,KAAK,UAAU,QAAQ;AAChC;AAEO,SAAS,qBACd,UACiB;CACjB,IAAI,CAAC,UACH,OAAO,CAAC;CAGV,IAAI;EACF,OAAO,2BAA2B,QAAQ;CAC5C,QAAQ;EACN,OAAO,CAAC;CACV;AACF;AAEA,SAAS,2BAA2B,UAAmC;CACrE,IAAI;CAEJ,IAAI;EACF,SAAS,KAAK,MAAM,QAAQ;CAC9B,SAAS,OAAO;EACd,MAAM,IAAI,MACR,yFACA,EAAE,OAAO,MAAM,CACjB;CACF;CAEA,IAAI,CAAC,wBAAwB,MAAM,GACjC,MAAM,IAAI,MACR,uFACF;CAGF,OAAO;AACT;AAEA,SAAS,wBAAwB,OAA0C;CACzE,IAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAC5D,OAAO;CAGT,MAAM,YAAY,OAAO,eAAe,KAAK;CAC7C,OAAO,cAAc,OAAO,aAAa,cAAc;AACzD;AAEO,SAAS,kCACd,cACe;CACf,IACE,aAAa,iBACb,gBAAgB,aAAa,aAAa,GAE1C,OAAO,aAAa;CAGtB,IAAI,aAAa,aACf,OAAO,oBAAoB,aAAa,aAAa,aAAa,IAAI;CAGxE,OAAO;AACT;AAEO,SAAS,2BACd,cACe;CACf,IAAI,aAAa,aACf,OAAO,aAAa;CAGtB,MAAM,qBAAqB,kCAAkC,YAAY;CACzE,IAAI,CAAC,oBACH,OAAO;CAGT,OAAO,mBAAmB,kBAAkB,CAAA,CAAE;AAChD;AAEO,SAAS,qCACd,cACyB;CACzB,IAAI,aAAa,eAAe,QAC9B,OAAO,CAAC;CAGV,MAAM,qBAAqB,kCAAkC,YAAY;CACzE,IAAI,CAAC,oBACH,OAAO,CAAC;CAGV,MAAM,gBAAgB,aAAa,OAAO;CAC1C,IAAI,CAAC,eACH,OAAO,CAAC;CAGV,MAAM,cACJ,aAAa,eACb,mBAAmB,kBAAkB,CAAA,CAAE;CAEzC,OAAO,OAAO,QAAQ,aAAa,CAAA,CAAE,KAAK,CAAC,SAAS,cAAc;EAChE,YAAY,iBAAiB,oBAAoB,OAAO;EACxD;EACA;EACA,WAAW,aAAa;EACxB;EACA,gBAAgB,QAAQ;EACxB,OAAO,QAAQ;EACf,aAAa,QAAQ;EACrB,UAAU,QAAQ;EAClB,YAAY,aAAa;CAC3B,EAAE;AACJ;AAEO,SAAS,gCACd,UACyB;CACzB,MAAM,QAAiC,CAAC;CAExC,KAAA,MAAW,CAAC,WAAW,cAAc,OAAO,QAAQ,SAAS,OAAO,GAClE,MAAM,KAAK,GAAG,sCAAsC,WAAW,SAAS,CAAC;CAG3E,OAAO;AACT;AAEO,SAAS,mCACd,UACa;CACb,MAAM,2BAAW,IAAI,IAAY;CAEjC,IAAI,SAAS,aACX,SAAS,IAAI,SAAS,WAAW;CAGnC,KAAA,MAAW,CAAC,WAAW,cAAc,OAAO,QAAQ,SAAS,OAAO,GAAG;EACrE,IAAI,UAAU,eAAe,QAC3B;EAGF,IAAI,UAAU,aAAa;GACzB,SAAS,IAAI,UAAU,WAAW;GAClC;EACF;EAEA,MAAM,qBAAqB,kCACzB,WACA,SACF;EACA,IAAI,oBACF,SAAS,IAAI,mBAAmB,kBAAkB,CAAA,CAAE,WAAW;CAEnE;CAEA,OAAO;AACT;AAEA,SAAS,sCACP,WACA,WACyB;CACzB,IAAI,UAAU,eAAe,QAC3B,OAAO,CAAC;CAGV,MAAM,WAAW,UAAU,gBAAgB;CAC3C,IAAI,CAAC,UACH,OAAO,CAAC;CAGV,MAAM,qBAAqB,kCACzB,WACA,SACF;CACA,IAAI,CAAC,oBACH,OAAO,CAAC;CAGV,MAAM,cACJ,UAAU,eAAe,mBAAmB,kBAAkB,CAAA,CAAE;CAElE,OAAO,OAAO,QAAQ,QAAQ,CAAA,CAAE,KAAK,CAAC,SAAS,cAAc;EAC3D,YAAY,iBAAiB,oBAAoB,OAAO;EACxD;EACA;EACA,WAAW,UAAU;EACrB;EACA,gBAAgB,QAAQ;EACxB,OAAO,QAAQ;EACf,aAAa,QAAQ;EACrB,UACE,QAAQ,YAAY,OAAO,QAAQ,aAAa,WAC3C,QAAQ,WACT,KAAA;EACN,YAAY,UAAU;CACxB,EAAE;AACJ;AAEA,SAAS,kCACP,WACA,WACe;CACf,IAAI,UAAU,iBAAiB,gBAAgB,UAAU,aAAa,GACpE,OAAO,UAAU;CAGnB,IAAI,gBAAgB,SAAS,GAC3B,OAAO;CAGT,IAAI,UAAU,aACZ,OAAO,oBAAoB,UAAU,aAAa,UAAU,SAAS;CAGvE,OAAO;AACT;AAEO,SAAS,2BACd,iBACA,SAIA;CACA,MAAM,OACJ,OAAO,oBAAoB,aACtB,kBACA,gBAAgB;CAEvB,MAAM,eAAe,eAAe,sBAAsB,IAAI;CAC9D,IAAI,CAAC,cACH,MAAM,IAAI,MACR,2BAA2B,QAAO,YAAa,MAAM,QAAQ,mBAAkB,iCACjF;CAGF,MAAM,qBAAqB,kCAAkC,YAAY;CACzE,IAAI,CAAC,oBACH,MAAM,IAAI,MACR,2BAA2B,QAAO,QAAS,aAAa,KAAI,sDAC9D;CAGF,MAAM,UAAU,aAAa,OAAO,WAAW;CAC/C,IAAI,CAAC,SACH,MAAM,IAAI,MACR,YAAY,QAAO,uBAAwB,mBAAkB,EAC/D;CAGF,OAAO;EACL,YAAY,iBAAiB,oBAAoB,OAAO;EACxD,gBAAgB,QAAQ;CAC1B;AACF;AAEO,SAAS,6BACd,YACqB;CACrB,MAAM,EAAE,oBAAoB,YAAY,gBAAgB,UAAU;CAMlE,SAJE,eAAe,wBAAwB,kBAAkB,KACzD,eAAe,SAAS,kBAAkB,EAAA,EAEd,OAAO,WAAW,SAAA,EAChC;AAClB;;;;;;;;;;;ACtVO,IAAM,oBAAN,cAAgC,WAAW;CAChD,aAAqB;CACrB,cAAsB;CACtB,qBAA6B;CAC7B,YAAoB;CACpB,UAAkB;CAClB,iBAA0B;CAC1B,QAAgB;CAChB,cAAsB;CACtB,WAAmB;CACnB,aAAqB;CAErB,YAAY,UAAoC,CAAC,GAAG;EAClD,MAAM,OAAO;EAEb,IAAI,QAAQ,eAAe,KAAA,GAAW,KAAK,aAAa,QAAQ;EAChE,IAAI,QAAQ,gBAAgB,KAAA,GAC1B,KAAK,cAAc,QAAQ;EAC7B,IAAI,QAAQ,uBAAuB,KAAA,GACjC,KAAK,qBAAqB,QAAQ;EAEpC,IAAI,QAAQ,cAAc,KAAA,GAAW,KAAK,YAAY,QAAQ;EAC9D,IAAI,QAAQ,YAAY,KAAA,GAAW,KAAK,UAAU,QAAQ;EAC1D,IAAI,QAAQ,mBAAmB,KAAA,GAC7B,KAAK,iBAAiB,QAAQ;EAEhC,IAAI,QAAQ,UAAU,KAAA,GAAW,KAAK,QAAQ,QAAQ;EACtD,IAAI,QAAQ,gBAAgB,KAAA,GAC1B,KAAK,cAAc,QAAQ;EAC7B,IAAI,QAAQ,eAAe,KAAA,GAAW,KAAK,aAAa,QAAQ;EAChE,IAAI,QAAQ,aAAa,KAAA,GACvB,KAAK,WAAW,yBAAyB,QAAQ,QAAQ;CAE7D;CAEA,cAA+B;EAC7B,OAAO,qBAAqB,KAAK,QAAQ;CAC3C;CAEA,YAAY,UAAwC;EAClD,KAAK,WAAW,yBAAyB,QAAQ;CACnD;AACF;AA1Ca,oBAAN,kBAAA,CATN,KAAK;CACJ,WAAW;CAGX,KAAK;CACL,KAAK;CACL,KAAK;CACL,iBAAiB,CAAC,aAAa;AACjC,CAAC,CAAA,GACY,iBAAA;;;ACRN,IAAM,8BAAN,cAA0C,eAAkC;CACjF,OAAgB,aAAa;CAE7B,MAAM,iBACJ,YACmC;EAKnC,QAAO,MAJe,KAAK,KAAK;GAC9B,OAAO,EAAE,WAAW;GACpB,OAAO;EACT,CAAC,EAAA,CACc,MAAM;CACvB;CAEA,MAAM,kBAAkB,aAAmD;EACzE,OAAO,KAAK,KAAK,EACf,OAAO,EAAE,YAAY,EACvB,CAAC;CACH;CAEA,MAAM,iBAAiB,MAGpB;EACD,MAAM,WAAW,MAAM,KAAK,iBAAiB,KAAK,UAAU;EAE5D,IAAI,CAAC,UAAU;GACb,MAAM,UAAU,MAAM,KAAK,OAAO;IAChC,GAAG;IACH,UAAU,yBAAyB,KAAK,QAAQ;GAClD,CAAC;GACD,MAAM,QAAQ,KAAK;GACnB,OAAO;IAAE,YAAY;IAAS,QAAQ;GAAU;EAClD;EAEA,MAAM,eAAe,yBAAyB,KAAK,QAAQ;EAY3D,IAAI,EAVF,SAAS,gBAAgB,KAAK,eAC9B,SAAS,uBAAuB,KAAK,sBACrC,SAAS,cAAc,KAAK,aAC5B,SAAS,YAAY,KAAK,WAC1B,SAAS,mBAAmB,KAAK,kBACjC,SAAS,WAAW,KAAK,SAAS,OAClC,SAAS,iBAAiB,KAAK,eAAe,OAC9C,SAAS,aAAa,gBACtB,SAAS,gBAAgB,KAAK,cAAc,YAG5C,OAAO;GAAE,YAAY;GAAU,QAAQ;EAAY;EAGrD,SAAS,cAAc,KAAK;EAC5B,SAAS,qBAAqB,KAAK;EACnC,SAAS,YAAY,KAAK;EAC1B,SAAS,UAAU,KAAK;EACxB,SAAS,iBAAiB,KAAK;EAC/B,SAAS,QAAQ,KAAK,SAAS;EAC/B,SAAS,cAAc,KAAK,eAAe;EAC3C,SAAS,WAAW;EACpB,SAAS,aAAa,KAAK,cAAc;EACzC,MAAM,SAAS,KAAK;EAEpB,OAAO;GAAE,YAAY;GAAU,QAAQ;EAAU;CACnD;AACF;;;;;;;;;;;AC7CO,IAAM,kBAAN,cAA8B,WAAW;CAC9C,aAAqB;CACrB,YAA8B;CAC9B,UAAA;CACA,SAAgC,sBAAsB;CAEtD,YAAY,UAAkC,CAAC,GAAG;EAChD,MAAM,OAAO;EAEb,IAAI,QAAQ,eAAe,KAAA,GAAW,KAAK,aAAa,QAAQ;EAChE,IAAI,QAAQ,cAAc,KAAA,GAAW,KAAK,YAAY,QAAQ;EAC9D,IAAI,QAAQ,YAAY,KAAA,GAAW,KAAK,UAAU,QAAQ;EAC1D,IAAI,QAAQ,WAAW,KAAA,GAAW,KAAK,SAAS,QAAQ;CAC1D;CAEA,YAAqB;EACnB,OAAO,KAAK,WAAW,sBAAsB;CAC/C;CAEA,YAAqB;EACnB,OAAO,KAAK,WAAW,sBAAsB;CAC/C;CAEA,aAAsB;EACpB,OAAO,KAAK,WAAW,sBAAsB;CAC/C;AACF;AA1Ba,kBAAN,gBAAA,CAPN,KAAK;CACJ,WAAW;CACX,KAAK;CACL,KAAK;CACL,KAAK;CACL,iBAAiB;EAAC;EAAe;EAAc;CAAU;AAC3D,CAAC,CAAA,GACY,eAAA;;;ACCN,IAAM,oCAAN,cAAgD,MAAM;CAE3D,YAAqB,SAAsC;EACzD,MACE,oBAAoB,QAAQ,UAAS,cAAe,QAAQ,UAAS,OACvE;EAHmB,KAAA,UAAA;EAInB,KAAK,OAAO;CACd;CALqB;CADZ,SAAS;AAOpB;AAUO,IAAM,yBAAN,MAA6B;CAClC,YACmB,WACA,WACjB;EAFiB,KAAA,YAAA;EACA,KAAA,YAAA;CAChB;CAFgB;CACA;CAGnB,MAAM,YACJ,YACA,WACA,SACA,QAC0B;EAC1B,MAAM,KAAK,QAAQ;GACjB,WAAW;GACX;GACA;GACA;GACA;EACF,CAAC;EACD,OAAO,KAAK,UAAU,YAAY,YAAY,WAAW,SAAS,MAAM;CAC1E;CAEA,MAAM,eACJ,YACA,WACA,SACkB;EAClB,MAAM,KAAK,QAAQ;GAAE,WAAW;GAAU;GAAY;GAAW;EAAQ,CAAC;EAC1E,OAAO,KAAK,UAAU,eAAe,YAAY,WAAW,OAAO;CACrE;CAEA,MAAc,QAAQ,SAAqD;EACzE,IAAI,UAAU;EACd,IAAI;GACF,UAAW,MAAM,KAAK,UAAU,OAAO,MAAO;EAChD,QAAQ;GACN,UAAU;EACZ;EACA,IAAI,CAAC,SAAS,MAAM,IAAI,kCAAkC,OAAO;CACnE;AACF;;;AC1EO,IAAM,4BAAN,cAAwC,eAAgC;CAC7E,OAAgB,aAAa;CAE7B,MAAM,iBAAiB,YAAgD;EACrE,OAAO,KAAK,KAAK,EACf,OAAO,EAAE,WAAW,EACtB,CAAC;CACH;CAEA,MAAM,sBACJ,YACA,WACA,SACiC;EAKjC,QAAO,MAJe,KAAK,KAAK;GAC9B,OAAO;IAAE;IAAY;IAAW;GAAQ;GACxC,OAAO;EACT,CAAC,EAAA,CACc,MAAM;CACvB;CAEA,MAAM,kBAAkB,YAAqD;EAC3E,OAAO,KAAK,sBACV,YACA,UAAA,GAEF;CACF;CAEA,MAAM,kBACJ,YACA,UACiC;EACjC,OAAO,KAAK,sBAAsB,YAAY,UAAU,QAAQ;CAClE;CAEA,MAAM,eACJ,YACA,WACA,UACuC;EACvC,MAAM,yBAAS,IAAI,IAA6B;EAChD,IAAI,SAAS,WAAW,GACtB,OAAO;EAGT,MAAM,YAAY,MAAM,KAAK,KAAK,EAChC,OAAO;GAAE;GAAY;GAAW,SAAS;EAAS,EACpD,CAAC;EAED,KAAA,MAAW,YAAY,WACrB,OAAO,IAAI,SAAS,SAAS,QAAQ;EAGvC,OAAO;CACT;CAEA,MAAM,YACJ,YACA,WACA,SACA,QAC0B;EAC1B,MAAM,WAAW,MAAM,KAAK,sBAC1B,YACA,WACA,OACF;EAEA,IAAI,UAAU;GACZ,SAAS,SAAS;GAClB,MAAM,SAAS,KAAK;GACpB,OAAO;EACT;EAEA,MAAM,UAAU,MAAM,KAAK,OAAO;GAChC;GACA;GACA;GACA;EACF,CAAC;EACD,MAAM,QAAQ,KAAK;EACnB,OAAO;CACT;CAEA,MAAM,kBACJ,YACA,QAC0B;EAC1B,OAAO,KAAK,YACV,YACA,UAAA,KAEA,MACF;CACF;CAEA,MAAM,kBACJ,YACA,UACA,QAC0B;EAC1B,OAAO,KAAK,YAAY,YAAY,UAAU,UAAU,MAAM;CAChE;CAEA,MAAM,eACJ,YACA,WACA,SACkB;EAClB,MAAM,WAAW,MAAM,KAAK,sBAC1B,YACA,WACA,OACF;EAEA,IAAI,CAAC,UACH,OAAO;EAGT,MAAM,SAAS,OAAO;EACtB,OAAO;CACT;AACF;;;ACjHO,IAAM,kBAAN,MAAsB;CACV;CACA;CACT;CACA;CACA,wBAA8C;CAC9C,yBACN;CAEF,YACE,UAA4B,CAAC,GAC7B,kBAA0C,CAAC,GAC3C;EACA,KAAK,UAAU;EACf,KAAK,kBAAkB;CACzB;CAEA,MAAM,UACJ,YACA,UAAoC,CAAC,GACnB;EAClB,MAAM,KAAK,kBAAkB;EAE7B,MAAM,YAAY,MAAM,KAAK,iBAAiB,UAAU;EACxD,MAAM,iBACJ,MAAM,KAAK,iBAAiB,kBAAkB,UAAU;EAC1D,MAAM,cAAc,KAAK,cAAc,WAAW,gBAAgB,MAAM;EAExE,IAAI,CAAC,QAAQ,UACX,OAAO;EAGT,MAAM,kBAAkB,MAAM,KAAK,mBAAmB;EACtD,IAAI,CAAC,iBAAiB;GACpB,MAAM,iBAAiB,MAAM,KAAK,iBAAiB,kBACjD,YACA,QAAQ,QACV;GACA,OAAO,KAAK,cAAc,aAAa,gBAAgB,MAAM;EAC/D;EAEA,MAAM,QAAQ,MAAM,gBAAgB,SAAS,QAAQ,QAAQ;EAC7D,IAAI,MAAM,WAAW,GAAG;GACtB,MAAM,iBAAiB,MAAM,KAAK,iBAAiB,kBACjD,YACA,QAAQ,QACV;GACA,OAAO,KAAK,cAAc,aAAa,gBAAgB,MAAM;EAC/D;EAEA,MAAM,YAAY,MAAM,KAAK,iBAAiB,eAC5C,YACA,UACA,MAAM,KAAK,SAAS,KAAK,EAAE,CAC7B;EAEA,IAAI,iBAAiB;EAErB,KAAA,IAAS,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS;GACjD,MAAM,UAAU,MAAM;GACtB,MAAM,WAAW,QAAQ,IAAI,MAAM,QAAQ,KAAK;GAKhD,MAAM,WAHJ,UAAU,KACT,CAAC,CAAC,UAAU,sBAAsB,QAAQ,qBAEZ,iBAAiB;GAClD,MAAM,WAAW,UAAU,IAAI,QAAQ,EAAE;GACzC,iBAAiB,KAAK,cAAc,UAAU,UAAU,MAAM;EAChE;EAEA,OAAO;CACT;CAEA,MAAM,aACJ,iBACA,SACA,UAAoC,CAAC,GACnB;EAClB,MAAM,EAAE,eAAe,2BAA2B,iBAAiB,OAAO;EAC1E,OAAO,KAAK,UAAU,YAAY,OAAO;CAC3C;CAEA,MAAc,oBAAmC;EAC/C,IAAI,CAAC,KAAK,uBACR,KAAK,yBAAyB,YAAY;GACxC,KAAK,qBAAqB,MAAM,4BAA4B,OAC1D,KAAK,OACP;GACA,KAAK,mBAAmB,MAAM,0BAA0B,OACtD,KAAK,OACP;EACF,EAAA,CAAG;EAGL,MAAM,KAAK;CACb;CAEA,MAAc,iBAAiB,YAAsC;EACnE,MAAM,kBAAkB,6BAA6B,UAAU;EAC/D,IAAI,oBAAoB,KAAA,GACtB,OAAO;EAGT,MAAM,aACJ,MAAM,KAAK,mBAAmB,iBAAiB,UAAU;EAC3D,IAAI,CAAC,YACH,MAAM,IAAI,MACR,YAAY,WAAU,iEACxB;EAGF,OAAO,WAAW;CACpB;CAEQ,cACN,cACA,QACS;EACT,QAAQ,QAAR;GACE,KAAK,sBAAsB,QACzB,OAAO;GACT,KAAK,sBAAsB,SACzB,OAAO;GACT,SACE,OAAO;EACX;CACF;CAEA,MAAc,qBAAqE;EACjF,IAAI,CAAC,KAAK,wBAAwB;GAChC,MAAM,SACJ,KAAK,gBAAgB,yBACrB;GACF,KAAK,yBAAyB,OAAO,KAAK,OAAO;EACnD;EAEA,OAAO,KAAK;CACd;AACF;AAEA,eAAe,6BACb,SACgD;CAChD,IAAI;EAOF,MAAM,mBAAmB,OAAM,MANL,sBAA0C;GAClE,aAAa;GACb,aAAa;GACb,SAAS;EACX,CAAC,EAAA,CAE0C,iBAAiB,OAAO,OAAO;EAC1E,OAAO,EACL,MAAM,SAAS,UAAgD;GAC7D,MAAM,SAAS,MAAM,iBAAiB,IAAI,EAAE,IAAI,SAAS,CAAC;GAC1D,IAAI,CAAC,QACH,OAAO,CAAC;GAIV,OAAO,CAAC,GAAG,MADa,iBAAiB,qBAAqB,QAAQ,GAChD,MAAM,CAAA,CAAE,KAAK,UAAU;IAC3C,IAAI,OAAO,KAAK,EAAE;IAClB,oBAAoB,QAAQ,KAAK,kBAAkB;IACnD,oBAAoB,QAAQ,KAAK,kBAAkB;GACrD,EAAE;EACJ,EACF;CACF,SAAS,OAAO;EACd,IAAI,yBAAyB,KAAK,GAChC,OAAO;EAET,MAAM;CACR;AACF;AAEA,SAAS,yBAAyB,OAAyB;CACzD,IAAI,EAAE,iBAAiB,QACrB,OAAO;CAGT,MAAM,eACJ,MAAM,iBAAiB,QAAQ,IAAI,MAAM,MAAM,YAAY;CAC7D,MAAM,OAAO,GAAG,MAAM,UAAU;CAEhC,OACE,KAAK,SAAS,2BAA2B,MACxC,KAAK,SAAS,oBAAoB,KACjC,KAAK,SAAS,gBAAgB,KAC9B,KAAK,SAAS,gBAAgB;AAEpC;;;AC3LO,IAAM,qBAAN,MAAyB;CACb;CACT;CACA,wBAA8C;CAEtD,YAAY,UAA4B,CAAC,GAAG;EAC1C,KAAK,UAAU;CACjB;CAEA,MAAM,gBACJ,UAAkC,CAAC,GACP;EAC5B,MAAM,KAAK,kBAAkB;EAC7B,MAAM,gBAAgB,KAAK,qBAAqB,OAAO;EACvD,MAAM,cAAc,KAAK,oCAAoC,aAAa;EAC1E,MAAM,kBACJ,KAAK,wCAAwC,aAAa;EAI5D,MAAM,aAFJ,QAAQ,QAAQ,YAAY,MAAM,KAClC,QAAQ,QAAQ,cAAc,MAAM,IACF,QAAS,QAAQ,cAAc;EAEnE,OAAO,KAAK,iBAAiB,aAAa,iBAAiB,UAAU;CACvE;CAEA,MAAM,aACJ,UACA,UAA+B,CAAC,GACJ;EAC5B,MAAM,KAAK,kBAAkB;EAC7B,MAAM,cAAc,gCAAgC,QAAQ;EAC5D,MAAM,kBAAkB,mCAAmC,QAAQ;EACnE,OAAO,KAAK,iBACV,aACA,iBACA,QAAQ,cAAc,IACxB;CACF;CAEA,MAAc,oBAAmC;EAC/C,IAAI,CAAC,KAAK,uBACR,KAAK,yBAAyB,YAAY;GACxC,KAAK,qBAAqB,MAAM,4BAA4B,OAC1D,KAAK,OACP;EACF,EAAA,CAAG;EAGL,MAAM,KAAK;CACb;CAEQ,oCACN,eACyB;EACzB,MAAM,cAAuC,CAAC;EAE9C,KAAA,MAAW,gBAAgB,eACzB,YAAY,KAAK,GAAG,qCAAqC,YAAY,CAAC;EAGxE,OAAO;CACT;CAEQ,wCACN,eACa;EACb,MAAM,2BAAW,IAAI,IAAY;EAEjC,KAAA,MAAW,gBAAgB,eAAe;GACxC,IAAI,aAAa,eAAe,QAC9B;GAGF,MAAM,cAAc,2BAA2B,YAAY;GAC3D,IAAI,aACF,SAAS,IAAI,WAAW;EAE5B;EAEA,OAAO;CACT;CAEQ,qBACN,SACqB;EACrB,IAAI,QAAQ,YAAY,QACtB,OAAO,QAAQ,WACZ,KAAK,SAAS,eAAe,SAAS,IAAI,CAAC,CAAA,CAC3C,QAAQ,UAA8C,CAAC,CAAC,KAAK;EAGlE,IAAI,QAAQ,cAAc,QACxB,OAAO,QAAQ,aACZ,KAAK,SAAS,eAAe,sBAAsB,IAAI,CAAC,CAAA,CACxD,QAAQ,UAA8C,CAAC,CAAC,KAAK;EAGlE,MAAM,gBAAqC,CAAC;EAC5C,MAAM,uBAAO,IAAI,IAAuB;EAExC,KAAA,MAAW,gBAAgB,eAAe,cAAc,CAAA,CAAE,OAAO,GAAG;GAClE,IAAI,KAAK,IAAI,YAAY,GACvB;GAEF,KAAK,IAAI,YAAY;GACrB,cAAc,KAAK,YAAY;EACjC;EAEA,OAAO;CACT;CAEA,MAAc,iBACZ,aACA,iBACA,YAC4B;EAC5B,MAAM,0BAAU,IAAI,IAAmC;EACvD,KAAA,MAAW,cAAc,aACvB,QAAQ,IAAI,WAAW,YAAY,UAAU;EAG/C,IAAI,UAAU;EACd,IAAI,UAAU;EACd,IAAI,YAAY;EAChB,IAAI,UAAU;EAEd,MAAM,qBAAqB,MAAM,KAAK,QAAQ,OAAO,CAAC;EACtD,MAAM,cAAc,IAAI,IACtB,mBAAmB,KAAK,eAAe,WAAW,UAAU,CAC9D;EACA,MAAM,gBAAgB,MAAM,QAAQ,IAClC,mBAAmB,KAAK,eACtB,KAAK,mBAAmB,iBAAiB,UAAU,CACrD,CACF;EACA,KAAA,MAAW,UAAU,eAAe;GAClC,IAAI,OAAO,WAAW,WAAW;GACjC,IAAI,OAAO,WAAW,WAAW;GACjC,IAAI,OAAO,WAAW,aAAa;EACrC;EAEA,IAAI,YAAY;GAOd,MAAM,oBAAmB,MANO,QAAQ,IACtC,MAAM,KAAK,kBAAkB,gBAC3B,KAAK,mBAAmB,kBAAkB,WAAW,CACvD,CACF,EAAA,CAE2C,SAAS,aAClD,SAAS,QACN,eAAe,CAAC,YAAY,IAAI,WAAW,UAAU,CACxD,CACF;GAEA,MAAM,QAAQ,IACZ,iBAAiB,KAAK,eAAe,WAAW,OAAO,CAAC,CAC1D;GACA,UAAU,iBAAiB;EAC7B;EAEA,OAAO;GACL,OAAO,QAAQ;GACf;GACA;GACA;GACA;GACA,aAAa,MAAM,KAAK,WAAW,CAAA,CAAE,KAAK;EAC5C;CACF;AACF"}