Skip to main content
This guide helps you migrate between major versions of Oso Cloud SDKs. Each major version introduces breaking changes that improve the developer experience, add new features, and enhance type safety.

General Migration Strategy

For all SDKs, follow this general approach when migrating:
  1. Update imports and package references
  2. Convert fact representations to new format
  3. Replace bulk operations with batch API
  4. Migrate query calls to QueryBuilder API
  5. Update wildcard usage to explicit patterns
  6. Test thoroughly with new API patterns

Node.js Migration (v1 → v2)

The v2 release represents a significant rethinking of the developer experience. The biggest new feature is generating TypeScript types from your Polar policy. Key Changes:
  • Minimum Node.js version: 14 → 16
  • Centralized authorization data API: 6 methods → 4 methods
  • New QueryBuilder API replaces Query API
  • TypeScript type generation from policies

Breaking Changes

  • Facts API
  • Batch Operations
  • Query API
  • TypeScript Types
// OLD: tell() method
await oso.tell("has_role", user, "member", repo);

// NEW: insert() with array format
await oso.insert(["has_role", user, "member", repo]);

// OLD: delete() method
await oso.delete("has_role", user, "member", repo);

// NEW: delete() with array format and wildcard support
await oso.delete(["has_role", user, "member", repo]);
await oso.delete(["has_role", user, null, null]); // Remove all roles for user

// OLD: get() method
const roles = await oso.get("has_role", user, null, null);

// NEW: get() with array format
const roles = await oso.get(["has_role", user, null, null]);

New Features

// Chain additional conditions
const query = oso.buildQuery(["allow", user, "read", repo])
  .and(["has_relation", repo, "folder", folder]);

// Constrain variables to specific value sets
const filteredQuery = oso.buildQuery(["allow", user, action, repo])
  .in(repo, repositories);

// Add context facts to queries
const contextQuery = oso.buildQuery(["allow", user, "read", repo])
  .withContextFacts([["has_role", user, "owner", repo]]);

// Various evaluation formats
const exists = await query.evaluate();                           // Boolean
const actions = await query.evaluate(action);                    // Single variable
const pairs = await query.evaluate([action, repository]);        // Tuple variables
const mapped = await query.evaluate(new Map([[repository, action]])); // Map

Python Migration (v1 → v2)

The v2 release represents a significant rethinking of the developer experience with changes to fact representation and input types. Key Changes:
  • Facts now represented as tuples instead of dicts
  • Arguments as Value objects instead of dicts
  • Input types changed from Value/Fact to IntoValue/IntoFact
  • Management API condensed from 6 methods to 4

Breaking Changes

  • Fact Representation
  • Input Types
  • Management API
  • Batch Operations
  • Query API
# OLD: Dict-based facts
context_fact = {"name": "has_role", "args": [user, "member", repo]}

# NEW: Tuple-based facts
context_fact = ("has_role", user, "member", repo)

# OLD: Dict-based arguments
alice = {"type": "User", "id": "alice"}

# NEW: Value objects
from oso_cloud import Value
alice = Value("User", "alice")

New Features

  • QueryBuilder Methods
  • Value Types
# Chain additional conditions
query = oso.build_query(("allow", user, "read", repo)) \
    .and_(("has_relation", repo, "folder", folder))

# Constrain variables to specific value sets
filtered_query = oso.build_query(("allow", user, action, repo)) \
    .in_(repo, repositories)

# Add context facts to queries
context_query = oso.build_query(("allow", user, "read", repo)) \
    .with_context_facts([("has_role", user, "owner", repo)])

# Various evaluation formats
exists = query.evaluate()                              # Boolean
actions = query.evaluate(action)                       # Single variable
pairs = query.evaluate((action, repository))           # Tuple variables
mapped = query.evaluate({repository: action})          # Dictionary

Go Migration (v1 → v2)

The v2 release represents a significant rethinking of the developer experience with structural changes and new APIs. Key Changes:
  • Import path changed to include /v2
  • Instance struct replaced with Value struct
  • Separate FactPattern type for patterns
  • Helper functions for ergonomic construction
  • API condensed from 6 methods to 4

Breaking Changes

  • Imports & Structs
  • Centralized Authorization Data API
  • Batch Operations
  • Query API
// OLD: Import path
import (oso "github.com/osohq/go-oso-cloud")

// NEW: Import path with /v2
import (oso "github.com/osohq/go-oso-cloud/v2")

// OLD: Fact.Name field
// Fact.Name field

// NEW: Fact.Predicate field
// Fact.Predicate field

// OLD: Instance struct
oso.Instance{Type: "User", ID: "alice"}

// NEW: Value struct (cannot have zero-valued ID or Type)
oso.NewValue("User", "alice")

// OLD: Fact used for both concrete facts and patterns
// Fact used for both concrete facts and patterns

// NEW: Separate FactPattern for patterns
oso.NewFact("has_role", alice, oso.String("reader"), repo)        // Concrete fact
oso.NewFactPattern("has_role", alice, nil, nil)                   // Pattern

New Features

  • Helper Functions
  • QueryBuilder Methods
// Ergonomic Value construction
user := oso.NewValue("User", "alice")

// Ergonomic Fact construction
fact := oso.NewFact("has_role", user, oso.String("admin"), repo)

// Ergonomic FactPattern construction
pattern := oso.NewFactPattern("has_role", user, nil, nil)

// Ergonomic QueryFact construction
queryFact := oso.NewQueryFact("allow", user, oso.String("read"), repo)

Java Migration (v0 → v1)

The v1 release represents a significant rethinking of the developer experience with the new Query Builder API and consolidated packages. Key Changes:
  • Public API consolidated under com.osohq.oso_cloud package
  • Explicit wildcard behavior with ValuePattern types
  • New QueryBuilder API with fluent interface
  • Enhanced type safety with FactPattern

Breaking Changes

  • Packages & Imports
  • Centralized Authorization Data API
  • Batch Operations
  • Query API
// OLD: Imports from api package
import com.osohq.oso_cloud.api.Value;
import com.osohq.oso_cloud.api.Fact;

// NEW: Imports from main package
import com.osohq.oso_cloud.Value;
import com.osohq.oso_cloud.Fact;

// OLD: Constructors accepted null
// Value and Fact constructors accepted null for type/id fields

// NEW: Explicit wildcards with ValuePattern
// Use ValuePattern.ANY and ValuePattern.ValueOfType for wildcards

New Features

  • QueryBuilder API
  • Value Patterns
QueryBuilder query = oso.buildQuery("allow", user, action, repo);

// Chain additional conditions
QueryBuilder constrainedQuery = query.and("has_relation", repo, new Value("folder"), folder);

// Constrain variables to specific value sets
QueryBuilder filteredQuery = query.in(repoVar, repoIds);

// Add context facts to queries
QueryBuilder contextQuery = query.withContextFacts(contextFacts);

// Various evaluation formats
Boolean allowed = query.evaluate(EvaluateArgs.exists());                           // Boolean
List<String> actions = query.evaluate(EvaluateArgs.values(actionVar));            // Values
Map<String, List<String>> mapped = query.evaluate(                                // Map
    EvaluateArgs.map(repositoryVar, EvaluateArgs.values(actionVar))
);

Migration Testing

After completing your migration:
  1. Run your existing tests to ensure functionality is preserved
  2. Test edge cases with wildcards and batch operations
  3. Verify performance with the new QueryBuilder API
  4. Check type safety if using TypeScript or other typed languages
  5. Update documentation to reflect new API patterns