Vasili's Blog

Everybody has a love/hate relationship with ESLint. It guides you in the right ways of code, but it also nags you with all of those mundane asks...

So, sometimes you switch things to “warn”, to be generally appraised of what's happening with a Scout's Honour promise to “fix it later”. Pinky swear. And then the whole thing gets wired up to CI and you never really see those warnings ever again. Once you see that green checkmark of a passing stage – why bother going in and reading console output, right?

Well, we can make GitLab soft-fail a stage. It will not break the build, but it'll show that nagging Yellow Exclamation Mark of Concern.

Sadly there's no command-line option for eslint to say: “exit with a non-successful status code in case there are only warnings”, so we have to improvise.

jq to the rescue (once we manage to crawl though its obtuse syntax).

  stage: lint
  allow_failure: true
    - apk add --update --no-cache jq
    - eslint . -f json | jq 'map(.warningCount) | add | if(.>0) then halt_error(5) else halt_error(0) end'

This runs eslint, producing a JSON output where we sum all the warning counts and bail out with an error code if there are any.

Technically we can set the allow_fail to permit only specific status codes.

    - 5

I couldn't get it to work naively though. But this works too. You have a stage that soft-fails on warnings.

#gitlab #ci #eslint

So, for the #podcast I'm doing a bit of audio cleanup... Running some VST plugins to de-reverb, remove noises, chair creaks, desk bangs, etc...

