feat(web): AASA-Endpoint für cards-native Universal-Links
Some checks are pending
CI / validate (push) Waiting to run

SvelteKit-Server-Route unter /.well-known/apple-app-site-association
mit Content-Type application/json. Apple holt diese Datei beim ersten
App-Launch und matched gegen das applinks:cardecky.mana.how-Entitlement
in cards-native (siehe Tag v0.8.0 in git.mana.how/till/cards-native).

- paths: /d/* (Public-Deck-Detail) + /u/* (Author-Profile)
- Team-ID via env PUBLIC_APPLE_TEAM_ID, Default Platzhalter XXXXXXXXXX
- Cache-Control: public, max-age=3600

Production-Deploy braucht echte Team-ID — bis dahin akzeptiert Apple
die AASA nicht. Details: cards-native/docs/RELEASE_CHECKLIST.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-05-13 01:56:36 +02:00
parent 9f019d8e2f
commit bdce9c98b6

View file

@ -0,0 +1,53 @@
import { env } from '$env/dynamic/public';
import type { RequestHandler } from './$types';
/**
* Apple App-Site Association für die cards-native iOS-App.
*
* Apple holt diese Datei beim ersten App-Launch (und gelegentlich danach)
* von `https://cardecky.mana.how/.well-known/apple-app-site-association`
* und vergleicht sie mit dem `applinks:cardecky.mana.how`-Entitlement
* der App. Bei Match werden Links auf `/d/<slug>` direkt in die App
* geöffnet statt im Browser.
*
* **Pflichtbedingungen:**
* 1. Antwort MUSS `Content-Type: application/json` haben (nicht
* `application/json; charset=utf-8`, nicht `text/json`).
* 2. Antwort darf KEINE Redirects haben.
* 3. Pfad MUSS exakt `/.well-known/apple-app-site-association` lauten.
*
* Team-ID kommt via env `PUBLIC_APPLE_TEAM_ID`. Default ist Platzhalter
* `XXXXXXXXXX` produktiv muss die echte Team-ID des mana-e.V.-Apple-
* Developer-Accounts gesetzt werden, sonst akzeptiert Apple die AASA
* nicht.
*
* Cross-Ref: `cards-native/docs/RELEASE_CHECKLIST.md` "Server-seitige
* Vorbedingungen".
*/
export const GET: RequestHandler = async () => {
const teamId = env.PUBLIC_APPLE_TEAM_ID ?? 'XXXXXXXXXX';
const bundleId = 'ev.mana.cards';
const payload = {
applinks: {
apps: [],
details: [
{
appID: `${teamId}.${bundleId}`,
paths: ['/d/*', '/u/*'],
},
],
},
};
return new Response(JSON.stringify(payload), {
status: 200,
headers: {
'Content-Type': 'application/json',
// 1 Stunde Cache — Apple respektiert Cache, refetched aber auch
// bei App-Update und gelegentlich proaktiv. Längere TTLs würden
// Roll-Outs von Team-ID-Wechseln blockieren.
'Cache-Control': 'public, max-age=3600',
},
});
};