Skip to content

feat(ui): setup FullStory - WF-368#840

Merged
madeindjs merged 2 commits into
devfrom
WF-368
Jun 30, 2025
Merged

feat(ui): setup FullStory - WF-368#840
madeindjs merged 2 commits into
devfrom
WF-368

Conversation

@madeindjs

@madeindjs madeindjs commented Apr 28, 2025

Copy link
Copy Markdown
Collaborator

Install @fullstory/browser and initialize it in useWriterTracking

We load the Writer's env variables from /env/config.js. It safely fails if the URL doesn't exist (like for local or self-hosted mode).

Summary by CodeRabbit

  • New Features

    • Added support for FullStory analytics integration, enabling enhanced event and page tracking.
    • Expanded file language detection to include JavaScript and TypeScript files.
    • Introduced dynamic loading and caching of environment configuration from a remote source.
  • Bug Fixes

    • Improved error handling during collaboration feature initialization to prevent unhandled promise rejections.
    • Broadened checks for user ID validity in collaboration updates to handle both null and undefined values.
  • Chores

    • Updated dependencies to include the FullStory browser package.
    • Removed obsolete Chameleon analytics integration and related test mocks.
    • Updated test setups to reflect changes in analytics integration.
    • Added TypeScript support for Vite client environment types.
    • Removed TypeScript expect-error comments for cleaner code.

@madeindjs madeindjs self-assigned this Apr 28, 2025
@madeindjs
madeindjs force-pushed the WF-368 branch 2 times, most recently from 46efc2e to 6c1df18 Compare May 7, 2025 15:14
@madeindjs
madeindjs marked this pull request as ready for review May 7, 2025 15:28
@madeindjs
madeindjs marked this pull request as draft May 20, 2025 09:16
@madeindjs

Copy link
Copy Markdown
Collaborator Author

Moving as draft because I'm waiting for Fullstory is activated on writer.com

@hackerone-code hackerone-code Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ This pull request was succesfully scanned and it was determined that it does not contain any changes that present immediate security concerns. If you would still like for it to be reviewed by an expert from our reviewer community, you can submit it manually via the HackerOne PullRequest dashboard.

⏱️ Latest scan covered changes up to commit 6c1df18 (latest)

@coderabbitai

coderabbitai Bot commented Jun 27, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This change introduces FullStory analytics integration into the Writer Cloud app, enabling session recording when in cloud and edit mode. It adds FullStory dependencies, implements dynamic loading and initialization, expands event tracking to support both API and FullStory, and removes the previous Chameleon integration. Supporting utilities and tests are updated accordingly.

Changes

File(s) Change Summary
src/ui/package.json Added @fullstory/browser dependency.
src/ui/src/composables/useWriterTracking.ts, src/ui/src/utils/writerCloudEnvConfig.ts Added FullStory integration, dynamic imports, and environment config loader; removed Chameleon logic.
src/ui/src/composables/useWriterTracking.spec.ts, src/ui/src/builder/BuilderSwitcher.spec.ts Updated/removed mocks and test setup for Chameleon and new config utility.
src/ui/src/writerApi.ts Removed loadAndIdentifyChameleon method from WriterApi.
src/ui/src/composables/useCollaborationManager.ts Broadened guard clause for incomingUserId to check for undefined or null.
src/ui/src/core/useSourceFiles.ts Added support for recognizing .js, .mjs, and .ts file extensions.
src/ui/src/main.ts Added error handling to enableCollaboration call.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant App
    participant WriterApi
    participant FullStory
    participant EnvConfig

    User->>App: Mounts app in cloud & edit mode
    App->>WriterApi: fetchUserProfile()
    App->>EnvConfig: getWriterCloudEnvConfig()
    App->>FullStory: Dynamically import & initialize with orgId
    App->>FullStory: Identify user with profile
    App->>WriterApi: analyticsIdentify(user)
    App->>App: User triggers event
    App->>WriterApi: analyticsTrack(event, props)
    App->>FullStory: trackEventAsync(event, props)
Loading

Assessment against linked issues

Objective Addressed Explanation
Integrate FullStory to record user sessions in cloud & edit mode (AB-51)
Ensure tracking is conditional on cloud and edit mode (AB-51)
Remove or replace previous Chameleon integration (AB-51)

Assessment against linked issues: Out-of-scope changes

