@happyvertical/smrt-features 0.35.2 → 0.35.3
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/dist/index.d.ts +24 -5
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +2 -2
- package/dist/smrt-knowledge.json +4 -4
- package/dist/types.d.ts +23 -3
- package/dist/types.js.map +1 -1
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -117,7 +117,7 @@ export declare class FeatureResolver {
|
|
|
117
117
|
private tenantHierarchyPromise;
|
|
118
118
|
constructor(options?: SmrtClassOptions, resolverOptions?: FeatureResolverOptions);
|
|
119
119
|
isEnabled(featureKey: string, context?: FeatureResolutionContext): Promise<boolean>;
|
|
120
|
-
isEnabledFor(classOrInstance: object |
|
|
120
|
+
isEnabledFor(classOrInstance: object | FeatureTargetConstructor, localId: string, context?: FeatureResolutionContext): Promise<boolean>;
|
|
121
121
|
private ensureInitialized;
|
|
122
122
|
private resolveBaseState;
|
|
123
123
|
private applyOverride;
|
|
@@ -153,6 +153,14 @@ export declare class FeatureSyncService {
|
|
|
153
153
|
private applyDefinitions;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Constructor type for any `@smrt()`-decorated class that may declare feature
|
|
158
|
+
* toggles. Feature targets always extend `SmrtObject`, so this mirrors
|
|
159
|
+
* `@happyvertical/smrt-core`'s internal (non-exported) `SmrtObjectConstructor`
|
|
160
|
+
* and remains assignable to it for `ObjectRegistry.getClassByConstructor`.
|
|
161
|
+
*/
|
|
162
|
+
declare type FeatureTargetConstructor = new (...args: unknown[]) => SmrtObject;
|
|
163
|
+
|
|
156
164
|
export declare type FeatureTenantHierarchyLoader = (options: SmrtClassOptions) => Promise<FeatureTenantHierarchyProvider | null>;
|
|
157
165
|
|
|
158
166
|
export declare interface FeatureTenantHierarchyProvider {
|
|
@@ -170,12 +178,23 @@ export declare interface FeatureUsersModule {
|
|
|
170
178
|
create(options: SmrtClassOptions): Promise<{
|
|
171
179
|
get(criteria: {
|
|
172
180
|
id: string;
|
|
173
|
-
}): Promise<
|
|
174
|
-
getAncestorsFromRoot(tenantId: string): Promise<
|
|
181
|
+
}): Promise<FeatureUsersTenantRecord | null>;
|
|
182
|
+
getAncestorsFromRoot(tenantId: string): Promise<FeatureUsersTenantRecord[]>;
|
|
175
183
|
}>;
|
|
176
184
|
};
|
|
177
185
|
}
|
|
178
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Minimal structural shape of a tenant record returned by
|
|
189
|
+
* `@happyvertical/smrt-users`. Only the permission-cascade fields consumed by
|
|
190
|
+
* feature resolution are modeled; everything else is left unconstrained.
|
|
191
|
+
*/
|
|
192
|
+
declare interface FeatureUsersTenantRecord {
|
|
193
|
+
id: string;
|
|
194
|
+
inheritPermissions?: boolean;
|
|
195
|
+
cascadePermissions?: boolean;
|
|
196
|
+
}
|
|
197
|
+
|
|
179
198
|
export declare function findFeatureDefaultInRegistry(featureKey: string): boolean | undefined;
|
|
180
199
|
|
|
181
200
|
export declare const GLOBAL_FEATURE_SCOPE_ID = "*";
|
|
@@ -185,14 +204,14 @@ export declare function parseFeatureKey(featureKey: string): {
|
|
|
185
204
|
localId: string;
|
|
186
205
|
};
|
|
187
206
|
|
|
188
|
-
export declare function resolveFeatureKeyForTarget(classOrInstance: object |
|
|
207
|
+
export declare function resolveFeatureKeyForTarget(classOrInstance: object | FeatureTargetConstructor, localId: string): {
|
|
189
208
|
featureKey: string;
|
|
190
209
|
defaultEnabled: boolean;
|
|
191
210
|
};
|
|
192
211
|
|
|
193
212
|
export declare interface SyncDefinitionsOptions {
|
|
194
213
|
classNames?: string[];
|
|
195
|
-
constructors?:
|
|
214
|
+
constructors?: FeatureTargetConstructor[];
|
|
196
215
|
pruneStale?: boolean;
|
|
197
216
|
}
|
|
198
217
|
|
package/dist/index.js
CHANGED
|
@@ -513,9 +513,7 @@ class FeatureResolver {
|
|
|
513
513
|
if (!this.initializationPromise) {
|
|
514
514
|
this.initializationPromise = (async () => {
|
|
515
515
|
this.featureDefinitions = await FeatureDefinitionCollection.create(this.options);
|
|
516
|
-
this.featureOverrides = await FeatureOverrideCollection.create(
|
|
517
|
-
this.options
|
|
518
|
-
);
|
|
516
|
+
this.featureOverrides = await FeatureOverrideCollection.create(this.options);
|
|
519
517
|
})();
|
|
520
518
|
}
|
|
521
519
|
await this.initializationPromise;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","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// `new URL('./manifest.json', import.meta.url)` resolves at runtime to the\n// manifest sitting next to this module's compiled output. Vite warns at build\n// time that it cannot pre-resolve the URL; that is the intended behavior —\n// the URL must resolve to dist/manifest.json at runtime, not be inlined.\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 { FeatureDefinitionSeed, FeatureMetadata } from './types.js';\n\ntype 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 | (new (...args: any[]) => any),\n localId: string,\n): {\n featureKey: string;\n defaultEnabled: boolean;\n} {\n const ctor =\n typeof classOrInstance === 'function'\n ? (classOrInstance as new (\n ...args: any[]\n ) => any)\n : (classOrInstance as any).constructor;\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 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 | (new (...args: any[]) => any),\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 (\n FeatureDefinitionCollection as any\n ).create(this.options);\n this.featureOverrides = await (FeatureOverrideCollection as any).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: any) => ({\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} 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 (\n FeatureDefinitionCollection as any\n ).create(this.options);\n })();\n }\n\n await this.initializationPromise;\n }\n\n private collectDefinitionsFromRegistrations(\n registrations: Array<any>,\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: Array<any>,\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(options: SyncDefinitionsOptions): Array<any> {\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 as any))\n .filter((value): value is NonNullable<typeof value> => !!value);\n }\n\n const registrations: any[] = [];\n const seen = new Set<any>();\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"],"names":["__decorateClass"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","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// `new URL('./manifest.json', import.meta.url)` resolves at runtime to the\n// manifest sitting next to this module's compiled output. Vite warns at build\n// time that it cannot pre-resolve the URL; that is the intended behavior —\n// the URL must resolve to dist/manifest.json at runtime, not be inlined.\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 =\n await FeatureDefinitionCollection.create(this.options);\n this.featureOverrides =\n await FeatureOverrideCollection.create(this.options);\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 =\n await FeatureDefinitionCollection.create(this.options);\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"],"names":["__decorateClass"],"mappings":"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"}
|
package/dist/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1.0.0",
|
|
3
|
-
"timestamp":
|
|
3
|
+
"timestamp": 1782345907136,
|
|
4
4
|
"packageName": "@happyvertical/smrt-features",
|
|
5
|
-
"packageVersion": "0.35.
|
|
5
|
+
"packageVersion": "0.35.3",
|
|
6
6
|
"objects": {
|
|
7
7
|
"@happyvertical/smrt-features:FeatureDefinition": {
|
|
8
8
|
"name": "featuredefinition",
|
package/dist/smrt-knowledge.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"generatedAt": "2026-06-
|
|
3
|
+
"generatedAt": "2026-06-25T00:05:09.268Z",
|
|
4
4
|
"packageName": "@happyvertical/smrt-features",
|
|
5
|
-
"packageVersion": "0.35.
|
|
5
|
+
"packageVersion": "0.35.3",
|
|
6
6
|
"sourceManifestPath": "dist/manifest.json",
|
|
7
7
|
"agentDocPath": "AGENTS.md",
|
|
8
8
|
"sourceHashes": {
|
|
9
|
-
"manifest": "
|
|
10
|
-
"packageJson": "
|
|
9
|
+
"manifest": "7d8e20347ecbc2a19d387c4fd3275be20fe948c10c526c795a7cb2401c7a913d",
|
|
10
|
+
"packageJson": "a4f3f8481eb1e0933679acbdc607097e672bd16342dfd9019a3f0acfe7cf61e6",
|
|
11
11
|
"agents": "0d14be2150e562d6834a67a6fd2a5d8bf63a1654e1f5a5165d1c97c2057574a8"
|
|
12
12
|
},
|
|
13
13
|
"exports": [
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SmartObjectManifest } from '@happyvertical/smrt-core';
|
|
2
2
|
import { SmrtClassOptions } from '@happyvertical/smrt-core';
|
|
3
|
+
import { SmrtObject } from '@happyvertical/smrt-core';
|
|
3
4
|
|
|
4
5
|
export declare interface FeatureDefinitionOptions {
|
|
5
6
|
id?: string;
|
|
@@ -69,6 +70,14 @@ export declare interface FeatureSyncResult {
|
|
|
69
70
|
featureKeys: string[];
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Constructor type for any `@smrt()`-decorated class that may declare feature
|
|
75
|
+
* toggles. Feature targets always extend `SmrtObject`, so this mirrors
|
|
76
|
+
* `@happyvertical/smrt-core`'s internal (non-exported) `SmrtObjectConstructor`
|
|
77
|
+
* and remains assignable to it for `ObjectRegistry.getClassByConstructor`.
|
|
78
|
+
*/
|
|
79
|
+
export declare type FeatureTargetConstructor = new (...args: unknown[]) => SmrtObject;
|
|
80
|
+
|
|
72
81
|
export declare type FeatureTenantHierarchyLoader = (options: SmrtClassOptions) => Promise<FeatureTenantHierarchyProvider | null>;
|
|
73
82
|
|
|
74
83
|
export declare interface FeatureTenantHierarchyProvider {
|
|
@@ -86,12 +95,23 @@ export declare interface FeatureUsersModule {
|
|
|
86
95
|
create(options: SmrtClassOptions): Promise<{
|
|
87
96
|
get(criteria: {
|
|
88
97
|
id: string;
|
|
89
|
-
}): Promise<
|
|
90
|
-
getAncestorsFromRoot(tenantId: string): Promise<
|
|
98
|
+
}): Promise<FeatureUsersTenantRecord | null>;
|
|
99
|
+
getAncestorsFromRoot(tenantId: string): Promise<FeatureUsersTenantRecord[]>;
|
|
91
100
|
}>;
|
|
92
101
|
};
|
|
93
102
|
}
|
|
94
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Minimal structural shape of a tenant record returned by
|
|
106
|
+
* `@happyvertical/smrt-users`. Only the permission-cascade fields consumed by
|
|
107
|
+
* feature resolution are modeled; everything else is left unconstrained.
|
|
108
|
+
*/
|
|
109
|
+
export declare interface FeatureUsersTenantRecord {
|
|
110
|
+
id: string;
|
|
111
|
+
inheritPermissions?: boolean;
|
|
112
|
+
cascadePermissions?: boolean;
|
|
113
|
+
}
|
|
114
|
+
|
|
95
115
|
export declare const GLOBAL_FEATURE_SCOPE_ID = "*";
|
|
96
116
|
|
|
97
117
|
export { SmartObjectManifest }
|
|
@@ -100,7 +120,7 @@ export { SmrtClassOptions }
|
|
|
100
120
|
|
|
101
121
|
export declare interface SyncDefinitionsOptions {
|
|
102
122
|
classNames?: string[];
|
|
103
|
-
constructors?:
|
|
123
|
+
constructors?: FeatureTargetConstructor[];
|
|
104
124
|
pruneStale?: boolean;
|
|
105
125
|
}
|
|
106
126
|
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sources":["../src/types.ts"],"sourcesContent":["import type {\n SmartObjectManifest,\n SmrtClassOptions,\n} from '@happyvertical/smrt-core';\n\nexport const GLOBAL_FEATURE_SCOPE_ID = '*';\n\nexport type FeatureScopeType = 'global' | 'tenant';\n\nexport enum FeatureOverrideEffect {\n INHERIT = 'inherit',\n ENABLE = 'enable',\n DISABLE = 'disable',\n}\n\nexport interface FeatureMetadata {\n [key: string]: unknown;\n}\n\nexport interface FeatureDefinitionOptions {\n id?: string;\n featureKey?: string;\n packageName?: string;\n qualifiedClassName?: string;\n className?: string;\n localId?: string;\n defaultEnabled?: boolean;\n label?: string;\n description?: string;\n metadata?: FeatureMetadata | string | null;\n visibility?: string;\n createdAt?: Date;\n updatedAt?: Date;\n}\n\nexport interface FeatureOverrideOptions {\n id?: string;\n featureKey?: string;\n scopeType?: FeatureScopeType;\n scopeId?: string;\n effect?: FeatureOverrideEffect;\n createdAt?: Date;\n updatedAt?: Date;\n}\n\nexport interface FeatureDefinitionSeed {\n featureKey: string;\n packageName: string;\n qualifiedClassName: string;\n className: string;\n localId: string;\n defaultEnabled: boolean;\n label?: string;\n description?: string;\n metadata?: FeatureMetadata;\n visibility?: string;\n}\n\nexport interface SyncDefinitionsOptions {\n classNames?: string[];\n constructors?:
|
|
1
|
+
{"version":3,"file":"types.js","sources":["../src/types.ts"],"sourcesContent":["import type {\n SmartObjectManifest,\n SmrtClassOptions,\n SmrtObject,\n} from '@happyvertical/smrt-core';\n\nexport const GLOBAL_FEATURE_SCOPE_ID = '*';\n\nexport type FeatureScopeType = 'global' | 'tenant';\n\n/**\n * Constructor type for any `@smrt()`-decorated class that may declare feature\n * toggles. Feature targets always extend `SmrtObject`, so this mirrors\n * `@happyvertical/smrt-core`'s internal (non-exported) `SmrtObjectConstructor`\n * and remains assignable to it for `ObjectRegistry.getClassByConstructor`.\n */\nexport type FeatureTargetConstructor = new (\n ...args: unknown[]\n) => SmrtObject;\n\nexport enum FeatureOverrideEffect {\n INHERIT = 'inherit',\n ENABLE = 'enable',\n DISABLE = 'disable',\n}\n\nexport interface FeatureMetadata {\n [key: string]: unknown;\n}\n\nexport interface FeatureDefinitionOptions {\n id?: string;\n featureKey?: string;\n packageName?: string;\n qualifiedClassName?: string;\n className?: string;\n localId?: string;\n defaultEnabled?: boolean;\n label?: string;\n description?: string;\n metadata?: FeatureMetadata | string | null;\n visibility?: string;\n createdAt?: Date;\n updatedAt?: Date;\n}\n\nexport interface FeatureOverrideOptions {\n id?: string;\n featureKey?: string;\n scopeType?: FeatureScopeType;\n scopeId?: string;\n effect?: FeatureOverrideEffect;\n createdAt?: Date;\n updatedAt?: Date;\n}\n\nexport interface FeatureDefinitionSeed {\n featureKey: string;\n packageName: string;\n qualifiedClassName: string;\n className: string;\n localId: string;\n defaultEnabled: boolean;\n label?: string;\n description?: string;\n metadata?: FeatureMetadata;\n visibility?: string;\n}\n\nexport interface SyncDefinitionsOptions {\n classNames?: string[];\n constructors?: FeatureTargetConstructor[];\n pruneStale?: boolean;\n}\n\nexport interface SyncManifestOptions {\n pruneStale?: boolean;\n}\n\nexport interface FeatureSyncResult {\n total: number;\n created: number;\n updated: number;\n unchanged: number;\n deleted: number;\n featureKeys: string[];\n}\n\nexport interface FeatureResolutionContext {\n tenantId?: string;\n}\n\nexport interface FeatureTenantNode {\n id: string;\n inheritPermissions: boolean;\n cascadePermissions: boolean;\n}\n\nexport interface FeatureTenantHierarchyProvider {\n getChain(tenantId: string): Promise<FeatureTenantNode[]>;\n}\n\nexport type FeatureTenantHierarchyLoader = (\n options: SmrtClassOptions,\n) => Promise<FeatureTenantHierarchyProvider | null>;\n\nexport interface FeatureResolverOptions {\n tenantHierarchyLoader?: FeatureTenantHierarchyLoader;\n}\n\n/**\n * Minimal structural shape of a tenant record returned by\n * `@happyvertical/smrt-users`. Only the permission-cascade fields consumed by\n * feature resolution are modeled; everything else is left unconstrained.\n */\nexport interface FeatureUsersTenantRecord {\n id: string;\n inheritPermissions?: boolean;\n cascadePermissions?: boolean;\n}\n\nexport interface FeatureUsersModule {\n TenantCollection: {\n create(options: SmrtClassOptions): Promise<{\n get(criteria: { id: string }): Promise<FeatureUsersTenantRecord | null>;\n getAncestorsFromRoot(\n tenantId: string,\n ): Promise<FeatureUsersTenantRecord[]>;\n }>;\n };\n}\n\nexport type { SmrtClassOptions, SmartObjectManifest };\n"],"names":["FeatureOverrideEffect"],"mappings":"AAMO,MAAM,0BAA0B;AAchC,IAAK,0CAAAA,2BAAL;AACLA,yBAAA,SAAA,IAAU;AACVA,yBAAA,QAAA,IAAS;AACTA,yBAAA,SAAA,IAAU;AAHA,SAAAA;AAAA,GAAA,yBAAA,CAAA,CAAA;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/smrt-features",
|
|
3
|
-
"version": "0.35.
|
|
3
|
+
"version": "0.35.3",
|
|
4
4
|
"description": "Code-first feature flags and tenant-aware overrides for the SMRT framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -19,16 +19,16 @@
|
|
|
19
19
|
"./manifest.json": "./dist/manifest.json"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@happyvertical/smrt-core": "0.35.
|
|
22
|
+
"@happyvertical/smrt-core": "0.35.3"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "25.0.9",
|
|
26
26
|
"typescript": "^5.9.3",
|
|
27
27
|
"vite": "^7.3.1",
|
|
28
28
|
"vitest": "^4.0.17",
|
|
29
|
-
"@happyvertical/smrt-
|
|
30
|
-
"@happyvertical/smrt-
|
|
31
|
-
"@happyvertical/smrt-vitest": "0.35.
|
|
29
|
+
"@happyvertical/smrt-users": "0.35.3",
|
|
30
|
+
"@happyvertical/smrt-cli": "0.35.3",
|
|
31
|
+
"@happyvertical/smrt-vitest": "0.35.3"
|
|
32
32
|
},
|
|
33
33
|
"keywords": [
|
|
34
34
|
"smrt",
|