featurefly 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +687 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +22 -0
- package/dist/react/index.d.ts +54 -0
- package/dist/react/index.js +126 -0
- package/dist/shared/cache.d.ts +40 -0
- package/dist/shared/cache.js +80 -0
- package/dist/shared/circuit-breaker.d.ts +46 -0
- package/dist/shared/circuit-breaker.js +90 -0
- package/dist/shared/client.d.ts +153 -0
- package/dist/shared/client.js +560 -0
- package/dist/shared/edge-evaluator.d.ts +35 -0
- package/dist/shared/edge-evaluator.js +127 -0
- package/dist/shared/event-emitter.d.ts +29 -0
- package/dist/shared/event-emitter.js +68 -0
- package/dist/shared/experiment.d.ts +9 -0
- package/dist/shared/experiment.js +51 -0
- package/dist/shared/index.d.ts +7 -0
- package/dist/shared/index.js +7 -0
- package/dist/shared/logger.d.ts +14 -0
- package/dist/shared/logger.js +37 -0
- package/dist/shared/metrics.d.ts +79 -0
- package/dist/shared/metrics.js +147 -0
- package/dist/shared/retry.d.ts +10 -0
- package/dist/shared/retry.js +39 -0
- package/dist/shared/rollout.d.ts +14 -0
- package/dist/shared/rollout.js +77 -0
- package/dist/shared/streaming.d.ts +35 -0
- package/dist/shared/streaming.js +117 -0
- package/dist/shared/targeting.d.ts +10 -0
- package/dist/shared/targeting.js +133 -0
- package/dist/shared/types.d.ts +248 -0
- package/dist/shared/types.js +4 -0
- package/dist/vue/index.d.ts +60 -0
- package/dist/vue/index.js +136 -0
- package/package.json +97 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// FeatureFly — Vue Composables
|
|
3
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// Thin wrapper providing Vue 3 composables for FeatureFly SDK.
|
|
6
|
+
// Requires Vue 3.x (Composition API).
|
|
7
|
+
//
|
|
8
|
+
// Usage:
|
|
9
|
+
// import { FeatureFlyPlugin, useFeatureFlag, useAllFlags } from 'featurefly/vue';
|
|
10
|
+
//
|
|
11
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
12
|
+
import { inject, ref, onMounted, onUnmounted, watch, } from 'vue';
|
|
13
|
+
// ─── Plugin & Injection Key ─────────────────────────────────────────────────────
|
|
14
|
+
const FEATUREFLY_KEY = Symbol('featurefly');
|
|
15
|
+
/**
|
|
16
|
+
* Vue Plugin that provides the FeatureFlagsClient to the entire app.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { createApp } from 'vue';
|
|
21
|
+
* import { FeatureFlyPlugin } from 'featurefly/vue';
|
|
22
|
+
*
|
|
23
|
+
* const app = createApp(App);
|
|
24
|
+
* app.use(FeatureFlyPlugin, { client: featureFlyClient });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export const FeatureFlyPlugin = {
|
|
28
|
+
install(app, options) {
|
|
29
|
+
app.provide(FEATUREFLY_KEY, options.client);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
function useClient() {
|
|
33
|
+
const client = inject(FEATUREFLY_KEY);
|
|
34
|
+
if (!client) {
|
|
35
|
+
throw new Error('useFeatureFlag must be called inside a component where FeatureFlyPlugin is installed. ' +
|
|
36
|
+
'Use app.use(FeatureFlyPlugin, { client }) in your main.ts.');
|
|
37
|
+
}
|
|
38
|
+
return client;
|
|
39
|
+
}
|
|
40
|
+
// ─── useFeatureFlag ─────────────────────────────────────────────────────────────
|
|
41
|
+
/**
|
|
42
|
+
* Vue composable for evaluating a single feature flag.
|
|
43
|
+
* Returns a reactive `Ref` that auto-updates on flag changes.
|
|
44
|
+
*
|
|
45
|
+
* @param slug Flag slug identifier
|
|
46
|
+
* @param defaultValue Default value while loading
|
|
47
|
+
* @param context Optional reactive evaluation context
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```vue
|
|
51
|
+
* <script setup>
|
|
52
|
+
* import { useFeatureFlag } from 'featurefly/vue';
|
|
53
|
+
*
|
|
54
|
+
* const darkMode = useFeatureFlag('dark-mode', false);
|
|
55
|
+
* </script>
|
|
56
|
+
*
|
|
57
|
+
* <template>
|
|
58
|
+
* <div :class="{ dark: darkMode.value }">...</div>
|
|
59
|
+
* </template>
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export function useFeatureFlag(slug, defaultValue, context) {
|
|
63
|
+
const client = useClient();
|
|
64
|
+
const value = ref(defaultValue);
|
|
65
|
+
const unsubs = [];
|
|
66
|
+
const evaluate = async () => {
|
|
67
|
+
try {
|
|
68
|
+
const ctx = context && 'value' in context ? context.value : context;
|
|
69
|
+
const result = await client.evaluateFlag(slug, ctx);
|
|
70
|
+
value.value = result;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Keep current value on error
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
onMounted(() => {
|
|
77
|
+
evaluate();
|
|
78
|
+
unsubs.push(client.on('flagsUpdated', () => evaluate()));
|
|
79
|
+
unsubs.push(client.on('flagChanged', (payload) => {
|
|
80
|
+
if (payload.slug === slug)
|
|
81
|
+
evaluate();
|
|
82
|
+
}));
|
|
83
|
+
// If context is reactive, re-evaluate when it changes
|
|
84
|
+
if (context && 'value' in context) {
|
|
85
|
+
watch(context, () => evaluate(), { deep: true });
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
onUnmounted(() => {
|
|
89
|
+
unsubs.forEach((u) => u());
|
|
90
|
+
});
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
// ─── useAllFlags ────────────────────────────────────────────────────────────────
|
|
94
|
+
/**
|
|
95
|
+
* Vue composable for batch-evaluating all feature flags.
|
|
96
|
+
* Returns a reactive `Ref<Record<string, FlagValue>>` that auto-updates.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```vue
|
|
100
|
+
* <script setup>
|
|
101
|
+
* import { useAllFlags } from 'featurefly/vue';
|
|
102
|
+
*
|
|
103
|
+
* const flags = useAllFlags({ workspaceId: 'ws-123' });
|
|
104
|
+
* </script>
|
|
105
|
+
*
|
|
106
|
+
* <template>
|
|
107
|
+
* <NewFeature v-if="flags['new-feature']" />
|
|
108
|
+
* </template>
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export function useAllFlags(context) {
|
|
112
|
+
const client = useClient();
|
|
113
|
+
const flags = ref({});
|
|
114
|
+
const unsubs = [];
|
|
115
|
+
const evaluate = async () => {
|
|
116
|
+
try {
|
|
117
|
+
const ctx = context && 'value' in context ? context.value : context;
|
|
118
|
+
const result = await client.evaluateAllFlags(ctx);
|
|
119
|
+
flags.value = result;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// Keep current value on error
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
onMounted(() => {
|
|
126
|
+
evaluate();
|
|
127
|
+
unsubs.push(client.on('flagsUpdated', () => evaluate()));
|
|
128
|
+
if (context && 'value' in context) {
|
|
129
|
+
watch(context, () => evaluate(), { deep: true });
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
onUnmounted(() => {
|
|
133
|
+
unsubs.forEach((u) => u());
|
|
134
|
+
});
|
|
135
|
+
return flags;
|
|
136
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "featurefly",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Lightweight, framework-agnostic Feature Flags SDK with built-in caching, retry, circuit breaker, targeting, A/B testing, and real-time streaming",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"sideEffects": false,
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc && tsc --project tsconfig.esm.json",
|
|
14
|
+
"dev": "tsc --watch",
|
|
15
|
+
"test": "jest --coverage",
|
|
16
|
+
"test:watch": "jest --watch",
|
|
17
|
+
"lint": "eslint src --ext .ts",
|
|
18
|
+
"clean": "rm -rf dist",
|
|
19
|
+
"prepublishOnly": "npm run clean && npm run build && npm test"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"feature-flags",
|
|
23
|
+
"feature-toggles",
|
|
24
|
+
"featurefly",
|
|
25
|
+
"sdk",
|
|
26
|
+
"typescript",
|
|
27
|
+
"framework-agnostic",
|
|
28
|
+
"feature-management",
|
|
29
|
+
"ab-testing",
|
|
30
|
+
"gradual-rollout",
|
|
31
|
+
"circuit-breaker",
|
|
32
|
+
"targeting",
|
|
33
|
+
"streaming",
|
|
34
|
+
"edge-evaluation",
|
|
35
|
+
"react-hooks",
|
|
36
|
+
"vue-composables"
|
|
37
|
+
],
|
|
38
|
+
"author": "Arrua Platform Team",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"homepage": "https://github.com/ArruaBrian/featurefly#readme",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/ArruaBrian/featurefly/issues"
|
|
43
|
+
},
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "https://github.com/ArruaBrian/featurefly.git"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"axios": "^1.6.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/jest": "^29.0.0",
|
|
53
|
+
"@types/node": "^20.0.0",
|
|
54
|
+
"@types/react": "^18.3.28",
|
|
55
|
+
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
|
56
|
+
"@typescript-eslint/parser": "^6.21.0",
|
|
57
|
+
"eslint": "^8.57.1",
|
|
58
|
+
"eslint-config-prettier": "^10.1.8",
|
|
59
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
60
|
+
"jest": "^29.0.0",
|
|
61
|
+
"ts-jest": "^29.0.0",
|
|
62
|
+
"typescript": "^5.0.0",
|
|
63
|
+
"vue": "^3.5.29"
|
|
64
|
+
},
|
|
65
|
+
"peerDependencies": {
|
|
66
|
+
"react": ">=18.0.0",
|
|
67
|
+
"vue": ">=3.0.0"
|
|
68
|
+
},
|
|
69
|
+
"peerDependenciesMeta": {
|
|
70
|
+
"react": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"vue": {
|
|
74
|
+
"optional": true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"exports": {
|
|
78
|
+
".": {
|
|
79
|
+
"import": "./dist/index.esm.js",
|
|
80
|
+
"require": "./dist/index.js",
|
|
81
|
+
"types": "./dist/index.d.ts"
|
|
82
|
+
},
|
|
83
|
+
"./react": {
|
|
84
|
+
"import": "./dist/react/index.js",
|
|
85
|
+
"require": "./dist/react/index.js",
|
|
86
|
+
"types": "./dist/react/index.d.ts"
|
|
87
|
+
},
|
|
88
|
+
"./vue": {
|
|
89
|
+
"import": "./dist/vue/index.js",
|
|
90
|
+
"require": "./dist/vue/index.js",
|
|
91
|
+
"types": "./dist/vue/index.d.ts"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"engines": {
|
|
95
|
+
"node": ">=18.0.0"
|
|
96
|
+
}
|
|
97
|
+
}
|