feat: add fluxer upstream source and self-hosting documentation

- Clone of github.com/fluxerapp/fluxer (official upstream)
- SELF_HOSTING.md: full VM rebuild procedure, architecture overview,
  service reference, step-by-step setup, troubleshooting, seattle reference
- dev/.env.example: all env vars with secrets redacted and generation instructions
- dev/livekit.yaml: LiveKit config template with placeholder keys
- fluxer-seattle/: existing seattle deployment setup scripts
This commit is contained in:
Vish
2026-03-13 00:55:14 -07:00
parent 5ceda343b8
commit 3b9d759b4b
5859 changed files with 1923440 additions and 0 deletions

View File

@@ -0,0 +1,181 @@
/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import {calculateAge, isUserAdult} from '@fluxer/api/src/utils/AgeUtils';
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
describe('calculateAge', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date(2026, 0, 24));
});
afterEach(() => {
vi.useRealTimers();
});
describe('with object input', () => {
it('calculates age for birthday earlier this year', () => {
expect(calculateAge({year: 2000, month: 1, day: 1})).toBe(26);
});
it('calculates age for birthday later this year', () => {
expect(calculateAge({year: 2000, month: 12, day: 31})).toBe(25);
});
it('calculates age for birthday today', () => {
expect(calculateAge({year: 2000, month: 1, day: 24})).toBe(26);
});
it('calculates age for birthday yesterday', () => {
expect(calculateAge({year: 2000, month: 1, day: 23})).toBe(26);
});
it('calculates age for birthday tomorrow', () => {
expect(calculateAge({year: 2000, month: 1, day: 25})).toBe(25);
});
it('calculates age for same month different day (before)', () => {
expect(calculateAge({year: 2000, month: 1, day: 1})).toBe(26);
});
it('calculates age for same month different day (after)', () => {
expect(calculateAge({year: 2000, month: 1, day: 31})).toBe(25);
});
it('handles leap year birthday on non-leap year', () => {
expect(calculateAge({year: 2004, month: 2, day: 29})).toBe(21);
});
it('calculates age of 0 for person born this year', () => {
expect(calculateAge({year: 2026, month: 1, day: 1})).toBe(0);
});
it('calculates age of 0 for person born later this year', () => {
expect(calculateAge({year: 2026, month: 6, day: 15})).toBe(-1);
});
it('calculates age for very old dates', () => {
expect(calculateAge({year: 1926, month: 1, day: 1})).toBe(100);
});
});
describe('with string input', () => {
it('parses and calculates age from ISO date string', () => {
expect(calculateAge('2000-01-01')).toBe(26);
});
it('parses date string with birthday later this year', () => {
expect(calculateAge('2000-12-31')).toBe(25);
});
it('parses date string with birthday today', () => {
expect(calculateAge('2000-01-24')).toBe(26);
});
it('parses date string with leading zeros', () => {
expect(calculateAge('2000-01-05')).toBe(26);
});
});
describe('boundary conditions', () => {
it('handles end of year birthday', () => {
expect(calculateAge({year: 2000, month: 12, day: 31})).toBe(25);
});
it('handles start of year birthday', () => {
expect(calculateAge({year: 2000, month: 1, day: 1})).toBe(26);
});
it('handles birthday on current date exactly', () => {
expect(calculateAge({year: 2008, month: 1, day: 24})).toBe(18);
});
});
});
describe('isUserAdult', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date(2026, 0, 24));
});
afterEach(() => {
vi.useRealTimers();
});
describe('with object input', () => {
it('returns true for person exactly 18', () => {
expect(isUserAdult({year: 2008, month: 1, day: 24})).toBe(true);
});
it('returns true for person over 18', () => {
expect(isUserAdult({year: 2000, month: 1, day: 1})).toBe(true);
});
it('returns false for person almost 18', () => {
expect(isUserAdult({year: 2008, month: 1, day: 25})).toBe(false);
});
it('returns false for person under 18', () => {
expect(isUserAdult({year: 2010, month: 6, day: 15})).toBe(false);
});
it('returns true for very old person', () => {
expect(isUserAdult({year: 1926, month: 1, day: 1})).toBe(true);
});
});
describe('with string input', () => {
it('returns true for adult with string date', () => {
expect(isUserAdult('2000-01-01')).toBe(true);
});
it('returns false for minor with string date', () => {
expect(isUserAdult('2010-06-15')).toBe(false);
});
it('handles exactly 18 with string date', () => {
expect(isUserAdult('2008-01-24')).toBe(true);
});
});
describe('handles null and undefined', () => {
it('returns false for null', () => {
expect(isUserAdult(null)).toBe(false);
});
it('returns false for undefined', () => {
expect(isUserAdult(undefined)).toBe(false);
});
});
describe('boundary on 18th birthday', () => {
it('returns true on 18th birthday', () => {
expect(isUserAdult({year: 2008, month: 1, day: 24})).toBe(true);
});
it('returns false one day before 18th birthday', () => {
expect(isUserAdult({year: 2008, month: 1, day: 25})).toBe(false);
});
it('returns true one day after 18th birthday', () => {
expect(isUserAdult({year: 2008, month: 1, day: 23})).toBe(true);
});
});
});