Timeline Sandbox

@alexonit@twtxt.alessandrocutolo.it

Writing code for work, fun and everything in between.

@alexonit@twtxt.alessandrocutolo.it

@lyse In my case it was a silver necklace, a hummingbird with a wing connected with the cold welding I mentioned using thin brass wires.

It made it in a goldsmithing class (I went to a private craftmanship high-school) so no phones allowed (no photos of it) and no "take home" of the works.

Here's a rough sketch of it drawn by memory, the dots in the wing is where it connects to the body.

Hummingbird necklace sketch

The technique is basically the same as i described, but the scale is much smaller, the whole piece was about 5-6 cm on the largest side.

The rivet was made by drilling a hole through the parts, than with a short and thicker drill you widen the hole on the surface to let the rivet settle flatter on the piece, then with a rubber hammer you hit it to flatten the head until it's snug on the hole, lock them together by doing the same on the other side.

Note that widening the hole with a thicker drill head won't make a difference with bigger holes, mine had holes of about 1-2 mm of diameter maximum.

Here's a sketch of what is going on for clarity.

Cold welding cross-section

In reply to: #72pp3ya 5 months ago
@alexonit@twtxt.alessandrocutolo.it

@lyse I actually decided to clean it after my mouse clicks became weirdly unresponsive.

As I began to pull dust out of the gap in the scroll wheel, a mysteryous red fluffy hair ball came out for some reason, so I decided to open it to clean the rest.

After I was done, I went and cleaned the keyboard too.

The mouse was but a teaser of the gore scenes I was about to see... 😱

In reply to: #hom6ofa 5 months ago
@alexonit@twtxt.alessandrocutolo.it

@zvava It is a common UI element in most social platform after all, it's easy to include when planning something similar.

In reply to: #uh5p56q 5 months ago
@alexonit@twtxt.alessandrocutolo.it

@zvava @bender At first I added it without thinking when planning the possible fields based on other UIs I was researching.

I was about to discard it but after thinking about it a bit I noticed that the services allowing to have a separated nick and display_name could unlock some good uses.

