State Management API Reference

Updated May 17, 20256 min read

The State Management API enables your TERE applications to securely store and retrieve data within the Trusted Execution Environment. All stored data is encrypted at rest and in transit, with granular access controls to protect sensitive information.

Getting Started

Prerequisites

To use the State Management API, you need:

  • The TERE SDK installed (npm install @praecise/tere)
  • A deployed TERE application (see the Runtime API)

How State is Used

State management in TERE works by:

  1. Your application code using the SDK calls state functions to store and retrieve data
  2. The TERE runtime securely encrypts the data before storage
  3. Access controls ensure only authorized code can access specific data
  4. All state operations are performed securely within the TEE

Working with State

The State Management API is primarily used through the TERE SDK. Here's how to use it:

Using State in TypeScript/JavaScript

For JavaScript or TypeScript applications, use the TERE SDK:

typescript
1// Import the TERE SDK
2import { State } from '@praecise/tere';
3
4// Store data
5export function saveUserPreferences(userId, preferences) {
6 const key = `user:${userId}:preferences`;
7 const value = JSON.stringify(preferences);
8
9 return State.set(key, value);
10}
11
12// Retrieve data
13export function getUserPreferences(userId) {
14 const key = `user:${userId}:preferences`;
15 const value = State.get(key);
16
17 if (!value) {
18 return null;
19 }
20
21 return JSON.parse(value);
22}
23
24// Check if data exists
25export function hasUserPreferences(userId) {
26 const key = `user:${userId}:preferences`;
27 return State.exists(key);
28}
29
30// Remove data
31export function deleteUserPreferences(userId) {
32 const key = `user:${userId}:preferences`;
33 return State.remove(key);
34}
Using state management in TypeScript

Client-side Usage

From your client application, you interact with state through function execution:

javascript
1import { TereClient } from '@praecise/tere';
2
3// Initialize client
4const client = new TereClient({
5 endpoint: 'https://api.tere.praecise.com',
6 apiKey: 'your-api-key'
7});
8
9async function manageUserPreferences() {
10 const userId = 'user123';
11 const userPreferences = {
12 theme: 'dark',
13 notifications: {
14 email: true,
15 push: false
16 },
17 language: 'en'
18 };
19
20 // Save preferences
21 await client.execute({
22 scriptId: 'script_abc123',
23 function: 'saveUserPreferences',
24 arguments: [userId, userPreferences]
25 });
26
27 console.log('Preferences saved');
28
29 // Get preferences
30 const result = await client.execute({
31 scriptId: 'script_abc123',
32 function: 'getUserPreferences',
33 arguments: [userId]
34 });
35
36 console.log('Retrieved preferences:', result.result);
37}
Working with state from client code

State API Reference

The following API is available within your code running in the TEE:

State.get

Retrieves a value from the secure state store by its key.

Parameters

key: stringRequired

The unique identifier for the state value

Returns

Uint8Array | string | null

The retrieved value, or null if the key does not exist

Examples

Basic retrieval

typescript
1// In your TEE code
2import { State } from '@praecise/tere';
3
4export function getConfig() {
5 const config = State.get('app:config');
6 if (!config) {
7 return null;
8 }
9
10 // Parse JSON string
11 return JSON.parse(config);
12}
State.set

Stores a value in the secure state store with the specified key.

Parameters

key: stringRequired

The unique identifier for the state value

value: Uint8Array | string | objectRequired

The value to store. Objects are automatically serialized to JSON.

callerId: string

Optional caller ID for access control verification

Returns

boolean

Returns true if the operation was successful

Examples

Storing a value

typescript
1// In your TEE code
2import { State } from '@praecise/tere';
3
4export function saveConfig(config) {
5 // Objects are automatically serialized
6 return State.set('app:config', config);
7}
State.remove

Removes a value from the secure state store.

Parameters

key: stringRequired

The unique identifier for the state value to remove

callerId: string

Optional caller ID for access control verification

Returns

Uint8Array | string | null

Returns the removed value if the key was found, or null if the key did not exist

Examples

Removing a value

typescript
1// In your TEE code
2import { State } from '@praecise/tere';
3
4export function deleteUserSession(sessionId) {
5 const key = `session:${sessionId}`;
6
7 // Remove session data
8 const removedData = State.remove(key);
9
10 // Return whether data was found and removed
11 return removedData !== null;
12}
State.exists

Checks if a key exists in the secure state store without retrieving its value.

Parameters

key: stringRequired

The key to check for existence

Returns

boolean

Returns true if the key exists, false otherwise

Examples

Checking if a key exists

typescript
1// In your TEE code
2import { State } from '@praecise/tere';
3
4export function isUserRegistered(userId) {
5 const key = `user:${userId}:profile`;
6
7 // Check if user profile exists
8 return State.exists(key);
9}

Advanced Usage

Advanced Access Control

TERE provides access control for state values to restrict who can read or write specific data:

typescript
1// Import the TERE SDK
2import { State, AccessControl } from '@praecise/tere';
3
4// Set up access control for a sensitive key
5export function setupAccessControl(key: string) {
6 // Define an access rule
7 const rule = {
8 readAccess: ['admin', 'user'], // Roles allowed to read
9 writeAccess: ['admin'] // Roles allowed to write
10 };
11
12 // Apply the access rule
13 return AccessControl.setAccessRule(key, rule);
14}
15
16// Write with access control check (requires admin role)
17export function writeProtectedData(key: string, value: any, callerId: string) {
18 // The callerId is passed to verify the caller's identity
19 return State.set(key, value, callerId);
20}
Using access control for state

