Compare commits

..

2 Commits

Author SHA1 Message Date
dean
63e1a7090a feat: Add auth handoff mutation operations
Adds GraphQL operations for:
- CreateAuthHandoffToken: Get handoff token for mobile-to-web auth
- ExchangeAuthHandoffToken: Exchange token for Firebase custom token

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-27 10:45:01 -08:00
dean
85c4ec6d40 feat: Add auth handoff mutations for mobile-to-web authentication
Adds GraphQL types and schema for:
- createAuthHandoffToken: Creates short-lived token for auth handoff
- exchangeAuthHandoffToken: Exchanges handoff token for Firebase custom token

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-27 10:44:38 -08:00
4 changed files with 90 additions and 9 deletions

View File

@@ -79,6 +79,12 @@ export enum AlignedIntervalEnum {
Year = "YEAR", Year = "YEAR",
} }
export type AuthHandoffTokenGql = {
__typename?: "AuthHandoffTokenGQL";
expiresInSeconds: Scalars["Int"]["output"];
token: Scalars["String"]["output"];
};
export type BankFeaturesGql = { export type BankFeaturesGql = {
__typename?: "BankFeaturesGQL"; __typename?: "BankFeaturesGQL";
bankAngle: Scalars["Float"]["output"]; bankAngle: Scalars["Float"]["output"];
@@ -140,6 +146,21 @@ export type BucketSetInputGql = {
feature: Scalars["String"]["input"]; feature: Scalars["String"]["input"];
}; };
export type CancellationFeedbackMetadataInput = {
appVersion?: InputMaybe<Scalars["String"]["input"]>;
gitRevision?: InputMaybe<Scalars["String"]["input"]>;
platform?: InputMaybe<Scalars["String"]["input"]>;
};
export enum CancellationReasonEnum {
DataNotAccurate = "DATA_NOT_ACCURATE",
DontPlayEnough = "DONT_PLAY_ENOUGH",
MissingFeatures = "MISSING_FEATURES",
Other = "OTHER",
TechnicalIssues = "TECHNICAL_ISSUES",
TooExpensive = "TOO_EXPENSIVE",
}
export type Challenge = { export type Challenge = {
__typename?: "Challenge"; __typename?: "Challenge";
createdAt: Scalars["DateTime"]["output"]; createdAt: Scalars["DateTime"]["output"];
@@ -303,6 +324,12 @@ export type EnumAggregation = {
feature: Scalars["String"]["input"]; feature: Scalars["String"]["input"];
}; };
export type ExchangeAuthHandoffResultGql = {
__typename?: "ExchangeAuthHandoffResultGQL";
customToken: Scalars["String"]["output"];
userId: Scalars["Int"]["output"];
};
export type FilterInput = export type FilterInput =
| { | {
andFilters: Array<FilterInput>; andFilters: Array<FilterInput>;
@@ -2327,6 +2354,7 @@ export type Mutation = {
blockUser: Scalars["Boolean"]["output"]; blockUser: Scalars["Boolean"]["output"];
cancelSubscription: UserSubscriptionStatusGql; cancelSubscription: UserSubscriptionStatusGql;
commentOnVideo: Scalars["Boolean"]["output"]; commentOnVideo: Scalars["Boolean"]["output"];
createAuthHandoffToken: AuthHandoffTokenGql;
createBucketSet: BucketSetGql; createBucketSet: BucketSetGql;
createChallenge: Challenge; createChallenge: Challenge;
createRuleSet: RuleSet; createRuleSet: RuleSet;
@@ -2344,6 +2372,7 @@ export type Mutation = {
editUploadStream: Scalars["Boolean"]["output"]; editUploadStream: Scalars["Boolean"]["output"];
editUser: UserGql; editUser: UserGql;
ensureStripeCustomerExists: UserGql; ensureStripeCustomerExists: UserGql;
exchangeAuthHandoffToken: ExchangeAuthHandoffResultGql;
findPrerecordTableLayout?: Maybe<HomographyInfoGql>; findPrerecordTableLayout?: Maybe<HomographyInfoGql>;
followUser: UserGql; followUser: UserGql;
getHlsInitUploadLink: GetUploadLinkReturn; getHlsInitUploadLink: GetUploadLinkReturn;
@@ -2361,6 +2390,7 @@ export type Mutation = {
setLoggerLevel: Scalars["Boolean"]["output"]; setLoggerLevel: Scalars["Boolean"]["output"];
setSegmentDuration: Scalars["Boolean"]["output"]; setSegmentDuration: Scalars["Boolean"]["output"];
startChallenge: ChallengeEntry; startChallenge: ChallengeEntry;
submitCancellationFeedback: Scalars["Boolean"]["output"];
submitChallengeEntry: ChallengeEntry; submitChallengeEntry: ChallengeEntry;
undismissChallenge: Scalars["Boolean"]["output"]; undismissChallenge: Scalars["Boolean"]["output"];
unfollowUser: UserGql; unfollowUser: UserGql;
@@ -2463,6 +2493,10 @@ export type MutationEditUserArgs = {
input: EditUserInputGql; input: EditUserInputGql;
}; };
export type MutationExchangeAuthHandoffTokenArgs = {
token: Scalars["String"]["input"];
};
export type MutationFindPrerecordTableLayoutArgs = { export type MutationFindPrerecordTableLayoutArgs = {
b64Image: Scalars["String"]["input"]; b64Image: Scalars["String"]["input"];
videoId: Scalars["Int"]["input"]; videoId: Scalars["Int"]["input"];
@@ -2537,6 +2571,12 @@ export type MutationStartChallengeArgs = {
challengeId: Scalars["ID"]["input"]; challengeId: Scalars["ID"]["input"];
}; };
export type MutationSubmitCancellationFeedbackArgs = {
feedback?: InputMaybe<Scalars["String"]["input"]>;
metadata?: InputMaybe<CancellationFeedbackMetadataInput>;
reasons?: InputMaybe<Array<CancellationReasonEnum>>;
};
export type MutationSubmitChallengeEntryArgs = { export type MutationSubmitChallengeEntryArgs = {
entryId: Scalars["ID"]["input"]; entryId: Scalars["ID"]["input"];
videoId: Scalars["ID"]["input"]; videoId: Scalars["ID"]["input"];
@@ -4017,7 +4057,6 @@ export type GetFeedQuery = {
private: boolean; private: boolean;
elapsedTime?: number | null; elapsedTime?: number | null;
tableSize: number; tableSize: number;
pocketSize?: number | null;
owner?: { owner?: {
__typename?: "UserGQL"; __typename?: "UserGQL";
id: number; id: number;
@@ -4119,7 +4158,6 @@ export type VideoCardFieldsFragment = {
private: boolean; private: boolean;
elapsedTime?: number | null; elapsedTime?: number | null;
tableSize: number; tableSize: number;
pocketSize?: number | null;
owner?: { owner?: {
__typename?: "UserGQL"; __typename?: "UserGQL";
id: number; id: number;
@@ -4217,7 +4255,6 @@ export type GetVideoFeedQuery = {
private: boolean; private: boolean;
elapsedTime?: number | null; elapsedTime?: number | null;
tableSize: number; tableSize: number;
pocketSize?: number | null;
owner?: { owner?: {
__typename?: "UserGQL"; __typename?: "UserGQL";
id: number; id: number;
@@ -6385,7 +6422,6 @@ export const VideoCardFieldsFragmentDoc = gql`
streamSegmentType streamSegmentType
} }
tableSize tableSize
pocketSize
tags { tags {
tagClasses { tagClasses {
name name

View File

@@ -50,7 +50,6 @@ fragment VideoCardFields on VideoGQL {
streamSegmentType streamSegmentType
} }
tableSize tableSize
pocketSize
tags { tags {
tagClasses { tagClasses {
name name

View File

@@ -63,3 +63,17 @@ mutation CancelSubscription {
stripeSubscriptionId stripeSubscriptionId
} }
} }
mutation CreateAuthHandoffToken {
createAuthHandoffToken {
token
expiresInSeconds
}
}
mutation ExchangeAuthHandoffToken($token: String!) {
exchangeAuthHandoffToken(token: $token) {
customToken
userId
}
}

View File

@@ -1072,6 +1072,13 @@ type Mutation {
deleteUser: Boolean! deleteUser: Boolean!
createSubscription(priceId: String!): CreateSubscriptionResultGQL! createSubscription(priceId: String!): CreateSubscriptionResultGQL!
cancelSubscription: UserSubscriptionStatusGQL! cancelSubscription: UserSubscriptionStatusGQL!
submitCancellationFeedback(
reasons: [CancellationReasonEnum!] = null
feedback: String = null
metadata: CancellationFeedbackMetadataInput = null
): Boolean!
createAuthHandoffToken: AuthHandoffTokenGQL!
exchangeAuthHandoffToken(token: String!): ExchangeAuthHandoffResultGQL!
findPrerecordTableLayout(b64Image: String!, videoId: Int!): HomographyInfoGQL findPrerecordTableLayout(b64Image: String!, videoId: Int!): HomographyInfoGQL
createUploadStream( createUploadStream(
videoMetadata: VideoMetadataInput! videoMetadata: VideoMetadataInput!
@@ -1108,7 +1115,7 @@ type AddShotAnnotationReturn {
} }
union SuccessfulAddAddShotAnnotationErrors = union SuccessfulAddAddShotAnnotationErrors =
| SuccessfulAdd SuccessfulAdd
| AddShotAnnotationErrors | AddShotAnnotationErrors
type SuccessfulAdd { type SuccessfulAdd {
@@ -1120,7 +1127,7 @@ type AddShotAnnotationErrors {
} }
union DoesNotOwnShotErrOtherErrorNeedsNote = union DoesNotOwnShotErrOtherErrorNeedsNote =
| DoesNotOwnShotErr DoesNotOwnShotErr
| OtherErrorNeedsNote | OtherErrorNeedsNote
type DoesNotOwnShotErr { type DoesNotOwnShotErr {
@@ -1163,7 +1170,7 @@ type GetProfileUploadLinkReturn {
} }
union UploadLinkGetProfileUploadLinkErrors = union UploadLinkGetProfileUploadLinkErrors =
| UploadLink UploadLink
| GetProfileUploadLinkErrors | GetProfileUploadLinkErrors
type UploadLink { type UploadLink {
@@ -1196,6 +1203,31 @@ type CreateSubscriptionResultGQL {
sessionId: String! sessionId: String!
} }
enum CancellationReasonEnum {
DONT_PLAY_ENOUGH
TOO_EXPENSIVE
MISSING_FEATURES
TECHNICAL_ISSUES
DATA_NOT_ACCURATE
OTHER
}
input CancellationFeedbackMetadataInput {
appVersion: String = null
gitRevision: String = null
platform: String = null
}
type AuthHandoffTokenGQL {
token: String!
expiresInSeconds: Int!
}
type ExchangeAuthHandoffResultGQL {
customToken: String!
userId: Int!
}
type CreateUploadStreamReturn { type CreateUploadStreamReturn {
videoId: Int! videoId: Int!
} }
@@ -1239,7 +1271,7 @@ type GetUploadLinkErrors {
} }
union MustHaveSetForUploadLinkErrSegmentAlreadyUploadedErrProcessingFailedErrNoInitForChunkedUploadErrTooManyProfileImageUploadsErrInitUploadAlreadyCompletedErrTooManyInitUploadsErr = union MustHaveSetForUploadLinkErrSegmentAlreadyUploadedErrProcessingFailedErrNoInitForChunkedUploadErrTooManyProfileImageUploadsErrInitUploadAlreadyCompletedErrTooManyInitUploadsErr =
| MustHaveSetForUploadLinkErr MustHaveSetForUploadLinkErr
| SegmentAlreadyUploadedErr | SegmentAlreadyUploadedErr
| ProcessingFailedErr | ProcessingFailedErr
| NoInitForChunkedUploadErr | NoInitForChunkedUploadErr