Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request headers not being set #836

Open
jahvi opened this issue Dec 11, 2023 · 3 comments
Open

Request headers not being set #836

jahvi opened this issue Dec 11, 2023 · 3 comments
Labels
area:core Issues related to `core`, which is the package that powers the SDKs at runtime bug Something isn't working good first issue Good for newcomers help wanted Extra attention is needed

Comments

@jahvi
Copy link

jahvi commented Dec 11, 2023

After installing my opneapi definitions:

npx api install @hytopia-api-internal/v1.0#1q9bc1r2lorj18va
# or
npx api@next install @hytopia-api-internal/v1.0#1q9bc1r2lorj18va

My TS definitions seem to be generated just fine, this request looks correct on my TS files:

const response = await api.upsertGameReview(
      {
        positive: true,
      },
      {
        gameId: "1234-1234-1234-1234",
        "X-Review-Provider-Key": "SECRET-KEY",
      },
    );

However looking at my API server the X-Review-Provider-Key is not being sent at all, also the X-Authorization header gets ignored as well even though the TS definitions allow it. Making the request through our documentation page in readme.io does work fine though.

Am I doing something wrong or is it a bug?

Edit: I get the same issue generating the SDK with the latest v7 beta branch.

@jahvi
Copy link
Author

jahvi commented Dec 11, 2023

