@anterprize/fturex 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +226 -0
  3. package/dist/FtureXClient.d.ts +72 -0
  4. package/dist/FtureXClient.js +427 -0
  5. package/dist/angular/feature-toggle.directive.d.ts +32 -0
  6. package/dist/angular/feature-toggle.directive.js +77 -0
  7. package/dist/angular/feature-toggle.pipe.d.ts +20 -0
  8. package/dist/angular/feature-toggle.pipe.js +37 -0
  9. package/dist/angular/fturex.config.d.ts +7 -0
  10. package/dist/angular/fturex.config.js +2 -0
  11. package/dist/angular/fturex.module.d.ts +23 -0
  12. package/dist/angular/fturex.module.js +48 -0
  13. package/dist/angular/fturex.service.d.ts +31 -0
  14. package/dist/angular/fturex.service.js +56 -0
  15. package/dist/angular/index.d.ts +6 -0
  16. package/dist/angular/index.js +5 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.js +2 -0
  19. package/dist/opentelemetry/FtureXOtelHook.d.ts +58 -0
  20. package/dist/opentelemetry/FtureXOtelHook.js +86 -0
  21. package/dist/opentelemetry/index.d.ts +2 -0
  22. package/dist/opentelemetry/index.js +1 -0
  23. package/dist/react/FeatureToggle.d.ts +14 -0
  24. package/dist/react/FeatureToggle.js +16 -0
  25. package/dist/react/FeatureToggleProvider.d.ts +15 -0
  26. package/dist/react/FeatureToggleProvider.js +17 -0
  27. package/dist/react/index.d.ts +3 -0
  28. package/dist/react/index.js +3 -0
  29. package/dist/react/useFeatureToggle.d.ts +27 -0
  30. package/dist/react/useFeatureToggle.js +104 -0
  31. package/dist/svelte/index.d.ts +2 -0
  32. package/dist/svelte/index.js +1 -0
  33. package/dist/svelte/useFeatureToggle.d.ts +54 -0
  34. package/dist/svelte/useFeatureToggle.js +85 -0
  35. package/dist/types.d.ts +122 -0
  36. package/dist/types.js +1 -0
  37. package/dist/vue/index.d.ts +1 -0
  38. package/dist/vue/index.js +2 -0
  39. package/dist/vue/useFeatureToggle.d.ts +32 -0
  40. package/dist/vue/useFeatureToggle.js +104 -0
  41. package/package.json +99 -0
  42. package/src/vue/FeatureToggle.vue +28 -0
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Configuration for the FtureX Client
3
+ */
4
+ export interface FtureXConfiguration {
5
+ /**
6
+ * Base URL of the feature toggle API
7
+ */
8
+ baseUrl: string;
9
+ /**
10
+ * Application API key for authentication
11
+ */
12
+ appKey: string;
13
+ /**
14
+ * Enable sending statistics to the API
15
+ * @default true
16
+ */
17
+ sendStatistics?: boolean;
18
+ }
19
+ /**
20
+ * Cache options for feature toggles
21
+ */
22
+ export interface FeatureCacheOptions {
23
+ /**
24
+ * Interval in seconds to refresh the feature manifest from the API
25
+ * @default 30
26
+ */
27
+ refreshIntervalSeconds?: number;
28
+ /**
29
+ * Enable persisting the manifest to localStorage
30
+ * @default true
31
+ */
32
+ enableLocalStoragePersistence?: boolean;
33
+ /**
34
+ * Key used for localStorage persistence
35
+ * @default 'feature-toggle-cache'
36
+ */
37
+ localStorageKey?: string;
38
+ }
39
+ /**
40
+ * Context properties for feature evaluation
41
+ */
42
+ export interface ContextProperties {
43
+ [key: string]: string;
44
+ }
45
+ /**
46
+ * A single condition rule as returned by the server manifest
47
+ */
48
+ export interface ConditionRule {
49
+ contextProperty: string;
50
+ operator: string;
51
+ value?: string;
52
+ conditionGroupValues?: string[];
53
+ /**
54
+ * Logical operator connecting this rule to the NEXT one.
55
+ * 'AND' (default when absent) — both this and the next rule must match.
56
+ * 'OR' — either this AND-segment or the next must match.
57
+ * Ignored on the last rule in the array.
58
+ */
59
+ logicAfter?: 'AND' | 'OR';
60
+ }
61
+ /**
62
+ * A single feature entry in the manifest
63
+ */
64
+ export interface ManifestEntry {
65
+ name: string;
66
+ enabled: boolean;
67
+ conditions: ConditionRule[];
68
+ }
69
+ /**
70
+ * Full feature manifest returned by GET /feature/manifest
71
+ */
72
+ export interface FeatureManifest {
73
+ features: ManifestEntry[];
74
+ }
75
+ /**
76
+ * Statistics for a feature
77
+ */
78
+ export interface FeatureStatistics {
79
+ featureName: string;
80
+ hitCount: number;
81
+ enabledCount: number;
82
+ disabledCount: number;
83
+ lastAccessed: Date;
84
+ }
85
+ /**
86
+ * Statistics report sent to the API
87
+ */
88
+ export interface StatisticsReport {
89
+ appKey: string;
90
+ features: FeatureStatistics[];
91
+ reportTimestamp: Date;
92
+ }
93
+ /**
94
+ * Describes how the flag value was determined.
95
+ * Follows OTel semantic conventions for feature flags.
96
+ */
97
+ export type EvaluationReason = 'static' | 'targeting_match' | 'default' | 'error' | 'stale' | 'disabled';
98
+ /**
99
+ * Context passed to hooks for each flag evaluation.
100
+ */
101
+ export interface HookContext {
102
+ flagKey: string;
103
+ evaluationContext?: ContextProperties;
104
+ defaultValue: boolean;
105
+ }
106
+ /**
107
+ * Result of a feature flag evaluation, passed to hooks.
108
+ */
109
+ export interface EvaluationResult {
110
+ value: boolean;
111
+ reason: EvaluationReason;
112
+ }
113
+ /**
114
+ * Hook interface for observing feature flag evaluations.
115
+ * Implement this to add custom telemetry, logging, or analytics.
116
+ * All methods are optional.
117
+ */
118
+ export interface FtureXHook {
119
+ before?(context: HookContext): void | Promise<void>;
120
+ after?(context: HookContext, result: EvaluationResult): void | Promise<void>;
121
+ error?(context: HookContext, error: unknown): void | Promise<void>;
122
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export { FeatureToggleClientKey, useFeatureToggle, useFeatureToggles } from './useFeatureToggle.js';
@@ -0,0 +1,2 @@
1
+ export { FeatureToggleClientKey, useFeatureToggle, useFeatureToggles } from './useFeatureToggle.js';
2
+ // FeatureToggle.vue SFC måste importeras direkt: import FeatureToggle from '@anterprize/fturex/vue/FeatureToggle.vue'
@@ -0,0 +1,32 @@
1
+ import { Ref, InjectionKey } from 'vue';
2
+ import { FtureXClient } from '../FtureXClient.js';
3
+ import { ContextProperties } from '../types.js';
4
+ export declare const FeatureToggleClientKey: InjectionKey<FtureXClient>;
5
+ /**
6
+ * Vue composable for checking feature toggles.
7
+ * Re-evaluates automatically whenever the client refreshes its manifest,
8
+ * so the UI updates without a page reload.
9
+ *
10
+ * @param featureName - Name of the feature to check
11
+ * @param context - Optional context properties for the feature check
12
+ * @returns Reactive object with isEnabled, loading, and error states
13
+ */
14
+ export declare function useFeatureToggle(featureName: string, context?: ContextProperties): {
15
+ isEnabled: Ref<boolean, boolean>;
16
+ loading: Ref<boolean, boolean>;
17
+ error: Ref<Error | null, Error | null>;
18
+ refresh: () => Promise<void>;
19
+ };
20
+ /**
21
+ * Vue composable for checking multiple feature toggles at once.
22
+ * Re-evaluates automatically whenever the client refreshes its manifest.
23
+ *
24
+ * @param featureNames - Array of feature names to check
25
+ * @returns Reactive object with features map, loading state, and error
26
+ */
27
+ export declare function useFeatureToggles(featureNames: string[]): {
28
+ features: Ref<Record<string, boolean>, Record<string, boolean>>;
29
+ loading: Ref<boolean, boolean>;
30
+ error: Ref<Error | null, Error | null>;
31
+ refresh: () => Promise<void>;
32
+ };
@@ -0,0 +1,104 @@
1
+ import { ref, inject, onMounted, onUnmounted } from 'vue';
2
+ export const FeatureToggleClientKey = Symbol('FeatureToggleClient');
3
+ /**
4
+ * Vue composable for checking feature toggles.
5
+ * Re-evaluates automatically whenever the client refreshes its manifest,
6
+ * so the UI updates without a page reload.
7
+ *
8
+ * @param featureName - Name of the feature to check
9
+ * @param context - Optional context properties for the feature check
10
+ * @returns Reactive object with isEnabled, loading, and error states
11
+ */
12
+ export function useFeatureToggle(featureName, context) {
13
+ const client = inject(FeatureToggleClientKey);
14
+ const isEnabled = ref(false);
15
+ const loading = ref(true);
16
+ const error = ref(null);
17
+ const evaluate = async () => {
18
+ if (!client) {
19
+ error.value = new Error('FeatureToggleClient not provided. Use app.provide() to provide the client.');
20
+ loading.value = false;
21
+ return;
22
+ }
23
+ try {
24
+ loading.value = true;
25
+ const enabled = context
26
+ ? await client.isEnabledWithContext(featureName, context)
27
+ : await client.isEnabled(featureName);
28
+ isEnabled.value = enabled;
29
+ error.value = null;
30
+ }
31
+ catch (err) {
32
+ error.value = err;
33
+ isEnabled.value = false;
34
+ }
35
+ finally {
36
+ loading.value = false;
37
+ }
38
+ };
39
+ onMounted(() => {
40
+ client?.on('update', evaluate);
41
+ client?.on('ready', evaluate);
42
+ evaluate();
43
+ });
44
+ onUnmounted(() => {
45
+ client?.off('update', evaluate);
46
+ client?.off('ready', evaluate);
47
+ });
48
+ return {
49
+ isEnabled,
50
+ loading,
51
+ error,
52
+ refresh: evaluate
53
+ };
54
+ }
55
+ /**
56
+ * Vue composable for checking multiple feature toggles at once.
57
+ * Re-evaluates automatically whenever the client refreshes its manifest.
58
+ *
59
+ * @param featureNames - Array of feature names to check
60
+ * @returns Reactive object with features map, loading state, and error
61
+ */
62
+ export function useFeatureToggles(featureNames) {
63
+ const client = inject(FeatureToggleClientKey);
64
+ const features = ref({});
65
+ const loading = ref(true);
66
+ const error = ref(null);
67
+ const evaluate = async () => {
68
+ if (!client) {
69
+ error.value = new Error('FeatureToggleClient not provided. Use app.provide() to provide the client.');
70
+ loading.value = false;
71
+ return;
72
+ }
73
+ try {
74
+ loading.value = true;
75
+ const results = {};
76
+ await Promise.all(featureNames.map(async (name) => {
77
+ results[name] = await client.isEnabled(name);
78
+ }));
79
+ features.value = results;
80
+ error.value = null;
81
+ }
82
+ catch (err) {
83
+ error.value = err;
84
+ }
85
+ finally {
86
+ loading.value = false;
87
+ }
88
+ };
89
+ onMounted(() => {
90
+ client?.on('update', evaluate);
91
+ client?.on('ready', evaluate);
92
+ evaluate();
93
+ });
94
+ onUnmounted(() => {
95
+ client?.off('update', evaluate);
96
+ client?.off('ready', evaluate);
97
+ });
98
+ return {
99
+ features,
100
+ loading,
101
+ error,
102
+ refresh: evaluate
103
+ };
104
+ }
package/package.json ADDED
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "@anterprize/fturex",
3
+ "version": "0.0.1",
4
+ "description": "Feature toggle client for React, Vue, Angular and Svelte applications",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ },
13
+ "./react": {
14
+ "import": "./dist/react/index.js",
15
+ "types": "./dist/react/index.d.ts"
16
+ },
17
+ "./vue": {
18
+ "import": "./dist/vue/index.js",
19
+ "types": "./dist/vue/index.d.ts"
20
+ },
21
+ "./vue/FeatureToggle.vue": "./src/vue/FeatureToggle.vue",
22
+ "./angular": {
23
+ "import": "./dist/angular/index.js",
24
+ "types": "./dist/angular/index.d.ts"
25
+ },
26
+ "./svelte": {
27
+ "import": "./dist/svelte/index.js",
28
+ "types": "./dist/svelte/index.d.ts"
29
+ },
30
+ "./opentelemetry": {
31
+ "import": "./dist/opentelemetry/index.js",
32
+ "types": "./dist/opentelemetry/index.d.ts"
33
+ }
34
+ },
35
+ "scripts": {
36
+ "build": "tsc",
37
+ "prepublishOnly": "npm run build",
38
+ "test": "jest",
39
+ "lint": "eslint src/**/*.ts"
40
+ },
41
+ "keywords": [
42
+ "feature-toggle",
43
+ "feature-flag",
44
+ "feature-flags",
45
+ "react",
46
+ "vue",
47
+ "angular",
48
+ "svelte",
49
+ "typescript"
50
+ ],
51
+ "author": "Anterprize",
52
+ "license": "MIT",
53
+ "peerDependencies": {
54
+ "@angular/core": ">=15.0.0",
55
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
56
+ "svelte": ">=4.0.0",
57
+ "vue": "^3.0.0"
58
+ },
59
+ "peerDependenciesMeta": {
60
+ "@angular/core": {
61
+ "optional": true
62
+ },
63
+ "vue": {
64
+ "optional": true
65
+ },
66
+ "react": {
67
+ "optional": true
68
+ },
69
+ "svelte": {
70
+ "optional": true
71
+ }
72
+ },
73
+ "devDependencies": {
74
+ "@angular/core": "^17.0.0",
75
+ "@types/jest": "^30.0.0",
76
+ "@types/node": "^25.5.2",
77
+ "@types/react": "^18.0.0",
78
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
79
+ "@typescript-eslint/parser": "^6.0.0",
80
+ "eslint": "^8.0.0",
81
+ "jest": "^29.0.0",
82
+ "jest-environment-jsdom": "^30.3.0",
83
+ "react": "^18.0.0",
84
+ "rxjs": "^7.8.0",
85
+ "svelte": "^5.55.1",
86
+ "ts-jest": "^29.4.6",
87
+ "typescript": "^5.0.0",
88
+ "vue": "^3.5.32"
89
+ },
90
+ "files": [
91
+ "dist",
92
+ "src/vue/FeatureToggle.vue",
93
+ "README.md"
94
+ ],
95
+ "repository": {
96
+ "type": "git",
97
+ "url": "https://github.com/Anterprize/fturex-sdk"
98
+ }
99
+ }
@@ -0,0 +1,28 @@
1
+ <template>
2
+ <div v-if="loading">
3
+ <slot name="loading"></slot>
4
+ </div>
5
+ <div v-else-if="error">
6
+ <slot name="error" :error="error"></slot>
7
+ </div>
8
+ <div v-else>
9
+ <slot v-if="isEnabled"></slot>
10
+ </div>
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ import { useFeatureToggle } from "./useFeatureToggle.js";
15
+ import { ContextProperties } from "../types.js";
16
+
17
+ interface Props {
18
+ featureName: string;
19
+ context?: ContextProperties;
20
+ }
21
+
22
+ const props = withDefaults(defineProps<Props>(), {});
23
+
24
+ const { isEnabled, loading, error } = useFeatureToggle(
25
+ props.featureName,
26
+ props.context,
27
+ );
28
+ </script>