puter.events.onLocal()Subscribes to a subject and calls handler every time something matching it changes. The subscription belongs to this client's connection: nothing is stored, nothing runs while the page is closed, and it ends when the connection does. See Events for the subject grammar and the event shape.
puter.events.onLocal(subject, handler)
puter.events.onLocal(subject, handler, options)
subject (String) (required)
What to watch: fs:<path or uid>[:<op>]. The path may be absolute (/alice/Documents) or home-relative (~/Documents), may name something that does not exist yet, and may contain * (within a path segment) or ** (across directories). The optional op is one of add, write, move, remove, meta — nothing emits meta yet.
handler (Function) (required)
Called with a single { event } object per delivery. event.op === 'gap' means events were dropped against a limit and the details are not available — re-read what you are watching. A handler that throws is reported on the console and does not end the subscription.
options (Object) (optional)
onError (Function): Called with { message, code } if the subscription lapses — the connection was lost and re-subscribing failed. The subscription is over at that point; call onLocal() again to resume. Without it, a lapse is reported on the console.timeout (Number): How long to wait for the server to confirm the subscription, in milliseconds. Defaults to 30000.A Promise that resolves, once the server has confirmed the subscription, to a subscription object:
subId (String | null): The server's id for the subscription. It changes whenever the connection is rebuilt, so don't store anything against it.subject (String): The subject you subscribed with.anchor (Object): { uid, path } of the node the subscription is keyed to — the nearest existing ancestor when the subject named something that does not exist yet.match (String | null): The pattern events under the anchor are matched against, if the subject had one.op (String | null): The single operation this subscription is limited to, or null for all of them.off (Function): Ends the subscription — see subscription.off().The promise rejects with { message, code }:
code |
Meaning |
|---|---|
invalid_subject |
The subject is not a non-empty string, or the server could not parse it. |
invalid_handler |
handler is not a function. |
invalid_subject_op |
The :op suffix is not one of the five operations. |
invalid_subject_pattern |
The match pattern is past the compile-cost bounds (256 characters, 16 segments). |
subject_does_not_exist |
The subject is not there, or this account cannot read it. |
events_subscription_limit |
This connection already holds the maximum number of subscriptions. |
too_many_requests |
Over the subscribe/unsubscribe call budget. |
events_disabled |
Events are not enabled on this server. |
reauth_required |
The session backing this connection is no longer valid. |
events_connection_failed |
The events connection could not be established, the server did not answer in time, or the server closed the connection. |
Watch a directory and print what changes
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<script>
(async () => {
// (1) Create a directory to watch
const dir = `~/${puter.randName()}`;
await puter.fs.mkdir(dir);
// (2) Subscribe to everything under it
const sub = await puter.events.onLocal(`fs:${dir}`, ({ event }) => {
if (event.op === 'gap') {
puter.print(`missed some changes (${event.reason})<br>`);
return;
}
puter.print(`${event.op}: ${event.path}<br>`);
});
// (3) Change something — the handler runs
await puter.fs.write(`${dir}/hello.txt`, 'Hello!');
// (4) Stop listening (cleanup)
setTimeout(() => sub.off(), 2000);
})();
</script>
</body>
</html>
React to a file that does not exist yet
<html>
<body>
<script src="https://js.puter.com/v2/"></script>
<script>
(async () => {
// (1) A directory to work in. `inbox/` below it does not exist yet.
const dir = `~/${puter.randName()}`;
await puter.fs.mkdir(dir);
// (2) Subscribe anyway — the subscription anchors on `dir` and
// matches the rest of the path as it appears.
const sub = await puter.events.onLocal(
`fs:${dir}/inbox/trigger.json:add`,
({ event }) => puter.print(`appeared: ${event.path}<br>`),
{ onError: (error) => puter.print(`subscription ended: ${error.code}<br>`) },
);
puter.print(`anchored on ${sub.anchor.path}, matching ${sub.match}<br>`);
// (3) Create it, several directories deep
await puter.fs.write(`${dir}/inbox/trigger.json`, '{}', {
createMissingParents: true,
});
setTimeout(() => sub.off(), 2000);
})();
</script>
</body>
</html>