Here's my spec file:
{
    "openapi": "3.0.0",
    "info": {
        "title": "HYTOPIA API",
        "version": "1.0.0",
        "description": "Complete HYTOPIA internal API",
        "termsOfService": "https://hytopia.com",
        "contact": {
            "name": "HYTOPIA Team",
            "email": "[email protected]",
            "url": "https://hytopia.com"
        }
    },
    "servers": [
        {
            "description": "HYTOPIA API Server",
            "url": "https://api.hytopia.com"
        },
        {
            "description": "Local Development Server",
            "url": "http://localhost:8001"
        }
    ],
    "components": {
        "parameters": {
            "headerAuthorizationUser": {
                "name": "X-Authorization",
                "in": "header",
                "description": "The `accessToken` of the authenticating user.",
                "example": "user_at_02z4Mv3c85Ig0gNowY9Dq0N2kjb1xwzr27ArLE0669RrRI6dLf822iPO26K1p1FP",
                "required": true,
                "schema": { "type": "string" }
            },
            "headerAuthorizationUserOptional": {
                "name": "X-Authorization",
                "in": "header",
                "description": "The `accessToken` of the authenticating user.",
                "example": "user_at_02z4Mv3c85Ig0gNowY9Dq0N2kjb1xwzr27ArLE0669RrRI6dLf822iPO26K1p1FP",
                "required": false,
                "schema": { "type": "string" }
            },
            "headerMetricProviderKey": {
                "name": "X-Metric-Provider-Key",
                "in": "header",
                "description": "The authorization key of a metric provider.",
                "example": "A5KHh5/BomXY/dMRG/BDUn7a4=XNP8MKb+5SbBtHWrZu",
                "required": true,
                "schema": { "type": "string" }
            },
            "headerReviewProviderKeyOptional": {
                "name": "X-Review-Provider-Key",
                "in": "header",
                "description": "The authorization key of a review provider.",
                "example": "A5KHh5/BomXY/dMRG/BDUn7a4=XNP8MKb+5SbBtHWrZu",
                "required": false,
                "schema": { "type": "string" }
            },
            "pathUserId": {
                "name": "userId",
                "in": "path",
                "description": "Any user id within the MetaFab platform.",
                "required": true,
                "schema": { "type": "string" }
            },
            "pathUserIdAuthenticated": {
                "name": "userId",
                "in": "path",
                "description": "The user id of the authenticating user.",
                "required": true,
                "schema": { "type": "string" }
            },
            "pathAssetId": {
                "name": "assetId",
                "in": "path",
                "description": "A valid asset id.",
                "required": true,
                "schema": { "type": "string" }
            },
            "pathFriendshipId": {
                "name": "friendshipId",
                "in": "path",
                "description": "A valid friendship id.",
                "required": true,
                "schema": { "type": "string" }
            },
            "pathGameId": {
                "name": "gameId",
                "in": "path",
                "description": "A valid game id.",
                "required": true,
                "schema": { "type": "string" }
            },
            "pathGameReviewId": {
                "name": "gameReviewId",
                "in": "path",
                "description": "A valid game review id.",
                "required": true,
                "schema": { "type": "string" }
            },
            "pathSlugName": {
                "name": "slugName",
                "in": "path",
                "description": "A valid slug name.",
                "required": true,
                "schema": { "type": "string" }
            },
            "queryAccessTokenExpiresAt": {
                "name": "accessTokenExpiresAt",
                "in": "query",
                "description": "An optional unix timestamp in seconds specifying when the returned `accessToken` should expire. If this value is provided, all prior `accessToken` will be invalidated and a new `accessToken` will be issued in the response. If no value is provided, the returned `accessToken` will not expire unless it is invalidated.",
                "example": 1677197460,
                "required": false,
                "schema": { "type": "number" }
            },
            "queryUsername": {
                "name": "username",
                "in": "query",
                "description": "A user username.",
                "example": "arkdev",
                "required": false,
                "schema": { "type": "string" }
            },
            "queryDiscordAuthCode": {
                "name": "discordAuthCode",
                "in": "query",
                "description": "A Discord OAuth 2.0 code.",
                "required": false,
                "schema": { "type": "string" }
            },
            "queryReferrerId": {
                "name": "referrerId",
                "in": "query",
                "description": "A user id representing the referrer.",
                "example": "8beffbb6-1f37-40c8-9656-b0c1097bbf7c",
                "required": false,
                "schema": { "type": "string" }
            },
            "queryResetAccessToken": {
                "name": "resetAccessToken",
                "in": "query",
                "description": "Set this query parameter to `true` to reset accessToken and authorityKey.",
                "example": "true",
                "required": false,
                "schema": { "type": "string" }
            },
            "queryRecaptchaToken": {
                "name": "recaptchaToken",
                "in": "query",
                "description": "A Recaptcha2 token generated client-side by completion of a user-facing recaptcha2 request.",
                "required": true,
                "schema": { "type": "string" }
            },
            "queryFriendshipStatus": {
                "name": "status",
                "in": "query",
                "description": "The type of friendships to return, such as `PENDING`, `ACCEPTED`, `DECLINED` or `BLOCKED`.",
                "schema": { "type": "string" }
            },
            "queryGameLogic": {
                "name": "logic",
                "in": "query",
                "description": "If the games must match all provided filter query parameters (and), or at least 1 filter query parameter to be returned (or). Valid values are: `and`, `or`. Defaults to `or`.",
                "schema": { "type": "string" }
            },
            "queryGameTagIds": {
                "name": "tagIds",
                "in": "query",
                "description": "A comma separated string of tag ids associated with games.",
                "schema": { "type": "string" }
            },
            "queryGameTagNames": {
                "name": "tagNames",
                "in": "query",
                "description": "A comma separated string of tag names associated with games.",
                "schema": { "type": "string" }
            },
            "queryGameSearch": {
                "name": "search",
                "in": "query",
                "description": "A search term used to search games with matching names.",
                "schema": { "type": "string" }
            },
            "queryGameSort": {
                "name": "sort",
                "in": "query",
                "description": "A top level Game column to sort by as well as the direction to sort (asc/desc) that is comma separated. For example: `name,desc`.",
                "schema": { "type": "string" }
            },
            "queryGameLimit": {
                "name": "limit",
                "in": "query",
                "description": "The number of games to return.",
                "schema": { "type": "string" }
            },
            "queryGameCursor": {
                "name": "cursor",
                "in": "query",
                "description": "The last game `id` from previous pagination. Will be excluded from the next \"page\" of results.",
                "schema": { "type": "string" }
            }
        },
        "responses": {
            "400": {
                "description": "An API level error occurred. This is often due to problematic data being provided by you.",
                "content": {
                    "application/json": { "schema": { "type": "string" } }
                }
            },
            "401": {
                "description": "An authorization error occured. This is often due to incorrect tokens or keys being provided, or accessing a resource that the provided tokens or keys do not have access to.",
                "content": {
                    "application/json": { "schema": { "type": "string" } }
                }
            }
        },
        "schemas": {
            "UserModel": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "referrerId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "username": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "email": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "phone": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "discordId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "microsoftId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "twitterId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "accessToken": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "address": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "authorityCiphertext": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "authorityBackupCiphertexts": {
                        "type": "object",
                        "description": "This field has not had a description added."
                    },
                    "authorityProofSignature": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "recoveryQuestions": {
                        "type": "object",
                        "description": "This field has not had a description added."
                    },
                    "verificationCode": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "isCurator": {
                        "type": "boolean",
                        "description": "This field has not had a description added."
                    },
                    "isChild": {
                        "type": "boolean",
                        "description": "This field has not had a description added."
                    },
                    "accessTokenExpiresAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "updatedAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "createdAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    }
                }
            },
            "UserNonceModel": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "userId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "nonce": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "createdAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    }
                }
            },
            "FriendshipModel": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "senderId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "receiverId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "status": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "updatedAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "createdAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    }
                }
            },
            "GameModel": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "submitterId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "ownerId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "iconImageAssetId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "featuredImageAssetId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "galleryMediaAssetIds": {
                        "type": "object",
                        "description": "This field has not had a description added."
                    },
                    "name": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "description": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "host": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "region": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "type": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "websiteUrl": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "discordUrl": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "twitterUrl": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "isPublished": {
                        "type": "boolean",
                        "description": "This field has not had a description added."
                    },
                    "isVerified": {
                        "type": "boolean",
                        "description": "This field has not had a description added."
                    },
                    "lastPlayerCount": {
                        "type": "integer",
                        "description": "This field has not had a description added."
                    },
                    "lastPlayerCapacity": {
                        "type": "integer",
                        "description": "This field has not had a description added."
                    },
                    "lastPlayerCountAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "lastPlayerCapacityAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "updatedAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "createdAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    }
                }
            },
            "GameMetricModel": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "gameId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "name": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "value": {
                        "type": "object",
                        "description": "This field has not had a description added."
                    },
                    "createdAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    }
                }
            },
            "GameReviewModel": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "gameId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "userId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "content": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "positive": {
                        "type": "boolean",
                        "description": "This field has not had a description added."
                    },
                    "ip": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "updatedAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "createdAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    }
                }
            },
            "GameToTagModel": {
                "type": "object",
                "properties": {
                    "gameId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "tagId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "updatedAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "createdAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    }
                }
            },
            "TagModel": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "userId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "name": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "updatedAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "createdAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    }
                }
            },
            "SlugModel": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "userId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "gameId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "name": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "updatedAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "createdAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    }
                }
            },
            "AssetModel": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "userId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "s3Url": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "cdnUrl": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "mime": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "extension": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "checksum": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "size": {
                        "type": "integer",
                        "description": "This field has not had a description added."
                    },
                    "updatedAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "createdAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    }
                }
            },
            "TransactionModel": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "userId": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "address": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "function": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "data": {
                        "type": "object",
                        "description": "This field has not had a description added."
                    },
                    "value": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "hash": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    },
                    "createdAt": {
                        "type": "string",
                        "description": "This field has not had a description added."
                    }
                }
            },
            "AnyValue": {
                "description": "Can be anything. String, number, object, array, boolean, etc."
            }
        },
        "securitySchemes": {
            "basicAuth": { "type": "http", "scheme": "basic" }
        }
    },
    "tags": [
        { "name": "Games", "description": "Game related operations" },
        { "name": "Slugs", "description": "Slug related operations" },
        { "name": "Tags", "description": "Tag related operations" },
        {
            "name": "Transactions",
            "description": "Transaction related operations"
        },
        { "name": "Users", "description": "User related operations" }
    ],
    "paths": {
        "/v1/assets": {
            "get": {
                "operationId": "getAssets",
                "summary": "Get assets",
                "description": "Returns an array of assets that have been uploaded by the authorized user ordered by most recent creation.",
                "tags": ["Assets"],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/headerAuthorizationUser"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Returns an array of asset objects.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "$ref": "#/components/schemas/AssetModel"
                                    }
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" }
                }
            },
            "post": {
                "operationId": "createAsset",
                "summary": "Create asset",
                "description": "Create an asset object by uploading a file in base64. Returns an asset object.",
                "tags": ["Assets"],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/headerAuthorizationUser"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "fileBase64": {
                                        "type": "string",
                                        "description": "The base64 string of the asset being uploaded. Uploads may not exceed 10mb."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Returns a created asset object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AssetModel"
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" }
                }
            }
        },
        "/v1/assets/{assetId}": {
            "get": {
                "operationId": "getAsset",
                "summary": "Get asset",
                "description": "Return an asset object that has been uploaded by the authorized user for the provided assetId.",
                "tags": ["Assets"],
                "parameters": [
                    { "$ref": "#/components/parameters/pathAssetId" },
                    {
                        "$ref": "#/components/parameters/headerAuthorizationUser"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Returns an asset object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/AssetModel"
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" }
                }
            }
        },
        "/v1/friendships": {
            "get": {
                "operationId": "getFriendships",
                "summary": "Get friendships",
                "description": "Returns an array of friendships for the authenticated user.",
                "tags": ["Friendships"],
                "parameters": [
                    { "$ref": "#/components/parameters/queryFriendshipStatus" }
                ],
                "responses": {
                    "200": {
                        "description": "Returns an array of friendship objects.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "allOf": [
                                            {
                                                "$ref": "#/components/schemas/FriendshipModel"
                                            },
                                            {
                                                "type": "object",
                                                "properties": {
                                                    "receiver": {
                                                        "$ref": "#/components/schemas/UserModel"
                                                    },
                                                    "sender": {
                                                        "$ref": "#/components/schemas/UserModel"
                                                    }
                                                }
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" },
                    "401": { "$ref": "#/components/responses/401" }
                }
            },
            "post": {
                "operationId": "createFriendship",
                "summary": "Create friendship",
                "description": "Create a new friendship. If a pending friendship exists between the authorized user as the receiver and target userId as the sender, the pending friendship will be accepted. If no friendship between the two users exists, a new friendship object with the `PENDING` status will be created.",
                "tags": ["Friendships"],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "userId": {
                                        "type": "string",
                                        "description": "The userId of the target user to create a pending friendship with for the authenticated user."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Successfully created a new friendship or returned a relevant existing one. Returns a friendship object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/FriendshipModel"
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" },
                    "401": { "$ref": "#/components/responses/401" }
                }
            }
        },
        "/v1/friendships/{friendshipId}": {
            "patch": {
                "operationId": "updateFriendship",
                "summary": "Update friendship",
                "description": "Update a friendship. Primarily used for altering the status of a pending friendship by the receiver of the friendship. Status can be changed by the receiver to `ACCEPTED`, `DECLINED` or `BLOCKED`",
                "tags": ["Friendships"],
                "parameters": [
                    { "$ref": "#/components/parameters/pathFriendshipId" }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "status": {
                                        "type": "string",
                                        "description": "The status to update this friendship with when the authenticated user is the receiver. Valid values are `ACCEPTED`, `DECLINED` or `BLOCKED`."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Successfully updated a friendship. Returns a friendship object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/FriendshipModel"
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" },
                    "401": { "$ref": "#/components/responses/401" }
                }
            },
            "delete": {
                "operationId": "deleteFriendship",
                "summary": "Delete friendship",
                "description": "Delete a friendship. May be done by the sender or receiver of a friendship regardless of its current status.",
                "tags": ["Friendships"],
                "parameters": [
                    { "$ref": "#/components/parameters/pathFriendshipId" }
                ],
                "responses": {
                    "204": {
                        "description": "Successfully deleted a friendship. Returns an empty response."
                    },
                    "400": { "$ref": "#/components/responses/400" },
                    "401": { "$ref": "#/components/responses/401" }
                }
            }
        },
        "/v1/games": {
            "get": {
                "operationId": "getGames",
                "summary": "Get games",
                "description": "Returns an array of games",
                "tags": ["Games"],
                "parameters": [
                    { "$ref": "#/components/parameters/queryGameLogic" },
                    { "$ref": "#/components/parameters/queryGameTagIds" },
                    { "$ref": "#/components/parameters/queryGameTagNames" },
                    { "$ref": "#/components/parameters/queryGameSearch" },
                    { "$ref": "#/components/parameters/queryGameSort" },
                    { "$ref": "#/components/parameters/queryGameLimit" },
                    { "$ref": "#/components/parameters/queryGameCursor" }
                ],
                "responses": {
                    "200": {
                        "description": "Returns an array of game objects.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "allOf": [
                                            {
                                                "$ref": "#/components/schemas/GameModel"
                                            },
                                            {
                                                "type": "object",
                                                "properties": {
                                                    "iconImageAsset": {
                                                        "$ref": "#/components/schemas/AssetModel"
                                                    },
                                                    "featuredImageAsset": {
                                                        "$ref": "#/components/schemas/AssetModel"
                                                    },
                                                    "tags": {
                                                        "type": "array",
                                                        "items": {
                                                            "$ref": "#/components/schemas/TagModel"
                                                        }
                                                    },
                                                    "slugs": {
                                                        "type": "array",
                                                        "items": {
                                                            "$ref": "#/components/schemas/SlugModel"
                                                        }
                                                    }
                                                }
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" }
                }
            },
            "post": {
                "operationId": "createGame",
                "summary": "Create game",
                "description": "Create a new game. Currently can only be called by users that are marked as `isCurator` in the database.",
                "tags": ["Games"],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/headerAuthorizationUser"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "description": "The display name of the game. Must be at least 3 characters."
                                    },
                                    "description": {
                                        "type": "string",
                                        "description": "The description of the game, supports markdown. Must be at least 20 characters."
                                    },
                                    "slug": {
                                        "type": "string",
                                        "description": "The slug used in the url for seo. Must be a combination of letters, numbers, and/or dashes (-)."
                                    },
                                    "host": {
                                        "type": "string",
                                        "description": "The url/host used to connect to this game or server. Minecraft JAVA/Bedrock or HYTOPIA servers are supported."
                                    },
                                    "region": {
                                        "type": "string",
                                        "description": "An arbitrary field to define a server region (USA, China, etc)"
                                    },
                                    "websiteUrl": {
                                        "type": "string",
                                        "description": "The website url of the game."
                                    },
                                    "discordUrl": {
                                        "type": "string",
                                        "description": "The url to join the discord server of this game."
                                    },
                                    "twitterUrl": {
                                        "type": "string",
                                        "description": "The url of the twitter profile for this game."
                                    },
                                    "isPublished": {
                                        "type": "boolean",
                                        "description": "If the game should be published."
                                    },
                                    "isVerified": {
                                        "type": "boolean",
                                        "description": "If the game is verified."
                                    },
                                    "iconImageAssetId": {
                                        "type": "string",
                                        "description": "The id of an asset the requesting user has uploaded that represents the icon image of the game."
                                    },
                                    "featuredImageAssetId": {
                                        "type": "string",
                                        "description": "The id of an asset the requesting user has uploaded that represents the featured image of the game."
                                    },
                                    "galleryMediaAssetIds": {
                                        "type": "array",
                                        "description": "ids of assets the requesting user has uploaded that represent an image or video shown in the games scrollable gallery of preview media.",
                                        "items": { "type": "string" }
                                    },
                                    "tagIds": {
                                        "type": "array",
                                        "description": "The ids of tags associated with this game. These allow players to filter games by assigned tag, etc.",
                                        "items": { "type": "string" }
                                    }
                                },
                                "required": [
                                    "name",
                                    "description",
                                    "host",
                                    "region",
                                    "iconImageAssetId"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Successfully created a new game. Returns a game object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/GameModel"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "iconImageAsset": {
                                                    "$ref": "#/components/schemas/AssetModel"
                                                },
                                                "featuredImageAsset": {
                                                    "$ref": "#/components/schemas/AssetModel",
                                                    "nullable": true
                                                },
                                                "tags": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/TagModel"
                                                    }
                                                },
                                                "slugs": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/SlugModel"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" },
                    "401": { "$ref": "#/components/responses/401" }
                }
            }
        },
        "/v1/games/{gameId}": {
            "get": {
                "operationId": "getGame",
                "summary": "Get game",
                "description": "Returns a detailed game object that includes galleryMediaAssets.",
                "tags": ["Games"],
                "parameters": [
                    { "$ref": "#/components/parameters/pathGameId" }
                ],
                "responses": {
                    "200": {
                        "description": "Returns a game object that includes galleryMediaAssets",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/GameModel"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "iconImageAsset": {
                                                    "$ref": "#/components/schemas/AssetModel"
                                                },
                                                "featuredImageAsset": {
                                                    "$ref": "#/components/schemas/AssetModel",
                                                    "nullable": true
                                                },
                                                "galleryMediaAssets": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/AssetModel"
                                                    }
                                                },
                                                "tags": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/TagModel"
                                                    }
                                                },
                                                "slugs": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/SlugModel"
                                                    }
                                                },
                                                "metrics": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/GameMetricModel"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" }
                }
            },
            "patch": {
                "operationId": "updateGame",
                "summary": "Update game",
                "description": "Update various fields specific to a game.",
                "tags": ["Games"],
                "parameters": [
                    { "$ref": "#/components/parameters/pathGameId" },
                    {
                        "$ref": "#/components/parameters/headerAuthorizationUser"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "description": "The display name of the game. Must be at least 3 characters."
                                    },
                                    "description": {
                                        "type": "string",
                                        "description": "The description of the game, supports markdown. Must be at least 20 characters."
                                    },
                                    "slug": {
                                        "type": "string",
                                        "description": "The slug used in the url for seo. Must be a combination of letters, numbers, and/or dashes (-)."
                                    },
                                    "host": {
                                        "type": "string",
                                        "description": "The url/host used to connect to this game or server. Minecraft JAVA/Bedrock or HYTOPIA servers are supported."
                                    },
                                    "region": {
                                        "type": "string",
                                        "description": "An arbitrary field to define a server region (USA, China, etc)"
                                    },
                                    "websiteUrl": {
                                        "type": "string",
                                        "description": "The website url of the game."
                                    },
                                    "discordUrl": {
                                        "type": "string",
                                        "description": "The url to join the discord server of this game."
                                    },
                                    "twitterUrl": {
                                        "type": "string",
                                        "description": "The url of the twitter profile for this game."
                                    },
                                    "isPublished": {
                                        "type": "boolean",
                                        "description": "If the game is published or not."
                                    },
                                    "isVerified": {
                                        "type": "boolean",
                                        "description": "If the game is verified or not."
                                    },
                                    "iconImageAssetId": {
                                        "type": "string",
                                        "description": "The id of an asset the requesting user has uploaded that represents the icon image of the game."
                                    },
                                    "featuredImageAssetId": {
                                        "type": "string",
                                        "description": "The id of an asset the requesting user has uploaded that represents the featured image of the game."
                                    },
                                    "galleryMediaAssetIds": {
                                        "type": "array",
                                        "description": "ids of assets the requesting user has uploaded that represent an image or video shown in the games scrollable gallery of preview media. Provided galleryMediaAssetIds will overwrite all existing galleryMedaiAssets.",
                                        "items": { "type": "string" }
                                    },
                                    "tagIds": {
                                        "type": "array",
                                        "description": "The ids of tags associated with this game. These allow players to filter games by assigned tag, etc. Provided tagIds will overwrite all existings tags.",
                                        "items": { "type": "string" }
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Returns the updated user object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/GameModel"
                                        },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "iconImageAsset": {
                                                    "$ref": "#/components/schemas/AssetModel"
                                                },
                                                "featuredImageAsset": {
                                                    "$ref": "#/components/schemas/AssetModel",
                                                    "nullable": true
                                                },
                                                "tags": {
                                                    "type": "array",
                                                    "items": {
                                                        "$ref": "#/components/schemas/TagModel"
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" },
                    "401": { "$ref": "#/components/responses/401" }
                }
            }
        },
        "/v1/games/{gameId}/metrics": {
            "post": {
                "operationId": "createGameMetric",
                "summary": "Create game metric",
                "description": "Creates a game metric for the game associated with the provided gameId. Game metrics track game historical data like player counts over time and more.",
                "tags": ["Games"],
                "parameters": [
                    { "$ref": "#/components/parameters/pathGameId" },
                    {
                        "$ref": "#/components/parameters/headerMetricProviderKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "description": "The name of the metric, For example, `PLAYER_COUNT`."
                                    },
                                    "value": {
                                        "description": "A value tied to this specific metric. Type is metric dependent."
                                    }
                                },
                                "required": ["name", "value"]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Successfully created a new game metric. Returns a game metric object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GameMetricModel"
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" },
                    "401": { "$ref": "#/components/responses/401" }
                }
            }
        },
        "/v1/games/{gameId}/reviews": {
            "get": {
                "operationId": "getGameReviews",
                "summary": "Get game reviews",
                "description": "Get user reviews specific to a game.",
                "tags": ["Games"],
                "parameters": [
                    { "$ref": "#/components/parameters/pathGameId" }
                ],
                "responses": {
                    "200": {
                        "description": "Returns an array of game review objects.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "$ref": "#/components/schemas/GameReviewModel"
                                    }
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" }
                }
            },
            "post": {
                "operationId": "upsertGameReview",
                "summary": "Upsert game review",
                "description": "Create or update (upsert) a game review for the game associated with the provided gameId. A user or ip can submit 1 review per game, per 24 hours. This means a user may have multiple reviews for the same game. If a review exists in the last 24 hours for a matching user or user-less ip, it will updated instead of created. If a review provider submits the review, a unique ip of the reviewer must be included.",
                "tags": ["Games"],
                "parameters": [
                    { "$ref": "#/components/parameters/pathGameId" },
                    {
                        "$ref": "#/components/parameters/headerAuthorizationUserOptional"
                    },
                    {
                        "$ref": "#/components/parameters/headerReviewProviderKeyOptional"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "content": {
                                        "type": "string",
                                        "description": "The text content of the user review."
                                    },
                                    "positive": {
                                        "type": "boolean",
                                        "description": "Whether the user says this is a positive (true) review, or negative (false) review."
                                    },
                                    "ip": {
                                        "type": "string",
                                        "description": "The IP address of the reviewer. Must be provided if the review is submitted by an authorized review provider."
                                    }
                                },
                                "required": ["positive"]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Successfully created a new game review. Returns a game review object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GameReviewModel"
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" },
                    "401": { "$ref": "#/components/responses/401" }
                }
            }
        },
        "/v1/games/{gameId}/review/{gameReviewId}": {
            "patch": {
                "operationId": "updateGameReview",
                "summary": "Update game review",
                "description": "Update various fields specific to a game review.",
                "tags": ["Games"],
                "parameters": [
                    { "$ref": "#/components/parameters/pathGameId" },
                    { "$ref": "#/components/parameters/pathGameReviewId" },
                    {
                        "$ref": "#/components/parameters/headerAuthorizationUser"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "content": {
                                        "type": "string",
                                        "description": "The text content of the user review."
                                    },
                                    "positive": {
                                        "type": "boolean",
                                        "description": "Whether the user says this is a positive (true) review, or negative (false) review."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Successfully updated a game review. Returns the updated game review object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/GameReviewModel"
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" },
                    "401": { "$ref": "#/components/responses/401" }
                }
            }
        },
        "/v1/games/{gameId}/reviews/{gameReviewId}": {
            "delete": {
                "operationId": "deleteGameReview",
                "summary": "Delete game review",
                "description": "Delete a game review.",
                "tags": ["Games"],
                "parameters": [
                    { "$ref": "#/components/parameters/pathGameId" },
                    { "$ref": "#/components/parameters/pathGameReviewId" },
                    {
                        "$ref": "#/components/parameters/headerAuthorizationUser"
                    }
                ],
                "responses": {
                    "204": {
                        "description": "Successfully deleted a game review."
                    },
                    "400": { "$ref": "#/components/responses/400" },
                    "401": { "$ref": "#/components/responses/401" }
                }
            }
        },
        "/v1/slugs/{slugName}": {
            "get": {
                "operationId": "getSlug",
                "summary": "Get slug",
                "description": "Return a slug object retrieved by name. Slugs are used to attach plaintext name associations with specific resources, like games. This allows the creation of URL formats that include a slug like \"rpg-minecraft-heros\" for a game's url, and allows a frontend to pull the associate game id through this endpoint, to then use to retrieve the game.",
                "tags": ["Slugs"],
                "parameters": [
                    { "$ref": "#/components/parameters/pathSlugName" }
                ],
                "responses": {
                    "200": {
                        "description": "Returns a slug object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SlugModel"
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" }
                }
            }
        },
        "/v1/tags": {
            "get": {
                "operationId": "getTags",
                "summary": "Get tags",
                "description": "Returns an array of tags. These are currently used by games but may be used elsewhere in the future.",
                "tags": ["Tags"],
                "responses": {
                    "200": {
                        "description": "Returns an array of tags.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "allOf": [
                                            {
                                                "$ref": "#/components/schemas/TagModel"
                                            },
                                            {
                                                "type": "object",
                                                "properties": {
                                                    "gamesCount": {
                                                        "type": "number"
                                                    }
                                                }
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" }
                }
            },
            "post": {
                "operationId": "createTag",
                "summary": "Create tag",
                "description": "Create a new tag. Tags currently can be assigned to games by games, but may be assignable to other things in the future as well.",
                "tags": ["Tags"],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/headerAuthorizationUser"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "description": "The name of the tag"
                                    }
                                },
                                "required": ["name"]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Successfully created a new tag. Returns a tag object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TagModel"
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" }
                }
            }
        },
        "/v1/transactions": {
            "get": {
                "operationId": "getTransactions",
                "summary": "Get transactions",
                "description": "Returns an array of chronologically ordered transaction objects for the authenticated user.",
                "tags": ["Transactions"],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/headerAuthorizationUser"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Returns an array of transaction object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "array",
                                    "items": {
                                        "$ref": "#/components/schemas/TransactionModel"
                                    }
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" }
                }
            },
            "post": {
                "operationId": "createTransaction",
                "summary": "Create transaction",
                "description": "Create a new transaction on behalf of the user. HYTOPIAs central relayer takes care of covering gas costs. If you exclude the `func` argument, a standard transfer will be assumed and attempted based on the `value` provided.",
                "tags": ["Transactions"],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/headerAuthorizationUser"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "chainName": {
                                        "type": "string",
                                        "description": "The blockchain to submit the transaction to.",
                                        "enum": ["HYTOPIA", "HYTOPIATESTNET"]
                                    },
                                    "functionName": {
                                        "type": "string",
                                        "description": "The complete function name used to derive the function selector of the transaction. Such as `transfer(address,uint256)`."
                                    },
                                    "callRequest": {
                                        "type": "object",
                                        "description": "The callRequest object defining the transaction to execute. This should be generated by the `hytopia-crypto-js` library.",
                                        "properties": {
                                            "target": {
                                                "type": "string",
                                                "description": "The EOA or contract address target for this transaction."
                                            },
                                            "value": {
                                                "type": "string",
                                                "description": "The amount of $TOPIA in WEI notation to send with this transaction."
                                            },
                                            "nonce": {
                                                "type": "string",
                                                "description": "An arbitrary nonce generated for this transaction."
                                            },
                                            "data": {
                                                "type": "string",
                                                "description": "The calldata of the transaction. If performing a standard transfer, simply set to `0x`."
                                            }
                                        },
                                        "required": ["target", "nonce", "data"]
                                    },
                                    "callRequestSignature": {
                                        "type": "string",
                                        "description": "A signature generated using the private key for the user's authority address. This should be generated by the `hytopia-crypto-js` library."
                                    }
                                },
                                "required": [
                                    "chainName",
                                    "callRequest",
                                    "callRequestSignature"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Successfully created and confirmed a new transaction. Returns a transaction object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/TransactionModel"
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" }
                }
            }
        },
        "/v1/users": {
            "get": {
                "operationId": "getUsers",
                "summary": "Get users",
                "description": "Returns an array of users matching the provided query parameter filters, or a count of total users if no query parameters provided.",
                "tags": ["Users"],
                "parameters": [
                    { "$ref": "#/components/parameters/queryUsername" }
                ],
                "responses": {
                    "200": {
                        "description": "Returns an array of public user objects.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "type": "array",
                                            "items": { "type": "object" }
                                        },
                                        { "type": "number" }
                                    ]
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" }
                }
            },
            "post": {
                "operationId": "createUser",
                "summary": "Create user",
                "description": "Create a new user. User greedily has their SCA wallet computed prior to deployment using create2 calculation. This is assigned to the `address` property of the returned user object.",
                "tags": ["Users"],
                "parameters": [
                    { "$ref": "#/components/parameters/queryRecaptchaToken" },
                    { "$ref": "#/components/parameters/queryReferrerId" },
                    {
                        "$ref": "#/components/parameters/queryAccessTokenExpiresAt"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "username": {
                                        "type": "string",
                                        "description": "The users username, used to authenticate the user and represent them in-game. Usernames are unique. There cannot be 2 users with the same username. Required if registering using an email. Not required if using a social auth method like Discord or Microsoft - in this case the backend will auto determine a suitable username based on the social account."
                                    },
                                    "email": {
                                        "type": "string",
                                        "description": "An email address assigned to the user account. Used to send their 2fa login code, account updates, etc.",
                                        "example": "[email protected]"
                                    },
                                    "phone": {
                                        "type": "number",
                                        "description": "A phone number assigned to the user account. Used to send their 2fa login code, account updates, etc.",
                                        "example": 12534351231
                                    },
                                    "authorityAddress": {
                                        "type": "string",
                                        "description": "The wallet address associated with the private key used to generate the authorityProofSignature. This should be generated by the `hytopia-crypto-js` library."
                                    },
                                    "authorityCiphertext": {
                                        "type": "string",
                                        "description": "The encrypted ciphertext of the private key associated with the provided authorityAddress. This should be generated by the `hytopia-crypto-js` library."
                                    },
                                    "authorityBackupCodeCiphertext": {
                                        "type": "string",
                                        "description": "The encrypted ciphertext for backup recovery of a private key using a randomly generated code on the player's client. This should be generated by the `hytopia-crypto-js` library."
                                    },
                                    "authorityBackupQuestionsCiphertext": {
                                        "type": "string",
                                        "description": "The encrypted ciphertext for backup recovery of a private key using the concatenated answers to the player's recovery questions. This includes the recovery questions and backup code ciphertexts. This should be generated by the `hytopia-crypto-js` library."
                                    },
                                    "authorityProofSignature": {
                                        "type": "string",
                                        "description": "The proof signature required for deferred smart contract account creation. This should be generated by the `hytopia-crypto-js` library."
                                    },
                                    "salt": {
                                        "type": "string",
                                        "description": "An arbitrary salt used by the player's client along with their client-side provided password to derive a PBKDF2 key for decrypting their authority wallet's private key."
                                    },
                                    "recoveryQuestions": {
                                        "type": "array",
                                        "description": "An array of any arbitrary questions to display to the user when going through account recovery."
                                    },
                                    "isChild": {
                                        "type": "boolean",
                                        "description": "A true or false value indicating if a child is younger than 13 (true), or older (false)."
                                    },
                                    "discordAuthCode": {
                                        "type": "string",
                                        "description": "An auth `code` returned from the Discord oauth2 flow. Used as an alternative account registration method."
                                    },
                                    "microsoftAuthCode": {
                                        "type": "string",
                                        "description": "An auth `code` returned from the Microsoft oauth2 flow. Used as an alternative account registration method."
                                    },
                                    "twitterAuthCode": {
                                        "type": "string",
                                        "description": "An auth `code` returned from the Twitter oauth2 flow. Used as an alternative account registration method."
                                    }
                                },
                                "required": [
                                    "authorityAddress",
                                    "authorityCiphertext",
                                    "authorityProofSignature",
                                    "salt"
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Successfully created a new user. Returns a user object that excludes accessToken. Sends a verification code to the email or phone number associated with the account. A user access token must be retrieved by using the GET /v1/users/auth endpoint with the received verificationCode, this is required to finish the user auth process for new users.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/UserModel"
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" }
                }
            }
        },
        "/v1/users/{userId}": {
            "patch": {
                "operationId": "updateUser",
                "summary": "Update user",
                "description": "Update various fields specific to a user.",
                "tags": ["Users"],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/pathUserIdAuthenticated"
                    },
                    {
                        "$ref": "#/components/parameters/headerAuthorizationUser"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "email": {
                                        "type": "string",
                                        "description": "A valid, unique email address that is not currently assigned to another account."
                                    },
                                    "phone": {
                                        "type": "string",
                                        "description": "A valid, unique phone number that is not currently assigned to another account."
                                    },
                                    "authorityAddress": {
                                        "type": "string",
                                        "description": "The wallet address associated with the private key used to generate the authorityProofSignature. This should be generated by the `hytopia-crypto-js` library. 1-time assignment, intended for setting of preregistration accounts."
                                    },
                                    "authorityCiphertext": {
                                        "type": "string",
                                        "description": "The encrypted ciphertext of the private key associated with the provided authorityAddress. This should be generated by the `hytopia-crypto-js` library. 1-time assignment, intended for setting of preregistration accounts."
                                    },
                                    "authorityBackupCodeCiphertext": {
                                        "type": "string",
                                        "description": "A ciphertext from encrypting a players authority private key with an arbitrary backup code generated and store on their client."
                                    },
                                    "authorityBackupQuestionsCiphertext": {
                                        "type": "string",
                                        "description": "A ciphertext from encrypting a players authority private key with the concatenanted answers to their recovery questions."
                                    },
                                    "authorityProofSignature": {
                                        "type": "string",
                                        "description": "The proof signature required for deferred smart contract account creation. This should be generated by the `hytopia-crypto-js` library. 1-time assignment, intended for setting of preregistration accounts."
                                    },
                                    "salt": {
                                        "type": "string",
                                        "description": "An arbitrary salt used by the player's client along with their client-side provided password to derive a PBKDF2 key for decrypting their authority wallet's private key. 1-time assignment, intended for setting of preregistration accounts."
                                    },
                                    "recoveryQuestions": {
                                        "type": "array",
                                        "description": "An array of any arbitrary questions to display to the user when going through account recovery.",
                                        "items": { "type": "string" }
                                    },
                                    "isChild": {
                                        "type": "boolean",
                                        "description": "A true or false value indicating if a child is younger than 13 (true), or older (false)."
                                    },
                                    "resetAccessToken": {
                                        "type": "boolean",
                                        "description": "Revokes the user's current access token and returns a new one if true."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Returns the updated user object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/UserModel"
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" },
                    "401": { "$ref": "#/components/responses/401" }
                }
            }
        },
        "/v1/users/auth": {
            "get": {
                "operationId": "verifyUserAuth",
                "summary": "Verify user authentication",
                "description": "Returns an existing user object containing access token, authority key, and other details when provided a Discord auth code or a username and verification code using Basic Auth.",
                "tags": ["Users"],
                "parameters": [
                    {
                        "$ref": "#/components/parameters/queryAccessTokenExpiresAt"
                    },
                    { "$ref": "#/components/parameters/queryResetAccessToken" },
                    { "$ref": "#/components/parameters/queryDiscordAuthCode" }
                ],
                "security": [{ "basicAuth": [] }, {}],
                "responses": {
                    "200": {
                        "description": "Successfully authorized the user and returns a user object.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/UserModel"
                                }
                            }
                        }
                    },
                    "400": { "$ref": "#/components/responses/400" },
                    "401": { "$ref": "#/components/responses/401" }
                }
            },
            "post": {
                "operationId": "startUserAuth",
                "summary": "Start user authentication",
                "description": "Send a verification code to the user's associated email address for their account. This code should be used with verifyUserAuth to finalize account authentication.",
                "tags": ["Users"],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "properties": {
                                    "email": {
                                        "type": "string",
                                        "description": "The email address of the user account."
                                    },
                                    "username": {
                                        "type": "string",
                                        "description": "The username of the user account."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "204": {
                        "description": "Successfully started user auth and sent a verification code to the user's associated email for their account."
                    },
                    "400": { "$ref": "#/components/responses/400" },
                    "401": { "$ref": "#/components/responses/401" }
                }
            }
        }
    }
}

@jahvi
Copy link
Author

jahvi commented Dec 12, 2023

After some debugging looks like the problem was that the SDK was lowercasing the headers but the spec expected it as mixed case (eg: x-authorization vs X-Authorization), so I worked around this by lowercasing all my headers in my spec.

I'm not sure if it's still an issue though, headers should be case insensitive so it should work either way.

@erunion erunion added bug Something isn't working help wanted Extra attention is needed good first issue Good for newcomers area:core Issues related to `core`, which is the package that powers the SDKs at runtime labels Dec 19, 2023
@thetrevdev
Copy link

This is still an issue when using a third party spec. None of the headers get sent if their spec has the headers as anything but lower case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:core Issues related to `core`, which is the package that powers the SDKs at runtime bug Something isn't working good first issue Good for newcomers help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants