-
Notifications
You must be signed in to change notification settings - Fork 44
Feature Request: Support custom storage implementation for identityStorage option #1061
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Labels
enhancement
New feature or request
Comments
Another weird approach for a future reference: import {browser} from 'wxt/browser';
interface StorageSubstitute {
getItem(key: string): Promise<string | null>;
setItem(key: string, value: string): Promise<void>;
removeItem(key: string): Promise<void>;
clear(): Promise<void>;
}
interface CookieStorageOptions {
domain?: string;
expirationDays?: number;
sameSite?: string;
secure?: boolean;
}
export class CookieStorage implements StorageSubstitute {
private options: CookieStorageOptions;
private websiteUrl: string;
constructor(websiteUrl: string, options?: CookieStorageOptions) {
this.options = {...options};
this.websiteUrl = import.meta.env.WXT_MATHAI_WEBSITE;
}
async getItem(key: string): Promise<string | null> {
try {
const cookie = await browser.cookies.get({
url: this.websiteUrl,
name: key
});
if (!cookie?.value) {
return null;
}
try {
const decodedValue = decodeURIComponent(atob(cookie.value));
return decodedValue;
} catch {
try {
const decodedValue = decodeURIComponent(atob(decodeURIComponent(cookie.value)));
return decodedValue;
} catch (error) {
console.error(`[CookieStorage] Failed to decode cookie value for key: ${key}, value: ${cookie.value}`);
return null;
}
}
} catch (error) {
console.error(`[CookieStorage] Error getting "${key}":`, error);
return null;
}
}
async setItem(key: string, value: string): Promise<void> {
try {
if (value === null || value === undefined) {
await this.removeItem(key);
return;
}
const expirationDays = this.options.expirationDays ?? 0;
let expirationDate: number | undefined = undefined;
if (expirationDays) {
expirationDate = Math.floor(Date.now() / 1000) + (expirationDays * 24 * 60 * 60);
}
let domain = this.options.domain;
if (!domain && this.websiteUrl) {
try {
const url = new URL(this.websiteUrl);
domain = url.hostname;
} catch (error) {
console.error('[CookieStorage] Invalid URL:', this.websiteUrl);
}
}
const encodedValue = btoa(encodeURIComponent(value));
await browser.cookies.set({
url: this.websiteUrl,
name: key,
value: encodedValue,
domain: domain,
path: '/',
secure: this.options.secure ?? this.websiteUrl.startsWith('https://'),
httpOnly: false,
expirationDate: expirationDate,
sameSite: this.options.sameSite as any || 'lax'
});
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`[CookieStorage] Failed to set cookie for key: ${key}. Error: ${errorMessage}`);
}
}
async removeItem(key: string): Promise<void> {
try {
await browser.cookies.remove({
url: this.websiteUrl,
name: key
});
} catch (error) {
console.error(`[CookieStorage] Error removing "${key}":`, error);
}
}
async clear(): Promise<void> {
return Promise.resolve();
}
}
let ourContext = {
localStorage: new CookieStorage(import.meta.env.WXT_MATHAI_WEBSITE, {
expirationDays: 30,
secure: true
}),
};
const contextProxy = new Proxy(ourContext, {
get(target: any, prop: string | symbol, receiver: any): any {
if (prop in target) {
return target[prop];
}
const value = (globalThis as any)[prop];
if (typeof value === 'function') {
return function (...args: any[]): any {
return value.apply(globalThis, args);
};
}
return value;
}
});
globalThis.ampIntegrationContext = contextProxy; amplitude.init(import.meta.env.WXT_AMPLITUDE_API_KEY, {
// WARNING: We actually use our own storage.
identityStorage: "localStorage",
}) |
Thanks for the request. I'll add this to our backlog, but of course I can't give any promises on timelines. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Summary
Allow passing custom storage implementation to
identityStorage
option instead of only supporting predefined types:cookie
localStorage
sessionStorage
none
Motivations
Consistent session tracking between background script, sidepanel, and website is critical for accurate analytics. Sessions currently break across these contexts because Amplitude doesn't support Chrome's extension-specific storage APIs.
Background scripts, sidepanel, and website can all access shared storage through Chrome's extension APIs (
chrome.cookies
, etc.), but Amplitude only supports standard web storage mechanisms which don't work across extension contexts.Allowing custom storage implementations would enable developers to implement consistent session tracking using Chrome's extension APIs without requiring Amplitude to include extension-specific dependencies in their core package.
The text was updated successfully, but these errors were encountered: