| 1 | import { describe, expect, it } from "vite-plus/test"; |
| 2 | import * as OpenApi from "effect/http-api/OpenApi"; |
| 3 | import * as Schema from "effect/Schema"; |
| 4 | |
| 5 | import { RelayApi, RelayDeviceRegistrationRequest } from "./relay.ts"; |
| 6 | |
| 7 | const decodeDevice = Schema.decodeUnknownExit(RelayDeviceRegistrationRequest); |
| 8 | const device = { |
| 9 | deviceId: "device", |
| 10 | label: "Phone", |
| 11 | pushToken: "token", |
| 12 | preferences: { |
| 13 | notificationsEnabled: true, |
| 14 | liveActivitiesEnabled: true, |
| 15 | notifyOnApproval: true, |
| 16 | notifyOnInput: true, |
| 17 | notifyOnCompletion: true, |
| 18 | notifyOnFailure: true, |
| 19 | }, |
| 20 | }; |
| 21 | |
| 22 | describe("mobile device platforms", () => { |
| 23 | it.each([ |
| 24 | [23, "Failure"], |
| 25 | [24, "Success"], |
| 26 | [37, "Success"], |
| 27 | ])("enforces the Android minimum without an upper bound (API %i)", (androidApiLevel, result) => { |
| 28 | expect(decodeDevice({ ...device, platform: "android", androidApiLevel })._tag).toBe(result); |
| 29 | }); |
| 30 | |
| 31 | it("accepts Android tokens without Apple routing and preserves older iOS registrations", () => { |
| 32 | expect(decodeDevice({ ...device, platform: "android", androidApiLevel: 36 })._tag).toBe( |
| 33 | "Success", |
| 34 | ); |
| 35 | expect(decodeDevice({ ...device, platform: "ios", iosMajorVersion: 18 })._tag).toBe("Success"); |
| 36 | }); |
| 37 | it("rejects missing platform versions and Apple activity tokens on Android", () => { |
| 38 | expect(decodeDevice({ ...device, platform: "ios" })._tag).toBe("Failure"); |
| 39 | expect(decodeDevice({ ...device, platform: "android" })._tag).toBe("Failure"); |
| 40 | expect( |
| 41 | decodeDevice({ |
| 42 | ...device, |
| 43 | platform: "android", |
| 44 | androidApiLevel: 36, |
| 45 | pushToStartToken: "apple-token", |
| 46 | })._tag, |
| 47 | ).toBe("Failure"); |
| 48 | }); |
| 49 | }); |
| 50 | |
| 51 | describe("RelayApi security", () => { |
| 52 | it("describes DPoP access tokens using the HTTP DPoP authorization scheme", () => { |
| 53 | const document = OpenApi.fromApi(RelayApi); |
| 54 | |
| 55 | expect(document.components.securitySchemes?.relayDpop).toEqual({ |
| 56 | type: "http", |
| 57 | scheme: "DPoP", |
| 58 | description: "DPoP-bound access token. Requests must also include the DPoP proof JWT header.", |
| 59 | }); |
| 60 | }); |
| 61 | }); |