feat(server): name the event in a push and offer a booking as a Google Wallet pass

The push payload carries the event it reports, so the Android app can file a
notification under a channel of its own (chat, trip updates, invitations).
A browser and the iOS extension ignore the field.

GET /api/trips/:tripId/reservations/:id/wallet-pass/google sends the same
request the Apple Wallet signer takes to the TREK services' Google route and
answers with the signed save-to-wallet link the Android app opens. Off with the
other TREK services, and a clear 404 while liketrek has no Wallet issuer yet.
This commit is contained in:
Maurice
2026-11-07 14:11:22 +01:00
parent 41c713fd9a
commit d41a4f0827
9 changed files with 151 additions and 2 deletions
@@ -199,5 +199,7 @@ describe('pushPayloadSchema', () => {
expect(pushPayloadSchema.safeParse({ title: 'T' }).success).toBe(false);
expect(pushPayloadSchema.safeParse({ body: 'B' }).success).toBe(false);
expect(pushPayloadSchema.safeParse({ title: 'T', body: 'B', tag: 5 }).success).toBe(false);
expect(pushPayloadSchema.safeParse({ title: 'T', body: 'B', event: 'trip_invite' }).success).toBe(true);
expect(pushPayloadSchema.safeParse({ title: 'T', body: 'B', event: 1 }).success).toBe(false);
});
});
@@ -125,5 +125,10 @@ export const pushPayloadSchema = z.object({
body: z.string(),
url: z.string().optional(),
tag: z.string().optional(),
/**
* The event it reports (trip_invite, collab_message, ...). The Android app
* sorts notifications into its channels by it; a browser ignores it.
*/
event: z.string().optional(),
});
export type PushPayload = z.infer<typeof pushPayloadSchema>;
@@ -402,3 +402,13 @@ export const bookingImportConfirmResponseSchema = z.object({
created: z.array(reservationSchema),
});
export type BookingImportConfirmResponse = z.infer<typeof bookingImportConfirmResponseSchema>;
/**
* GET /api/trips/:tripId/reservations/:id/wallet-pass/google: the booking as a
* Google Wallet pass, by the save link the TREK services signed. The Android app
* opens it, and Google Wallet adds the pass (native/wallet.ts).
*/
export const googleWalletSaveResponseSchema = z.object({
saveUrl: z.string().url().startsWith('https://pay.google.com/gp/v/save/'),
});
export type GoogleWalletSaveResponse = z.infer<typeof googleWalletSaveResponseSchema>;