Code Change (file_path) Explanation
Broadened guard clause for incomingUserId to check for undefined or null (src/ui/src/composables/useCollaborationManager.ts) This change is not directly related to FullStory integration or analytics tracking.
Added support for .js, .mjs, and .ts file extensions (src/ui/src/core/useSourceFiles.ts) Recognizing new file extensions is unrelated to analytics or FullStory objectives.
Added error handling to enableCollaboration call (src/ui/src/main.ts) Error handling for collaboration is not part of the FullStory tracking objective.

Possibly related PRs

  • fix(ui): Small fixes UI #975: Modifies the same test file and mock function (loadAndIdentifyChameleon) but in the opposite direction, indicating a direct relationship.
  • feat: Chameleon #974: Adds the loadAndIdentifyChameleon method and its usage, which this PR removes and replaces with FullStory, making them directly related.

Poem

A rabbit hops with analytic delight,
FullStory now tracks each cloud-edit flight.
Chameleon has left the show,
As new events and sessions flow.
With code and carrots, we leap ahead—
Let every session be insight-fed!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@hackerone-code hackerone-code Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ This pull request was succesfully scanned and it was determined that it does not contain any changes that present immediate security concerns. If you would still like for it to be reviewed by an expert from our reviewer community, you can submit it manually via the HackerOne PullRequest dashboard.

⏱️ Latest scan covered changes up to commit 338c7a9 (latest)

@madeindjs
madeindjs force-pushed the WF-368 branch 2 times, most recently from 65ab3a9 to 91aee0c Compare June 30, 2025 08:07

@hackerone-code hackerone-code Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ This pull request was succesfully scanned and it was determined that it does not contain any changes that present immediate security concerns. If you would still like for it to be reviewed by an expert from our reviewer community, you can submit it manually via the HackerOne PullRequest dashboard.

⏱️ Latest scan covered changes up to commit 91aee0c (latest)

@hackerone-code hackerone-code Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ This pull request was succesfully scanned and it was determined that it does not contain any changes that present immediate security concerns. If you would still like for it to be reviewed by an expert from our reviewer community, you can submit it manually via the HackerOne PullRequest dashboard.

⏱️ Latest scan covered changes up to commit b1e73cc (latest)

@madeindjs
madeindjs marked this pull request as ready for review June 30, 2025 09:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/ui/src/utils/writerCloudEnvConfig.ts (1)

32-76: Security consideration: Dynamic import of remote JavaScript.

While the implementation includes proper error handling and resource cleanup, loading and executing remote JavaScript via dynamic imports poses potential security risks. However, the risk is mitigated since:

  1. The URL is constructed from trusted sources (same origin or environment variable)
  2. It uses credentials: "include" which suggests same-origin requests
  3. Comprehensive error handling prevents failures from breaking the app

Consider documenting the security assumptions and ensuring the /env/config.js endpoint is properly secured on the server side.

src/ui/src/composables/useWriterTracking.ts (1)

136-151: Remove redundant canTrack checks.

The canTrack check in track() makes the checks in trackWithFullStory and trackWithApi redundant.

 async function trackWithFullStory(
 	eventName: string,
 	properties: EventProperties,
 ) {
-	if (!canTrack.value) return;
 	const fullstoryOrgId = await getFullstoryOrgId();
 	if (!fullstoryOrgId) return;

 	const { FullStory } = await import("@fullstory/browser");
 	return FullStory("trackEventAsync", { name: eventName, properties });
 }

 function trackWithApi(eventName: string, properties: EventProperties) {
-	if (!canTrack.value) return;
 	return writerApi.analyticsTrack(eventName, properties);
 }

Also applies to: 182-197

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65f45e1 and 7614faf.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (9)
  • src/ui/package.json (1 hunks)
  • src/ui/src/builder/BuilderSwitcher.spec.ts (0 hunks)
  • src/ui/src/composables/useCollaborationManager.ts (1 hunks)
  • src/ui/src/composables/useWriterTracking.spec.ts (1 hunks)
  • src/ui/src/composables/useWriterTracking.ts (4 hunks)
  • src/ui/src/core/useSourceFiles.ts (1 hunks)
  • src/ui/src/main.ts (1 hunks)
  • src/ui/src/utils/writerCloudEnvConfig.ts (1 hunks)
  • src/ui/src/writerApi.ts (0 hunks)