Advanced Batch Operations

For working with multiple state values efficiently:

typescript
1// Import the TERE SDK
2import { State } from '@praecise/tere';
3
4// Get multiple values at once
5export function getUserProfile(userId: string) {
6 // Define the keys to retrieve
7 const keys = [
8 `user:${userId}:profile`,
9 `user:${userId}:preferences`,
10 `user:${userId}:settings`
11 ];
12
13 // Use a helper function to get multiple values
14 const result: Record<string, any> = {};
15
16 for (const key of keys) {
17 const value = State.get(key);
18 if (value) {
19 // Extract the last part of the key as the property name
20 const prop = key.split(':').pop() || '';
21 result[prop] = JSON.parse(value);
22 }
23 }
24
25 return result;
26}
27
28// Set multiple values at once
29export function updateUserProfile(
30 userId: string,
31 profile: any,
32 preferences: any,
33 settings: any
34) {
35 // Create a batch of updates
36 const updates: Record<string, any> = {
37 [`user:${userId}:profile`]: profile,
38 [`user:${userId}:preferences`]: preferences,
39 [`user:${userId}:settings`]: settings
40 };
41
42 // Apply all updates
43 const results: Record<string, boolean> = {};
44
45 for (const [key, value] of Object.entries(updates)) {
46 results[key] = State.set(key, value);
47 }
48
49 return results;
50}
Batch state operations

Best Practices

  • Use Namespaced Keys

    Organize your state keys using a hierarchical namespace pattern (e.g.,app:user:123:preferences) to avoid key collisions and improve organization.

    javascript
    1// Good namespacing practice
    2const userKey = `user:${userId}:profile`;
    3const settingsKey = `app:settings:global`;
    4const sessionKey = `session:${sessionId}:data`;
  • Consistent Serialization

    Use consistent serialization and deserialization methods (e.g., JSON.stringify/parse) for storing complex data structures.

    javascript
    1// Helper functions for consistent serialization
    2function serializeObject(obj) {
    3 return JSON.stringify(obj);
    4}
    5
    6function deserializeObject(str) {
    7 return JSON.parse(str);
    8}
  • Apply Access Control

    Set appropriate access controls for sensitive data to ensure only authorized callers can read or modify it.

  • Maintain State Versions

    Include version information in stored data to help with schema migrations as your application evolves.

    javascript
    1// Data with version info
    2const userData = {
    3 version: 2,
    4 profile: {
    5 name: "Alice Smith",
    6 email: "alice@example.com"
    7 }
    8};
    9
    10// Helper for handling different versions
    11function getUserData(userId) {
    12 const data = JSON.parse(State.get(`user:${userId}`));
    13
    14 // Handle different versions
    15 if (data.version === 1) {
    16 // Migrate v1 to v2 format
    17 return migrateUserDataV1ToV2(data);
    18 }
    19
    20 return data;
    21}

Example Applications

Secure User Profile Management

typescript
1// Import the TERE SDK
2import { State } from '@praecise/tere';
3
4// Create or update a user profile
5export function createOrUpdateUser(userId: string, profile: any) {
6 const key = `user:${userId}:profile`;
7
8 // Check if user exists already
9 const existingData = State.get(key);
10
11 // Current timestamp for tracking modifications
12 const timestamp = new Date().toISOString();
13
14 if (existingData) {
15 // Update existing profile
16 const existingProfile = JSON.parse(existingData);
17
18 // Merge with new data
19 const updatedProfile = {
20 ...existingProfile,
21 ...profile,
22 updatedAt: timestamp
23 };
24
25 State.set(key, updatedProfile);
26 return { updated: true, profile: updatedProfile };
27 } else {
28 // Create new profile
29 const newProfile = {
30 ...profile,
31 createdAt: timestamp,
32 updatedAt: timestamp
33 };
34
35 State.set(key, newProfile);
36 return { created: true, profile: newProfile };
37 }
38}
39
40// Get a user profile
41export function getUserProfile(userId: string) {
42 const key = `user:${userId}:profile`;
43 const data = State.get(key);
44
45 if (!data) {
46 return null;
47 }
48
49 return JSON.parse(data);
50}
51
52// Delete a user profile
53export function deleteUser(userId: string) {
54 const key = `user:${userId}:profile`;
55 return State.remove(key) !== null;
56}
Secure user profile management example

Secure Counter Implementation

typescript
1// Import the TERE SDK
2import { State } from '@praecise/tere';
3
4// Increment a counter
5export function incrementCounter(name: string): number {
6 const key = `counter:${name}`;
7
8 // Get current value
9 const currentData = State.get(key);
10 let count = 0;
11
12 if (currentData) {
13 count = parseInt(currentData, 10);
14 if (isNaN(count)) count = 0;
15 }
16
17 // Increment and store
18 count++;
19 State.set(key, count.toString());
20
21 return count;
22}
23
24// Get a counter value
25export function getCounter(name: string): number {
26 const key = `counter:${name}`;
27 const data = State.get(key);
28
29 if (!data) {
30 return 0;
31 }
32
33 const count = parseInt(data, 10);
34 return isNaN(count) ? 0 : count;
35}
36
37// Reset a counter
38export function resetCounter(name: string): number {
39 const key = `counter:${name}`;
40 State.set(key, "0");
41 return 0;
42}
Secure counter implementation example

Related Documentation