diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ccc690fe..8bb2098e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 3.0.3 +### Optimisation: +- Solves n+1 query issue on the `AssetResolver` `resolvedUrls` field resolver, by reusing `storageBagId` field if available. Resulting in faster query times and inpacting home page loading speed for front end application significantly. This fix involves only the `orion_graphql-server` microservice +### Misc +- adds `http://localhost:3000` and `http://127.0.0.1:3000` as authorized CORS origins for local front end testing # 3.0.2 ### Bug Fixes: - Store membership handles both as utf-8 string and raw bytes - [#4950](https://github.com/Joystream/joystream/pull/4950) diff --git a/docs/developer-guide/architecture-overview.md b/docs/developer-guide/architecture-overview.md index bb6ccaa9b..60d334978 100644 --- a/docs/developer-guide/architecture-overview.md +++ b/docs/developer-guide/architecture-overview.md @@ -12,10 +12,10 @@ Most of the services are part of the [Subsquid framework](https://subsquid.io/), - [Polkadot JS](https://polkadot.js.org/docs/) (a set of libraries providing common Substrate utilities) - [TypeORM](https://typeorm.io/#/) (ORM used for interacting with the PostgreSQL database) - [PostgreSQL](https://www.postgresql.org/docs/14/index.html) (database management system) -- [TypeGraphQL](https://typegraphql.com/docs/introduction.html) (TypeScript library used for extening Subsquid's GraphQL API with [custom resolvers](https://docs.subsquid.io/develop-a-squid/graphql-api/custom-resolvers/)) +- [TypeGraphQL](https://typegraphql.com/docs/introduction.html) (TypeScript library used for extending Subsquid's GraphQL API with [custom resolvers](https://docs.subsquid.io/develop-a-squid/graphql-api/custom-resolvers/)) - [Apollo Server](https://www.apollographql.com/docs/apollo-server/) (GraphQL server library used by Subquid) - [Express.js](https://expressjs.com/en/4x/api.html) (http server library used by the [auth server](./tutorials/authentication-api.md)) -- [OpenAPI](https://swagger.io/specification/) (API speification standard used for describing the auth server API) +- [OpenAPI](https://swagger.io/specification/) (API specification standard used for describing the auth server API) - [Express OpenAPI validator](https://github.com/cdimascio/express-openapi-validator/wiki/Documentation) (express middleware used by the auth server) - [Handlebars](https://handlebarsjs.com/guide/) (e-mail templating engine) @@ -80,4 +80,4 @@ The services can be divided into 2 main categories: - `2000000000000-Views.js` - additional migration responsible for splitting the database into a `public` and `admin` schema, where `public` schema only exposes the data that is publically available (through the use of SQL views), while `admin` schema contains the original tables which include private data. For more details see _[Managing entity visibility](./tutorials/entity-visibility.md)_ guide. - `2100000000000-Indexes.js` - additional PostgreSQL indexes (mostly expression indexes on `jsonb` fields, as those are not supported natively by Subsquid). - `2200000000000-Operator.js` - a migration which inserts the initial operator (root) user based on the environment config. For more details, check the _[Authentication API](./tutorials/authentication-api.md)_ guide. - - `/postgres.conf` - contains PostgreSQL database service configuration. \ No newline at end of file + - `/postgres.conf` - contains PostgreSQL database service configuration. diff --git a/docs/developer-guide/code-style.md b/docs/developer-guide/code-style.md index 4803bce8a..6720e815e 100644 --- a/docs/developer-guide/code-style.md +++ b/docs/developer-guide/code-style.md @@ -5,13 +5,13 @@ We're using [ESLint](https://eslint.org/) and [Prettier](https://prettier.io/) t We rely on [GitHub workflows](https://docs.github.com/en/actions/using-workflows/about-workflows) like [this one](../../.github/workflows/checks.yml) to make sure the code is linted and formatted according to the ESLint and Prettier rules when a new pull request is opened. To make sure your code is always properly formatted and linted you can: -- Run `npm run lint --fix && npm run format && git add .` before comitting your changes and pushing them to GitHub. +- Run `npm run lint --fix && npm run format && git add .` before committing your changes and pushing them to GitHub. - Add an extension to your IDE which will automatically lint and format your code upon saving a file (see: [VSCode extension](#vscode-extension)). - Run `npm run checks` to make sure your pull request will pass the linting & formatting check. ## VSCode extension -If you're using VSCode as your IDE, you can install [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) extension and configure it to automatically fromat and lint the code for you each time you save a file inside the Orion workspace. +If you're using VSCode as your IDE, you can install [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) extension and configure it to automatically format and lint the code for you each time you save a file inside the Orion workspace. Once you install the extension you can add following config to the `.vscode/settings.json` file inside the Orion workspace: ```json @@ -20,4 +20,4 @@ Once you install the extension you can add following config to the `.vscode/sett "source.fixAll.eslint": true } } -``` \ No newline at end of file +``` diff --git a/docs/developer-guide/running-local-instance.md b/docs/developer-guide/running-local-instance.md index bbc6c5892..64d9230f6 100644 --- a/docs/developer-guide/running-local-instance.md +++ b/docs/developer-guide/running-local-instance.md @@ -15,7 +15,7 @@ If you need a full local Joystream playground setup which includes: - [Storage node](https://github.com/Joystream/joystream/tree/master/storage-node) - [Distributor node](https://github.com/Joystream/joystream/tree/master/distributor-node) -You can run it in a following way: +You can run it in the following way: ```bash # Clone the Orion repository (if not already done) @@ -50,7 +50,7 @@ yarn start ### Local Orion endpoints -After executing those steps you will be able to access the the local instance of Orion at: +After executing those steps you will be able to access the local instance of Orion at: - http://localhost:4074/playground ([Auth API](./tutorials/authentication-api.md) playground) - http://localhost:4350/graphql (GraphQL API playground) @@ -140,4 +140,4 @@ docker logs --tail 10 -f orion_processor Again, the local Orion API endpoints are going to be the same as those described in the first section ([Local Orion endpoints](#local-orion-endpoints)) -After you're done with the tests you can use either `make down` or `docker-compose down -v` to bring down all Orion services. \ No newline at end of file +After you're done with the tests you can use either `make down` or `docker-compose down -v` to bring down all Orion services. diff --git a/docs/developer-guide/tutorials/adding-custom-queries.md b/docs/developer-guide/tutorials/adding-custom-queries.md index 976165bd2..fa7a5a683 100644 --- a/docs/developer-guide/tutorials/adding-custom-queries.md +++ b/docs/developer-guide/tutorials/adding-custom-queries.md @@ -130,7 +130,7 @@ Here's a step by step process of how you could do that: days!: number } ``` - In this specific case the `ChannelWhereInput` already exists in `src/server-extension/resolvers/baseTypes.ts` and it's definition looks like this: + In this specific case the `ChannelWhereInput` already exists in `src/server-extension/resolvers/baseTypes.ts` and its definition looks like this: ```typescript export const ChannelWhereInput = new GraphQLScalarType({ name: 'ChannelWhereInput', @@ -151,7 +151,7 @@ Here's a step by step process of how you could do that: } ``` Just like in case of `ChannelWhereInput`, the `Channel` [type placeholder](#placeholder-types) in also already defined inside `src/server-extension/resolvers/baseTypes.ts`. -3. Now you can add a new query to the already existing `ChannelsResolver`. The detailed explaination of how it's done is provided in the comments insde the code snippet below: +3. Now you can add a new query to the already existing `ChannelsResolver`. The detailed explanation of how it's done is provided in the comments inside the code snippet below: ```typescript // src/server-extension/resolvers/ChannelsResolver/index.ts import 'reflect-metadata' @@ -175,7 +175,7 @@ Here's a step by step process of how you could do that: @Ctx() ctx: Context ): Promise { // Parse the GraphQL resolve tree (which describes the shape of the result) - // using an untility exposed by `@subsquid/openreader` + // using a utility exposed by `@subsquid/openreader` const tree = getResolveTree(info) // Parse `where` and `limit` args of the query using Subsquid's `parseSqlArguments` utility @@ -278,7 +278,7 @@ Here's a step by step process of how you could do that: } } ``` -4. To test this new query, you can follow a process similar to the one descibed in [Testing new queries](#testing-new-queries) section. For example, you can try executing following queries: +4. To test this new query, you can follow a process similar to the one described in [Testing new queries](#testing-new-queries) section. For example, you can try executing following queries: ```graphql query Top10VideoUploaders30Days { recentlyActiveChannels(days: 30, limit: 10) { @@ -324,6 +324,6 @@ If you're interested in the details of how Subsquid generates the entity queries Behind the scenes, Subsquid uses `mergeSchemas` method from `@graphql-tools/schema` (see: _[Schema Merging](https://the-guild.dev/graphql/tools/docs/schema-merging)_) to merge the schema built from the custom TypeGraphQL resolvers (`src/server-extension/resolvers`) with the schema autogenerated by `@subsquid/openreader` from the [input schema](https://docs.subsquid.io/basics/schema-file/). You can see this process [here](https://github.com/subsquid/squid-sdk/blob/%40subsquid/graphql-server_v3.2.4/graphql-server/src/server.ts#L118). -In the original Subsquid implementation, the schema built from the custom resolvers is merged on top of the autogenerated schema, which means that the types defined in the custom resolvers schema take priority. In the Orion implementation however, we use a [patched version of `@subsquid/graphql-server`](../../../assets/patches/@subsquid+graphql-server+3.3.2.patch) which does the merge the other way around. This means that even if we define a type like `ChannelWhereInput` as a simple scalar in our custom resolvers, it will be overriden by the `ChannelWhereInput` type coming from the schema autogenerated by `@subsquid/openreader`. +In the original Subsquid implementation, the schema built from the custom resolvers is merged on top of the autogenerated schema, which means that the types defined in the custom resolvers schema take priority. In the Orion implementation however, we use a [patched version of `@subsquid/graphql-server`](../../../assets/patches/@subsquid+graphql-server+3.3.2.patch) which does the merge the other way around. This means that even if we define a type like `ChannelWhereInput` as a simple scalar in our custom resolvers, it will be overridden by the `ChannelWhereInput` type coming from the schema autogenerated by `@subsquid/openreader`. -Note however, that the definitions of 2 object types with the same name are merged together (not overriden), so if we create a _placeholder type_ with the same name as one of the autogenerated types, but with a property that doesn't exist in the original, autogenerated type, the autogenerated type will not completely override our placeholder type, but instead our new property will be added to the autogenerated type. \ No newline at end of file +Note however, that the definitions of 2 object types with the same name are merged together (not overridden), so if we create a _placeholder type_ with the same name as one of the autogenerated types, but with a property that doesn't exist in the original, autogenerated type, the autogenerated type will not completely override our placeholder type, but instead our new property will be added to the autogenerated type. diff --git a/docs/developer-guide/tutorials/adding-mutations.md b/docs/developer-guide/tutorials/adding-mutations.md index 209606d97..576aa72c2 100644 --- a/docs/developer-guide/tutorials/adding-mutations.md +++ b/docs/developer-guide/tutorials/adding-mutations.md @@ -1,9 +1,9 @@ ## Adding mutations Adding new mutations is generally similar to [adding custom queries](./adding-custom-queries.md). -The baisc idea is that you add new method to a [custom resolver](https://docs.subsquid.io/graphql-api/custom-resolvers/), decorated with `@Mutation` [TypeGraphQL](https://typegraphql.com/) decorator. +The basic idea is that you add new method to a [custom resolver](https://docs.subsquid.io/graphql-api/custom-resolvers/), decorated with `@Mutation` [TypeGraphQL](https://typegraphql.com/) decorator. -However, usually when thinking about implementing mutations we need to consider the execution context. Most of the mutations will require some specific permissions, for example, they will only be available for the gateway operator or useres with registered accounts. +However, usually when thinking about implementing mutations we need to consider the execution context. Most of the mutations will require some specific permissions, for example, they will only be available for the gateway operator or users with registered accounts. Another important thing to keep in mind when implementing mutations is the [visibility of the entities](./entity-visibility.md). @@ -25,7 +25,7 @@ import { AccountOnly } from '../middleware' @Resolver() export class VideosResolver { - // Set by depenency injection + // Set by dependency injection constructor(private em: () => Promise) {} // ... // Adding this middleware will prevent anyone who doesn't have an account from accessing @@ -54,4 +54,4 @@ export class VideosResolver { }) } } -``` \ No newline at end of file +``` diff --git a/docs/developer-guide/tutorials/adding-new-event-handlers.md b/docs/developer-guide/tutorials/adding-new-event-handlers.md index 64f668027..2191cd495 100644 --- a/docs/developer-guide/tutorials/adding-new-event-handlers.md +++ b/docs/developer-guide/tutorials/adding-new-event-handlers.md @@ -86,7 +86,7 @@ channelById.title = 'New title' overlay.getRepository(Channel).remove(channelById) ``` -It is imporant to understand that although the `overlay` will always provide access to the latest state, you may recieve stale state if you try to query the database directly: +It is important to understand that although the `overlay` will always provide access to the latest state, you may receive stale state if you try to query the database directly: ```typescript overlay.getRepository(Channel).new({ @@ -107,4 +107,4 @@ But this should generally be avoided in event handlers, as it may negate the per ### `MAX_CACHED_ENTITIES` environment variable -You can limit the number of entities that the overlay will store in memory by setting the `MAX_CACHED_ENTITIES` environment variable. Increasing this value too much may cause the processor to run out of memory or result in SQL errors due to queries being too large. \ No newline at end of file +You can limit the number of entities that the overlay will store in memory by setting the `MAX_CACHED_ENTITIES` environment variable. Increasing this value too much may cause the processor to run out of memory or result in SQL errors due to queries being too large. diff --git a/docs/developer-guide/tutorials/authentication-api.md b/docs/developer-guide/tutorials/authentication-api.md index 88d4e740b..a270ba1ce 100644 --- a/docs/developer-guide/tutorials/authentication-api.md +++ b/docs/developer-guide/tutorials/authentication-api.md @@ -3,13 +3,13 @@ - **_Client App_** - the application which uses Orion as a backend, responsible for authenticating the user via the Auth API, - **_Auth API_** - Orion's authentication REST API, separate from the Orion GraphQL API - **_GraphQL API_** - Orion's GraphQL API, exposing all the GraphQL queries and mutations, accessible only by authenticated users, -- **_User_** - any user of the _Client App_ / Orion, regarldess of whether they have a registered Gateway account or not, +- **_User_** - any user of the _Client App_ / Orion, regardless of whether they have a registered Gateway account or not, - **_Anonymous user_** - a user who either doesn't have a Gateway account or is not logged in to a Gateway account and therefore uses [anonymous authentication](#anonymous-auth). -- **_Root user_** - a special kind of a user, typically a gateway operator, with extra privileges to execute certain _GraphQL API_ queries and mutations. It is initially created during database migration step based on the environment variables provided by the gateway administrator. +- **_Root user_** - a special kind of user, typically a gateway operator, with extra privileges to execute certain _GraphQL API_ queries and mutations. It is initially created during database migration step based on the environment variables provided by the gateway administrator. - **_Gateway account owner_** - _User_ that has registered and owns a Gateway account. -- **_Authenticated request_** - a request which inlcudes a valid session cookie (as described [here](#sessions-and-authenticated-requests)) and can therefore be associated with an existing, active session (stored in Orion's database). +- **_Authenticated request_** - a request which includes a valid session cookie (as described [here](#sessions-and-authenticated-requests)) and can therefore be associated with an existing, active session (stored in Orion's database). - **_Authentication request_** - a request to perform the authentication and start a new session (either `POST /login` or `POST /anonymous-auth`). -- **_Gateway account_** - an account that exists in Orion's database and can be logged in to, not to be confused with _Blockchain account_ or _Blockchain membership_. Each _Gateway account_ is associated with exactly one _Blockchain account_ (which can be chnaged via `POST /change-account` endpoint) and exactly one _Blockchain membership_ (which is immutable). +- **_Gateway account_** - an account that exists in Orion's database and can be logged in to, not to be confused with _Blockchain account_ or _Blockchain membership_. Each _Gateway account_ is associated with exactly one _Blockchain account_ (which can be changed via `POST /change-account` endpoint) and exactly one _Blockchain membership_ (which is immutable). - **_Blockchain account_** - an account that exists on the Joystream blockchain and can be identified with an address, such as `j4W7rVcUCxi2crhhjRq46fNDRbVHTjJrz6bKxZwehEMQxZeSf` for example. A _Blockchain account_ can be associated with exactly one _Gateway account_. - **_Blockchain membership_** - a [membership created on a Joystream blockchain](https://handbook.joystream.org/system/memberships), which can be identified with a `handle`. A _Blockchain membership_ can be associated with exactly one _Gateway account_. @@ -17,7 +17,7 @@ Orion's auth API is a REST API, separate from the GraphQL API (the main Orion API), which is being secured by it. -This approach can also be called [_out-of-band_ authenticaiton](https://cloudcity.io/blog/2021/08/22/GraphQL-Authentication-Why-out-of-band-authentication-is-better-than-in-band/), to distinguish it from _in-band_ authentiation, which would be an authentication implemented as part of the same GraphQL api that is being secured by it. +This approach can also be called [_out-of-band_ authenticaiton](https://cloudcity.io/blog/2021/08/22/GraphQL-Authentication-Why-out-of-band-authentication-is-better-than-in-band/), to distinguish it from _in-band_ authentication, which would be an authentication implemented as part of the same GraphQL api that is being secured by it. The Auth API implementation can be found in the [`src/auth-server`](../../../src/auth-server/) directory. @@ -46,7 +46,7 @@ Some example functionality that can be enabled for an _anonymous_ `User`s (not a We may choose not to provide all of those features to _anonymous_ Users, but it should be possible to at least collect the user activity data, which can later be preserved once the user creates an account (and becomes a _gateway account owner_), because of the `User` <=> `Account` association. -**Importat:** `id` of a `User` that has been associated with an `Account` can no longer be used to authenticate as _anonymous user_ (ie. cannot be used for [anonymous authentication](#anonymous-auth))! +**Important:** `id` of a `User` that has been associated with an `Account` can no longer be used to authenticate as _anonymous user_ (ie. cannot be used for [anonymous authentication](#anonymous-auth))! ### `Session` entity @@ -82,7 +82,7 @@ A token has an expiry date which depends on the Orion configuration (see: [Confi Those configuration variables can be set as part of the environment, for more details about config variables see [Config variables](./config-variables.md). -- `OPERATOR_SECRET` - a secret string used as an identifier of the _Root user_, which is created during the database migration step. **Important:** Anyone who knows this secret can authenticate as the _Root user_ (Gateway operator) and access the restriced queries and mutations! +- `OPERATOR_SECRET` - a secret string used as an identifier of the _Root user_, which is created during the database migration step. **Important:** Anyone who knows this secret can authenticate as the _Root user_ (Gateway operator) and access the restricted queries and mutations! - `SESSION_EXPIRY_AFTER_INACTIVITY_MINUTES` - after how many minutes does the session expire in case they are no [authenticated requests](#sessions-and-authenticated-requests) associated with the session being performed. - `SESSION_MAX_DURATION_HOURS` - after how many hours does the session expire regardless of whether there were any recent [authenticated requests](#sessions-and-authenticated-requests) associated with the session performed. - `SENDGRID_API_KEY` - API key for the Sendgrid API, used for sending e-mails to the _Gateway account owners_ by Orion (currently only for the purpose of e-mail confirmation) @@ -118,7 +118,7 @@ It is required that: This basically means that `ip`, `brower`, `os` and `device` should not change during the course of a given session. In case any of those change, a re-authentication is required. -This solution makes it possible to track the activitiy of a given `User` more accurately and adds additional layer of security, as even a stolen session cookie would be useless unless the attacker can make requests from the user's ip. +This solution makes it possible to track the activity of a given `User` more accurately and adds additional layer of security, as even a stolen session cookie would be useless unless the attacker can make requests from the user's ip. ### Session expiry @@ -217,7 +217,7 @@ POST /api/v1/anonymous-auth - `joystreamAccountId` is the address of the keypair generated from `seed` (see step _2._) - `memberId` must be the id of the on-chain membership created in step _3._ (the membership must be already processed by Orion) - `gatewayName` must match the `APP_NAME` environment variable - - `timestamp` must be current timestamp in miliseconds + - `timestamp` must be current timestamp in milliseconds - `action` must be `createAccount` - `email` must be the e-mail provided by the user in step _2._ - `encryptionArtifacts` must be the same as the ones generated in step _2._ @@ -269,10 +269,10 @@ POST /api/v1/anonymous-auth } ``` Where: - - `signature` is a signature over `JSON.stringify(pyaload)` + - `signature` is a signature over `JSON.stringify(payload)` - `joystreamAccountId` is the address of the account from the decrypted seed - `gatewayName` must match the `APP_NAME` environment variable - - `timestamp` must be current timestamp in miliseconds + - `timestamp` must be current timestamp in milliseconds - `action` must be `login` In response you'll get the `accountId` of the logged in account. You can always check the data associated with the logged in account using the [`accountData` GraphQL query](#retrieve-logged-in-gateway-account-data). @@ -301,7 +301,7 @@ In order to do this: You can change the _Blockchain account_ and remove or update _EncryptionArtifacts_ associated with the _Gateway account_ at the same time using [`POST /change-account`](../../../src/auth-server/docs/Apis/DefaultApi.md#change-account) endpoint. -There are 2 main use-cases for this: +There are 2 main use cases for this: 1. **Migrating from password-based authentication to a more secure external signer authentication**: In this case you usually change the _Blockchain account_ and remove the _EncryptionArtifacts_ (ie. not provide the `newArtifacts` field in the request) 2. **Changing the account's password**: In this case you can either change the _EncryptionArtifacts_, but keep the old _Blockchain account_ or change both (in which case you need to migrate the assets and the membership to the new account first) @@ -324,10 +324,10 @@ POST /api/v1/change-account } ``` Where: -- `signature` is a signature over `JSON.stringify(pyaload)` (from the **new** _Blockchain account_) +- `signature` is a signature over `JSON.stringify(payload)` (from the **new** _Blockchain account_) - `joystreamAccountId` is the address of the new _Blockchain account_ (can be the same as the currently used one) - `gatewayName` must match the `APP_NAME` environment variable -- `timestamp` must be current timestamp in miliseconds +- `timestamp` must be current timestamp in milliseconds - `action` must be `changeAccount` - `gatewayAccountId` must be the `accountId` of the logged in _Gateway account_ (as provided by the server in response to `POST /api/v1/login` or `accountData` GraphQL query) - `newArtifacts` optionally, the new _EncryptionArtifacts_ if password-authentication is still being used diff --git a/docs/developer-guide/tutorials/config-variables.md b/docs/developer-guide/tutorials/config-variables.md index ce7c5b4b6..cd8a35d32 100644 --- a/docs/developer-guide/tutorials/config-variables.md +++ b/docs/developer-guide/tutorials/config-variables.md @@ -51,7 +51,7 @@ The process of adding such config variable will consist of the following steps: @Resolver() export class AdminResolver { - // Set by depenency injection + // Set by dependency injection constructor(private em: () => Promise) {} // ... @UseMiddleware(OperatorOnly) @@ -71,4 +71,4 @@ The process of adding such config variable will consist of the following steps: return JSON.stringify(await config.get(ConfigVariable.AllowedCountries, em)) } } - ``` \ No newline at end of file + ``` diff --git a/docs/developer-guide/tutorials/entity-visibility.md b/docs/developer-guide/tutorials/entity-visibility.md index 4f8da04e8..e49a23465 100644 --- a/docs/developer-guide/tutorials/entity-visibility.md +++ b/docs/developer-guide/tutorials/entity-visibility.md @@ -13,7 +13,7 @@ We can generally divide the data stored in Orion's database into 2 categories: For this reason the Orion's database is split into 2 [schemas](https://www.postgresql.org/docs/current/ddl-schemas.html): - `public` schema which includes publically available tables and [database views](https://www.postgresql.org/docs/current/tutorial-views.html) that "override" tables which contain (either in part or in whole) private data. -- `admin` schema which includes the original tables "overriden" by `public` views, along with all the private data. +- `admin` schema which includes the original tables "overridden" by `public` views, along with all the private data. It is very important to be aware of which schema is being used when you're executing queries against the database, otherwise you risk either exposing private data to the public or not being able to access/modify the private data you're supposed to. @@ -34,15 +34,15 @@ The general rules about what schema is being used in which context are as follow - `admin` schema is by default used by Orion's event processor, as it needs to be able to process events related to hidden/censored entities as well. - `admin` schema is also used whenever you use the global entity manager (`globalEm` from `src/utils/globalEm.ts`). - `public` schema is by default used by the GraphQL API, also when you're executing queries from inside the custom GraphQL resolvers (if you use the injected entity manager, ie. `const em = await this.em()`), **unless** the user executing the query / mutation is an authenticated Gateway operator (in which case the `search_path` is set to `admin,public`. This is done by the `requestCheck` function inside `src/server-extension/check.ts`). -- `admin` schema is used when executring queries from inside a function wrapped in `withHiddenEntities` call (`src/utils/sql.ts`) +- `admin` schema is used when executing queries from inside a function wrapped in `withHiddenEntities` call (`src/utils/sql.ts`) ## Managing entity visibility -In order to adjust the visibility of the data, either because you're intoducing new entities / fields or because you'd like to change the existing rules, you can modify the `getViewDefinitions` method in `db/migrations/2000000000000-Views.js`. +In order to adjust the visibility of the data, either because you're introducing new entities / fields or because you'd like to change the existing rules, you can modify the `getViewDefinitions` method in `db/migrations/2000000000000-Views.js`. This method returns an object which maps the database table name to one of the following: - an **array** of `WHERE` conditions that will be applied to the public view of that table. Those `WHERE` conditions are used to filter out the hidden entities from the public view. They will be joined using `AND` operator. In case you wish to hide the whole table, you can set the conditions to `['FALSE']`, which will result in a view that always returns an empty result set. -- a **string** containing the entrie view query in case you need more flexibility. +- a **string** containing the entire view query in case you need more flexibility. Suppose you introduced a new `UserOpinion` entity, which will hold user's feedback about the Gateway. The input schema for this entity may look like this: ```graphql @@ -133,11 +133,11 @@ The result when executing the same query as an authenticated Gateway operator: ### Disabling entity queries -Sometimes you may want to hide the entire entity/table from the public view. In this case you may want the users to get a clear error message (like `Unauthorized`) when they try to execute one of the entitiy queries associated with that entity, instead of just getting an empty result set. +Sometimes you may want to hide the entire entity/table from the public view. In this case you may want the users to get a clear error message (like `Unauthorized`) when they try to execute one of the entity queries associated with that entity, instead of just getting an empty result set. Let's suppose you added a new entity called `UserFeedback` and you wish to hide it completely from the public view. It should only be accessible to authenticated Gateway operators, otherwise all the queries associated with this entity should return `Unauthorized`. -To achive that you should: +To achieve that you should: 1. Add `UserFeedback: ['FALSE']` entry inside `getViewDefinitions` method in `db/migrations/2000000000000-Views.js` file as described above. 2. Update the `autogeneratedOperatorQueries` constant inside `src/server-extension/check.ts` with the names of all the queries that should be disabled for standard users, so usually: ```typescript @@ -150,4 +150,4 @@ To achive that you should: 'userFeedbacks', 'userFeedbacksConnection', ] - ``` \ No newline at end of file + ``` diff --git a/docs/developer-guide/tutorials/preserving-offchain-state.md b/docs/developer-guide/tutorials/preserving-offchain-state.md index 78029f3a8..dc810ed32 100644 --- a/docs/developer-guide/tutorials/preserving-offchain-state.md +++ b/docs/developer-guide/tutorials/preserving-offchain-state.md @@ -4,7 +4,7 @@ We can divide the data stored in Orion's database into 2 categories: - **Chain data**: the data that is a result of processing the Joystream blockchain events. This data, even if lost, can be reconstructed given an archival Joystream node endpoint or a Subsquid archive endpoint. - **Offchain data**: the data specific to a given Gateway, which cannot be reconstructed from the chain data. It includes: categories supported by the Gateway and other Gateway configuration values, video views, channel follows, user accounts, other authentication data etc. -Making changes to the [input schema](./updating-schema.md), intoducing [new event handlers](./adding-new-event-handlers.md) or updating the existing event handlers, will usually require all the Joystream blockchain events to be reprocessed by Orion and the _Chain data_ to be reconstructed from scratch. At the same time, we usually want to preserve the _Offchain data_. +Making changes to the [input schema](./updating-schema.md), introducing [new event handlers](./adding-new-event-handlers.md) or updating the existing event handlers, will usually require all the Joystream blockchain events to be reprocessed by Orion and the _Chain data_ to be reconstructed from scratch. At the same time, we usually want to preserve the _Offchain data_. To support that, Orion provides the `OffchainState` service ([`src/utils/offchainState.ts`](../../../src/utils/offchainState.ts)), which is responsible for exporting and importing the _Offchain data_ during [Orion upgrades](../../operator-guide/tutorials/upgrading-orion.md) which involve event reprocessing. @@ -98,12 +98,12 @@ Suppose that a new release of Orion is coming: `2.3.0` (we're assuming that the ```diff type Session @entity { # ... -- "Operating system (as deterimned based on user-agent header)" +- "Operating system (as determined based on user-agent header)" - os: String! -+ "Operating system name (as deterimned based on user-agent header)" ++ "Operating system name (as determined based on user-agent header)" + osName: String! + -+ "Operating system version (as deterimned based on user-agent header)" ++ "Operating system version (as determined based on user-agent header)" + osVersion: String! } ``` @@ -146,4 +146,4 @@ For example, if the export file has `orionVersion` set to `2.3.0`, the current v '2.3.0': migrateExportDataV230, } ``` -Then the `OffchainState` service will first convert the export data using `migrateExportDataV231` and then run `migrateExportDataV240` on the result of that conversion (`migrateExportDataV230` will be skipped because in this case the export was already made on version `2.3.0`). \ No newline at end of file +Then the `OffchainState` service will first convert the export data using `migrateExportDataV231` and then run `migrateExportDataV240` on the result of that conversion (`migrateExportDataV230` will be skipped because in this case the export was already made on version `2.3.0`). diff --git a/docs/developer-guide/tutorials/releasing.md b/docs/developer-guide/tutorials/releasing.md index 3b0320149..b1459a6a0 100644 --- a/docs/developer-guide/tutorials/releasing.md +++ b/docs/developer-guide/tutorials/releasing.md @@ -2,14 +2,14 @@ When releasing new version of Orion make sure that: 1. All pull requests you wish to include in the release are already merged into the `master` branch. -1. Orion version has been bumped and the `CHANGELOG` file has been updated acording to instructions provided in [_Versioning_](../versioning.md). +1. Orion version has been bumped and the `CHANGELOG` file has been updated according to instructions provided in [_Versioning_](../versioning.md). 1. The `CHANGELOG` clearly states all changes included in the release that: - could break or in some other way significantly affect the behavior of previous versions of Atlas (ie. are affecting the GraphQL API / Auth API), - require additional steps to be taken by the Gateway operators that wish to upgrade to the new version. For example: - introduction of new environment variables or changes to existing environment variables, - changes to database schema that would require the operators to execute non-standard migration steps, - changes to default docker-compose configuration that would require the Operators make adjustments to their current setup. -1. All other documentation has been porperly updated to reflect any significant changes introduced in the release. This includes both this documentation (the [Orion Developer Guide](../index.md)) and the [Orion Operator Guide](../../operator-guide/index.md). +1. All other documentation has been properly updated to reflect any significant changes introduced in the release. This includes both this documentation (the [Orion Developer Guide](../index.md)) and the [Orion Operator Guide](../../operator-guide/index.md). 1. In case of any changes related to environment variables or docker configuration, make sure a PR to update Orion docker setup in the [Joystream monorepo](https://github.com/Joystream/joystream) has been created and merged as well (example: https://github.com/Joystream/joystream/pull/4730) 1. In case any changes are affecting [Offchain data](../tutorials/preserving-offchain-state.md) schema in a non-backward-compatible way, make sure a proper export data migration step was added accordingly to _[Introducing breaking changes to Offchain data schema](../tutorials/preserving-offchain-state.md#introducing-breaking-changes-to-offchain-data-schema)_. @@ -24,4 +24,4 @@ Once all of those conditions are met, you can proceed with [creating a GitHub re ## Updating Orion for Gleev -When updating Orion instance used by the Gleev gateway, you should generally follow _[Upgrading Orion](../../operator-guide/tutorials/upgrading-orion.md)_ tutorial from the Orion Operator Guide. If you notice that any deviations from the standard upgrade process are required, make sure they are mentioned in the release notes as described above. \ No newline at end of file +When updating Orion instance used by the Gleev gateway, you should generally follow _[Upgrading Orion](../../operator-guide/tutorials/upgrading-orion.md)_ tutorial from the Orion Operator Guide. If you notice that any deviations from the standard upgrade process are required, make sure they are mentioned in the release notes as described above. diff --git a/docs/developer-guide/tutorials/supporting-runtime-upgrades.md b/docs/developer-guide/tutorials/supporting-runtime-upgrades.md index 4a7a3fdd8..6a9933d74 100644 --- a/docs/developer-guide/tutorials/supporting-runtime-upgrades.md +++ b/docs/developer-guide/tutorials/supporting-runtime-upgrades.md @@ -1,7 +1,7 @@ # Updating event handlers to support an incoming runtime upgrade Each event handler has to support all versions of a given event. -If there is an incoming runtime upgrade and some exising event signature is going to change (for example, a new field will be added to `Members.MemberRemarked` event), you will need to: +If there is an incoming runtime upgrade and some existing event signature is going to change (for example, a new field will be added to `Members.MemberRemarked` event), you will need to: - Update the `joystream.jsonl` file, - Generate new types (`src/types/events.ts`) using `make typegen`, - Adjust the event handler by adding support for the new version of the event. @@ -59,7 +59,7 @@ In this case, array destructuring works, because `payment` is an optional field ## Possible future runtime upgrade scenario -Now let's imagine a scenario where the runtime is about to be upgraded to a spec version `3000` and the `Members.MemberRemarked` event signature is going to change again. To make things more complex, we won't be introducing a new field, but instead change the type of the exising `payment` field, so that the event signature will now look like this: +Now let's imagine a scenario where the runtime is about to be upgraded to a spec version `3000` and the `Members.MemberRemarked` event signature is going to change again. To make things more complex, we won't be introducing a new field, but instead change the type of the existing `payment` field, so that the event signature will now look like this: ``` MemberRemarked(MemberId, Vec, Vec<(AccountId, Balance)>) ``` @@ -95,4 +95,4 @@ In order to support this change in Orion, you will need to: ``` The processor should now be able to handle all three versions of the event. -**Important:** In case any other existing events were to change during a runtime upgrade to spec version `3000`, you would need to update their corresponding handlers in a similar way! \ No newline at end of file +**Important:** In case any other existing events were to change during a runtime upgrade to spec version `3000`, you would need to update their corresponding handlers in a similar way! diff --git a/package-lock.json b/package-lock.json index 1d54a0c9b..3b555cea1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "orion", - "version": "3.0.1", + "version": "3.0.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "orion", - "version": "3.0.1", + "version": "3.0.2", "hasInstallScript": true, "dependencies": { "@joystream/js": "^1.4.0", diff --git a/package.json b/package.json index 38618f3b1..cd101bc85 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orion", - "version": "3.0.2", + "version": "3.0.3", "engines": { "node": ">=16" }, diff --git a/src/server-extension/resolvers/AssetsResolver/index.ts b/src/server-extension/resolvers/AssetsResolver/index.ts index 7b674131a..7f77aefb5 100644 --- a/src/server-extension/resolvers/AssetsResolver/index.ts +++ b/src/server-extension/resolvers/AssetsResolver/index.ts @@ -1,7 +1,6 @@ import { FieldResolver, Root, ObjectType, Field, Resolver, Ctx } from 'type-graphql' import { EntityManager } from 'typeorm' import { - StorageDataObject as DataObjectEntity, DistributionBucket, DistributionBucketOperatorMetadata, DistributionBucketOperatorStatus, @@ -226,11 +225,20 @@ function getResolvedUrlsLimit(ctx: Context): number { return parseInt(ctx.req.headers['x-asset-urls-limit']?.toString() || '0') } +@ObjectType() +class StorageBag { + @Field() + id!: string +} + @ObjectType() export class StorageDataObject { @Field() id!: string + @Field() + storageBag: StorageBag + @Field(() => [String]) resolvedUrls: string[] } @@ -242,20 +250,19 @@ export class AssetsResolver { @FieldResolver(() => [String]) async resolvedUrls(@Root() object: StorageDataObject, @Ctx() ctx: Context): Promise { - const em = await this.em() + if (!object.storageBag) { + throw new Error( + 'incorrect query: to use resolvedUrls make sure to add storageBag.id into query for StorageDataObject' + ) + } const clientLoc = await getClientLoc(ctx) const limit = await getResolvedUrlsLimit(ctx) // The resolvedUrl field is initially populated with the object ID const [objectId] = object.resolvedUrls - if (!objectId) { - return [] - } - const { storageBagId } = - (await em.getRepository(DataObjectEntity).findOneBy({ id: objectId })) || {} - if (!storageBagId) { + if (!object.storageBag?.id || !objectId) { return [] } - const buckets = await distributionBucketsCache.getBucketsByBagId(storageBagId) + const buckets = await distributionBucketsCache.getBucketsByBagId(object.storageBag.id) const nodes = buckets.flatMap((b) => b.nodes) if (clientLoc) { sortNodesByClosest(nodes, clientLoc) diff --git a/src/utils/auth.ts b/src/utils/auth.ts index 213e879e2..0ed599b3c 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -232,6 +232,8 @@ export function getCorsOrigin(): (RegExp | string)[] | boolean { const corsOrigin = [ `https://${rootDomain}`, + `http://localhost:3000`, + `http://127.0.0.1:3000`, new RegExp(`https://.+\\.${rootDomain.replace('.', '\\.')}$`), ] diff --git a/src/utils/offchainState.ts b/src/utils/offchainState.ts index 6968cbe0c..68cd0a9a1 100644 --- a/src/utils/offchainState.ts +++ b/src/utils/offchainState.ts @@ -78,6 +78,7 @@ export class OffchainState { // destination version : [global counters names] '3.0.1': ['Account'], '3.0.2': ['Account'], + '3.0.3': ['Account'], } private migrations: Migrations = {