feat: add Vue integration package#182
Conversation
|
@austin33133-maker is attempting to deploy a commit to the cstrnt's projects Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughThis PR introduces the ChangesVue Integration Package
Sequence DiagramsequenceDiagram
participant Component as Vue Component
participant Plugin as AbbyPlugin.install()
participant Context as InjectionContext
participant Abby as Abby Core Instance
participant Storage as StorageService (Cookies)
participant Server as Abby API Server
Component->>Plugin: app created with createAbby(config)
Plugin->>Abby: instantiate with config & storage handlers
Abby->>Storage: get(testKey) on init
Storage-->>Abby: null or persisted variant
Plugin->>Server: loadProjectData(projectId)
Server-->>Plugin: tests, flags, remoteConfig
Plugin->>Context: app.provide(AbbyContextKey, reactive data)
Component->>Component: mount with useAbby('test')
Component->>Context: inject(AbbyContextKey)
Context-->>Component: computed data & selected variant
Component->>Server: sendData(PING event)
Component->>Component: user triggers onAct()
Component->>Storage: set(testKey, variant)
Component->>Server: sendData(ACT event)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
packages/vue/tests/setup.ts (1)
6-6: 💤 Low valueConsider a more specific type assertion.
The
as anycast bypasses all type checking. While the type mismatch betweennode-fetchand the nativefetchAPI can make precise typing difficult, consider usingas unknown as typeof fetchfor a slightly safer assertion path, or accepting the type incompatibility if the current approach works reliably.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/vue/tests/setup.ts` at line 6, Replace the broad "as any" cast on the global fetch assignment to preserve more type safety: change the assignment of globalThis.fetch (where you currently do "globalThis.fetch = fetch as any;") to use a safer assertion like "as unknown as typeof fetch" so TypeScript treats the value as the native fetch signature instead of bypassing type checks entirely.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/vue/README.md`:
- Around line 40-43: The README example uses useAbby, useFeatureFlag, and
useRemoteConfig which return ComputedRef objects; update the snippet to show
accessing their .value in script context so consumers don’t misuse them.
Specifically, show that variant and onAct (from useAbby), newCheckout (from
useFeatureFlag), and ctaText (from useRemoteConfig) must be read as .value (or
assign .value to local variables) when used in plain script code and update the
example text accordingly.
In `@packages/vue/src/index.ts`:
- Around line 101-113: The FlagStorageService.set and
RemoteConfigStorageService.set handlers currently write cookies unconditionally;
update both set handlers to honor the cookie opt-out by checking
config.cookies?.disableByDefault (same check used by the AB test cookie logic
around line 91) and skip calling FlagStorageService.set or
RemoteConfigStorageService.set when disableByDefault is true, leaving get
behavior unchanged.
---
Nitpick comments:
In `@packages/vue/tests/setup.ts`:
- Line 6: Replace the broad "as any" cast on the global fetch assignment to
preserve more type safety: change the assignment of globalThis.fetch (where you
currently do "globalThis.fetch = fetch as any;") to use a safer assertion like
"as unknown as typeof fetch" so TypeScript treats the value as the native fetch
signature instead of bypassing type checks entirely.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: f41a6488-09b3-4702-b10f-0e945b484c69
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (13)
.changeset/fresh-vans-dream.mdpackages/vue/README.mdpackages/vue/package.jsonpackages/vue/src/StorageService.tspackages/vue/src/index.tspackages/vue/tests/mocks/handlers.tspackages/vue/tests/mocks/server.tspackages/vue/tests/setup.tspackages/vue/tests/types.test.tspackages/vue/tests/useAbby.test.tspackages/vue/tsconfig.jsonpackages/vue/tsup.config.tspackages/vue/vite.config.ts
| const { variant, onAct } = useAbby("headline"); | ||
| const newCheckout = useFeatureFlag("newCheckout"); | ||
| const ctaText = useRemoteConfig("ctaText"); | ||
| ``` |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Vue 3 Composition API, do ref/computedreturn values require.value access in script code (outside templates)?
💡 Result:
No—inside normal script code (Composition API, i.e., within setup / <script setup>), refs and computed refs require.value access to read the underlying value. Vue’s reactivity APIs define that a ref object has a single.value property that points to the inner value [1]. Vue’s computed returns a (readonly) reactive ref object, and the docs show using plusOne.value in script code (e.g., console.log(plusOne.value)) [1]. By contrast, in templates Vue auto-un-wraps refs/computed refs, so you can use them without.value [2]. Rule of thumb: - Script code (outside templates): refVar.value / computedVar.value - Template expressions: refVar / computedVar (no.value) Caveat: unwrapping isn’t universal (for example, refs inside arrays/collection elements don’t get unwrapped), where you may still need.value [3].
Citations:
- 1: https://vuejs.org/api/reactivity-core
- 2: https://vuejs.org/api/sfc-script-setup
- 3: https://vuejs.org/api/reactivity-core.html
🏁 Script executed:
# Check the README file at lines 40-43
sed -n '30,55p' packages/vue/README.mdRepository: tryabby/abby
Length of output: 401
🏁 Script executed:
# Find where these composables are defined
find packages/vue -type f -name "*.ts" -o -name "*.js" | head -20Repository: tryabby/abby
Length of output: 341
🏁 Script executed:
# Search for the composable definitions
rg -l "useAbby|useFeatureFlag|useRemoteConfig" packages/vue --type ts --type jsRepository: tryabby/abby
Length of output: 150
🏁 Script executed:
# Check the index.ts to see what these composables return
cat -n packages/vue/src/index.tsRepository: tryabby/abby
Length of output: 10391
Clarify .value access requirement for composables in script context.
useAbby, useFeatureFlag, and useRemoteConfig return ComputedRef objects, which require .value access when used in script code. The README example should demonstrate this to prevent misuse.
✏️ Suggested doc fix
const { variant, onAct } = useAbby("headline");
const newCheckout = useFeatureFlag("newCheckout");
const ctaText = useRemoteConfig("ctaText");
+
+// In script context, access the computed values via .value:
+console.log(variant.value, newCheckout.value, ctaText.value);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const { variant, onAct } = useAbby("headline"); | |
| const newCheckout = useFeatureFlag("newCheckout"); | |
| const ctaText = useRemoteConfig("ctaText"); | |
| ``` | |
| const { variant, onAct } = useAbby("headline"); | |
| const newCheckout = useFeatureFlag("newCheckout"); | |
| const ctaText = useRemoteConfig("ctaText"); | |
| // In script context, access the computed values via .value: | |
| console.log(variant.value, newCheckout.value, ctaText.value); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/vue/README.md` around lines 40 - 43, The README example uses
useAbby, useFeatureFlag, and useRemoteConfig which return ComputedRef objects;
update the snippet to show accessing their .value in script context so consumers
don’t misuse them. Specifically, show that variant and onAct (from useAbby),
newCheckout (from useFeatureFlag), and ctaText (from useRemoteConfig) must be
read as .value (or assign .value to local variables) when used in plain script
code and update the example text accordingly.
| set: (key: string, value: string) => { | ||
| if (typeof window === "undefined") return; | ||
| FlagStorageService.set(config.projectId, key, value); | ||
| }, | ||
| }, | ||
| { | ||
| get: (key: string) => { | ||
| if (typeof window === "undefined") return null; | ||
| return RemoteConfigStorageService.get(config.projectId, key); | ||
| }, | ||
| set: (key: string, value: string) => { | ||
| if (typeof window === "undefined") return; | ||
| RemoteConfigStorageService.set(config.projectId, key, value); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify all cookie write paths consistently gate on disableByDefault in Vue integration.
rg -n -C2 'disableByDefault|TestStorageService\.set|FlagStorageService\.set|RemoteConfigStorageService\.set' packages/vue/src/index.tsRepository: tryabby/abby
Length of output: 725
Respect disableByDefault config for flag and remote-config writes.
Flag and remote-config cookies are written regardless of config.cookies?.disableByDefault, while AB test cookies properly check this setting (line 91). This inconsistency breaks cookie opt-out behavior.
🛠️ Suggested fix
set: (key: string, value: string) => {
- if (typeof window === "undefined") return;
+ if (typeof window === "undefined" || config.cookies?.disableByDefault)
+ return;
FlagStorageService.set(config.projectId, key, value);
},
@@
set: (key: string, value: string) => {
- if (typeof window === "undefined") return;
+ if (typeof window === "undefined" || config.cookies?.disableByDefault)
+ return;
RemoteConfigStorageService.set(config.projectId, key, value);
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| set: (key: string, value: string) => { | |
| if (typeof window === "undefined") return; | |
| FlagStorageService.set(config.projectId, key, value); | |
| }, | |
| }, | |
| { | |
| get: (key: string) => { | |
| if (typeof window === "undefined") return null; | |
| return RemoteConfigStorageService.get(config.projectId, key); | |
| }, | |
| set: (key: string, value: string) => { | |
| if (typeof window === "undefined") return; | |
| RemoteConfigStorageService.set(config.projectId, key, value); | |
| set: (key: string, value: string) => { | |
| if (typeof window === "undefined" || config.cookies?.disableByDefault) | |
| return; | |
| FlagStorageService.set(config.projectId, key, value); | |
| }, | |
| }, | |
| { | |
| get: (key: string) => { | |
| if (typeof window === "undefined") return null; | |
| return RemoteConfigStorageService.get(config.projectId, key); | |
| }, | |
| set: (key: string, value: string) => { | |
| if (typeof window === "undefined" || config.cookies?.disableByDefault) | |
| return; | |
| RemoteConfigStorageService.set(config.projectId, key, value); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/vue/src/index.ts` around lines 101 - 113, The FlagStorageService.set
and RemoteConfigStorageService.set handlers currently write cookies
unconditionally; update both set handlers to honor the cookie opt-out by
checking config.cookies?.disableByDefault (same check used by the AB test cookie
logic around line 91) and skip calling FlagStorageService.set or
RemoteConfigStorageService.set when disableByDefault is true, leaving get
behavior unchanged.
|
Closing this — I should have checked the bounty status before opening it. Looking back at #68, the bounty has already been awarded:
So this PR is redundant. Apologies for the noise on the queue — happy to pull from this branch if any of the unmerged work here is useful in a follow-up, but otherwise this can stay closed. |
Summary
@tryabby/vuepackage that consumes@tryabby/core.Testing
biome ci packages/vue .changeset/fresh-vans-dream.mdtsc --noEmitfrompackages/vuevitest --run --config vite.config.tsfrompackages/vuetsup src/frompackages/vueCloses #68
Summary by CodeRabbit
Release Notes
New Features
Documentation