sync

The sync object is the runtime behind the playground's two-way sync; The IOSync model explains the sync itself. In the playground window, from the console or from io.eval.js, it runs a sync by hand with sync.output() and sync.editor(), controls Locate and Shadow Source Materialization, and supplies the metadata that workers receive as request.rt: sync.requestRT. In the output window, from o.eval.js, sync.input looks up the authored source of the elements of that output.

The global exists in both windows, with different members. Deployed pages on RTEdge.net do not have it: there, the edge supplies request.rt.

Instance properties

sync.requestRT

A function that you can replace: ({ rt, url, method }) => object | Promise<object>. The playground calls it for every worker invocation and for every same-origin ::su lookup, and the plain object it returns becomes request.rt of that request. The default is ({ rt }) => ({ ...rt, user: window.user?.email ?? null }), which adds the email of the signed-in account as user. Reloading the editor restores it.

rt

The default metadata of the output: { ip, code: true, user: null, domain, route, vendor: 'Elefunc, Inc.', server: 'RTCode.io', worker: { version: { shell, fetch }, bindings: { KV: ['code'] } } }. domain and route are the host of the output, and ip is the public address of the device, or null. Spread rt to keep these defaults.

url, method

The URL and the method of the request.

The contract:

  • The function may be synchronous or asynchronous. It must produce a plain object, with the prototype Object.prototype or null, that survives structured cloning, within 5 seconds.
  • A value that is not a plain object, a clone failure, an exception, a timeout, or an output reload during the call makes the worker fall back to the default rt with user: null.
  • A change applies to later requests, without recompiling the workers. Requests for plain static files do not call it.
sync.input Experimental

Only in the output window, for example in o.eval.js. It has the methods and the return values of o.input: pos, sel, inner, innerAll, outer, outerAll, and .concat on the last two. Each accepts a selector string, an Element, or an iterable of elements, such as a NodeList, from this output document. Anything else throws TypeError('input.*() expects a selector, Element, or iterable of Elements from this output document.'). For the singular methods, inner and outer, an iterable is validated completely and then its first item is used.

The playground installs sync.input before every o.eval.js run and every o.input call, bound to the editor text at that moment. It is not there before the first agent call, and it becomes stale, with an InvalidStateError, as soon as the source changes. It is meant for agent evals, not for the code of your page. The errors and the matching rules are those of o.input.

sync.output.ready Experimental Read only

A Promise for the latest full load of the output. It never rejects. It resolves to { length: 1 }, { superseded: true } or { e: message }.

sync.scrollLock Experimental

The Locate API, which maps editor cursors to elements of the output and back (Locating source). The name is historical and has nothing to do with the Scroll Lock key. It has these members:

active

A getter: whether Locate is on.

set(active, options), toggle(options)

Turn Locate on or off, or flip it, and return the resulting boolean. They show no toast and do not write the URL themselves; the key sm follows with the next URL write.

refresh(options)

Seeds the cursor pins again. Returns a Promise.

setManual, toggleManual, clearManual, apply

The methods underneath. The F8 command uses them; it also shows the toast Locate enabled or Locate disabled and writes the URL at once.

sync.shadowRootMaterialization Experimental

A boolean flag: whether Shadow Source Materialization is on. sync.shadowRootSynthesis is an alias. Change it with sync.shadowRootMaterializationToggle(): assigning the flag directly does not notify the outputs. The state is stored in the URL as srs.

sync.ver Experimental Read only

A getter that returns a Promise of a multi-line string with the versions of the RTCode parts: RTCode Core, RTCode Work from the output's service worker and RTCode Edit. The About dialog shows it.

Instance methods

sync.output() Experimental

Pushes the editor source to the output.

js
await sync.output()
await sync.output(options)

The optional options object has these properties:

force Optional

A boolean value: true runs the sync although the input editor does not have focus. It does not override a Live Input → Output toggle that is off.

io Optional

An object: { checked: true } runs the sync although Live Input → Output is off.

trigger Optional

A string: 'F5' forces a full reload of the output.

It returns a Promise of a status object:

{ skipped: true }

Live Input → Output is off and io.checked was not passed, or the call was not forced and the editor does not have focus.

{ superseded: true }

A newer editor revision exists.

{ e: message }

The sync failed.

{ length: n }

It worked. After a hot patch, n is the number of outputs that changed. A full reload gives { length: 1 }.

