Loading...
Loading...
Sync construction with async property pattern. Use when creating clients that need async initialization but must be exportable from modules and usable synchronously in UI components.
npx skill4agent add epicenterhq/epicenter sync-construction-async-property-ui-render-gate-patternThe initialization of the client is synchronous. The async work is stored as a property you can await, while passing the reference around.
awaitawait getX()// This doesn't work
export const client = await createClient(); // Top-level await breaks bundlerslet client: Client | null = null;
export async function getClient() {
if (!client) {
client = await createClient();
}
return client;
}
// Every consumer must await
const client = await getClient();await// client.ts
export const client = createClient();
// Sync access works immediately
client.save(data);
client.load(id);
// Await the async work when you need to
await client.whenSynced;whenSynced<!-- +layout.svelte -->
<script>
import { client } from '$lib/client';
</script>
{#await client.whenSynced}
<LoadingSpinner />
{:then}
{@render children?.()}
{/await}withCapabilities()function createClient() {
const state = initializeSyncState();
return {
save(data) {
/* sync method */
},
load(id) {
/* sync method */
},
withCapabilities({ persistence }) {
const whenSynced = persistence(state);
return Object.assign(this, { whenSynced });
},
};
}
// Usage
export const client = createClient().withCapabilities({
persistence: (state) => loadFromIndexedDB(state),
});| Aspect | Async Construction | Sync + whenSynced |
|---|---|---|
| Module export | Can't export directly | Export the object |
| Consumer code | | Direct import, sync use |
| UI integration | Awkward promise handling | Single |
| Type signature | | |
const provider = new IndexeddbPersistence('my-db', doc);
// Constructor returns immediately
provider.on('update', handleUpdate); // Sync access works
await provider.whenSynced; // Wait when you need to