Files
landing-api/public/api-types.d.ts
Josep Piguillem 9f970808ca
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
Tag blog posts and sign them with a member
Tags are named in every language and made from the page form; the byline is
the member who signs a post on the site. The public API sends both, filters
posts by tag and lists the tags in use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:01:18 +02:00

427 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[];
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[];
}