💤 Files with no reviewable changes (2)
  • src/ui/src/builder/BuilderSwitcher.spec.ts
  • src/ui/src/writerApi.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/ui/src/composables/useWriterTracking.spec.ts (1)
src/ui/src/writerApi.ts (3)
  • fetchUserProfile (113-119)
  • analyticsIdentify (129-137)
  • analyticsTrack (139-150)
⏰ Context from checks skipped due to timeout of 90000ms (13)
  • GitHub Check: build (3.10)
  • GitHub Check: build (3.9)
  • GitHub Check: build (3.10)
  • GitHub Check: build (3.11)
  • GitHub Check: build (3.13)
  • GitHub Check: build (3.12)
  • GitHub Check: build (3.13)
  • GitHub Check: build (3.11)
  • GitHub Check: build (3.12)
  • GitHub Check: build (3.9)
  • GitHub Check: tests (firefox)
  • GitHub Check: tests (webkit)
  • GitHub Check: tests (chromium)
🔇 Additional comments (13)
src/ui/package.json (1)

26-26: FullStory Dependency Version Confirmed

The @fullstory/browser dependency at version ^2.0.6 is the latest stable release, and there are no known security advisories affecting it. Keep the caret range to allow safe minor/patch updates as usual.

src/ui/src/core/useSourceFiles.ts (1)

160-164: LGTM! Clean extension mapping for JavaScript and TypeScript.

The language detection logic correctly maps JavaScript and TypeScript file extensions to their respective language identifiers, following the established pattern used for other languages.

src/ui/src/utils/writerCloudEnvConfig.ts (3)

15-27: Good error handling for remote config fetching.

The error handling in getWriterCloudEnvConfigText is robust - it properly catches fetch failures and returns undefined instead of throwing, which allows the calling code to handle missing configs gracefully.


46-59: Proper resource management with blob URLs.

The implementation correctly creates and cleans up blob URLs, ensuring no memory leaks. The use of finally block guarantees cleanup even if the import fails.


61-73: Robust config format handling.

The code properly handles multiple config formats (object, base64-encoded string) with appropriate fallbacks. The use of atob() for base64 decoding and proper JSON parsing with error handling is well implemented.

src/ui/src/composables/useCollaborationManager.ts (1)

47-47: Good defensive programming with comprehensive null checks.

The expanded guard clause now properly handles both undefined and null values for incomingUserId, making the collaboration system more robust against edge cases.

src/ui/src/main.ts (1)

66-66: Excellent error handling improvement.

Adding .catch(logger.error) ensures that any failures in collaboration enablement are properly logged rather than causing unhandled promise rejections. This follows the same pattern used for secretsManager.load() and improves application reliability.

src/ui/src/composables/useWriterTracking.spec.ts (1)

9-9: LGTM! Mock updates align with implementation changes.

The mock updates correctly reflect the refactored implementation:

  • Replaced loadAndIdentifyChameleon with fetchUserProfile
  • Added mock for getWriterCloudEnvConfig returning empty object, which prevents FullStory initialization in tests

Also applies to: 15-15, 19-22

src/ui/src/composables/useWriterTracking.ts (5)

57-67: Good refactoring with centralized tracking condition.

The canTrack computed property effectively centralizes the tracking logic, and getFullstoryOrgId safely retrieves the organization ID with proper cloud app validation.


74-79: Excellent optimization with shared promise.

Smart use of Promise.all for parallel execution and sharing the fetchUserProfile promise between initialization functions to avoid duplicate API calls.


153-159: Clean extraction of component information logic.

Good refactoring that improves code organization and handles edge cases properly.


89-106: Critical: Remove hardcoded API key from source code.

The Chameleon API key is hardcoded in the source code, which is a security risk. API keys should be loaded from environment configuration.

 async function initializeChameleon(
 	fetchUserProfile: Promise<WriterApiUserProfile>,
 ) {
+	const config = await getWriterCloudEnvConfig();
+	const chameleonApiKey = config["CHAMELEON_API_KEY"];
+	if (!chameleonApiKey) {
+		logger.warn("Chameleon API key not found in environment config");
+		return;
+	}
+
 	const chameleon = await import("@chamaeleonidae/chmln");
 	chameleon.init(
-		"S6dr31v4MO4wuteztVhxysLkoA9HsZ6HnDaOTDLqNXHYZq-1P02ek-E3BR4Zgv4pMwdoYO",
+		String(chameleonApiKey),
 		{
 			fastUrl: "https://fast.chameleon.io/",
 		},
 	);
 	const profile = await fetchUserProfile;
 	chameleon.identify(profile.id, {
 		email: profile?.email,
 		name:
 			profile?.fullName ??
 			`${profile?.firstName} ${profile.lastName}`,
 	});
 }
