SK-3053: Split SDK into skyflow-android-sdk (v1) + skyflow-flowvault-android-sdk (v2) sharing a common core - #194
Conversation
…les — foundation Restructure the single SDK into two independently publishable modules sharing a contract-agnostic core, per docs/sdk-split-plan.md. Published artifact ids are unchanged (skyflow-android-sdk; new skyflow-flowvault-android-sdk). - Rename module Skyflow -> skyvault (legacy/v1); add flowvault module (v1.0.0) - Extract shared sources into common/ (compiled into each module via source set, so Kotlin `internal` visibility is preserved without a separate :core module) - Container marker classes -> common; per-product container ops stay per-module - Base+extend for divergent types: BaseSkyflowClient / BaseConfiguration / BaseCollectElementInput / BaseRevealElementInput in common; legacy subclasses keep v1 shapes (table / skyflowID / redaction / /v1/vaults/ URL) - Error model: common SkyflowInternalError (exception) + legacy typealias SkyflowError (flowvault will bind SkyflowError to its v2 data class) - SdkInfo identity in common, stamped by each product's init() - Split Utils: neutral helpers -> common; v1-only helpers -> LegacyUtils - Add docs/sdk-split-plan.md Verified: skyvault v1 test suite passes; common compiles standalone inside the flowvault module (proving self-containment). FlowVault v2 port is in progress. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nd docs Builds on the split foundation to finish the two-SDK architecture from one codebase: FlowVault (v2) module — port the beta v2 contract onto shared common/: - base+extend subclasses: CollectElementInput(tableName/skyflowId), RevealElementInput (no redaction), Configuration (no /v1/vaults/ suffix), Client (wires FlowDBAPIClient, no standalone client methods), Init (stamps SdkInfo) - v2 types + FlowDB* API layer, MockCVV, typed callbacks, container extensions (client.apiClient reached via (client as Client) since Container.client is BaseSkyflowClient) - 93-test v2 suite green (MockCVV/Response/Composable/InputFormatting/Utils/Validation) Common (kept contract-neutral): - promote JWTUtils to common/core (shared by both api clients) - add neutral okHttpClient superset to BaseConfiguration; add Element.skyflowId read alias Versioning + CI: - bump_version.sh takes a leading product arg (legacy|flowvault) - runOnGitHub + pr.yml build/test both modules - legacy release workflows retargeted to :skyvault; new mirrored flowvault_* workflows keyed to flowvault/* tags Both modules compile, lint, test, assembleRelease, and publishToMavenLocal (skyflow-android-sdk:1.27.0, skyflow-flowvault-android-sdk:1.0.0); flowvault POM carries no common module dependency. v1/v2 source coverage verified complete. docs/sdk-split-plan.md finalized to match the implementation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
✅ Gitleaks Findings: No secrets detected. Safe to proceed! |
|
Semgrep Findings: Issues with Error level severity are found (Error is Highest severity in Semgrep), Please resolve the issues before merging. |
Pure file relocation (git mv, 58 files) across common/skyvault/flowvault: move the files that sat flat in src/main/kotlin/Skyflow/ into logical subfolders — client/, config/, container/, element/, options/, response/, error/, logging/, auth/, style/, connection/. No content changes: every file keeps its `package Skyflow` declaration, so fully-qualified names, consumer imports, samples, and the published AAR API are all unchanged (all 58 changes are 100%-similarity renames). Kotlin allows package != folder, so kotlinc/Gradle/CI are unaffected; only the IDE shows a cosmetic folder-vs-package hint. Pre-existing package anomalies (com.Skyflow.* validations, ContainerProtocol, State.kt), test sources, and build/CI config are intentionally left untouched. Verified: both modules compile, lint, test (skyvault v1 + flowvault 93-test v2), and assembleRelease — all green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
✅ Gitleaks Findings: No secrets detected. Safe to proceed! |
|
Semgrep Findings: Issues with Error level severity are found (Error is Highest severity in Semgrep), Please resolve the issues before merging. |
APIClient (v1) and FlowDBAPIClient (v2) had byte-identical token handling (isValidToken + getAccessToken) — the only difference was SkyflowError vs SkyflowInternalError, which are the same type (skyvault aliases SkyflowError to SkyflowInternalError). Pull that lifecycle into a new internal common/core/BaseApiClient; both api clients now extend it and keep only their contract-specific request methods and endpoints. Same base-class pattern as BaseSkyflowClient/BaseConfiguration. Both api clients are internal, so no public API change; behavior is unchanged. Verified: both modules compile; skyvault v1 suite + flowvault 93-test v2 suite green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
✅ Gitleaks Findings: No secrets detected. Safe to proceed! |
|
Semgrep Findings: Issues with Error level severity are found (Error is Highest severity in Semgrep), Please resolve the issues before merging. |
…or binary compat) Previously the thrown exception was defined once in common as SkyflowInternalError, with skyvault aliasing `SkyflowError` onto it. That changed the legacy artifact's JVM class from `Skyflow.SkyflowError` (1.27.0) to `Skyflow.SkyflowInternalError` — a source break for Java consumers and a binary break for precompiled/reflection consumers. Now each product defines its own error class; common only *references* the neutral throw-name `SkyflowInternalError` (shared source, resolved per module): - common: no longer defines the exception (deleted SkyflowInternalError.kt). - skyvault: restores the real v1 `class SkyflowError` (byte-identical to 1.27.0) and adds `internal typealias SkyflowInternalError = SkyflowError`, so common's throws produce real `Skyflow.SkyflowError` instances again. - flowvault: adds its own `internal class SkyflowInternalError` (plumbing only) and keeps the public `SkyflowError` data class unchanged. Verified against the clean AARs: skyvault exposes `Skyflow.SkyflowError` (no SkyflowInternalError class); flowvault has the SkyflowError data class + internal SkyflowInternalError. Both modules compile, assemble, and pass tests (skyvault v1 + flowvault 93-test v2). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
✅ Gitleaks Findings: No secrets detected. Safe to proceed! |
|
Semgrep Findings: Issues with Error level severity are found (Error is Highest severity in Semgrep), Please resolve the issues before merging. |
…ta/internal) Collapse the six release workflows into three. Each now triggers on both products' refs and derives the product from a single "Determine product" step: - release.yml : tags x.y.z (legacy) | flowvault/x.y.z (flowvault) - beta_release.yml : tags *.*.*-beta.* | flowvault/*-beta.* - internal_release.yml: branches release/* | flowvault-release/* The step sets product / module / version / gradle_file / label as step outputs; the shared bump / commit / publish steps read them, so the logic lives once. Deleted the three flowvault_*.yml duplicates. Also modernized the deprecated `::set-output` to $GITHUB_OUTPUT. Publish routing is unchanged (skyvault vs flowvault by ref namespace). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
✅ Gitleaks Findings: No secrets detected. Safe to proceed! |
|
Semgrep Findings: Issues with Error level severity are found (Error is Highest severity in Semgrep), Please resolve the issues before merging. |
…client (v1-safe) Mirror the JS/Java SDK restructure on Android, as far as Kotlin allows, keeping the v1 (skyvault) public API byte-compatible — every change is additive or internal. Shared into common (written once): - ISkyflowClient — public client contract the base implements (analogue of JS ISkyflow). - initClient<T : BaseSkyflowClient> — the shared init body with a generic return (analogue of JS `static init<T>`); each product's `init(Configuration): Client` is a one-line delegate that supplies the concrete Client + its BuildConfig. - BaseCollectContainer / BaseRevealContainer — the byte-identical `create` body (createElement / createLabel) and element validation (validateElements/validateElement), reused by both products. Stays per-product (the genuine divergence): - the public `create(CollectElementInput)` / `create(RevealElementInput)` — thin delegates that keep each product's own input type and unchanged public/binary signature. - collect/reveal/post/get/update — contract-specific (v1 APIClient `/v1/vaults/` vs v2 FlowDBAPIClient `/v2/…`). - the concrete Client + init entry point (Kotlin can't inherit/specialize a static factory). Also tightened the element-input bases (BaseCollectElementInput/BaseRevealElementInput) from open to abstract (new in the split, never instantiated directly). Not done (flagged infeasible in Kotlin): container as an interface / member methods (ops are extension functions — would break v1 binary), CRTP self-type (no fluent client API), element inputs as interfaces (they hold state). Verified: both modules compile, lint, test (skyvault 430 + flowvault 93), assembleRelease; skyvault public-API surface unchanged except the additive ISkyflowClient superinterface (Client/Container/SkyflowError/CollectElementInput/Configuration byte-identical). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
✅ Gitleaks Findings: No secrets detected. Safe to proceed! |
|
Semgrep Findings: Issues with Error level severity are found (Error is Highest severity in Semgrep), Please resolve the issues before merging. |
Cosmetic rename of the shared generic init helper (and the two per-module init delegates' calls + KDoc references). No behavior or signature change; the public `init(Configuration): Client` entry points are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
✅ Gitleaks Findings: No secrets detected. Safe to proceed! |
|
Semgrep Findings: Issues with Error level severity are found (Error is Highest severity in Semgrep), Please resolve the issues before merging. |
…scope of change
Rework internal_release.yml so one release/* branch (one PR, no separate
flowvault-release branch) publishes both dev SDKs based on what changed vs main —
mirroring the skyflow-js internal workflow:
- common/ or a shared root (scripts, root build.gradle, settings.gradle, gradle
wrapper, .github/workflows) changed -> publish BOTH skyvault + flowvault
- only skyvault/ changed -> publish skyvault
- only flowvault/ changed -> publish flowvault
Scope = git diff against merge-base with main (idempotent across re-pushes). So
merging the split PR into release/* (which touches common/) publishes both dev
artifacts in one run. Public/beta workflows are unchanged (still per-product by
tag namespace) — scope logic is internal-only.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- README.md -> slim product index (SkyVault v1 / FlowVault v2) linking each package guide + sample - skyvault/README.md: v1 guide (moved from root); sample links -> samples/skyvault/ - flowvault/README.md: v2 guide (from beta-release/26.7.0) with install coordinates repointed to the NEW separate package (com.skyflowapi.android:skyflow-flowvault-android-sdk:1.0.0) - samples/skyvault/: v1 sample (-> :skyvault); samples/flowvault/: v2 sample (-> :flowvault, distinct applicationId) - samples/README.md: two-sample index + shared vault-setup prerequisites Samples stay reference-only (not wired into settings.gradle), mirroring the iOS layout. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace RevealRecord.metadata (Map<String, Any?>) with a typed RevealMetadata(tableName, skyflowId), matching the iOS RevealResponse. Update toJson/fromJson accordingly (fromJson tolerates the raw 'skyflowID' key as well as the normalized 'skyflowId') and add a metadata-parsing test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
FlowVault is a new package versioned from 1.0.0 that targets the v2 API - it is not 'SDK v2'. Match the skyflow-js package-split README: distinguish the two SDKs by vault type + API version (skyflow-android-sdk = PDB vault (v1 API); skyflow-flowvault-android-sdk = Flow vault (v2 API)) and add the backward-compat guidance. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What & why
Splits the single
skyflow-androidcodebase into two independently publishable AAR SDKs that share one common core, with the variant fixed by which artifact an app installs — no build flags, no runtime switch.:skyvaultskyflow-android-sdk(unchanged)/v1/vaults/, untypedCallback,table/fields/skyflow_idmain(1.27.0):flowvaultskyflow-flowvault-android-sdk(new,1.0.0)tokenGroupRedactions,/v2/records|tokens/, typed callbacks,tableName/tokens/skyflowIdbeta-release/26.7.0(1.28.0-beta.1)common/(shared source folder, not a module)common/is a plain source folder added to both modules' source sets, so Kotlininternalworks natively (no@RestrictToleakage) and each AAR is self-contained. FlowVault is implemented by extending shared base types (BaseSkyflowClient,BaseConfiguration,BaseCollectElementInput,BaseRevealElementInput), not by branching inside shared code.Backward compatibility: the legacy v1 public surface is unchanged (branch cut from
main;Configurationkeeps its/v1/vaults/suffix via subclass; v1 wire keys preserved).Key mechanics
SkyflowError= coreSkyflowInternalErrorin v1; a typed data class in v2).JWTUtilspromoted tocommon/core; neutralokHttpClientsuperset onBaseConfiguration;Element.skyflowIdread alias.bump_version.sh <legacy|flowvault> …), per-product release workflows keyed to tag namespaces (x.y.z/*-beta.*→ skyvault;flowvault/*→ flowvault), PR CI builds+tests both.Verification (all green)
:skyvault+:flowvaultcompile, lint, test, andassembleRelease(runOnGitHub→ BUILD SUCCESSFUL).publishToMavenLocal→skyflow-android-sdk:1.27.0andskyflow-flowvault-android-sdk:1.0.0; flowvault POM has nocommonmodule dependency (shared source compiled into the AAR).Skyflow/module removed with no stale references.Notes / deliberate deviations
Skyflowpackage with each layer, so a leak is an unqualified reference, not an import). CI builds both modules, so any violation breaks the build. A Konsist AST test is left as an optional future enhancement rather than adding a network dependency.samples/remains the v1 reference app (points at:skyvault, standalone as onmain). No dedicated FlowVault sample in this PR.