diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index bf50c87b..150bdc2b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -17,7 +17,7 @@ jobs: cache: "yarn" cache-dependency-path: "**/yarn.lock" registry-url: "https://registry.npmjs.org" - scope: "@bucketco" + scope: "@reflag" - name: Install dependencies run: yarn install --immutable - name: Build packages @@ -44,6 +44,6 @@ jobs: run: | cd bucket-docs git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@bucket.co" + git config user.email "github-actions[bot]@reflag.com" git add sdk git commit -m "Update documentation" && git push || echo "No docs changes to commit" diff --git a/.gitignore b/.gitignore index 9b388fbb..abc48840 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,4 @@ junit.xml .next eslint-report.json -bucket.config.json +reflag.config.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 28999edc..e1279eab 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -43,6 +43,8 @@ "booleanish", "bucketco", "openfeature", - "PKCE" + "PKCE", + "reflag", + "VITE" ] } diff --git a/README.md b/README.md index 79c23088..486d8075 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Bucket +# Reflag Feature flags for SaaS that run on TypeScript. [Learn more and get started](https://bucket.co/) @@ -27,21 +27,21 @@ Use this for Cloudflare Workers as well. [Read the docs](packages/node-sdk/README.md) -## Bucket CLI +## Reflag CLI -CLI to interact with Bucket and generate types +CLI to interact with Reflag and generate types [Read the docs](packages/cli/README.md) ## OpenFeature Browser Provider -Use Bucket with OpenFeature in the browser through the Bucket OpenFeature Browser Provider +Use Reflag with OpenFeature in the browser through the Reflag OpenFeature Browser Provider [Read the docs](packages/openfeature-browser-provider/README.md) ## OpenFeature Node.js Provider -Use the Bucket with OpenFeature on the server in Node.js through the Bucket OpenFeature Node.js Provider +Use the Reflag with OpenFeature on the server in Node.js through the Reflag OpenFeature Node.js Provider [Read the docs](packages/openfeature-node-provider/README.md) diff --git a/docs.sh b/docs.sh index 9f1b15a9..9b57fa72 100755 --- a/docs.sh +++ b/docs.sh @@ -16,7 +16,7 @@ typedoc --treatWarningsAsErrors SEDCOMMAND='s/globals.md#(.*)-[0-9]+/globals.md#\1/g' # Find all markdown files including globals.md -FILES=$(find dist/docs/@bucketco -name "*.md") +FILES=$(find dist/docs/@reflag -name "*.md") echo "Processing markdown files..." for file in $FILES diff --git a/packages/browser-sdk/FEEDBACK.md b/packages/browser-sdk/FEEDBACK.md index 6dcdc80f..0b54fb54 100644 --- a/packages/browser-sdk/FEEDBACK.md +++ b/packages/browser-sdk/FEEDBACK.md @@ -1,21 +1,21 @@ -# Bucket Feedback UI +# Reflag Feedback UI -The Bucket Browser SDK includes a UI you can use to collect feedback from user -about particular features. +The Reflag Browser SDK includes a UI you can use to collect feedback from user +about particular flags. ![image](https://github.com/bucketco/bucket-javascript-sdk/assets/34348/c387bac1-f2e2-4efd-9dda-5030d76f9532) ## Global feedback configuration -The Bucket Browser SDK feedback UI is configured with reasonable defaults, +The Reflag Browser SDK feedback UI is configured with reasonable defaults, positioning itself as a [dialog](#dialog) in the lower right-hand corner of the viewport, displayed in English, and with a [light-mode theme](#custom-styling). -These settings can be overwritten when initializing the Bucket Browser SDK: +These settings can be overwritten when initializing the Reflag Browser SDK: ```typescript -const bucket = new BucketClient({ - publishableKey: "bucket-publishable-key", +const reflag = new ReflagClient({ + publishableKey: "reflag-publishable-key", user: { id: "42" }, feedback: { ui: { @@ -47,23 +47,23 @@ See also: Automated feedback surveys are enabled by default. -When automated feedback surveys are enabled, the Bucket Browser SDK -will open and maintain a connection to the Bucket service. When a user -triggers an event tracked by a feature and is eligible to be prompted -for feedback, the Bucket service will send a request to the SDK instance. -By default, this request will open up the Bucket feedback UI in the user's +When automated feedback surveys are enabled, the Reflag Browser SDK +will open and maintain a connection to the Reflag service. When a user +triggers an event tracked by a flag and is eligible to be prompted +for feedback, the Reflag service will send a request to the SDK instance. +By default, this request will open up the Reflag feedback UI in the user's browser, but you can intercept the request and override this behavior. The live connection for automated feedback is established when the -`BucketClient` is initialized. +`ReflagClient` is initialized. ### Disabling automated feedback surveys -You can disable automated collection in the `BucketClient` constructor: +You can disable automated collection in the `ReflagClient` constructor: ```typescript -const bucket = new BucketClient({ - publishableKey: "bucket-publishable-key", +const reflag = new ReflagClient({ + publishableKey: "reflag-publishable-key", user: { id: "42" }, feedback: { enableAutoFeedback: false, @@ -78,8 +78,8 @@ event arrives, you can can [override the global defaults](#global-feedback-confi or intercept and override settings at runtime like this: ```javascript -const bucket = new BucketClient({ - publishableKey: "bucket-publishable-key", +const reflag = new ReflagClient({ + publishableKey: "reflag-publishable-key", user: { id: "42" }, feedback: { autoFeedbackHandler: (promptMessage, handlers) => { @@ -114,23 +114,23 @@ See also: ## Manual feedback collection -To open up the feedback collection UI, call `bucketClient.requestFeedback(options)` +To open up the feedback collection UI, call `reflagClient.requestFeedback(options)` with the appropriate options. This approach is particularly beneficial if you wish to retain manual control over feedback collection from your users while leveraging -the convenience of the Bucket feedback UI to reduce the amount of code you need +the convenience of the Reflag feedback UI to reduce the amount of code you need to maintain. Examples of this could be if you want the click of a `give us feedback`-button or the end of a specific user flow, to trigger a pop-up displaying the feedback user interface. -### bucketClient.requestFeedback() options +### reflagClient.requestFeedback() options Minimal usage with defaults: ```javascript -bucketClient.requestFeedback({ - featureKey: "bucket-feature-key", +reflagClient.requestFeedback({ + flagKey: "reflag-flag-key", title: "How satisfied are you with file uploads?", }); ``` @@ -138,8 +138,8 @@ bucketClient.requestFeedback({ All options: ```javascript -bucketClient.requestFeedback({ - featureKey: "bucket-feature-key", // [Required] +reflagClient.requestFeedback({ + flagKey: "flag-key", // [Required] userId: "your-user-id", // [Optional] if user persistence is // enabled (default in browsers), companyId: "users-company-or-account-id", // [Optional] @@ -202,7 +202,7 @@ does not interact with it. Using a dialog is a soft push for feedback. It lets the user continue their work with a minimal amount of intrusion. The user can opt-in to respond but is not -required to. A good use case for this behavior is when a user uses a feature where +required to. A good use case for this behavior is when a user uses a flag where the expected outcome is predictable, possibly because they have used it multiple times before. For example: Uploading a file, switching to a different view of a visualization, visiting a specific page, or manipulating some data. @@ -244,8 +244,8 @@ Popover feedback button example: + + Reflag feedback collection + - - + +``` + +If using Nuxt, wrap `` in ``. `` only renders client-side currently. + +### 2. Create a new flag and set up type safety + +Install the Reflag CLI: + +```shell +npm i --save-dev @reflag/cli +``` + +Run `npx reflag new` to create your first flag! +On the first run, it will sign into Reflag and set up type generation for your project: + +```shell +❯ npx reflag new +Opened web browser to facilitate login: https://app.bucket.co/api/oauth/cli/authorize + +Welcome to Reflag! + +? Where should we generate the types? gen/flags.d.ts +? What is the output format? vue +✔ Configuration created at reflag.config.json. + +Creating flag for app Slick app. +? New flag name: Huddle +? New flag key: huddle +✔ Created flag Huddle with key huddle (https://app.bucket.co/features/huddles) +✔ Generated vue types in gen/flags.d.ts. ``` -If using Nuxt, wrap `` in ``. `` only renders client-side currently. +> [!Note] +> By default, types will be generated in `gen/flags.d.ts`. +> The default `tsconfig.json` file `include`s this file by default, but if your `tsconfig.json` is different, make sure the file is covered in the `include` property. + +### 3. Use `useFlag()` to get flag value -### 2. Use `useFeature(key)` to get feature status +Using the `useFlag` composable from your components lets you manage functionality in your app and track flag usage: ```vue ``` -See [useFeature()](#usefeature) for a full example +`useFlag` can help you do much more. See a full example for `useFlag` [see below](#useflag). ## Setting `user` and `company` -Bucket determines which features are active for a given `user`, `company`, or `otherContext`. -You pass these to the `BucketProvider` as props. +Reflag determines which flags are active for a given `user`, `company`, or `otherContext`. +You pass these to the `ReflagProvider` as props. If you supply `user` or `company` objects, they must include at least the `id` property otherwise they will be ignored in their entirety. -In addition to the `id`, you must also supply anything additional that you want to be able to evaluate feature targeting rules against. +In addition to the `id`, you must also supply anything additional that you want to be able to evaluate flag targeting rules against. Attributes which are not properties of the `user` or `company` can be supplied using the `otherContext` prop. Attributes cannot be nested (multiple levels) and must be either strings, numbers or booleans. @@ -69,126 +101,256 @@ A number of special attributes exist: - `avatar` -- the URL for `user`/`company` avatar image. ```vue - - + ``` -To retrieve features along with their targeting information, use `useFeature(key: string)` hook (described in a section below). +To retrieve flags along with their targeting information, use `useFlag(flagKey: FlagKey)` composable (described in a section below). + +Note that calling `useFlag()` automatically generates a `check` event. + +## Migrating from Bucket SDK + +If you're migrating from the legacy Bucket SDK to Reflag SDK, here are the key changes you need to make: + +### Provider changes + +- **`BucketProvider`** → **`ReflagProvider`** +- **`BucketClient`** → **`ReflagClient`** + +### Composable changes + +- **`useFeature()`** → **`useFlag()`** +- **`useTrack()`** → **`useTrackCustom()`** for custom events (not flag keys) +- **`useTrack()`** now requires a flag key +- **`useSendFeedback()`** now requires a flag key +- **`useRequestFeedback()`** now requires a flag key -Note that accessing `isEnabled` on the object returned by `useFeature()` automatically -generates a `check` event. +**Important**: The new `useFlag()` composable returns the flag value directly (boolean or object), not an object with methods. The methods that were previously returned by `useFeature()` are now available as separate composables: -## Remote config +- **`useFeature().isEnabled`** → **`useFlag()`** (returns boolean for "toggle" flags) +- **`useFeature().config`** → **`useFlag()`** (returns object for "multi-variate" flags) +- **`useFeature().track`** → **`useTrack()`** (separate composable) +- **`useFeature().requestFeedback`** → **`useRequestFeedback()`** (separate composable) +- **`useFeature().isLoading`** → **`useIsLoading()`** (separate composable) -Remote config is a dynamic and flexible approach to configuring feature behavior outside of your app – without needing to re-deploy it. +### Configuration changes -Similar to `isEnabled`, each feature accessed using the `useFeature()` hook, has a `config` property. This configuration is managed from within Bucket. It is managed similar to the way access to features is managed, but instead of the -binary `isEnabled` you can have multiple configuration values which are given to different user/companies. +- **`fallbackFeatures`** → **`fallbackFlags`** -### Get started with Remote config + ```vue + + + :fallback-features="{ + 'feature1': true, + 'feature2': { key: 'variant-a', payload: { limit: 100 } } + }" + > + + + + :fallback-flags="{ + 'flag1': true, + 'flag2': { key: 'variant-a', payload: { limit: 100 } } + }" + > + ``` + +### Type changes + +- **`Feature`** → **`Flag`** +- **`Features`** → **`Flags`** +- **`FeatureKey`** → **`FlagKey`** +- **`TypedFeatures`** → **`TypedFlags`** + +### Feedback changes + +- **`featureKey`** → **`flagKey`** (in feedback requests) +- **`featureId`** was removed + +### Event changes + +- **`featuresUpdated`** → **`flagsUpdated`** +- **`enabledCheck`** → **`check`** (use the unified `check` event instead) +- **`configCheck`** → **`check`** (use the unified `check` event instead) + +### Example migration + +```vue + + + + -```ts -const { - isEnabled, - config: { key, payload }, -} = useFeature("huddles"); + + -// isEnabled: true, -// key: "gpt-3.5", -// payload: { maxTokens: 10000, model: "gpt-3.5-beta1" } + ``` -`key` is mandatory for a config, but if a feature has no config or no config value was matched against the context, the `key` will be `undefined`. Make sure to check against this case when trying to use the configuration in your application. `payload` is an optional JSON value for arbitrary configuration needs. +### Type definitions -Note that, similar to `isEnabled`, accessing `config` on the object returned by `useFeature()` automatically -generates a `check` event. +Update your type definitions: -## `` component +```typescript +// Old (Bucket SDK) +declare module "@bucket/vue-sdk" { + interface Features { + "my-feature": boolean; + } +} -The `` initializes the Bucket SDK, fetches features and starts listening for automated feedback survey events. The component can be configured using a number of props: +// New (Reflag SDK) +declare module "@reflag/vue-sdk" { + interface Flags { + "my-flag": boolean; + } +} +``` -- `publishableKey` is used to connect the provider to an _environment_ on Bucket. Find your `publishableKey` under [environment settings](https://app.bucket.co/env-current/settings/app-environments) in Bucket, -- `company`, `user` and `otherContext` make up the _context_ that is used to determine if a feature is enabled or not. `company` and `user` contexts are automatically transmitted to Bucket servers so the Bucket app can show you which companies have access to which features etc. +## `` component - > [!Note] - > If you specify `company` and/or `user` they must have at least the `id` property, otherwise they will be ignored in their entirety. You should also supply anything additional you want to be able to evaluate feature targeting against, +The `` initializes the Reflag SDK, fetches flags and starts listening for automated feedback survey events. The component can be configured using a number of props: -- `timeoutMs`: Timeout in milliseconds when fetching features from the server, -- `staleWhileRevalidate`: If set to `true`, stale features will be returned while refetching features in the background, -- `expireTimeMs`: If set, features will be cached between page loads for this duration (in milliseconds), -- `staleTimeMs`: Maximum time (in milliseconds) that stale features will be returned if `staleWhileRevalidate` is true and new features cannot be fetched. +- `publishableKey` is used to connect the provider to an _environment_ on Reflag. Find your `publishableKey` under [environment settings](https://app.bucket.co/env-current/settings/app-environments) in Reflag, +- `company`, `user` and `otherContext` make up the _context_ that is used to determine if a flag is enabled or not. `company` and `user` contexts are automatically transmitted to Reflag servers so the Reflag app can show you which companies have access to which features, etc. -- `enableTracking`: Set to `false` to stop sending tracking events and user/company updates to Bucket. Useful when you're impersonating a user (defaults to `true`), -- `apiBaseUrl`: Optional base URL for the Bucket API. Use this to override the default API endpoint, -- `appBaseUrl`: Optional base URL for the Bucket application. Use this to override the default app URL, + > [!Note] + > If you specify `company` and/or `user` they must have at least the `id` property, otherwise they will be ignored in their entirety. You should also supply anything additional you want to be able to evaluate flag targeting against, + +- `fallbackFlags`: A list of strings which specify which flags to consider enabled if the SDK is unable to fetch flags: + + ```ts + fallbackFlags: { + "flag1": true, // just enable a "toggle" flag + "flag2": { // specify the variant for a "multi-variate" flag + key: "variant-a", + payload: { + limit: 100, + mode: "test" + } + } + } + ``` + +- `timeoutMs`: Timeout in milliseconds when fetching flags from the server +- `staleWhileRevalidate`: If set to `true`, stale flags will be returned while refetching flags in the background +- `expireTimeMs`: If set, flags will be cached between page loads for this duration (in milliseconds) +- `staleTimeMs`: Maximum time (in milliseconds) that stale flags will be returned if `staleWhileRevalidate` is true and new flags cannot be fetched +- `offline`: Provide this option when testing or in local development environments to avoid contacting Reflag servers +- `enableTracking`: Set to `false` to stop sending tracking events and user/company updates to Reflag. Useful when you're impersonating a user (defaults to `true`), +- `apiBaseUrl`: Optional base URL for the Reflag API. Use this to override the default API endpoint, +- `appBaseUrl`: Optional base URL for the Reflag application. Use this to override the default app URL, - `sseBaseUrl`: Optional base URL for Server-Sent Events. Use this to override the default SSE endpoint, - `debug`: Set to `true` to enable debug logging to the console, -- `toolbar`: Optional [configuration](https://docs.bucket.co/supported-languages/browser-sdk/globals#toolbaroptions) for the Bucket toolbar, +- `toolbar`: Optional [configuration](https://docs.bucket.co/supported-languages/browser-sdk/globals#toolbaroptions) for the Reflag toolbar, - `feedback`: Optional configuration for feedback collection ### Loading states -BucketProvider lets you define a template to be shown while BucketProvider is inititalizing: +ReflagProvider lets you define a template to be shown while ReflagProvider is initializing: ```vue ``` -If you want more control over loading screens, `useIsLoading()` returns a Ref which you can use to customize the loading experience. +If you want more control over loading screens, `useIsLoading()` returns a `Ref` which you can use to customize the loading experience. -## Hooks +## Composables -### `useFeature()` +### `useFlag()` -Returns the state of a given feature for the current context. The composable provides access to feature flags and their configurations. +Returns the value of a given flag for the current context. The composable provides type-safe access to flag values and their configurations. +Returns `undefined` if the client is not ready yet. -`useFeature()` returns an object with this shape: - -```ts -{ - isEnabled: boolean, // is the feature enabled - track: () => void, // send a track event when the feature is used - requestFeedback: (...) => void // open up a feedback dialog - config: {key: string, payload: any}, // remote configuration for this feature - isLoading: boolean // if you want to manage loading state at the feature level -} -``` +For "toggle" flags, `useFlag()` returns `true`/`false`. For multi-variate flags, it returns an object of type `{ key: string, payload: TypeOfPayload }`. Example: ```vue ``` -### `useIsLoading()` - -Returns a `Ref` to indicate if Bucket has finished loading. - ## Content Security Policy (CSP) -See [CSP](https://github.com/bucketco/bucket-javascript-sdk/blob/main/packages/browser-sdk/README.md#content-security-policy-csp) for info on using Bucket React SDK with CSP +See [CSP](https://github.com/bucketco/bucket-javascript-sdk/blob/main/packages/browser-sdk/README.md#content-security-policy-csp) for info on using Reflag Vue SDK with CSP ## License diff --git a/packages/vue-sdk/dev/plain/App.vue b/packages/vue-sdk/dev/plain/App.vue index e535c509..009d60d4 100644 --- a/packages/vue-sdk/dev/plain/App.vue +++ b/packages/vue-sdk/dev/plain/App.vue @@ -1,7 +1,7 @@ diff --git a/packages/vue-sdk/dev/plain/components/MissingKeyMessage.vue b/packages/vue-sdk/dev/plain/components/MissingKeyMessage.vue index 96e9b429..72a74283 100644 --- a/packages/vue-sdk/dev/plain/components/MissingKeyMessage.vue +++ b/packages/vue-sdk/dev/plain/components/MissingKeyMessage.vue @@ -12,7 +12,7 @@

Missing Publishable Key

The VITE_PUBLISHABLE_KEY environment variable is not set. - Please set this variable in your .env file to use the Bucket + Please set this variable in your .env file to use the Reflag SDK.

diff --git a/packages/vue-sdk/dev/plain/components/RequestFeedback.vue b/packages/vue-sdk/dev/plain/components/RequestFeedback.vue index 80b37c5b..1e6e5878 100644 --- a/packages/vue-sdk/dev/plain/components/RequestFeedback.vue +++ b/packages/vue-sdk/dev/plain/components/RequestFeedback.vue @@ -3,7 +3,7 @@ import { useRequestFeedback } from "../../../src"; import Section from "./Section.vue"; -const requestFeedback = useRequestFeedback(); +const requestFeedback = useRequestFeedback("demo-feature");