⛔ Skipped due to learnings
Learnt from: ramedina86
PR: writer/writer-framework#974
File: src/ui/src/writerApi.ts:141-155
Timestamp: 2025-06-24T14:00:42.917Z
Learning: Client-side API keys for user onboarding services like Chameleon are meant to be publicly visible in the client bundle and are not security issues when hardcoded in client-side code.

199-210: Keep the explicit writerOrgId check

The canTrack guard ensures mode === "edit" and isWriterCloudApp (which is true if either writerAppId or writerOrgId is defined), but writerOrgId can still be undefined when only writerAppId exists. The extra if (!wf.writerOrgId.value) prevents calling analyticsPage without a valid org ID. No change needed.

Comment thread src/ui/src/composables/useWriterTracking.ts

@hackerone-code hackerone-code Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ This pull request was succesfully scanned and it was determined that it does not contain any changes that present immediate security concerns. If you would still like for it to be reviewed by an expert from our reviewer community, you can submit it manually via the HackerOne PullRequest dashboard.

⏱️ Latest scan covered changes up to commit 7614faf (latest)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
src/ui/src/composables/useWriterTracking.ts (3)

132-132: This duplicates a previous review concern - verify the segment prefix necessity.

The literal "segment-prefix-" may not be necessary for your integration.

Please confirm whether this prefix is required by your Segment analytics integration. If not needed, remove it:

-uid: `segment-prefix-${profile.id}`,
+uid: String(profile.id),

123-127: This duplicates a previous review concern - add error handling for FullStory initialization.

The module.init call lacks proper error handling, which could lead to unhandled promise rejections.

Wrap the initialization in a try-catch block:

-module.init({
-  orgId: fullstoryOrgId,
-  // @ts-expect-error importing vite variable
-  devMode: import.meta.env.DEV,
-});
+try {
+  module.init({
+    orgId: fullstoryOrgId,
+    devMode: import.meta.env.DEV,
+  });
+} catch (e) {
+  logger.error("Failed to initialize FullStory", e);
+  return;
+}

125-126: This duplicates a previous review concern - fix TypeScript error suppression.

The @ts-expect-error indicates missing Vite type definitions in your TypeScript configuration.

Add Vite types to your tsconfig.json:

{
  "compilerOptions": {
    "types": ["vite/client"]
  }
}
🧹 Nitpick comments (2)
src/ui/src/composables/useWriterTracking.ts (2)

60-66: Consider caching the config result.

The function correctly handles the Writer Cloud app check, but multiple calls to getWriterCloudEnvConfig() could impact performance since this is called in multiple places.

Consider caching the config result:

+let configCache: Promise<Record<string, unknown>> | null = null;
+
 async function getFullstoryOrgId() {
   if (!wf.isWriterCloudApp.value) return undefined;
-  const config = await getWriterCloudEnvConfig();
+  if (!configCache) {
+    configCache = getWriterCloudEnvConfig();
+  }
+  const config = await configCache;
   return config["FULLSTORY_ORG_ID"]
     ? String(config["FULLSTORY_ORG_ID"])
     : undefined;
 }

198-201: Consider independent tracking failure handling.

The current Promise.all approach means if one tracking provider fails, both fail. This could reduce tracking reliability.

Consider allowing independent failures:

