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.

explanation

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 groupKey for searches: Prevents race conditions — previous requests with the same groupKey are cancelled when a new one starts.
  • Handle all three message types: Always account for MSG_HTTP_SUCCESS, MSG_HTTP_ERROR, and MSG_HTTP_ABORT to 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 lParam for HTTP status: Quick status checks via event.lParam are cleaner than inspecting event.detail for 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.