@buildrflags/vue 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/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # @buildrflags/vue
2
+
3
+ Official Vue 3 SDK for [BuildrFlags](https://flags.buildrlab.com) — feature flags made simple.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @buildrflags/vue
9
+ # or
10
+ pnpm add @buildrflags/vue
11
+ # or
12
+ yarn add @buildrflags/vue
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ### 1. Install the Plugin
18
+
19
+ ```ts
20
+ // main.ts
21
+ import { createApp } from 'vue';
22
+ import { BuildrFlagsPlugin } from '@buildrflags/vue';
23
+ import App from './App.vue';
24
+
25
+ const app = createApp(App);
26
+
27
+ app.use(BuildrFlagsPlugin, {
28
+ apiKey: 'bf_production_xxx', // Your BuildrFlags API key
29
+ });
30
+
31
+ app.mount('#app');
32
+ ```
33
+
34
+ ### 2. Use Feature Flags in Components
35
+
36
+ ```vue
37
+ <script setup lang="ts">
38
+ import { useFlag } from '@buildrflags/vue';
39
+
40
+ const { enabled, isLoading } = useFlag('new-checkout-flow');
41
+ </script>
42
+
43
+ <template>
44
+ <LoadingSpinner v-if="isLoading" />
45
+ <NewCheckout v-else-if="enabled" />
46
+ <OldCheckout v-else />
47
+ </template>
48
+ ```
49
+
50
+ ## Composables
51
+
52
+ ### `useFlag(flagKey)`
53
+
54
+ Get the evaluation result for a single flag.
55
+
56
+ ```vue
57
+ <script setup lang="ts">
58
+ import { useFlag } from '@buildrflags/vue';
59
+
60
+ const { enabled, isLoading } = useFlag('dark-mode');
61
+ </script>
62
+
63
+ <template>
64
+ <DarkTheme v-if="enabled" />
65
+ <LightTheme v-else />
66
+ </template>
67
+ ```
68
+
69
+ ### `useFlagValue(flagKey, defaultValue?)`
70
+
71
+ Simple boolean access with optional default value.
72
+
73
+ ```vue
74
+ <script setup lang="ts">
75
+ import { useFlagValue } from '@buildrflags/vue';
76
+
77
+ // Returns false while loading, true once flag is fetched (if enabled)
78
+ const showBanner = useFlagValue('promo-banner', false);
79
+ </script>
80
+
81
+ <template>
82
+ <PromoBanner v-if="showBanner" />
83
+ </template>
84
+ ```
85
+
86
+ ### `useFlags()`
87
+
88
+ Get all flags with loading/error state and manual refresh.
89
+
90
+ ```vue
91
+ <script setup lang="ts">
92
+ import { useFlags } from '@buildrflags/vue';
93
+
94
+ const { flags, isLoading, error, refresh } = useFlags();
95
+ </script>
96
+
97
+ <template>
98
+ <div v-if="error" class="error">{{ error }}</div>
99
+ <button @click="refresh">Refresh Flags</button>
100
+ <pre>{{ flags }}</pre>
101
+ </template>
102
+ ```
103
+
104
+ ### `useFlagsEnabled(flagKeys, mode?)`
105
+
106
+ Check multiple flags at once. Mode can be `'all'` (default) or `'any'`.
107
+
108
+ ```vue
109
+ <script setup lang="ts">
110
+ import { useFlagsEnabled } from '@buildrflags/vue';
111
+
112
+ // All flags must be enabled
113
+ const canAccessPremium = useFlagsEnabled(['premium-tier', 'new-dashboard'], 'all');
114
+
115
+ // At least one flag must be enabled
116
+ const showAnyPromo = useFlagsEnabled(['black-friday', 'cyber-monday'], 'any');
117
+ </script>
118
+
119
+ <template>
120
+ <PremiumDashboard v-if="canAccessPremium" />
121
+ <PromoSection v-if="showAnyPromo" />
122
+ </template>
123
+ ```
124
+
125
+ ## Plugin Options
126
+
127
+ ```ts
128
+ interface BuildrFlagsPluginOptions {
129
+ // Required: Your BuildrFlags API key
130
+ apiKey: string;
131
+
132
+ // Optional: Custom API base URL
133
+ // Default: 'https://api.flags.buildrlab.com'
134
+ baseUrl?: string;
135
+
136
+ // Optional: Auto-refresh interval in milliseconds
137
+ // Set to 0 to disable auto-refresh
138
+ // Default: 60000 (1 minute)
139
+ refreshInterval?: number;
140
+
141
+ // Optional: Pre-loaded flags for SSR/SSG
142
+ initialFlags?: Record<string, boolean>;
143
+ }
144
+ ```
145
+
146
+ ## Server-Side Rendering (SSR)
147
+
148
+ For SSR with Nuxt or similar, you can pre-load flags server-side:
149
+
150
+ ```ts
151
+ // Server-side: fetch flags during SSR
152
+ const response = await fetch('https://api.flags.buildrlab.com/api/evaluate/all', {
153
+ headers: { 'X-API-Key': 'bf_production_xxx' },
154
+ });
155
+ const { flags } = await response.json();
156
+
157
+ // Convert to a simple map
158
+ const initialFlags: Record<string, boolean> = {};
159
+ for (const flag of flags) {
160
+ initialFlags[flag.flagKey] = flag.enabled;
161
+ }
162
+
163
+ // Pass to plugin
164
+ app.use(BuildrFlagsPlugin, {
165
+ apiKey: 'bf_production_xxx',
166
+ initialFlags,
167
+ });
168
+ ```
169
+
170
+ ## TypeScript Support
171
+
172
+ This package is written in TypeScript and includes full type definitions.
173
+
174
+ ```ts
175
+ import type {
176
+ BuildrFlagsPluginOptions,
177
+ BuildrFlagsState,
178
+ UseFlagResult,
179
+ UseFlagsResult,
180
+ } from '@buildrflags/vue';
181
+ ```
182
+
183
+ ## Requirements
184
+
185
+ - Vue 3.3+
186
+ - TypeScript 5.0+ (optional, but recommended)
187
+
188
+ ## License
189
+
190
+ MIT © [BuildrLab](https://buildrlab.com)
@@ -0,0 +1,89 @@
1
+ import { type ComputedRef } from 'vue';
2
+ import type { UseFlagResult, UseFlagsResult } from './types.js';
3
+ /**
4
+ * Composable to get the evaluation result for a single flag.
5
+ *
6
+ * @param flagKey - The key of the flag to evaluate
7
+ * @returns Object with reactive `enabled` and `isLoading` refs
8
+ *
9
+ * @example
10
+ * ```vue
11
+ * <script setup lang="ts">
12
+ * import { useFlag } from '@buildrflags/vue';
13
+ *
14
+ * const { enabled, isLoading } = useFlag('features.darkMode');
15
+ * </script>
16
+ *
17
+ * <template>
18
+ * <Spinner v-if="isLoading" />
19
+ * <DarkTheme v-else-if="enabled" />
20
+ * <LightTheme v-else />
21
+ * </template>
22
+ * ```
23
+ */
24
+ export declare function useFlag(flagKey: string): UseFlagResult;
25
+ /**
26
+ * Composable to get all flags and loading/error state.
27
+ *
28
+ * @returns Object with reactive `flags`, `isLoading`, `error`, and `refresh` function
29
+ *
30
+ * @example
31
+ * ```vue
32
+ * <script setup lang="ts">
33
+ * import { useFlags } from '@buildrflags/vue';
34
+ *
35
+ * const { flags, isLoading, error, refresh } = useFlags();
36
+ * </script>
37
+ *
38
+ * <template>
39
+ * <div v-if="error">Error: {{ error }}</div>
40
+ * <button @click="refresh">Refresh</button>
41
+ * </template>
42
+ * ```
43
+ */
44
+ export declare function useFlags(): UseFlagsResult;
45
+ /**
46
+ * Composable that returns just the boolean value for a flag as a computed ref.
47
+ * Returns the `defaultValue` (or `false`) while loading or if the flag is not found.
48
+ *
49
+ * @param flagKey - The key of the flag to evaluate
50
+ * @param defaultValue - Value to return while loading or when flag is missing (default: false)
51
+ * @returns Computed boolean ref
52
+ *
53
+ * @example
54
+ * ```vue
55
+ * <script setup lang="ts">
56
+ * import { useFlagValue } from '@buildrflags/vue';
57
+ *
58
+ * const showBanner = useFlagValue('ui.showBanner', true);
59
+ * </script>
60
+ *
61
+ * <template>
62
+ * <Banner v-if="showBanner" />
63
+ * </template>
64
+ * ```
65
+ */
66
+ export declare function useFlagValue(flagKey: string, defaultValue?: boolean): ComputedRef<boolean>;
67
+ /**
68
+ * Composable to check if multiple flags are enabled.
69
+ * Useful for checking feature combinations.
70
+ *
71
+ * @param flagKeys - Array of flag keys to check
72
+ * @param mode - 'all' (default) requires all flags enabled, 'any' requires at least one
73
+ * @returns Computed boolean ref
74
+ *
75
+ * @example
76
+ * ```vue
77
+ * <script setup lang="ts">
78
+ * import { useFlagsEnabled } from '@buildrflags/vue';
79
+ *
80
+ * // All flags must be enabled
81
+ * const allEnabled = useFlagsEnabled(['feature.a', 'feature.b'], 'all');
82
+ *
83
+ * // At least one flag must be enabled
84
+ * const anyEnabled = useFlagsEnabled(['feature.a', 'feature.b'], 'any');
85
+ * </script>
86
+ * ```
87
+ */
88
+ export declare function useFlagsEnabled(flagKeys: string[], mode?: 'all' | 'any'): ComputedRef<boolean>;
89
+ //# sourceMappingURL=composables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composables.d.ts","sourceRoot":"","sources":["../src/composables.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,WAAW,EAAY,MAAM,KAAK,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAoB,MAAM,YAAY,CAAC;AAqBlF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAUtD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,QAAQ,IAAI,cAAc,CAIzC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,UAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,CAOxF;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,GAAE,KAAK,GAAG,KAAa,GAC1B,WAAW,CAAC,OAAO,CAAC,CAStB"}
@@ -0,0 +1,128 @@
1
+ import { inject, computed } from 'vue';
2
+ import { BUILDR_FLAGS_KEY } from './types.js';
3
+ /**
4
+ * Injects the BuildrFlags state from the plugin.
5
+ *
6
+ * @throws Error if used outside of a component with BuildrFlagsPlugin installed
7
+ * @internal
8
+ */
9
+ function useBuildrFlagsContext() {
10
+ const state = inject(BUILDR_FLAGS_KEY);
11
+ if (!state) {
12
+ throw new Error('BuildrFlags: useFlag/useFlags must be used within a component tree that has BuildrFlagsPlugin installed.');
13
+ }
14
+ return state;
15
+ }
16
+ /**
17
+ * Composable to get the evaluation result for a single flag.
18
+ *
19
+ * @param flagKey - The key of the flag to evaluate
20
+ * @returns Object with reactive `enabled` and `isLoading` refs
21
+ *
22
+ * @example
23
+ * ```vue
24
+ * <script setup lang="ts">
25
+ * import { useFlag } from '@buildrflags/vue';
26
+ *
27
+ * const { enabled, isLoading } = useFlag('features.darkMode');
28
+ * </script>
29
+ *
30
+ * <template>
31
+ * <Spinner v-if="isLoading" />
32
+ * <DarkTheme v-else-if="enabled" />
33
+ * <LightTheme v-else />
34
+ * </template>
35
+ * ```
36
+ */
37
+ export function useFlag(flagKey) {
38
+ const { flags, isLoading } = useBuildrFlagsContext();
39
+ // Create a computed ref that tracks the specific flag
40
+ const enabled = computed(() => flags.value[flagKey] ?? false);
41
+ return {
42
+ enabled: enabled,
43
+ isLoading,
44
+ };
45
+ }
46
+ /**
47
+ * Composable to get all flags and loading/error state.
48
+ *
49
+ * @returns Object with reactive `flags`, `isLoading`, `error`, and `refresh` function
50
+ *
51
+ * @example
52
+ * ```vue
53
+ * <script setup lang="ts">
54
+ * import { useFlags } from '@buildrflags/vue';
55
+ *
56
+ * const { flags, isLoading, error, refresh } = useFlags();
57
+ * </script>
58
+ *
59
+ * <template>
60
+ * <div v-if="error">Error: {{ error }}</div>
61
+ * <button @click="refresh">Refresh</button>
62
+ * </template>
63
+ * ```
64
+ */
65
+ export function useFlags() {
66
+ const { flags, isLoading, error, refresh } = useBuildrFlagsContext();
67
+ return { flags, isLoading, error, refresh };
68
+ }
69
+ /**
70
+ * Composable that returns just the boolean value for a flag as a computed ref.
71
+ * Returns the `defaultValue` (or `false`) while loading or if the flag is not found.
72
+ *
73
+ * @param flagKey - The key of the flag to evaluate
74
+ * @param defaultValue - Value to return while loading or when flag is missing (default: false)
75
+ * @returns Computed boolean ref
76
+ *
77
+ * @example
78
+ * ```vue
79
+ * <script setup lang="ts">
80
+ * import { useFlagValue } from '@buildrflags/vue';
81
+ *
82
+ * const showBanner = useFlagValue('ui.showBanner', true);
83
+ * </script>
84
+ *
85
+ * <template>
86
+ * <Banner v-if="showBanner" />
87
+ * </template>
88
+ * ```
89
+ */
90
+ export function useFlagValue(flagKey, defaultValue = false) {
91
+ const { flags, isLoading } = useBuildrFlagsContext();
92
+ return computed(() => {
93
+ if (isLoading.value)
94
+ return defaultValue;
95
+ return flags.value[flagKey] ?? defaultValue;
96
+ });
97
+ }
98
+ /**
99
+ * Composable to check if multiple flags are enabled.
100
+ * Useful for checking feature combinations.
101
+ *
102
+ * @param flagKeys - Array of flag keys to check
103
+ * @param mode - 'all' (default) requires all flags enabled, 'any' requires at least one
104
+ * @returns Computed boolean ref
105
+ *
106
+ * @example
107
+ * ```vue
108
+ * <script setup lang="ts">
109
+ * import { useFlagsEnabled } from '@buildrflags/vue';
110
+ *
111
+ * // All flags must be enabled
112
+ * const allEnabled = useFlagsEnabled(['feature.a', 'feature.b'], 'all');
113
+ *
114
+ * // At least one flag must be enabled
115
+ * const anyEnabled = useFlagsEnabled(['feature.a', 'feature.b'], 'any');
116
+ * </script>
117
+ * ```
118
+ */
119
+ export function useFlagsEnabled(flagKeys, mode = 'all') {
120
+ const { flags, isLoading } = useBuildrFlagsContext();
121
+ return computed(() => {
122
+ if (isLoading.value)
123
+ return false;
124
+ const checkFn = mode === 'all' ? 'every' : 'some';
125
+ return flagKeys[checkFn]((key) => flags.value[key] === true);
126
+ });
127
+ }
128
+ //# sourceMappingURL=composables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composables.js","sourceRoot":"","sources":["../src/composables.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAA8B,MAAM,KAAK,CAAC;AAEnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;GAKG;AACH,SAAS,qBAAqB;IAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAEvC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,0GAA0G,CAC3G,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,qBAAqB,EAAE,CAAC;IAErD,sDAAsD;IACtD,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC;IAE9D,OAAO;QACL,OAAO,EAAE,OAAkC;QAC3C,SAAS;KACV,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,QAAQ;IACtB,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,qBAAqB,EAAE,CAAC;IAErE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,YAAY,GAAG,KAAK;IAChE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,qBAAqB,EAAE,CAAC;IAErD,OAAO,QAAQ,CAAC,GAAG,EAAE;QACnB,IAAI,SAAS,CAAC,KAAK;YAAE,OAAO,YAAY,CAAC;QACzC,OAAO,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,YAAY,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAkB,EAClB,OAAsB,KAAK;IAE3B,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,qBAAqB,EAAE,CAAC;IAErD,OAAO,QAAQ,CAAC,GAAG,EAAE;QACnB,IAAI,SAAS,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QAElC,MAAM,OAAO,GAAG,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;QAClD,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * BuildrFlags Vue SDK
3
+ *
4
+ * Vue composables and plugin for feature flag evaluation.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * // main.ts
9
+ * import { createApp } from 'vue';
10
+ * import { BuildrFlagsPlugin } from '@buildrflags/vue';
11
+ * import App from './App.vue';
12
+ *
13
+ * const app = createApp(App);
14
+ *
15
+ * app.use(BuildrFlagsPlugin, {
16
+ * apiKey: 'bf_production_xxx',
17
+ * });
18
+ *
19
+ * app.mount('#app');
20
+ * ```
21
+ *
22
+ * @example
23
+ * ```vue
24
+ * <!-- MyComponent.vue -->
25
+ * <script setup lang="ts">
26
+ * import { useFlag } from '@buildrflags/vue';
27
+ *
28
+ * const { enabled } = useFlag('my-feature');
29
+ * </script>
30
+ *
31
+ * <template>
32
+ * <NewFeature v-if="enabled" />
33
+ * <OldFeature v-else />
34
+ * </template>
35
+ * ```
36
+ *
37
+ * @packageDocumentation
38
+ */
39
+ export { BuildrFlagsPlugin, createBuildrFlagsState } from './plugin.js';
40
+ export { useFlag, useFlags, useFlagValue, useFlagsEnabled } from './composables.js';
41
+ export type { BuildrFlagsPluginOptions, BuildrFlagsState, UseFlagResult, UseFlagsResult, FlagResult, BulkEvaluateResponse, } from './types.js';
42
+ export { BUILDR_FLAGS_KEY } from './types.js';
43
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAGH,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAGxE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGpF,YAAY,EACV,wBAAwB,EACxB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,UAAU,EACV,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * BuildrFlags Vue SDK
3
+ *
4
+ * Vue composables and plugin for feature flag evaluation.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * // main.ts
9
+ * import { createApp } from 'vue';
10
+ * import { BuildrFlagsPlugin } from '@buildrflags/vue';
11
+ * import App from './App.vue';
12
+ *
13
+ * const app = createApp(App);
14
+ *
15
+ * app.use(BuildrFlagsPlugin, {
16
+ * apiKey: 'bf_production_xxx',
17
+ * });
18
+ *
19
+ * app.mount('#app');
20
+ * ```
21
+ *
22
+ * @example
23
+ * ```vue
24
+ * <!-- MyComponent.vue -->
25
+ * <script setup lang="ts">
26
+ * import { useFlag } from '@buildrflags/vue';
27
+ *
28
+ * const { enabled } = useFlag('my-feature');
29
+ * </script>
30
+ *
31
+ * <template>
32
+ * <NewFeature v-if="enabled" />
33
+ * <OldFeature v-else />
34
+ * </template>
35
+ * ```
36
+ *
37
+ * @packageDocumentation
38
+ */
39
+ // Plugin
40
+ export { BuildrFlagsPlugin, createBuildrFlagsState } from './plugin.js';
41
+ // Composables
42
+ export { useFlag, useFlags, useFlagValue, useFlagsEnabled } from './composables.js';
43
+ // Injection key (for advanced usage)
44
+ export { BUILDR_FLAGS_KEY } from './types.js';
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,SAAS;AACT,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAExE,cAAc;AACd,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAYpF,qCAAqC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { type Plugin } from 'vue';
2
+ import type { BuildrFlagsPluginOptions, BuildrFlagsState } from './types.js';
3
+ /**
4
+ * Creates the BuildrFlags state with automatic fetching and refresh.
5
+ *
6
+ * @internal
7
+ */
8
+ export declare function createBuildrFlagsState(options: BuildrFlagsPluginOptions): BuildrFlagsState;
9
+ /**
10
+ * Vue plugin for BuildrFlags.
11
+ *
12
+ * Install this plugin in your Vue app to provide feature flag state
13
+ * to all components via composables.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { createApp } from 'vue';
18
+ * import { BuildrFlagsPlugin } from '@buildrflags/vue';
19
+ * import App from './App.vue';
20
+ *
21
+ * const app = createApp(App);
22
+ *
23
+ * app.use(BuildrFlagsPlugin, {
24
+ * apiKey: 'bf_production_xxx',
25
+ * });
26
+ *
27
+ * app.mount('#app');
28
+ * ```
29
+ */
30
+ export declare const BuildrFlagsPlugin: Plugin<[BuildrFlagsPluginOptions]>;
31
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,KAAK,CAAC;AACjD,OAAO,KAAK,EACV,wBAAwB,EACxB,gBAAgB,EAEjB,MAAM,YAAY,CAAC;AAMpB;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,wBAAwB,GAAG,gBAAgB,CA2E1F;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,CAAC,wBAAwB,CAAC,CAKhE,CAAC"}
package/dist/plugin.js ADDED
@@ -0,0 +1,101 @@
1
+ import { ref } from 'vue';
2
+ import { BUILDR_FLAGS_KEY } from './types.js';
3
+ const DEFAULT_BASE_URL = 'https://api.flags.buildrlab.com';
4
+ const DEFAULT_REFRESH_INTERVAL = 60_000; // 1 minute
5
+ /**
6
+ * Creates the BuildrFlags state with automatic fetching and refresh.
7
+ *
8
+ * @internal
9
+ */
10
+ export function createBuildrFlagsState(options) {
11
+ const { apiKey, baseUrl, refreshInterval, initialFlags } = options;
12
+ const resolvedBaseUrl = (baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '');
13
+ const resolvedRefreshInterval = refreshInterval ?? DEFAULT_REFRESH_INTERVAL;
14
+ const flags = ref(initialFlags ?? {});
15
+ const isLoading = ref(initialFlags === undefined);
16
+ const error = ref(null);
17
+ let intervalId;
18
+ let mounted = true;
19
+ const fetchFlags = async () => {
20
+ try {
21
+ const response = await fetch(`${resolvedBaseUrl}/api/evaluate/all`, {
22
+ method: 'GET',
23
+ headers: {
24
+ 'X-API-Key': apiKey,
25
+ },
26
+ });
27
+ if (!response.ok) {
28
+ const text = await response.text().catch(() => 'Unknown error');
29
+ throw new Error(`API request failed: ${response.status} ${text}`);
30
+ }
31
+ const data = (await response.json());
32
+ if (!mounted)
33
+ return;
34
+ const flagMap = {};
35
+ for (const flag of data.flags) {
36
+ flagMap[flag.flagKey] = flag.enabled;
37
+ }
38
+ flags.value = flagMap;
39
+ error.value = null;
40
+ isLoading.value = false;
41
+ }
42
+ catch (err) {
43
+ if (!mounted)
44
+ return;
45
+ const message = err instanceof Error ? err.message : 'Failed to fetch flags';
46
+ error.value = message;
47
+ isLoading.value = false;
48
+ }
49
+ };
50
+ // Initial fetch
51
+ void fetchFlags();
52
+ // Set up auto-refresh
53
+ if (resolvedRefreshInterval > 0) {
54
+ intervalId = setInterval(() => {
55
+ void fetchFlags();
56
+ }, resolvedRefreshInterval);
57
+ }
58
+ // Cleanup function (called when plugin is uninstalled)
59
+ const cleanup = () => {
60
+ mounted = false;
61
+ if (intervalId !== undefined) {
62
+ clearInterval(intervalId);
63
+ }
64
+ };
65
+ // Store cleanup on the state for potential future use
66
+ flags.__cleanup = cleanup;
67
+ return {
68
+ flags,
69
+ isLoading,
70
+ error,
71
+ refresh: fetchFlags,
72
+ };
73
+ }
74
+ /**
75
+ * Vue plugin for BuildrFlags.
76
+ *
77
+ * Install this plugin in your Vue app to provide feature flag state
78
+ * to all components via composables.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * import { createApp } from 'vue';
83
+ * import { BuildrFlagsPlugin } from '@buildrflags/vue';
84
+ * import App from './App.vue';
85
+ *
86
+ * const app = createApp(App);
87
+ *
88
+ * app.use(BuildrFlagsPlugin, {
89
+ * apiKey: 'bf_production_xxx',
90
+ * });
91
+ *
92
+ * app.mount('#app');
93
+ * ```
94
+ */
95
+ export const BuildrFlagsPlugin = {
96
+ install(app, options) {
97
+ const state = createBuildrFlagsState(options);
98
+ app.provide(BUILDR_FLAGS_KEY, state);
99
+ },
100
+ };
101
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import type { InjectionKey, Ref } from 'vue';
2
+ /**
3
+ * A single flag result from the bulk evaluation API.
4
+ */
5
+ export interface FlagResult {
6
+ flagKey: string;
7
+ enabled: boolean;
8
+ reason: string;
9
+ fetchedAt: string;
10
+ }
11
+ /**
12
+ * Response shape from GET /api/evaluate/all.
13
+ */
14
+ export interface BulkEvaluateResponse {
15
+ flags: FlagResult[];
16
+ }
17
+ /**
18
+ * State held in the BuildrFlags Vue context.
19
+ */
20
+ export interface BuildrFlagsState {
21
+ /** Map of flagKey → enabled boolean. */
22
+ flags: Ref<Record<string, boolean>>;
23
+ /** True until the first successful fetch completes. */
24
+ isLoading: Ref<boolean>;
25
+ /** Error message from the most recent fetch, or null. */
26
+ error: Ref<string | null>;
27
+ /** Manually refresh flags from the API. */
28
+ refresh: () => Promise<void>;
29
+ }
30
+ /**
31
+ * Options for the BuildrFlags plugin.
32
+ */
33
+ export interface BuildrFlagsPluginOptions {
34
+ /** Your BuildrFlags API key (starts with "bf_"). */
35
+ apiKey: string;
36
+ /** Base URL for the BuildrFlags API. @default "https://api.flags.buildrlab.com" */
37
+ baseUrl?: string;
38
+ /** Auto-refresh interval in milliseconds. Set to 0 to disable. @default 60000 */
39
+ refreshInterval?: number;
40
+ /** Pre-loaded flags for SSG/SSR (skips initial fetch when provided). */
41
+ initialFlags?: Record<string, boolean>;
42
+ }
43
+ /**
44
+ * Return type for the useFlag composable.
45
+ */
46
+ export interface UseFlagResult {
47
+ /** Whether the flag is enabled (reactive). */
48
+ enabled: Ref<boolean>;
49
+ /** True until the first fetch completes (reactive). */
50
+ isLoading: Ref<boolean>;
51
+ }
52
+ /**
53
+ * Return type for the useFlags composable.
54
+ */
55
+ export interface UseFlagsResult {
56
+ /** All flags as a key → boolean map (reactive). */
57
+ flags: Ref<Record<string, boolean>>;
58
+ /** True until the first fetch completes (reactive). */
59
+ isLoading: Ref<boolean>;
60
+ /** Error message from the most recent fetch, or null (reactive). */
61
+ error: Ref<string | null>;
62
+ /** Manually refresh flags from the API. */
63
+ refresh: () => Promise<void>;
64
+ }
65
+ /**
66
+ * Injection key for the BuildrFlags context.
67
+ */
68
+ export declare const BUILDR_FLAGS_KEY: InjectionKey<BuildrFlagsState>;
69
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACpC,uDAAuD;IACvD,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,yDAAyD;IACzD,KAAK,EAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1B,2CAA2C;IAC3C,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,8CAA8C;IAC9C,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACtB,uDAAuD;IACvD,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACpC,uDAAuD;IACvD,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACxB,oEAAoE;IACpE,KAAK,EAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1B,2CAA2C;IAC3C,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,YAAY,CAAC,gBAAgB,CAA0B,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Injection key for the BuildrFlags context.
3
+ */
4
+ export const BUILDR_FLAGS_KEY = Symbol('buildr-flags');
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAuEA;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAmC,MAAM,CAAC,cAAc,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@buildrflags/vue",
3
+ "version": "0.1.0",
4
+ "description": "Vue composables and plugin for BuildrFlags feature flag evaluation",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "dev": "tsc --watch",
22
+ "lint": "eslint src --ext .ts",
23
+ "lint:fix": "eslint src --ext .ts --fix",
24
+ "typecheck": "tsc --noEmit",
25
+ "test": "vitest run",
26
+ "test:watch": "vitest",
27
+ "test:coverage": "vitest run --coverage",
28
+ "clean": "rm -rf dist node_modules"
29
+ },
30
+ "keywords": [
31
+ "feature-flags",
32
+ "buildrflags",
33
+ "vue",
34
+ "vue3",
35
+ "composables",
36
+ "feature-toggles"
37
+ ],
38
+ "author": "BuildrLab <hello@buildrlab.com>",
39
+ "license": "MIT",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/buildrlab/buildrflags.git",
43
+ "directory": "sdks/vue"
44
+ },
45
+ "homepage": "https://flags.buildrlab.com",
46
+ "bugs": {
47
+ "url": "https://github.com/buildrlab/buildrflags/issues"
48
+ },
49
+ "peerDependencies": {
50
+ "vue": "^3.3.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^25.2.3",
54
+ "@vitejs/plugin-vue": "^6.0.4",
55
+ "@vue/test-utils": "^2.4.0",
56
+ "eslint": "^10.0.0",
57
+ "happy-dom": "^20.6.1",
58
+ "typescript": "^5.6.0",
59
+ "vite": "^7.3.1",
60
+ "vitest": "^4.0.18",
61
+ "vue": "^3.5.0"
62
+ }
63
+ }