-return await Promise.all([
-  trackWithApi(eventNameFormated, propertiesExpanded),
-  trackWithFullStory(eventNameFormated, propertiesExpanded),
-]).catch(logger.error);
+const results = await Promise.allSettled([
+  trackWithApi(eventNameFormated, propertiesExpanded),
+  trackWithFullStory(eventNameFormated, propertiesExpanded),
+]);
+
+results.forEach((result, index) => {
+  if (result.status === 'rejected') {
+    const provider = index === 0 ? 'API' : 'FullStory';
+    logger.error(`${provider} tracking failed:`, result.reason);
+  }
+});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7614faf and 3a17fe2.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (12)
  • src/ui/package.json (1 hunks)
  • src/ui/src/builder/BuilderSwitcher.spec.ts (0 hunks)
  • src/ui/src/components/core/embed/CorePDF.vue (0 hunks)
  • src/ui/src/composables/useCollaborationManager.ts (1 hunks)
  • src/ui/src/composables/useWriterApi.ts (0 hunks)
  • src/ui/src/composables/useWriterTracking.spec.ts (1 hunks)
  • src/ui/src/composables/useWriterTracking.ts (3 hunks)
  • src/ui/src/core/useSourceFiles.ts (1 hunks)
  • src/ui/src/main.ts (1 hunks)
  • src/ui/src/utils/writerCloudEnvConfig.ts (1 hunks)
  • src/ui/src/writerApi.ts (0 hunks)
  • src/ui/tsconfig.json (1 hunks)
💤 Files with no reviewable changes (4)
  • src/ui/src/composables/useWriterApi.ts
  • src/ui/src/components/core/embed/CorePDF.vue
  • src/ui/src/builder/BuilderSwitcher.spec.ts
  • src/ui/src/writerApi.ts
✅ Files skipped from review due to trivial changes (1)
  • src/ui/tsconfig.json
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/ui/package.json
  • src/ui/src/composables/useCollaborationManager.ts
  • src/ui/src/main.ts
  • src/ui/src/utils/writerCloudEnvConfig.ts
  • src/ui/src/composables/useWriterTracking.spec.ts
  • src/ui/src/core/useSourceFiles.ts
⏰ Context from checks skipped due to timeout of 90000ms (14)
  • GitHub Check: build (3.10)
  • GitHub Check: build (3.12)
  • GitHub Check: build (3.11)
  • GitHub Check: build (3.13)
  • GitHub Check: build (3.9)
  • GitHub Check: tests (firefox)
  • GitHub Check: tests (webkit)
  • GitHub Check: tests (chromium)
  • GitHub Check: build (3.9)
  • GitHub Check: build (3.13)
  • GitHub Check: build (3.10)
  • GitHub Check: build (3.12)
  • GitHub Check: build (3.11)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
src/ui/src/composables/useWriterTracking.ts (4)

3-5: LGTM! Good reactive state management setup.

The addition of Vue composition API imports and the new environment config utility properly supports the refactored reactive tracking logic.


56-58: Excellent centralized tracking condition.

The canTrack computed property provides a clean, reactive way to determine when tracking should be enabled, consolidating the edit mode and Writer Cloud app checks.


187-202: Good parallel tracking implementation.

The async refactor and parallel tracking calls provide good performance while maintaining proper error logging. The conditional checks ensure tracking only occurs when appropriate.


98-103: Security concern: Hardcoded Chameleon key.

The Chameleon initialization uses a hardcoded API key. This could be a security risk and makes environment management difficult.

Consider moving this to environment configuration:

 async function initializeChameleon(
   fetchUserProfile = writerApi.fetchUserProfile(),
 ) {
+  const config = await getWriterCloudEnvConfig();
+  const chameleonKey = config["CHAMELEON_API_KEY"];
+  if (!chameleonKey) return;
+  
   const chameleon = await import("@chamaeleonidae/chmln");
   chameleon.init(
-    "S6dr31v4MO4wuteztVhxysLkoA9HsZ6HnDaOTDLqNXHYZq-1P02ek-E3BR4Zgv4pMwdoYO",
+    String(chameleonKey),
     {
       fastUrl: "https://fast.chameleon.io/",
     },
   );
⛔ Skipped due to learnings
Learnt from: ramedina86
PR: writer/writer-framework#974
File: src/ui/src/writerApi.ts:141-155
Timestamp: 2025-06-24T14:00:42.917Z
Learning: Client-side API keys for user onboarding services like Chameleon are meant to be publicly visible in the client bundle and are not security issues when hardcoded in client-side code.

@hackerone-code hackerone-code Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ This pull request was succesfully scanned and it was determined that it does not contain any changes that present immediate security concerns. If you would still like for it to be reviewed by an expert from our reviewer community, you can submit it manually via the HackerOne PullRequest dashboard.

⏱️ Latest scan covered changes up to commit 3a17fe2 (latest)

@madeindjs
madeindjs merged commit 4909a5b into dev Jun 30, 2025
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant