Networking
For requests initiated by a view, dispatch one of Hosanna's generated Http
commands. This keeps request execution consistent across web, native targets,
and Roku worker tasks.
Make a request from a view
import { Http } from '@src-generated/async/AsyncManagerCommands';
import { IHsFetchResponse } from '@hs-src/hosanna-bridge-core/api';
this.dispatch<IHsFetchResponse>(Http.Get, {
url: 'https://api.example.com/items',
headers: {
Authorization: `Bearer ${token}`,
},
})
.then((response) => {
this.items = response.json as Item[];
})
.catch((reason) => {
this.errorMessage = String(reason);
});
The supported commands are:
Http.GetHttp.PostHttp.PatchHttp.PutHttp.DeleteHttp.HeadHttp.DownloadFile
Request options sit beside url; there is no nested options object:
this.dispatch<IHsFetchResponse>(Http.Post, {
url: 'https://api.example.com/items',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'A new item',
}),
maxMs: 15_000,
});
body is a string. Serialize JSON yourself. Useful options include headers,
credentials, forceText, retainBodyError, maxMs, contextData, and
postProcessFunction.
An HTTP status response resolves as an IHsFetchResponse; inspect fields such
as ok, status, text, and json according to the endpoint. Transport or
command failures reject the HsPromise.
Post-process in the worker
postProcessFunction runs inside the HTTP command handler before the command is
completed. It must be an exported module-level function because Hosanna sends a
function pointer across the task boundary:
// response-handlers.ts
export function indexResponse(response: IHsFetchResponse) {
const requestKey = response.contextData?.requestKey;
console.info('Processed response for', requestKey);
}
// In the view
this.dispatch<IHsFetchResponse>(Http.Get, {
url: 'https://api.example.com/items',
contextData: { requestKey: 'featured' },
postProcessFunction: indexResponse,
}).then((response) => {
// This callback runs on the view side.
this.items = response.json as Item[];
});
The worker function must not capture this, mutate view state, or depend on
browser-only globals such as localStorage. Use the returned promise to update
the UI. If post-processing throws, the handler logs the error but still
completes the HTTP command.
contextData is attached to the response before post-processing and is useful
for serializable caller context. Inline functions, closures, and
.bind(this) are not valid function pointers.
Cancel a request
Pass an HsCancellationToken as the third argument to dispatch():
import { HsCancellationToken } from '@hs-src/hosanna-bridge-core/api';
private requestToken = new HsCancellationToken();
loadItems() {
return this.dispatch<IHsFetchResponse>(
Http.Get,
{ url: 'https://api.example.com/items' },
this.requestToken,
);
}
cancelLoad() {
this.requestToken.cancel();
}
Create a fresh token, or call reset(), before reusing a cancelled token.
Download a file
Http.DownloadFile uses a different argument and result shape:
this.dispatch<HttpDownloadFileResult>(Http.DownloadFile, {
url: 'https://cdn.example.com/catalogue.json',
path: 'tmp:/catalogue.json',
headers: { Authorization: `Bearer ${token}` },
timeoutMs: 30_000,
}).then((result) => {
if (!result.success) {
console.error(result.error);
}
});
The handler writes to a .partial file and renames it only after a successful
download.
Use HsFetch directly
Services already running in an appropriate execution context can call
HsFetch.fetch(url, options, cancellationToken) directly:
const fetcher = new HsFetch();
fetcher.fetch(
'https://api.example.com/items',
{ method: HttpMethod.GET },
cancellationToken,
);
For view code, prefer dispatch(Http.*) so task routing, mocks, and generated
command names remain in use.
Packaged Tizen and webOS URLs
TV packages launch from file://, so package resources must be relative or use
pkg:/. The shared Web resolver maps pkg:/ against the generated Vite package
map or document.baseURI; it is also used by ASCII reads, fonts, images, audio,
sound effects, and video. Never turn pkg:/assets/item.json into
/assets/item.json, because a leading slash escapes the package root.
An XHR status of 0 is successful only for a local file: URL with a valid
response. Status 0 from a network request remains a transport failure.
Development-server mirroring is disabled when location.origin is absent or
"null".
Production Tizen and webOS CSP permits package-local content by default. Add exact reviewed HTTP(S) origins for APIs, images, media, and DRM; do not allow an entire scheme or wildcard origin. Development staging replaces explicit tokens with the selected Mac LAN debugger origin and configured service/test-stream origins. The staged package fails validation if any token remains unresolved.
WebPersistentStore and normal Web storage remain the initial persistence
contract. Validate localStorage and IndexedDB across relaunch and a cold TV
restart before introducing a vendor-specific store.