- Static compiler with STRC pattern (Static Template Resolution with
Compartmentalized Layers)
- Template syntax: { } interpolation, { s-for }, { s-if/s-elif/s-else
}
- File types: .strata, .compiler.sts, .service.sts, .api.sts, .sts,
.scss
- CLI tools: strata dev, strata build, strata g (generators)
- create-strata scaffolding CLI with Pokemon API example
- Dev server with WebSocket HMR (Hot Module Replacement)
- Documentation: README, ARCHITECTURE, CHANGELOG, CONTRIBUTING,
LICENSE
101 lines
2.1 KiB
Plaintext
101 lines
2.1 KiB
Plaintext
/**
|
|
* User Store
|
|
* Manages user data with encryption and cross-tab sync
|
|
*/
|
|
|
|
import { createStore, strata } from 'strata';
|
|
|
|
interface User {
|
|
id: string;
|
|
name: string;
|
|
email: string;
|
|
phone?: string;
|
|
website?: string;
|
|
company?: {
|
|
name: string;
|
|
catchPhrase?: string;
|
|
};
|
|
}
|
|
|
|
interface UserState {
|
|
users: Record<string, User>;
|
|
currentUserId: string | null;
|
|
loading: boolean;
|
|
error: string | null;
|
|
}
|
|
|
|
export const userStore = createStore<UserState>('user', {
|
|
state: {
|
|
users: {},
|
|
currentUserId: null,
|
|
loading: false,
|
|
error: null,
|
|
},
|
|
|
|
actions: {
|
|
async fetchUsers() {
|
|
this.loading = true;
|
|
this.error = null;
|
|
|
|
try {
|
|
const users = await strata.fetch.get<User[]>('/users');
|
|
|
|
// Index users by ID for fast lookup
|
|
const usersById: Record<string, User> = {};
|
|
for (const user of users) {
|
|
usersById[user.id] = user;
|
|
}
|
|
|
|
this.users = usersById;
|
|
} catch (err) {
|
|
this.error = err instanceof Error ? err.message : 'Failed to fetch users';
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
},
|
|
|
|
async fetchUser(id: string) {
|
|
if (this.users[id]) {
|
|
return this.users[id]; // Already cached
|
|
}
|
|
|
|
try {
|
|
const user = await strata.fetch.get<User>(`/users/${id}`);
|
|
this.users[id] = user;
|
|
return user;
|
|
} catch (err) {
|
|
throw err;
|
|
}
|
|
},
|
|
|
|
setCurrentUser(id: string | null) {
|
|
this.currentUserId = id;
|
|
},
|
|
|
|
clearUsers() {
|
|
this.users = {};
|
|
this.currentUserId = null;
|
|
},
|
|
},
|
|
|
|
// Encrypt sensitive data
|
|
encrypt: ['currentUserId'],
|
|
|
|
// Persist user cache across page reloads
|
|
persist: ['users'],
|
|
|
|
// Share current user across all tabs
|
|
shared: ['currentUserId'],
|
|
});
|
|
|
|
// Computed values (derived state)
|
|
export const getCurrentUser = () => {
|
|
const state = userStore.getState();
|
|
if (!state.currentUserId) return null;
|
|
return state.users[state.currentUserId] || null;
|
|
};
|
|
|
|
export const getUserCount = () => {
|
|
return Object.keys(userStore.getState().users).length;
|
|
};
|