# I am the Watcher. I am your guide through this vast new twtiverse.
# 
# Usage:
#     https://watcher.sour.is/api/plain/users              View list of users and latest twt date.
#     https://watcher.sour.is/api/plain/twt                View all twts.
#     https://watcher.sour.is/api/plain/mentions?uri=:uri  View all mentions for uri.
#     https://watcher.sour.is/api/plain/conv/:hash         View all twts for a conversation subject.
# 
# Options:
#     uri     Filter to show a specific users twts.
#     offset  Start index for quey.
#     limit   Count of items to return (going back in time).
# 
# twt range = 1 7
# self = https://watcher.sour.is/conv/dekbu6q
Hi everyone, here's a little introduction of my twtxt client (still WIP).

The client I'm developing is a single tenant project that runs entirely in the browser (it might use an optional backend).

It's entirely based on native web-components and vanilla JS, it is designed to act closer to a toolkit than a full-fledged client, allowing users to "DIY" their own interface with pure html or plain javascript functions.

Users can also build their own *engines* by including a global javascript object that implement the defined internal API (TBD).

I'm planning to build a system that is easy enough to build and use with any skill level, using only pure html (with a homebrew minimal template engine) or via plain JS (I'll be also providing some pre-made templates too).

Everything can be self-hosted on any static hosting provider, this allows to spread twtxt within communities like Neocities and similarly hosted websites (basically any Indieweb/Smallweb/Digital garden website and any of the common GitHub/Lab/Berg/lify Pages).

It will be probably named something like TxtCraft or craf.txt but I'm not really sure yet... 🤔 (Maybe some suggestions could help)

I'm still in the experimental phase, so there's no decent source-code to share yet, but it will soon enough!
@alexonit so, a PWA, right?
@bender Yes and no.

To build a compliant PWA you need to provide a webmanifest json and a service worker.

Those requirements are not directly part of this project.

You can build the client as a standalone PWA or even as a widget inside an existing page.

The general steps are closer to how you would include a third-party library in an existing project, by importing it as a dependency and using it in your website.

I'm pretty sure most users would expect a PWA (me included) so I plan to provide a ready-made template ready to be deployed as is.
@alexonit i tried making a webapp initially but i didn't even get into the initial stages of testing because no one sets the Access-Control-Allow-Origin header, so i just jumped into building a backend instead. did you find away around this limitation? :o
@zvava CORS is our worst enemy. 🥷

I too had the same issue being a browser-based request, so the only solution is using a proxy.

For testing (and real personal use) I rely on this one https://corsproxy.io/.

In my client, I first check if the source allows me to fetch it without issues first and fallback to prefixing with a proxy if it gives an error.

For security reasons the client don't give you a readable error for CORS, so you must use a catch-all for that, if it fails again with the proxy you can deal with any other errors it throws as you normally would (preferably outside of the fetch function).

After the fetching responded, I store the response.url value to fetch it again for updates without having to do extra calls (you can store it verbatim or as a flag to be able to change the proxy later).

Here an extract of my code:

t
export async function fetchWithProxy(url, proxy=null) {
    return await fetch(url).catch(err => {
        if (!proxy) throw err;
        return fetch(`${proxy}${encodeURIComponent(url)}`);
    });
}

// Using it with
const res = await fetchWithProxy('https://twtxt.net/user/zvava/twtxt.txt', 'https://corsproxy.io/?');

// Get the working url (direct or through proxy)
const fetchingURL = res.url;

// Get the twtxt feed content (or handle errors)
const text = await res.text();


I also plan to allow the user to define a custom proxy field, I like the solution used by Delta.chat in their android app, where you can define the URL format with a variable https://my-proxy?$TWTXT_URL since it allows you to define with more freedom any proxy without a prefix format.

If the idea of using a third-party proxy is not to the user liking they can use a self-hosted solution like cors-anywhere or build their own (with twtxt it should just be a GET).
@alexonit yeah, i didn't even consider this as an option lol, though if it works it works! will you be writing a compatible proxy for self-hosting separate from the custom backend you were thinking of? :o
@zvava I'm not sure, I could just set up a cors-anywhere via docker in a minute and it would work the same.

Still, I could write one with just a dozen lines of Go or Node.js, I might consider writing one after the client is working decently.