Skip to content

Latest commit

 

History

History
339 lines (271 loc) · 16.7 KB

api_reference.md

File metadata and controls

339 lines (271 loc) · 16.7 KB

Synura API Reference

This document details the JavaScript API available to Synura extensions.

Global Objects

synura

The core object for interacting with the Synura application.

Methods

  • synura.open(options, [context], [callback])

    • Opens a new view. Optionally connects to the view if callback is provided.
    • Arguments:
      • options (Object): Configuration for the view.
        • view (String): The type of view to open (e.g., '/views/list').
        • styles (Object): Styles configuration.
        • models (Object): Models data.
      • context (Object, Optional): Arbitrary data passed back in events. Can be omitted if only 2 arguments are passed and the 2nd is the callback.
      • callback (Function, Optional): Called when an event occurs. If provided, synura.connect is called automatically.
    • Returns: An object { success: boolean, viewId: number, viewName: string, error?: string }.
  • synura.update(viewId, data)

    • Updates an existing view.
    • Arguments:
      • viewId (Number): The ID of the view to update.
      • data (Object): New styles or models to merge.
    • Special Model Keys:
      • For '/views/list', data.models.append appends new list items to the existing contents instead of replacing them. This is useful for pagination.
      • For '/views/chat', data.models.append appends new chat messages.
    • Returns: An object { success: boolean, viewId: number, viewName: string, error?: string }.
  • synura.connect(viewId, context, callback)

    • Listens for events from a view.
    • Arguments:
      • viewId (Number): The ID of the view.
      • context (Object): Arbitrary data passed back in events (useful for tracking state).
      • callback (Function): Called when an event occurs. Receives an event object.
    • Returns: An object { success: boolean, viewId: number, error?: string }.
    • Note: Only one callback can be active per view. Calling connect again will overwrite the previous callback.
  • synura.close(viewId)

    • Closes a specific view.
    • Arguments:
      • viewId (Number): The ID of the view to close.
    • Returns: An object { success: boolean, viewId: number, viewName: string, error?: string }.
  • synura.parse(type, element): Parses a DOM element into a structured object based on the specified type.

    • type: A string specifying the parsing logic (e.g., 'post').
    • element: The DOM element to parse.
    • Returns: An array of objects representing the parsed content (e.g., [{type: 'text', value: '...'}, {type: 'image', value: '...'}]).

fetch(url, options)

A custom synchronous HTTP client (unlike Web API, it does not return a Promise).

Network failures, invalid URLs, denied permissions, timeouts, cancellation, and oversized responses throw an Error. HTTP error statuses such as 404 still return a response with ok: false. Invalid request headers throw a TypeError.

Host restriction: By default, extension requests must target SYNURA.domain. If an extension needs sibling subdomains or path-scoped hosts, declare SYNURA.host_permissions. synurart and the real Synura app use the same rule.

Network declarations (domain, host_permissions, and bypass) are validated and captured when the extension is loaded. Changing the JavaScript package object later does not change these settings. SYNURA.host_permissions is optional. When it is omitted or empty, the effective permission uses the host portion of SYNURA.domain:

[
  "http://<host>/*",
  "https://<host>/*"
]

When it is nonempty, it replaces the default fetch scope. Each pattern must be one of:

http://host/path
https://host/path
*://host/path