For example some added context or at-a-glance information like pronouns or statuses (like Artist [Accepting commissions] or App Name (v2.5)) while other used a more readable version of the nick (blog.domain.com became Person Name's Blog).

Of course it is absolutely optional and it can be safely ignored, but with my vision of being able to build more that a pure twtxt clients, giving it a first-class support just like the other known fields felt right to me.

In reply to: #x4s4mla 5 months ago
@alexonit@twtxt.alessandrocutolo.it

@lyse Great job!

I suggested it because I did it in the past, but never used it on bigger works.

In my case I did it exclusively on really small projects and used a thin rubber head hammer to prevent deforming the metal.

In reply to: #7ahwhrq 5 months ago
@alexonit@twtxt.alessandrocutolo.it

@movq I can confirm.

An intern practicing with turtle had an error when launching it the first time because it was missing tkinter which it use internally.

In reply to: #w2c5yxq 5 months ago
@alexonit@twtxt.alessandrocutolo.it

@lyse I think you should be able to find some even in general stores in the hardware section.

In reply to: #ttnduqa 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@movq So damn true.

I have a friend that might lock himself out of his home if there's a power outage while I keep removing apps and devices from my daily lives instead.

I recently switched from all the todo apps I used to sticky notes on my monitors and a pocket notebook for sketching and quick notes.

In reply to: #g3pajgq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@thecanine So cool!

It reminds me of the monsters in Heart of Darkness on PSX (just replayed the other day).

https://www.youtube.com/shorts/ZnGOpT5NKxc

In reply to: #7tzwq6q 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@bender The first format use the subject extension while the other is a new format that is inspired by mentions format, the first one should be compatible but I'm not sure, if it's used verbatim by the client it would work, but if we consider the new proposal for it to have an optional part it wont work on clients without changes.

In reply to: #3sqf67q 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@movq While using the a frament is pretty nice, I think we can have a twtxt only format if the formatting seems to be a problem.

In reply to: #lolhvka 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@lyse I think will be bad if handled incorrectly.

The client must reference both properly or it would miss posts, including both this way is a bit pointless if you can't use the hash or url separately.

Being a highly likely a breaking change anyway I think @zvava proposal looks much better.

In reply to: #2kiw2vq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@zvava That was my greatest concern with how it is currently handled, I'm afraid to break threads even by fixing a typo.

Handling it via the pod might work but I think it's not the best approach, external feeds and clients don't usually use a pod api but their own implementation, so any workaround won't work there.

That's why my proposals addressed those issues:

  • the idea of using a "key" instead of the url (with the url as a fallback), the key could even be a public key so it can be used verifieable in crypto functions
  • using the timestamp to prevent content changes to break threads (plus being simpler to implement)
  • using an explicit thread reference with an alternative subject format (like [<a href="?search=THREAD_ID" class="tag">#THREAD_ID</a>] Hello world and replies with (<a href="?search=REPLY_ID" class="tag">#REPLY_ID</a>) Ahoy) so the content can change without affecting the thread reference, and anyone can use their own schemes freely
In reply to: #xrswtvq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@zvava I just have plastic plants at home too.

In reply to: #hom6ofa 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@zvava Don't say that.

The eye candy is always good to have.

In reply to: #qz7eeeq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@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.

In reply to: #dekbu6q 6 months ago
@alexonit@twtxt.alessandrocutolo.it

Amazing game, Love the Peer-to-peer with other players and be able to communicate with them.

In reply to: #zlj2yjq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

So smart, would be great to sneak in as an easter egg in a app.

In reply to: #764k64q 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@lyse I can suggest you a trick to do a "cold" welding.

Using a copper wire or a similarly malleable material, pass it through a drilled hole, hammer it on one end until flat, then do the same on the other side.

It does the same job of a rivet but it's flatter and look nicer on both sides, it's of course weaker but still strong enough for small objects.

It's sometimes used to reduce risk of deformities due to heat in hand-crafted jewelry and to reduce costs of small tools.

In reply to: #guskv5a 6 months ago
@alexonit@twtxt.alessandrocutolo.it

I love it!

Giving the user multiple choices to do the same things is what is great about protocols in general.

In reply to: #oiy2mdq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@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:

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).

In reply to: #dekbu6q 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@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.

In reply to: #dekbu6q 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@lyse Beautiful handwork, how did you seal the corners? I don't see and hole or anything.

BTW, That Sheet Metal Dude is something else himself, skilled enough to teach others, can work properly with self-imposed contraints, care about safety and is humble enough to be wiling to learn from others, a true craftman worthy of respect.

In reply to: #yhoftja 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@lyse Thanks!

The way I have it setup right now would take me more work to integrate with your script though.

I'm keeping things dumb on purpose, I just have to finish my client to have all the cool buttons that do it for me.

In reply to: #xieb67a 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@prologic I too, self-host various services on a VPS (and considering buying a mini PC to keep at home instead).

I use most of it as a hosting platform for personal use only and as a remote development environment (I do share a couple of tools with a friend though).

But given the costant risks of DDoS, hacking, bots, etc. I keep any of my public facing resources purely static and on separate hosting providers (without lock-ins of course).

Lately, I began using homebrew PWAs with CouchDB as a sync database, this way I get a fantastic local-first experience and also have total control of my data, that also sync in a locally hosted backup instance in real-time.

Also, I was already aware of Salty.im, but what I'm thinking is a more feature complete solution that even my family can use quickly, Delta.chat with the new chatmail provider (self-hostable) might be the solution for my needs.

But I'm still thinking if it's worth the trouble. I might just drop everything and only use safe channels to speak with them (free 24/7 family tech-support is easy to manage πŸ˜†).

Also, I'll be waiting for the day you'll share with us your story, I'm pretty curious about it!

In reply to: #mjjph3a 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@prologic I think nobody will stop you if you replace the current hashing with SHA-256 if you call it improvementβ„’ πŸ˜‰

In reply to: #ce7zzfq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

That's what I'm using right now, while my own client is still in the making.

A simple bash script to write a post in a mktemp file then clean it with regex. I don't even bother to hash the replies, I just open https://twtxt.net and copy the hash by hand since I'm checking the new posts from there anyway (temporarily, as I might end up DoS-ing everyone's feed in my client right now).

In reply to: #ce7zzfq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@prologic Don't worry about it!

I also getting angry thinking how this Chat Control crap will escalate to.

I'm already thinking of countermeasures and self-hosted alternatives, while searching lists of affected apps and services to replace/drop in the worst scenario (and probably devices).

In reply to: #mjjph3a 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@zvava Amazing! I would love to see all the specs described this way. 🀩

In reply to: #x4pf6pq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@prologic Well, personally I would, as I already do for user feeds in my client.

That's why part of my proposal was to allow custom strings and be free from a specific format that need periodical upgrades, but it's not much of a problem in the end.

I'll adapt to what we can get out of this.

In reply to: #7fsi7yq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@prologic I think a counter in the client is not a good choice given the decentralized nature of twtxt, especially if someone use multiple cients together.

After thinking about it for a while I got to two solutions:

Proposal 1: Thread syntax (using subject)

Each post have an implicit and an optional explicit root reference:

  • Implicit (no action needed, all data required are already there)
In reply to: #vdkllnq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@prologic While it might work if you want to keep both, I think the point was to be able to use one or the other, if we still have to generate the hash anyway it might be pointless to use this format.

In reply to: #7fsi7yq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@prologic I admit that I was a bit confused about the meaning of the message, at least I understood it was a "yes" from the last sentence. πŸ˜…

In reply to: #ag5xxha 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@bender Well, you guessed correctly! 😁

Would be nice to have a fixed fee for that, a car is a car anywhere in the world...

In reply to: #xjvujya 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@prologic That is really great to hear!

If there are opposing opinions we either build a bridge or provide a new parallel road.

Also, I wouldn't call my opinion a "stance", I just wish for a better twtxt thanks to everyone's effort.

The last thing we need to do is decide a proper format for the location-based version.

My proposal is to keep the "Subject extension" unchanged and include the reference to the mention like this:

// Current hash format: starts with a '#'
(<a href="?search=hash" class="tag">#hash</a>) here's text
(<a href="?search=hash" class="tag">#hash</a>) <a href="/timeline/profile?url=url">@nick</a><a href="url" class="webmention"></a> here's text

// New location format: valid URL-like + '#' + TIMESTAMP (verbatim format of feed source)
(url#timestamp) here's text
(url#timestamp) <a href="/timeline/profile?url=url">@nick</a><a href="url" class="webmention"></a> here's text

I think the timestamp should be referenced verbatim to prevent broken references with multiple variations (especially with the many timezones out there) which would also make it even easier to implement for everyone.

I'm sure we can get @zvava, @lyse and everyone else to help on this one.

I personally think we should also consider allowing a generic format to build on custom references, this would allow for creating threads using any custom source (manual, computed or external generated), maybe using a new "Topic extension", here's some examples.

// New format for custom references: starts with a '!' maybe?
(!custom) here's text
(!custom) <a href="/timeline/profile?url=url">@nick</a><a href="url" class="webmention"></a> here's text

// A possible "Topic" parse as a thread root:
[!custom] start here
[custom] simpler format

This one is just an idea of mine, but I feel it can unleash new ways of using twtxt.

In reply to: #3h7w7ca 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@itsericwoodward I used the dates as is for indexing them as string, the ISO format allows for free auto sorting.

In reply to: #hmed7jq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@bender What?! In my country you have to pay 100€ every 10 years of which about 75% are just taxes...

In reply to: #yfma5gq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@lyse @prologic Can't we find a middle ground and support both?

The thread is defined by two parts:

  1. The hash
  2. The subject

The client/pod generate the hash and index it in it's database/cache, then it simply query the subject of other posts to find the related posts, right?

In my own client current implementation (using hashes), the only calculation is in the hash generation, the rest is a verbatim copy of the subject (minus the # character), if this is the common implemented approach then adding the location based one is somewhat simple.

function setPostIndex(post) {
    // Current hash approach
    const hash = createHash(post.url, post.timestamp, post.content);

    // New location approach
    const location = post.url + '#' + post.timestamp;

    // Unchanged (probably)
    const subject = post.subject;

    // Index them all
    addToIndex(hash, post);
    addToIndex(location, post);
    addToIndex(subject, post);
}

// Both should work if the index contains both versions
getThreadBySubject('<a href="?search=abcdef" class="tag">#abcdef</a>') => [post1, post2, post3]; // Hash
getThreadBySubject('https://example.com#2025-01-01T12:00:00') => [post1, post2, post3]; // Location

As I said before, the mention is already location based <a href="/timeline/profile?url=https://example.com/twtxt.txt">@example</a><a href="https://example.com/twtxt.txt" class="webmention"></a>, so I think we should keep that in consideration.

Of course this will lead to a bit of fragmentation (without merging the two) but I think this can make everyone happy.

Otherwise, the only other solution I can think of is a different approach where the value doesn't matter, allowing to use anything as a reference (hash, location, git commit) for greater flexibility and freedom of implementation (this probably need the use of a fixed "header" for each post, but it can be seen as a separate extension).

In reply to: #3h7w7ca 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@movq Happy equinox!

It looks amazing from the map, you probably can't tell even by looking from space.

In reply to: #bkbv6ta 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@kat Oh! A new place to spam dad jokes. πŸ₯³

In reply to: #orntm4a 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@prologic I can see the issues mentioned, but I think some can be fixed.

  1. The current hash relies on a url field too, by specification, it will use the first # url = <URL> in the feed's metadata if present, that too can be different from the fetching source, if that field changes it would break the existing hashes too, a better solution would be to use a non-URL key like # feed_id = <UNIQUE_RANDOM_STRING> with the url as fallback.

  2. We can prevent duplications if the reference uses that same url field too or the client "collapse" any reference of all the urls defined in the metadata.

  3. I agree that hashing based on content is good, but we still use the URL as part of the hashing, which is just a field in the feed, easily replicable by a bot, also noting that edits can also break the hash, for this issue an alternative solution (E.g. a private key not included in the feed) should be considered.

  4. For offline reading the source would be downloaded already, the fetching of non followed feeds would fill the gap in the same way mentions does, maybe I'm missing some context on this one.

  5. To prevent collisions there was a discussion on extending the hash (forgot if that was already fixed or not), but without a fallback that would break existing clients too, we should think of a parallel format that maintains current implementations unchanged, we are already backward compatible with the original that don't use threads at all, a mention style format for that could be even more user-friendly for those clients.

We should also keep in mind that the current mention format is already location based (<a href="/timeline/profile?url=https://example.com/twtxt.txt">@example</a><a href="https://example.com/twtxt.txt" class="webmention"></a>) so I'm not that worried about threads working the same way.

Hope to see some other thought about this matter. πŸ€“

In reply to: #altkl2a 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@thecanine Thanks!

Looking forward to it!✌️

In reply to: #s2lah7a 6 months ago
@alexonit@twtxt.alessandrocutolo.it

This looks so huggable, it feels like a plushie! πŸ₯°

After seeing so many resolutions, I think you're only missing a matrioska version of it. πŸͺ†

In reply to: #s2lah7a 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@lyse Yeah, the format is just an idea of how it could work.

The order of SOURCE > POST does make more sense indeed.

In reply to: #altkl2a 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@prologic thanks, I already follow @important_dev_news too.

BTW, the feed on https://feeds.twtxt.net/ seem down? It says it's in maintenance.

In reply to: #cqzexoq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@prologic Me neither, if there's any important news others usually tell me anyway. 😌

In reply to: #cqzexoq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@zvava I kinda fixed the issue by not stripping the timestamp at all.

Seems that more feeds work correctly this way. πŸ€”

In reply to: #s5wriqq 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@thecanine With a progressive web app (PWA) you can have a native like experience without having to trouble yourself with building a second project that act as a client.

You can even "wrap" it into a packaged installation and publish it on stores, theres even projects to streamline it https://www.pwabuilder.com/.

In reply to: #jdhwlna 6 months ago
@alexonit@twtxt.alessandrocutolo.it

My proposal is taken from https://texudus.readthedocs.io/en/latest/ BTW.

In reply to: #dvw775q 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@zvava @lyse I also think a location based reference might be better.

A thread is a single post of a single feed as a root, but the hash has the drawback of not referencing the source, in a distributed network like twtxt it might leave some people out of the whole conversation.

I suggest a simpler format, something like: (#<TIMESTAMP URL>)

This solves three issues:

  • Easier referencing: no need to generate a hash, just copy the timestamp and url, it's also simpler to implement in a client without the rish of collisions when putting things together
  • Fetchable source: you can find the source within the reference and construct the thread from there
  • Allow editing: If a post is modified the hash becomes invalid since it depends on [ timestamp, url, content ]
In reply to: #dvw775q 6 months ago
@alexonit@twtxt.alessandrocutolo.it

@zvava @lyse @movq I also was wondering how to handle this.

Currently my regex is like this: /@<((?<nick>[^\s]+)\s)?(?<url>\w+:\/\/[^>]+)>/g

It takes everything until the space and the nick is optional.

In reply to: #fzmmn2q 6 months ago
Comment via email