WakaSync
WakaSync integrates with WakaPAC as a plugin, delivering HTTP responses as messages through msgProc. This gives components a unified event-driven architecture for UI events, network events, and timers — all handled in the same dispatch table.
Getting Started
Register WakaSync with WakaPAC once, before creating any components. This gives every component automatic access to a scoped HTTP handle via this.http and automatic request cancellation when the component is destroyed.
<script src="https://cdn.jsdelivr.net/gh/quellabs/wakapac@main/wakapac.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/quellabs/wakapac@main/plugins/wakasync.min.js"></script>
<script>
wakaPAC.use(wakaSync);
</script>
The Basics
Once registered, every component has a this.http handle. Initiate requests with it; responses arrive in msgProc as messages. No promises, no try/catch — everything flows through the same dispatch table as clicks, keypresses, and timers.
wakaPAC('#app', {
user: null,
loading: false,
error: null,
init() {
this.loading = true;
this.http.get('/api/user');
},
msgProc(event) {
switch (event.message) {
case WakaSync.MSG_HTTP_SUCCESS:
this.user = event.detail.data;
this.loading = false;
break;
case WakaSync.MSG_HTTP_ERROR:
this.error = event.detail.error.message;
this.loading = false;
break;
case WakaSync.MSG_HTTP_ABORT:
this.loading = false;
break;
}
}
});
Messages
The plugin delivers three message types to msgProc. Use event.wParam to correlate responses to requests when a component has multiple requests in flight.
HTTP Success (MSG_HTTP_SUCCESS)
Fired when a request completes successfully.
For HEAD requests and responses with status 204, 205, or 304, event.detail.data is undefined.
Message Parameters
| Parameter | Type | Description |
|---|---|---|
wParam |
number | Request ID. Matches the return value of the originating this.http call. |
lParam |
number | Always 0. |
detail.data |
any | The parsed response body. |
detail.url |
string | The request URL. |
detail.method |
string | The HTTP method used (e.g. GET, POST). |
detail.timing |
object | Timing metadata: startTime, endTime, and duration in milliseconds. |
HTTP Error (MSG_HTTP_ERROR)
Fired when a request fails with an HTTP error, a network error, or a parse error.
event.lParam carries the HTTP status code (or 0 for non-HTTP errors), allowing quick filtering without inspecting event.detail:
case WakaSync.MSG_HTTP_ERROR:
switch (event.lParam) {
case 401:
window.location = '/login';
break;
case 404:
this.error = 'Not found';
break;
case 0:
this.error = 'Network error — check your connection';
break;
default:
this.error = event.detail.error.message;
break;
}
break;
Message Parameters
| Parameter | Type | Description |
|---|---|---|
wParam |
number | Request ID. Matches the return value of the originating this.http call. |
lParam |
number | HTTP status code, or 0 for network errors and parse errors. |
detail.error |
Error | The error object. detail.error.message contains a human-readable description. |
detail.code |
string | Error code for programmatic handling: HTTP_404, HTTP_500, PARSE_ERROR, INTERCEPTOR_ERROR, or INVALID_URL. |
detail.url |
string | The request URL. |
detail.method |
string | The HTTP method used. |
detail.status |
number | HTTP status code, or 0 for non-HTTP errors. |
HTTP Abort (MSG_HTTP_ABORT)
Fired when a request is cancelled. This covers timeouts, groupKey/latestOnly superseding, explicit this.http.cancel() calls, and automatic cancellation on component destruction.
The cancellation reason is available via event.detail.error.code: CANCEL_TIMEOUT if the request exceeded its timeout, CANCEL_CANCELLED if it was manually cancelled or the component was destroyed, or absent if it was superseded by a newer request in the same group.
Message Parameters
| Parameter | Type | Description |
|---|---|---|
wParam |
number | Request ID. Matches the return value of the originating this.http call. |
lParam |
number | Always 0. |
detail.error |
Error | The cancellation error. detail.error.code is CANCEL_TIMEOUT, CANCEL_CANCELLED, or absent if superseded by a newer request in the same group. |
detail.url |
string | The request URL. |
detail.method |
string | The HTTP method used. |
Request Correlation
Every call to this.http.get(), this.http.post(), etc. returns a request ID. When the response arrives, event.wParam carries the same ID. This lets components distinguish which response belongs to which request:
init() {
this._ordersReq = this.http.get('/api/orders');
this._usersReq = this.http.get('/api/users');
},
msgProc(event) {
if (event.message === WakaSync.MSG_HTTP_SUCCESS) {
if (event.wParam === this._ordersReq) {
this.orders = event.detail.data;
} else if (event.wParam === this._usersReq) {
this.users = event.detail.data;
}
}
}
HTTP Methods
The this.http handle provides convenience methods for all standard HTTP verbs. Each returns a request ID for correlation.
this.http.get('/api/users');
this.http.post('/api/users', { name: 'Alice' });
this.http.put('/api/users/123', { name: 'Alice Smith' });
this.http.patch('/api/users/123', { lastLogin: new Date().toISOString() });
this.http.delete('/api/users/123');
this.http.head('/api/users/123');
WakaSync sets Content-Type automatically based on the body type: objects are serialized as application/json, strings as text/plain, and Blob/ArrayBuffer as application/octet-stream. For FormData, Content-Type is left to the browser so it can set the correct multipart boundary.
Request Cancellation
Each component's requests are automatically grouped by its pacId. Call this.http.cancel() to cancel all in-flight requests for the component. Requests are also cancelled automatically when the component is destroyed.
For more granular control, pass an explicit groupKey to tag specific requests. When a new request is made with the same groupKey, all previous requests in that group are automatically cancelled:
watch: {
searchQuery(query) {
if (!query) {
this.results = [];
return;
}
// Previous requests with the same groupKey are
// cancelled automatically when a new one starts.
this.http.get('/api/search?q=' + encodeURIComponent(query), {
groupKey: 'search'
});
this.searching = true;
}
}
groupKey vs latestOnly
Both auto-cancel previous requests, but they work differently. Use groupKey when requests to different URLs should cancel each other — such as search queries where the URL changes with each keystroke. Use latestOnly when repeated requests hit the same URL and only the most recent response matters, such as polling or refreshing. If both are set, groupKey takes precedence.
// groupKey: cancels any previous request tagged 'search', regardless of URL
this.http.get('/api/search?q=' + query, { groupKey: 'search' });
// latestOnly: cancels previous requests to this exact URL
this.http.get('/api/dashboard/stats', { latestOnly: true });
Configuration
HTTP options are resolved in three layers, each overriding the previous: global defaults set on the wakaSync instance, component defaults passed via the http key in wakaPAC's options argument, and per-request options passed directly to this.http.get() etc.
Global Defaults
These apply to all requests unless overridden at the component or request level:
| Option | Default | Description |
|---|---|---|
timeout |
30000 | Request timeout in milliseconds. Set to 0 to disable. |
retries |
0 | Number of retry attempts on failure. |
retryDelay |
1000 | Base delay between retries in milliseconds, scaled by backoff strategy. |
retryBackoff |
'exponential' | Backoff strategy: 'exponential' (with jitter), 'linear', or 'fixed'. |
retryBackoffMax |
30000 | Maximum backoff delay in milliseconds. |
headers |
{} | Default headers applied to all requests. |
responseType |
'auto' | Response parsing: 'json', 'text', 'blob', 'response', or 'auto'. |
validateStatus |
response.ok | Function(response) that determines whether a response is treated as success or error. Default accepts 200–299. |
WakaSync retries requests that fail due to network errors, 5xx server errors, or 429 (rate limiting). It does not retry 4xx client errors since these indicate the request itself is wrong. Retries use exponential backoff with jitter by default, respect Retry-After headers on 429 responses, and are aborted if the request is cancelled during the delay.
To change global defaults, configure the wakaSync instance before registering:
wakaSync.config.timeout = 10000;
wakaSync.config.retries = 2;
wakaPAC.use(wakaSync);
Component Defaults
Set per-component defaults via the http key in wakaPAC's options argument. These override global defaults for all requests made by that component:
wakaPAC('#quick-lookup', {
init() { this.http.get('/api/autocomplete?q=test'); },
msgProc(event) { /* ... */ }
}, { http: { timeout: 5000 } });
wakaPAC('#resilient-dashboard', {
init() { this.http.get('/api/metrics'); },
msgProc(event) { /* ... */ }
}, { http: { retries: 3, retryDelay: 2000 } });
Per-Request Options
Override any option on individual requests. These take highest precedence:
| Option | Description |
|---|---|
groupKey |
Group identifier for batch cancellation (defaults to component's pacId). |
latestOnly |
Auto-cancel previous requests to the same URL. Ignored if groupKey is set. |
headers |
Request-specific headers, merged with defaults. |
timeout |
Override timeout for this request. |
retries |
Override retry count for this request. |
retryDelay |
Override base retry delay for this request. |
retryBackoff |
Override backoff strategy for this request. |
retryBackoffMax |
Override maximum backoff delay for this request. |
shouldRetry |
Custom function(error, attempt, maxAttempts) to control retry logic. |
responseType |
Override response parsing for this request. |
validateStatus |
Override status validation for this request. |
credentials, mode, cache, redirect, referrer, referrerPolicy, integrity, keepalive, priority |
Passed through directly to the underlying fetch() call. |
// Long timeout for a large export
this.http.get('/api/export/full', { timeout: 60000 });
// Aggressive retries for an unreliable endpoint
this.http.get('/api/unstable', { retries: 3, retryDelay: 1000 });
// Include cookies for cross-origin request
this.http.get('/api/external', { credentials: 'include' });
Response Types
By default, WakaSync auto-detects response type from the Content-Type header. Override this when you need specific handling:
this.http.get('/api/download', { responseType: 'blob' });
this.http.get('/api/page', { responseType: 'text' });
The parsed result arrives in event.detail.data, regardless of response type.
Timing Information
Successful responses include timing metadata in event.detail.timing:
case WakaSync.MSG_HTTP_SUCCESS:
console.log('Request took', event.detail.timing.duration, 'ms');
// timing.startTime, timing.endTime also available
break;
Interceptors
Interceptors transform requests before they're sent and responses after they're received. They apply globally to all requests made through the wakaSync instance. Each returns an unsubscribe function.
// Add auth token to every request
wakaSync.addRequestInterceptor(function(config) {
config.headers.set('Authorization', 'Bearer ' + getToken());
return config;
});
// Log all response timing
wakaSync.addResponseInterceptor(function(data, config, timing) {
console.log(config.method + ' ' + config.url + ' took ' + timing.duration + 'ms');
return data;
});
// Unsubscribe when no longer needed
const unsub = wakaSync.addRequestInterceptor(fn);
unsub();
Request interceptors may be async — useful for refreshing expired tokens before a request is sent. Interceptors should return the modified config or data. If nothing is returned (undefined), the original value is preserved. Any other return value — including falsy ones like 0, "", false, or null — replaces it.
Request Headers
WakaSync adds X-WakaSync-Request: true and X-WakaSync-Version to every request, along with a default Accept: application/json, text/plain, */* header. User-provided headers override these defaults.
Best Practices
- Register once: Call
wakaPAC.use(wakaSync)once before creating any components. - Use component defaults for shared behavior: Set
{ http: { retries: 3 } }on components that talk to unreliable endpoints rather than repeating options on every request. - Use
groupKeyfor searches: Prevents race conditions — previous requests with the samegroupKeyare cancelled when a new one starts. - Handle all three message types: Always account for
MSG_HTTP_SUCCESS,MSG_HTTP_ERROR, andMSG_HTTP_ABORTto keep loading states consistent. - Ignore aborts gracefully: Cancelled requests are expected during rapid typing or navigation — don't show error messages for
MSG_HTTP_ABORT. - Use
lParamfor HTTP status: Quick status checks viaevent.lParamare cleaner than inspectingevent.detailfor common cases like 401 or 404. - No manual cleanup needed: The plugin automatically cancels in-flight requests when a component is destroyed.
- Request IDs are optional: Store the return value of
this.http.get()only when you need to distinguish between multiple concurrent requests.