The host can be exact (api.example.com) or a left-most wildcard (*.example.com). The path can contain *. Omitting the path means /, not /*. Query strings and fragments are not allowed in permission patterns.

Examples:

var SYNURA = {
  domain: "github.io",
  host_permissions: [
    "https://*.github.io/*"
  ]
};

Security boundaries:

  • Permission hosts must stay in the same registrable domain family as SYNURA.domain.

  • Wildcards cannot target ICANN public suffixes such as *.io, *.com, or *.co.kr.

  • Private/public-suffix service domains such as github.io are handled by the public suffix list. For example, *.github.io is allowed only when the extension identity is scoped to github.io; a user.github.io extension cannot broaden to sibling pages.

  • For raw IPs and localhost, explicit permission ports must match the extension's domain declaration. A portless pattern, including the implicit host scope, accepts any port. To restrict a non-default port, include it in host_permissions, for example http://127.0.0.1:8080/*. Requests normalize default ports, so omit :80 and :443 from their respective HTTP/HTTPS patterns.

  • Options:

    • method: 'GET' | 'POST'
    • headers: Object { "Key": "Value" }. Values must be strings; null and arrays are not header objects.
    • body: String. Non-string JSON values are serialized as JSON; null means an empty body.
    • onProgress: Synura Custom Option. Function (current, total) => { ... }. Download positions are collected and delivered synchronously before fetch() returns. current and total are in bytes; total is -1 if unknown (e.g., chunked encoding). Only the final response in a redirect chain reports progress. Callback exceptions are ignored.
  • Returns: A Response object with:

    • status: (Number) The HTTP status code (e.g., 200, 404).
    • statusText: (String) The status description (e.g., "200 OK", "404 Not Found"). Use status for comparisons; older runtimes may omit the numeric prefix.
    • ok: (Boolean) true if the status code is in the range 200-299.
    • url: (String) The response URL visible to the runtime. If a runtime follows redirects internally, this can be the final URL. If a 3xx response is exposed to the extension, this remains the requested URL.
    • headers: (Object) Response header properties plus case-insensitive get(name) (string or undefined), getAll(name) (array), and entries() (array of all [name, value] pairs). Duplicate values are joined with ", " for property access and get(), except Set-Cookie, which uses newlines. Use getAll("set-cookie") to read individual cookies without splitting Expires dates.
    • text(): Decodes the body as UTF-8, replacing invalid byte sequences and retaining a leading BOM. It does not inspect the Content-Type charset or guess a language. Extensions handle other encodings explicitly with arrayBuffer() and TextDecoder(label).
    • arrayBuffer(): Returns the raw response body bytes as an ArrayBuffer.
    • json(): Parses the same string as text(). Empty or invalid JSON throws a SyntaxError.
    • dom(mimeType): Synura Custom Function. Parses the current response string as HTML (only 'text/html' supported). For non-UTF-8 pages, decode bytes first and use new DOMParser().parseFromString(...).

Redirects and limits: Fetch follows 3xx responses with a Location header, preserving method/body and checking each destination, up to 10 requests. followRedirects and redirect are not supported options. The response body limit is 8 MiB. Matching redirect cookies last for that fetch call only, and an explicit Cookie header takes precedence. Cookie names replace earlier names case-insensitively; this temporary redirect store does not process expiry attributes.

Legacy Charset Example

const response = fetch("https://example.com/page");
const raw = response.arrayBuffer();
const html = new TextDecoder("euc-kr").decode(raw);
const utf8Bytes = new TextEncoder().encode(html);

Redirect Inspection Example

const response = fetch("https://" + SYNURA.domain + "/some/path");
if (response.status >= 300 && response.status < 400) {
  const location = (response.headers && (response.headers["Location"] || response.headers["location"])) || "";
  console.log("redirect", response.url, location);
}

DOM API

Objects returned by response.dom(), new DOMParser().parseFromString(...), or element query methods provide a subset of the standard DOM API.

Element

  • Properties:

    • tagName (String): The tag name (upper case).
    • id (String): The element's ID.
    • className (String): The class attribute.
    • classList (DOMTokenList):
      • add(className): Adds a class.
      • remove(className): Removes a class.
      • toggle(className): Toggles a class.
      • contains(className): Checks if a class exists.
    • dataset (DOMStringMap):
      • Read/Write data attributes (e.g. el.dataset.foo maps to data-foo).
    • textContent (String): The text content of the element and its descendants.
    • innerText (String): The rendered text content of the element and its descendants.
    • childNodes (NodeList): List of child nodes.
    • firstChild, lastChild (Element): First/Last child element.
    • nextSibling (Element): Next sibling element.
    • nodeType (Number): 1 (Element) or 3 (Text).
  • Methods:

    • getAttribute(name): Returns the attribute value, or null if the attribute does not exist. For HTML documents, attribute name matching is case-insensitive.
    • hasAttribute(name): Returns true if the attribute exists, false otherwise.
    • querySelector(selector): Returns the first matching child element.
    • querySelectorAll(selector): Returns a NodeList of matching child elements.
    • remove(): Removes the element from its parent.
    • cloneNode(deep): Returns a clone of the node. If deep is true, the descendants are also cloned.

Document (from dom() or DOMParser)

  • querySelector(selector)
  • querySelectorAll(selector)

console

  • console.log(...args): Logs messages to the debug console (and logcat on Android).

navigator

  • navigator.language: The current locale exposed by the runtime as a BCP 47 language tag. In synurart, this defaults to en-US and can be changed with the locale <tag> command.

localStorage

Persistent key-value storage backed by a database.

  • localStorage.setItem(key, value)
    • Saves a key-value pair. Both must be strings (like Web API).
  • localStorage.getItem(key)
    • Returns the value (string) for the key, or null if not found.
  • localStorage.removeItem(key)
    • Removes the item with the specified key.
  • localStorage.clear()
    • Removes all items.

sessionStorage

Transient, in-memory key-value storage (LRU cache).

  • sessionStorage.setItem(key, value)
    • Saves a key-value pair. Value can be any JavaScript type (unlike Web API).
  • sessionStorage.getItem(key)
    • Returns the value for the key, or null if not found.
  • sessionStorage.removeItem(key)
    • Removes the item with the specified key.
  • sessionStorage.clear()
    • Removes all items.

Storage Example

localStorage.setItem("token", "12345");
const token = localStorage.getItem("token");
sessionStorage.setItem("cache", {
  lastPage: 1,
  items: []
});
const cache = sessionStorage.getItem("cache");

URLSearchParams

Query-string helpers available in the app and synurart: append, delete, get, getAll, has, set, keys, values, entries, and toString. The constructor accepts a query string, an iterable of pairs, or an object. set preserves the first matching parameter's position and removes duplicate values.

Use for...of to iterate. forEach and sort are not available.

for (const [name, value] of new URLSearchParams("q=hello&page=2")) {
    console.log(name, value);
}

TextEncoder

Browser-like UTF-8 encoder.

  • new TextEncoder()
  • encoding: Always "utf-8".
  • encode(input): Returns a Uint8Array containing UTF-8 bytes for the input string.
  • encodeInto(input, destination): Writes UTF-8 bytes into a destination Uint8Array and returns { read, written }.

TextDecoder

Browser-like byte decoder for supported charset labels.

  • new TextDecoder(label)
  • encoding: Canonical encoding label resolved by the runtime (for example "utf-8" or "euc-kr").
  • fatal: Always false.
  • ignoreBOM: Always false.
  • decode(input): Decodes an ArrayBuffer or typed array into a JavaScript string.

Common use cases include:

  • new TextDecoder("utf-8")
  • new TextDecoder("euc-kr")

Note: The API shape matches the Web Encoding API, but Synura's fetch() is synchronous. Methods like response.text() and response.arrayBuffer() return values directly instead of Promises.


Synura Models

Data passed to views via the models object follows a specific structure used by the Synura protocol.

Canonical Structure

The native model object consists of four optional fields:

  • message (String): Text content or JSON-serialized data.
  • code (Integer): Numeric data (counts, IDs, etc.).
  • value (Double): Decimal numeric data (ratings, percentages, etc.).
  • details (Array): A list of items (used for lists, comments, content blocks).
{
  "message": "Hello World",
  "code": 123,
  "value": 123.45,
  "details": [...]
}

Shorthands & Type Inference

To simplify development, you can pass standard JavaScript types, and Synura will automatically map them to the canonical structure:

JavaScript Type Maps To Example
String { message: "..." } title: "Hello"
Number { value: 123.45, code: 123 } rating: 4.5
Array { details: [...] } contents: [item1, item2]
Generic Object { message: JSON.stringify(...) } user: { name: "Bob", id: 1 }

Important: If you pass an object that contains keys other than message, code, value, or details (e.g., { message: "Hello", user: "Bob" }), it will be treated as a Generic Object and the entire object will be JSON-stringified into the message field. To use the explicit wrapper format, the object must only contain the allowed keys.

View Types

Views are opened via synura.open({ view: '/views/<type>', models: ..., styles: ... }).


Dialog Types

Dialogs are opened via synura.open({ view: '/dialogs/<type>', ... }). Unlike views, dialogs appear as modal overlays and do not navigate away from the current screen.


Events

Handle events in the synura.connect callback, or the optional callback passed to synura.open.

Event Structure

{
  eventId: "CLICK" | "LOAD" | "REFRESH" | "SCROLL_TO_END" | "MENU_CLICK" | "SUBMIT",
  context: {
    ...
  },
  data: {
    ...
  }
}

Common Events

  • LOAD / REFRESH: Triggered when the view loads or user pulls to refresh.
  • CLICK: User clicked an item. data contains the item object (e.g., { link: "...", index: 0 }).
  • SCROLL_TO_END: User scrolled to the bottom (List View). Fetch next page here.
  • MENU_CLICK: User clicked a menu item. data.menu contains the menu text.
  • AUTHOR_CLICK: User clicked the author. data contains author and optionally link.
  • SUBMIT: User submitted a form (Settings/Dialog). data contains form values.

System Limitations

Extension Size

  • Maximum Script Size: 128KB (131,072 bytes). Extensions exceeding this size will fail to install.

Router Pattern & State Management

Synura uses a passive router architecture to enable content pre-fetching and instant navigation.

See Router Pattern for full documentation on:

  • Router Handler (router(url))
  • Threading Model
  • State Sharing
  • Caching Strategy