I'm working on Episode 5 today, and I though that if there was a plugin to remove the inhale sounds – it should be called Asthma. You heard it here first, folks...

    Bookings {
        BookingId booking_id PK
        EventId event_id FK
        string full_name
        string email
        datetime booking_date
        number duration "Minutes"
        enum status

    Availability {
        AvailabilityId availability_id PK
        string name
        string time_zone

    AvailabilitySlots {
        AvailabilitySlotId availability_slot_id PK
        AvailabilityId availability_id FK
        number weekday "0 for Monday, 6 for Sunday"
        number start_time
        number end_time

    Overrides {
        OverrideId override_id PK
        AvailabilityId availability_id FK
        bool all_day

    OverrideSlots {
        OverrideSlotId override_slot_id
        OverrideId override_id
        number weekday "0 for Monday, 6 for Sunday"
        number start_time
        number end_time

    Events {
        EventId event_id PK
        AvailabilityId availability_id FK
        bool enabled "Is visible in UI"
        string title
        string description "Markdown"
        string slug "Public URL portion"
        number min_duration "Minutes"
        number max_duration "Minutes"
        number increment "Minutes"
        number daily_frequency_limit "Times"
        number weekly_frequency_limit "Times"
        number monthly_frequency_limit "Times"
        number yearly_frequency_limit "Times"
        number daily_duration_limit "Minutes"
        number weekly_duration_limit "Minutes"
        number monthly_duration_limit "Minutes"
        number yearly_duration_limit "Minutes"
        number days_into_future_limit
        number minimum_notice_limit
        enum minimum_notice_limit_unit "days/hours/minutes"
        number before_event_buffer "Minutes"
        number after_event_buffer "Minutes"
        number fixed_fee "Dollars"
        number rate "Dollars per minute"

    IntakeQuestions {
        IntakeQuestionId intake_question_id PK
        EventId event_id FK
        number ordinal
        bool required
        enum kind
        string identifier
        string label
        string description "Markdown"
        string placeholder
        json default_value
        bool locked

    IntakeQuestionOptions {
        IntakeQuestionOptionId intake_question_option_id PK
        IntakeQuestionId intake_question_id FK
        string identifier
        string label

    IntakeQuestionAnswers {
        IntakeQuestionAnswerId intake_question_answer_id PK
        BookingId booking_id FK
        number ordinal
        enum kind
        string identifier
        string label
        string description
        json answer

    Availability ||--|{ AvailabilitySlots : has
    Availability ||--o{ Overrides : has
    Events ||--|| Availability : "scheduled during"
    Bookings }o--|| Events : has
    Bookings ||--o{ IntakeQuestionAnswers : has
    Overrides ||--o{ OverrideSlots : has
    Events ||--|{ IntakeQuestions : has
    IntakeQuestions ||--o{ IntakeQuestionOptions : has


I've integrated diagramming support into this blog...

Check it out:

graph LR;
    A--> B & C & D;
    B--> A & E;
    C--> A & E;
    D--> A & E;
    E--> B & C & D;

Should probably back-port it to the mainline repo.


After the fiasco I think I'll try to roll out something simple, without too many dependencies, that can just run quickly...

Some Notes on the architecture, which I'll be updating.


It's like that Onion article...

Man Who Thought He'd Lost All Hope Loses Last Additional Bit Of Hope He Didn't Even Know He Still Had

Now that I'm running a mentorship #podcast, I'd like to get more people on it as guests, so I thought of deploying some sort of appointment management software. Browsing the Open Source alternatives section only really gives as something viable. A clean UI that integrates with CalDAV and offers great features (some behind paywall, but still). Self-hostable in theory...

I took a first stab at it, and was immediately blocked by something call turbo which is Vercel's new and shiny tool for building javascript apps.

So, immediately I was prevented from just doing the bare minimum I hope to expect from JS applications:

npm install
npm run

Okay, I get it, it's a Next.js app, so it needs some amount of compilation for all that Typescript and JSX.

My first portent was the fact that yarn was running for minutes, downloading all the dependencies. All 2.5 gigs of them...

After the download completed I proceeded with build. It ran for about five minutes and crashed with OOM exception. I've spent next hour trying to get it to work by passing the NODE_OPTIONS="--max-old-space-size=4096" and it kept failing.

After digging around some more, it looks like turbo specifically whitelists the environment variables passed to the applications being built, and NODE_OPTIONS was not one of them. After adding it to the turbo.json the build started progressing, but still failed soon after, completely saturating the available RAM on the small Vultr VPS I was using for this purpose...

I've cleared up some room on the disk and created a 2 gig swap file... Build process went on for 10 minutes and crashed. Okay, let's bump that up to 4 gigs... now it's running for 12 minutes and crashes... Eventually, after scrounging all remaining space on the box, the build has completed with 8 gigs of swap, after whopping 25 minutes.

The app was finally running...

Now my node_modules folder has a .turbo cache folder, that bring the total to 6 gigs of disk space...

Now I felt like Doc Brown in the famous 1.21 Gigawatts scene

All the bugs and configuration issues notwithstanding I have the software running...

A few weeks later I've fetched the most recent release, and the process had to be done once more. Now that they've upgraded to a newer version of NextJS, it now takes 40 minutes to build, and the site itself is slow beyond reason. I though that SSR and fancy new “Oh, we're just like PHP was 10 years ago, but with React on the server” it is supposed to be fast...

I'll likely be nuking this software from my server... I can't be using products that are only usable if you're paying Vercel for the privilege...

I can probably write a small subset of features that I need that will not require 2.5 gigs worth of NPM packages, and such insane build times.

It should just be

npm install
npm run

Or better yet, write it all in zig with a 10Mb binary with no extra dependencies...

I've been running my own infrastructure for about 20-ish year, as a hobby for fun and profit. In the early days it was a couple of boxes at home running some flavor of RedHat on a domestic ADSL connection. Then one day mail stopped working, and after much scramble we figured out that the ISP has simply blocked inbound port 25. I've upgrade the home connection to a business plan, which was twice as expensive, with same speed, but the ports were not restricted. It lasted for a while until one day a power outage happened and fried the hard drive. I've moved to the cloud using, one of the first VPS providers at a considerable $50/mo. qmail was compiled from scratch using some step-by-step guide, apache was chugging along serving PHP-based web sites and we were off. At the time the setup was based on SquirrelMail and Gallery. This server has survived until MediaTemple has completely discontinued the VPS plan they were offering, and suggested moving to another one (much cheaper), but the prospect of having to recompile and reconfigure qmail was a bit too much, and I've decided to go with something that runs out of the box, so I picked postfix, which still powers my mail setup today. Around that time Edward Snowden's revelations showed the depths of surveillance and I thought to move my stuff to a country with better privacy laws, so I switched to 1984 Hosting out of Iceland. I was pretty happy using them for quite a long time, but at some point their storage system has suffered a catastrophic failure and I had to plug the holes by re-routing my mail through Gmail. Hey, I was in a pinch. Eventually they were able to recover the files, but I've since moved on to Digital Ocean, as I wanted something on a cheaper side.

So, let me tell you about my current set-up.

I'm currently running on a Digital Ocean VPS that I've obtained shortly after the 2017 1984Hosting Crash. Originally provisioned with Ubuntu Server 17. It's been upgraded continuously and it's running the latest version now.

Category Purpose Software Stack
Monitoring System Load, etc. Munin Perl
Logging Grafana Go
Data Capture Collectd C
Analytics Matomo PHP
Connectivity Email (SMTP) Postfix C
Email (IMAP) Dovecot C
Email (Filtering) Pigeonhole Sieve C
Email (Antispam) MTPolicyD Perl
Email (Verification) OpenDKIM OpenDMARC C
Email (UI) RoundCube PHP
Video Calling Tlk NodeJS
Calendar + Contacts Baïkal PHP
To-Do Vikunja Go / TypeScript
Security VPN Wireguard C
VPN (Management UI) WG Provision NodeJS
VPN (DNS Tunneling) Iodine C
Password Management VaultWarden Rust / Typescript
Attack Mitigation Crowdsec Go
SSO Zitadel Go
Social Media Status updates Pleroma Elixir
Video Hosting PeerTube TypeScript
Blog WriteFreely Go
Collaboration Knowledge Base Outline TypeScript
VCS Gitea Go

My criteria for the software – preferably compiled, single binary, low memory footprint. This usually precludes things like Ruby and Java, but I do currently run some NodeJS based tools, but for most part they seem to behave.

Costs-wise: $32.5 CAD/mo for the server. $24 for the instance and $5 for additional volume + tax. Not sure what I pay for DNS, because I own a bunch of domains... I use EasyDNS + ZoneEdit, which I can highly recommend.