Files
landing-api/public/api-types.d.ts
Josep Piguillem 7e7d2847fe
Some checks failed
Tests / lint (push) Has been cancelled
Tests / test (push) Has been cancelled
Tests / test-postgres (push) Has been cancelled
Tests / mcp (push) Has been cancelled
Point the public site to each project's TaskStream board
A project with a board now carries its key, its address and the address
of the board's public showcase in the public API, so the website can show
its roadmap, releases and tickets for newcomers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:13:56 +02:00

431 lines
11 KiB
TypeScript

/**
* Pireon Admin API — the public payloads.
*
* Generated from openapi.yaml by `php artisan api:types`. Do not edit:
* change the specification instead, and the contract test will hold the
* API to it.
*/
/**
* The same record's path in each language that has a translation. Feed
* these straight into `<link rel="alternate" hreflang>`. Languages with
* no translation are absent, so no advertised URL ever 404s.
*/
export type Alternates = Record<string, string>;
/**
* Everything needed to render an image well server-side. A path alone
* was never enough: without `width`/`height` the page reflows as images
* arrive, without `srcset` every visitor downloads the original, and
* without `alt` the page is not accessible.
*
* Degrades on purpose — an upload whose derived versions are not ready
* yet still carries a `url`, with the rest null, so the frontend renders
* a plain `<img>` rather than a gap.
*/
export interface Image {
/**
* Absolute, because the frontend is on another host.
*/
url: string;
/**
* Empty string when the image is decorative — that is what `alt=""`
* means — never absent. Follows the requested language.
*/
alt: string;
width?: number;
height?: number;
aspect_ratio?: number;
mime?: string;
/**
* Tiny blurred data URI to paint while the real image loads.
*/
placeholder?: string;
/**
* Keyed by format, ready to use verbatim — build a `<picture>` with
* AVIF first and WebP behind it. Only widths that actually exist are
* listed, and an image is never scaled up.
*/
srcset?: Record<string, string>;
}
/**
* A call for contributors. The commitment fields are the point: time is
* the scarce resource in a volunteer collective, and stating it plainly
* is what lets someone decide.
*/
export interface PublicCall {
id: number;
locale: string;
title: string;
slug: string;
description?: string;
/**
* The explicit exchange offered for unpaid work.
*/
what_you_get?: string;
status: 'open' | 'filled' | 'closed';
hours_per_week?: number;
duration_weeks?: number;
total_hours?: number;
seniority?: 'any' | 'junior' | 'mid' | 'senior';
closes_at?: string;
project: PublicProject;
technologies: PublicTechnology[];
alternates: Alternates;
path?: string;
}
export interface PublicCategory {
id: number;
name?: string;
slug?: string;
description?: string;
color?: string;
position: number;
pages_count: number;
}
export interface PublicClient {
id: number;
/**
* A proper noun, so it is the same in every language.
*/
name: string;
slug: string;
sector?: string;
url?: string;
/**
* Its alt text is the organisation's name.
*/
logo?: Image;
projects_count: number;
}
export interface PublicIssue {
number: number;
title: string;
url: string;
labels: string[];
is_good_first_issue: boolean;
is_help_wanted: boolean;
/**
* Nobody has claimed it. A claimed issue is not an invitation.
*/
is_available: boolean;
comments: number;
created_at?: string;
repository: { full_name: string; url?: string; primary_language?: string; project?: { title: string; slug: string } };
}
export interface PublicMember {
id: number;
name: string;
slug: string;
headline?: string;
bio?: string;
avatar?: Image;
github_username?: string;
links: Record<string, string>;
is_founder: boolean;
/**
* False for people who have left; their work is kept.
*/
is_current: boolean;
joined_at?: string;
left_at?: string;
/**
* Their role on a project, when nested under one.
*/
role?: string;
technologies: PublicTechnology[];
projects: PublicProject[];
alternates: Alternates;
path: string;
}
export interface PublicPage {
id: number;
locale: string;
title?: string;
slug?: string;
excerpt?: string;
body?: string;
meta_title?: string;
meta_description?: string;
status: string;
is_featured: boolean;
featured_image?: Image;
published_at?: string;
/**
* When the record leaves the site. Enforced by the query itself, so
* it holds whether or not anything is running. Use it to expire a
* cache downstream at the same moment.
*/
unpublish_at?: string;
updated_at: string;
category: PublicCategory;
/**
* The ones named in this language, to link to the blog filtered by each.
*/
tags: ({ name: string; slug: string })[];
/**
* The member who signs it, when they have a public profile.
*/
byline?: { name: string; slug: string; headline?: string; avatar?: Image; path: string };
alternates: Alternates;
path?: string;
}
export interface PublicProject {
id: number;
locale: string;
title: string;
slug: string;
tagline?: string;
/**
* Detail endpoint only.
*/
description?: string;
/**
* Why the technical choices were made. Detail endpoint only.
*/
decisions?: string;
/**
* What went wrong and what was learned. Detail endpoint only.
*/
postmortem?: string;
/**
* What a search engine or a chat preview should show instead of the
* title. Detail endpoint only.
*/
meta_title?: string;
/**
* Detail endpoint only.
*/
meta_description?: string;
status: 'idea' | 'active' | 'paused' | 'completed' | 'archived';
is_featured: boolean;
/**
* Flagged directly, or carrying at least one open call.
*/
needs_help: boolean;
cover_image?: Image;
/**
* Screenshots and before-and-after, in the order they were arranged
* in the panel. **Detail endpoint only** — a listing of twenty
* projects has no use for every screenshot of each one.
*/
gallery: (Image & { caption?: string })[];
demo_url?: string;
/**
* The NGO or association the work serves. Used to be two free-text
* fields, which made the same organisation two different things.
*/
client?: PublicClient;
services: PublicService[];
testimonials: PublicTestimonial[];
talks: PublicTalk[];
started_at?: string;
ended_at?: string;
published_at?: string;
/**
* When the record leaves the site. Enforced by the query itself, so
* it holds whether or not anything is running. Use it to expire a
* cache downstream at the same moment.
*/
unpublish_at?: string;
updated_at: string;
technologies: PublicTechnology[];
members: PublicMember[];
lead: PublicMember;
calls: PublicCall[];
repositories: PublicRepository[];
/**
* Its board in TaskStream, if it has one. `showcase_url` answers without a token: roadmap, releases, the sprint under way and tickets labelled good-first-issue.
*/
taskstream?: { key: string; url: string; web_url: string; showcase_url: string };
alternates: Alternates;
path?: string;
}
/**
* Mirrored from the git provider and refreshed hourly.
*/
export interface PublicRepository {
id: number;
provider: 'github' | 'gitlab' | 'gitea';
full_name: string;
url?: string;
description?: string;
primary_language?: string;
/**
* Bytes of code per language.
*/
languages: Record<string, number>;
topics: string[];
license?: string;
stars: number;
forks: number;
contributors_count: number;
open_issues_count: number;
is_archived: boolean;
/**
* Nothing pushed for six months. Lets the frontend avoid presenting
* dead work as live.
*/
is_dormant: boolean;
pushed_at?: string;
synced_at?: string;
good_first_issues: PublicIssue[];
}
export interface PublicSearchResult {
type: 'page' | 'project' | 'service' | 'call' | 'member' | 'technology';
id: number;
title: string;
/**
* Plain text around the first match.
*/
excerpt: string;
path?: string;
/**
* Higher is a better match. Only comparable within one response.
*/
score: number;
}
export interface PublicService {
id: number;
locale: string;
title: string;
slug: string;
tagline?: string;
/**
* Detail endpoint only.
*/
description?: string;
/**
* What a search engine or a chat preview should show instead of the
* title. Detail endpoint only.
*/
meta_title?: string;
/**
* Detail endpoint only.
*/
meta_description?: string;
/**
* A Heroicons name, e.g. `heroicon-o-code-bracket`.
*/
icon?: string;
is_featured: boolean;
position: number;
/**
* So a cache downstream can tell whether its copy is still the
* current one.
*/
updated_at?: string;
/**
* The published work that backs the offer. Detail endpoint only.
*/
projects: PublicProject[];
technologies: PublicTechnology[];
testimonials: PublicTestimonial[];
alternates: Alternates;
path?: string;
}
export interface PublicTalk {
id: number;
/**
* Not translated: the name of a talk given once, in one language.
*/
title: string;
language: string;
summary?: string;
event: string;
city?: string;
held_at?: string;
video_url?: string;
slides_url?: string;
speaker?: PublicMember;
}
export interface PublicTechnology {
id: number;
/**
* Not translated — technology names are proper nouns.
*/
name: string;
slug: string;
category: 'language' | 'framework' | 'datastore' | 'infrastructure' | 'tool' | 'practice';
color?: string;
icon?: string;
/**
* The technology's own logo. Its `alt` is the technology's name —
* there is nothing to write and nothing to get wrong.
*/
logo?: Image;
website?: string;
/**
* Radar placement. Null for technologies used but not placed.
*/
ring?: 'adopt' | 'trial' | 'assess' | 'hold';
description?: string;
/**
* Why it sits in that ring.
*/
radar_note?: string;
projects_count: number;
members_count: number;
}
export interface PublicTestimonial {
id: number;
quote: string;
/**
* The language it was actually said in.
*/
original_locale: string;
/**
* False when the quote you are reading was translated by us. Say so —
* "translated from Spanish" — rather than implying they phrased it
* that way.
*/
is_original: boolean;
author: { name: string; role?: string; avatar?: Image };
given_at?: string;
client?: PublicClient;
}
/**
* Either a plain string (applies to the active language) or an object
* keyed by locale.
*/
export type TranslatedField = Record<string, string>;
/** What each public endpoint answers with, under `data`. */
export interface PublicApiPayloads {
'/public/v1/site': { locales: ({ code: string; name: string; flag: string; is_default: boolean })[]; default_locale: string; content_version: number; submissions_enabled: boolean; stats: { projects: number; active_projects: number; members: number; open_calls: number; good_first_issues: number; stars: number } };
'/public/v1/slugs': Record<string, ({ id: number; updated_at: string; alternates: Record<string, string> })[]>;
'/public/v1/redirects': ({ from: string; to: string; status: 301 | 302; locale?: string })[];
'/public/v1/search': PublicSearchResult[];
'/public/v1/tags': ({ name: string; slug: string; count: number })[];
'/public/v1/projects': PublicProject[];
'/public/v1/projects/{slug}': PublicProject;
'/public/v1/members': PublicMember[];
'/public/v1/members/{slug}': PublicMember;
'/public/v1/calls': PublicCall[];
'/public/v1/calls/{slug}': PublicCall;
'/public/v1/services': PublicService[];
'/public/v1/services/{slug}': PublicService;
'/public/v1/clients': PublicClient[];
'/public/v1/testimonials': PublicTestimonial[];
'/public/v1/talks': PublicTalk[];
'/public/v1/pages': PublicPage[];
'/public/v1/pages/{slug}': PublicPage;
'/public/v1/technologies': PublicTechnology[];
'/public/v1/radar': PublicTechnology[];
'/public/v1/good-first-issues': PublicIssue[];
}