The output reloads completely when the change needs it: F5, a <script reload> or sync=reload marker, changed scripts or <base>, and custom elements that are not pure. Otherwise the output is patched in place and keeps its state. Live sync and reloads lists the triggers. The keys call it like this: F4 (Once) is sync.output({ force: true, io: { checked: true } }), and F5 (Load) is the same with trigger: 'F5'.

sync.editor() Experimental

Writes the output's DOM back into the editor, the reverse sync.

js
await sync.editor()
await sync.editor(options)

The optional options object has force, as in sync.output(), and:

oi Optional

An object: { checked: true } runs the sync although Live Output → Input is off.

trigger Optional

A string: 'F6' makes the update an undo step of its own. Otherwise it merges into the previous one.

Calls are serialized. It returns a Promise that resolves to undefined when the call is skipped, to { superseded: true }, or to { length, html }, where html is the resulting editor text. F6 is sync.editor({ force: true, oi: { checked: true }, trigger: 'F6' }).

sync.shadowRootMaterializationToggle() Experimental

await sync.shadowRootMaterializationToggle(active) turns Shadow Source Materialization on or off (F7) and resolves to the new boolean. active defaults to the opposite of the current state. It updates the URL and the outputs and shows the toast Shadow source materialization enabled or disabled. Turning it off restores the source from before the materialization and removes the materialized shadow roots through a forced reverse sync. sync.shadowRootSynthesisToggle() is an alias.

sync.title() Experimental

Copies the output's <title> into the title of the playground tab. The playground calls it after each sync. See Selection and layout globals for how the tab title is built.

sync.icon() Experimental

Copies the output's link[rel*=icon] into the icon of the playground tab. The playground calls it after each sync.

Live sync toggles

The two Live toggles of the Sync menu, Input → Output (Alt+I) and Input ← Output (Alt+O), are the checkbox menu items io and oi. Both are on by default. They are stored in the URL as io and oi, with the values 1 and 0.

io.sync Experimental

A boolean accessor of the Input → Output toggle. Reading returns checked. Assigning a different value clicks the checkbox, with the effects of a click: turning it on runs sync.output({ force: true }) at once, and the URL is updated.

oi.sync Experimental

A boolean accessor of the Input ← Output toggle. Turning it on tells every output to enable reverse sync and then pulls the output once, as sync.editor({ force: true }) does; turning it off disables reverse sync in every output. The URL is updated.

Note: Assigning io.checked or oi.checked only changes the checkbox. It neither updates the URL nor runs a sync when you turn a toggle on. Assign io.sync or oi.sync instead.

Examples

Running one sync while Live Input → Output is off

Write this to io.eval.js. It is what F4 does.

js
await sync.output({ force: true, io: { checked: true } })

Reloading the output and waiting for it

js
await sync.output({ force: true, io: { checked: true }, trigger: 'F5' });
await sync.output.ready   // { length: 1 }

A worker that reports request.rt

Open this page in the playground. The iframe asks the worker for :me, and the worker answers with the user and the code flag of its request.rt.

html
<iframe src=:me></iframe>
<script type=worker>
  export default { fetch: r => Response.json({ user: r.rt.user, code: r.rt.code }) }
</script>

Mocking the signed-in user for worker tests

Write this to io.eval.js:

js
sync.requestRT = ({ rt }) => ({ ...rt, user: 'ada@example.com' })

After the next output load (F5) the iframe shows {"user":"ada@example.com","code":true}. Return { ...rt, user: null } to simulate a visitor who is signed out. Reload the editor to restore the default.

Turning Locate on

js
sync.scrollLock.set(true)   // true
sync.scrollLock.active      // true

Looking up authored source from the output

Write this to o.eval.js. It needs Agent Folder Share and an output that is in sync with the editor.

js
await sync.input.outerAll.concat(document.querySelectorAll('nav a'))

Specifications

Not part of any specification. sync is part of the RTCode.io runtime. The object that sync.requestRT returns is passed between the windows with structured cloning.

Availability

FeaturePlaygroundRTEdge.netNotes
sync.requestRTYesNoIn a deployment the edge supplies request.rt.
sync.output(), sync.editor()YesNoExperimental. Playground window.
sync.inputYesNoExperimental. Output window, after the first agent call. Needs Agent Folder Share.
sync.scrollLock, sync.shadowRootMaterialization, sync.verYesNoExperimental. Playground window.
io.sync, oi.syncYesNoExperimental.

See also