feat: adds workspace support#44
Conversation
WalkthroughThe PR refactors the SDK to replace "environment" terminology with "workspace" terminology throughout. It changes 🚥 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. 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: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Sources/FormbricksSDK/Formbricks.swift (1)
61-80:⚠️ Potential issue | 🟡 MinorAvoid leaving workspace state after failed setup validation.
Line 62 assigns
workspaceIdbeforeappUrlvalidation. If setup aborts for an invalid/non-HTTPS URL, the SDK remains uninitialized but still exposes staleappUrl,workspaceId,logger, andapiQueuestate. Move identifier assignment after validation, or clean up before returning.Proposed fix
- self.appUrl = config.appUrl - self.workspaceId = config.workspaceId self.logger?.logLevel = config.logLevel if config.usedDeprecatedEnvironmentId { Formbricks.logger?.debug("environmentId is deprecated and will be removed in a future version. Please use workspaceId instead.") @@ guard url.scheme?.lowercased() == "https" else { let errorMessage = "HTTP requests are blocked for security. Only HTTPS URLs are allowed. Provided app url: \(config.appUrl). SDK setup aborted." Formbricks.logger?.error(errorMessage) return } + + self.appUrl = config.appUrl + self.workspaceId = config.workspaceId🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/FormbricksSDK/Formbricks.swift` around lines 61 - 80, The setup assigns self.appUrl, self.workspaceId and mutates self.logger/apiQueue before validating the provided URL, leaving partial/invalid SDK state if validation fails; move the assignments of appUrl and workspaceId (and any logger/apiQueue initialization tied to config) to after the URL validation and HTTPS check in the initializer (or, alternatively, on validation failure revert/clear those properties), ensuring any early return from the initializer does not leave stale state; update references to Formbricks.logger, self.appUrl, self.workspaceId and apiQueue initialization points to be executed only after URL validation succeeds.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Sources/FormbricksSDK/Helpers/ConfigBuilder.swift`:
- Around line 5-17: The workspaceId property is internal so external Swift/Obj-C
consumers can't read it; make it a public (and `@objc` for Objective-C consumers)
property so callers can access the canonical value while keeping the deprecated
environmentId alias. Change the declaration of workspaceId from "let
workspaceId: String" to "@objc public let workspaceId: String" (or "public let
workspaceId: String" if Obj-C bridging isn't required), leaving the `@available`
deprecated environmentId computed property and usedDeprecatedEnvironmentId
behavior intact.
In `@Sources/FormbricksSDK/Manager/SurveyManager.swift`:
- Around line 147-153: The early return in refreshWorkspaceIfNeeded prevents
startRefreshTimer from being scheduled when a persisted, non-expired
workspaceResponse is used; update refreshWorkspaceIfNeeded to call
startRefreshTimer() (after calling filterSurveys()) before returning for the
cached valid path (i.e., inside the if that checks
workspaceResponse.data.expiresAt.timeIntervalSinceNow > 0 && !force) so the
refresh timer is scheduled to run when that cached response later expires.
- Around line 250-262: The getter in SurveyManager currently returns nil if data
for workspaceResponseObjectKey exists but fails to decode and it migrates legacy
data before validating it; change the flow so you first try decoding the new key
and if that succeeds return it, but if decoding the new key fails then attempt
to decode legacyEnvironmentResponseObjectKey and only if that legacy blob
successfully decodes to WorkspaceResponse migrate it (defaults.set(..., forKey:
SurveyManager.workspaceResponseObjectKey) and defaults.removeObject(forKey:
SurveyManager.legacyEnvironmentResponseObjectKey)) and return it; also ensure
you do not overwrite the new key with an invalid legacy blob and only remove the
legacy key after a successful decode/migration.
In `@Sources/FormbricksSDK/Model/Workspace/Surveys/Segment.swift`:
- Line 199: Remove the redundant explicit raw value on the enum case by changing
`case isPrivate = "isPrivate"` to the implicit form `case isPrivate` so it
matches the synthesized raw value used by the other cases; update the enum (the
CodingKeys/Coding enum around the `case isPrivate = "isPrivate"`) to fold this
into the implicit-cases section above.
In `@Sources/FormbricksSDK/Networking/Base/APIClient.swift`:
- Around line 80-84: Replace the forced cast "body = workspace as!
Request.Response" with a safe conditional cast and fallback: after decoding into
var body and checking "if var workspace = body as? WorkspaceResponse", set
workspace.responseString and then attempt "if let castBody = workspace as?
Request.Response { body = castBody }" else leave the original body unchanged (or
handle error); this removes the force-cast on WorkspaceResponse ->
Request.Response while preserving existing behavior in the APIClient decoding
block.
In `@Tests/FormbricksSDKTests/FormbricksSDKTests.swift`:
- Around line 222-226: Tests mutate global UserDefaults.standard by writing
corrupt/migrated data under SurveyManager.workspaceResponseObjectKey and
SurveyManager.legacyEnvironmentResponseObjectKey and do not reliably clean them
up, causing cross-test leakage; update the failing test (and other tests that
touch these keys) to remove those keys before and after the test (or switch to
an isolated UserDefaults via UserDefaults(suiteName:) for the test) and ensure
Formbricks.cleanup() does not rely on persisted workspace cache—specifically add
removal calls for SurveyManager.workspaceResponseObjectKey and
SurveyManager.legacyEnvironmentResponseObjectKey in the test's setup/tearDown or
replace usages of UserDefaults.standard with an isolated suite so
workspaceResponse is deterministic across tests.
---
Outside diff comments:
In `@Sources/FormbricksSDK/Formbricks.swift`:
- Around line 61-80: The setup assigns self.appUrl, self.workspaceId and mutates
self.logger/apiQueue before validating the provided URL, leaving partial/invalid
SDK state if validation fails; move the assignments of appUrl and workspaceId
(and any logger/apiQueue initialization tied to config) to after the URL
validation and HTTPS check in the initializer (or, alternatively, on validation
failure revert/clear those properties), ensuring any early return from the
initializer does not leave stale state; update references to Formbricks.logger,
self.appUrl, self.workspaceId and apiQueue initialization points to be executed
only after URL validation succeeds.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: bec6e3fa-5148-4378-99e0-2a3611c295d5
📒 Files selected for processing (30)
Sources/FormbricksSDK/Formbricks.swiftSources/FormbricksSDK/Helpers/ConfigBuilder.swiftSources/FormbricksSDK/Helpers/FormbricksWorkspace.swiftSources/FormbricksSDK/Manager/PresentSurveyManager.swiftSources/FormbricksSDK/Manager/SurveyManager.swiftSources/FormbricksSDK/Model/Environment/EnvironmentData.swiftSources/FormbricksSDK/Model/Environment/EnvironmentResponseData.swiftSources/FormbricksSDK/Model/Workspace/ActionClass/ActionClass.swiftSources/FormbricksSDK/Model/Workspace/Common/LocalizedText.swiftSources/FormbricksSDK/Model/Workspace/Settings/BrandColor.swiftSources/FormbricksSDK/Model/Workspace/Settings/Settings.swiftSources/FormbricksSDK/Model/Workspace/Settings/Styling.swiftSources/FormbricksSDK/Model/Workspace/Survey.swiftSources/FormbricksSDK/Model/Workspace/Surveys/ActionClassReference.swiftSources/FormbricksSDK/Model/Workspace/Surveys/Segment.swiftSources/FormbricksSDK/Model/Workspace/Surveys/Trigger.swiftSources/FormbricksSDK/Model/Workspace/WorkspaceData.swiftSources/FormbricksSDK/Model/Workspace/WorkspaceResponse.swiftSources/FormbricksSDK/Model/Workspace/WorkspaceResponseData.swiftSources/FormbricksSDK/Networking/Base/APIClient.swiftSources/FormbricksSDK/Networking/ClientAPI/Endpoints/Environment/GetEnvironmentRequest.swiftSources/FormbricksSDK/Networking/ClientAPI/Endpoints/User/PostUserRequest.swiftSources/FormbricksSDK/Networking/ClientAPI/Endpoints/Workspace/GetWorkspaceRequest.swiftSources/FormbricksSDK/Networking/Service/FormbricksService.swiftSources/FormbricksSDK/WebView/FormbricksViewModel.swiftTests/FormbricksSDKTests/FormbricksSDKTests.swiftTests/FormbricksSDKTests/FormbricksWorkspaceTests.swiftTests/FormbricksSDKTests/MockFormbricksService/MockFormbricksService.swiftTests/FormbricksSDKTests/Networking/APIClientTests.swiftTests/FormbricksSDKTests/Networking/ClientAPIEndpointsTests.swift
💤 Files with no reviewable changes (3)
- Sources/FormbricksSDK/Model/Environment/EnvironmentResponseData.swift
- Sources/FormbricksSDK/Networking/ClientAPI/Endpoints/Environment/GetEnvironmentRequest.swift
- Sources/FormbricksSDK/Model/Environment/EnvironmentData.swift
- Getter: fall back to legacy key when new-key blob fails to decode, and only migrate/delete legacy after it decodes as WorkspaceResponse so a corrupt blob can't poison the new key. - refreshWorkspaceIfNeeded: schedule startRefreshTimer on the cached-valid path so refresh still fires when the cached response later expires. - FormbricksConfig.workspaceId: expose as @objc public to match the deprecated environmentId alias visibility. - Tests: clear persisted workspace cache keys in setUp/tearDown to avoid cross-test leakage (Formbricks.cleanup() intentionally leaves them). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
macos-15 runners no longer ship the iPhone SE (3rd generation) iOS 18.5 simulator runtime, so the pinned destination fails with "no available devices matched the request". Switch to iPhone 16 with OS=latest so the runner picks whatever simulator runtime is installed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous run on macos-15 reported zero available iOS Simulator devices (only placeholders), meaning xcode-select was pointing at an Xcode without any installed simulator runtimes. Use maxim-lobanov/setup-xcode to pin to the latest stable Xcode (which ships with simulators), and print the sim device list so future failures are self-diagnosing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|



Adds workspace support to the ios sdk and also makes sure that environmentId still works (backwards compat)