fastify#FastifyInstance TypeScript Examples

The following examples show how to use fastify#FastifyInstance. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: test-utils.ts    From cardano-rosetta with Apache License 2.0 7 votes vote down vote up
setupServer = (database: Pool, disableSearchApi = false): FastifyInstance => {
  // let repositories;
  const repositories = Repositories.configure(database);
  const services = Services.configure(
    repositories,
    NETWORK_ID,
    // eslint-disable-next-line no-magic-numbers
    1097911063,
    JSON.parse(fs.readFileSync(path.resolve(process.env.TOPOLOGY_FILE_PATH)).toString()),
    Number(process.env.DEFAULT_RELATIVE_TTL)
  );
  return buildServer(services, cardanoCliMock, cardanoNodeMock, process.env.LOGGER_LEVEL, {
    networkId: NETWORK_ID,
    pageSize: Number(process.env.PAGE_SIZE) || DEFAULT_PAGE_SIZE,
    mock: true,
    disableSearchApi
  });
}
Example #2
Source File: utils.ts    From fastify-sse-v2 with MIT License 7 votes vote down vote up
export async function getFastifyServer(source: AsyncIterable<EventMessage>): Promise<FastifyInstance> {
  const server = fastify();
  server.register(FastifySSEPlugin);
  server.get("/", function (req, res) {
    res.header("x-test-header2", "test2");
    res.sse(source);
  });
  await server.ready();
  await new Promise<void>((resolve, reject) => {
    server.listen(0, "127.0.0.1", (err) => {
      if(err) {
        return reject(err);
      }
      resolve();
    });
  });
  return server;
}
Example #3
Source File: getBucket.ts    From storage-api with Apache License 2.0 6 votes vote down vote up
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export default async function routes(fastify: FastifyInstance) {
  const summary = 'Get details of a bucket'
  const schema = createDefaultSchema(successResponseSchema, {
    params: getBucketParamsSchema,
    summary,
    tags: ['bucket'],
  })
  fastify.get<getBucketRequestInterface>(
    '/:bucketId',
    {
      schema,
    },
    async (request, response) => {
      const { bucketId } = request.params
      const {
        data: results,
        error,
        status,
      } = await request.postgrest
        .from<Bucket>('buckets')
        .select('id, name, owner, public, created_at, updated_at')
        .eq('id', bucketId)
        .single()

      if (error) {
        request.log.error({ error, bucketId }, 'failed to retrieve bucket info')
        return response.status(400).send(transformPostgrestError(error, status))
      }
      request.log.info({ results }, 'results')

      response.send(results)
    }
  )
}
Example #4
Source File: netowork-status-api.test.ts    From cardano-rosetta with Apache License 2.0 6 votes vote down vote up
describe('/network/status endpoint', () => {
  let database: Pool;
  let server: FastifyInstance;
  beforeAll(async () => {
    database = setupDatabase();
    server = setupServer(database);
  });

  afterAll(async () => {
    await database.end();
  });

  // eslint-disable-next-line max-len
  test('If requested with valid payload, it should properly return an object containing proper status information', async () => {
    const response = await server.inject({
      method: 'post',
      url: NETWORK_STATUS_ENDPOINT,
      payload: generateNetworkPayload(CARDANO, MAINNET)
    });
    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json().genesis_block_identifier).toEqual(genesis_block_identifier);
    expect(response.json().current_block_identifier).toEqual(latestBlockIdentifier);
    expect(response.json().peers).toEqual(peers);
  });

  testInvalidNetworkParameters(
    NETWORK_STATUS_ENDPOINT,
    (blockchain, network) => generateNetworkPayload(blockchain, network),
    () => server
  );
});
Example #5
Source File: ipLocate.ts    From iplocate with MIT License 6 votes vote down vote up
ipLocate = async (fastify: FastifyInstance) => {
  fastify.get<SearchRequest>("/search", opts, (request, reply) => {
    const { ip } = request.query;
    const reader = getReader();
    const cityInfo = reader.city(ip);
    reply.send(cityInfo);
  });

  fastify.get("/health", {}, (_, reply) => {
    const reader = getReader();
    const cityInfo = reader.city("8.8.8.8");
    const country = emptyToPartial<CountryRecord>(cityInfo.country);
    reply.status(country ? 200 : 500);
    reply.send();
  });
}
Example #6
Source File: outputSchema.ts    From mercurius-typescript with MIT License 6 votes vote down vote up
export async function writeOutputSchema(
  app: FastifyInstance,
  config: string | boolean
) {
  if (!config) return

  let targetPath: string
  if (typeof config === 'boolean') {
    targetPath = resolve('./schema.gql')
  } else {
    targetPath = resolve(config)
  }

  const { printSchemaWithDirectives } = await import('@graphql-tools/utils')

  const schema = await formatPrettier(
    printSchemaWithDirectives(app.graphql.schema),
    'graphql'
  )

  await writeFileIfChanged(targetPath, schema)
}
Example #7
Source File: getAllBuckets.ts    From storage-api with Apache License 2.0 6 votes vote down vote up
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export default async function routes(fastify: FastifyInstance) {
  const summary = 'Gets all buckets'
  const schema = createDefaultSchema(successResponseSchema, {
    summary,
    tags: ['bucket'],
  })

  fastify.get<AuthenticatedRequest>(
    '/',
    {
      schema,
    },
    async (request, response) => {
      // get list of all buckets
      const {
        data: results,
        error,
        status,
      } = await request.postgrest
        .from<Bucket>('buckets')
        .select('id, name, public, owner, created_at, updated_at')

      if (error) {
        request.log.error({ error }, 'error bucket')
        return response.status(400).send(transformPostgrestError(error, status))
      }
      request.log.info({ results }, 'results')

      response.send(results)
    }
  )
}
Example #8
Source File: app.ts    From one-platform with MIT License 6 votes vote down vote up
fastifyAppClosePlugin = (app: FastifyInstance): ApolloServerPlugin => {
  return {
    async serverWillStart() {
      return {
        async drainServer() {
          await app.close();
        },
      };
    },
  };
}
Example #9
Source File: index.ts    From storage-api with Apache License 2.0 6 votes vote down vote up
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export default async function routes(fastify: FastifyInstance) {
  fastify.register(jwt)
  fastify.register(postgrest)

  fastify.register(createBucket)
  fastify.register(emptyBucket)
  fastify.register(getAllBuckets)
  fastify.register(getBucket)
  fastify.register(updateBucket)

  fastify.register(async (fastify) => {
    fastify.register(superUserPostgrest)

    fastify.register(deleteBucket)
  })
}
Example #10
Source File: index.ts    From fastify-now with MIT License 6 votes vote down vote up
function addRequestHandler(
  module: { [key in HTTPMethod]: NowRequestHandler },
  method: HTTPMethod,
  server: FastifyInstance,
  fileRouteServerPath: string,
) {
  const handler = module[method.toUpperCase()] as NowRequestHandler;
  if (handler) {
    server.log.debug(`${method.toUpperCase()} ${fileRouteServerPath}`);
    server[method](fileRouteServerPath, handler.opts || {}, handler);
  }
}
Example #11
Source File: app.ts    From one-platform with MIT License 6 votes vote down vote up
function fastifyAppClosePlugin(app: FastifyInstance): ApolloServerPlugin {
  return {
    async serverWillStart() {
      return {
        async drainServer() {
          await app.close();
        },
      };
    },
  };
}
Example #12
Source File: utils.ts    From fastify-sse-v2 with MIT License 6 votes vote down vote up
export function getBaseUrl(fastifyInstance: FastifyInstance): string {
  const address = fastifyInstance.server.address() as AddressInfo;
  return `http://${address.address}:${address.port}`;
}
Example #13
Source File: graphql.spec.ts    From nestjs-mercurius with MIT License 6 votes vote down vote up
graphqlSuite.before.each(async (ctx) => {
  const module = await Test.createTestingModule({
    imports: [ApplicationModule],
  }).compile();

  const app = module.createNestApplication<NestFastifyApplication>(
    new FastifyAdapter(),
  );

  await app.init();
  const fastify: FastifyInstance = app.getHttpAdapter().getInstance();
  await fastify.ready();
  ctx.app = app;
});
Example #14
Source File: deleteObject.ts    From storage-api with Apache License 2.0 5 votes vote down vote up
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export default async function routes(fastify: FastifyInstance) {
  const summary = 'Delete an object'

  const schema = createDefaultSchema(successResponseSchema, {
    params: deleteObjectParamsSchema,
    summary,
    tags: ['object'],
  })

  fastify.delete<deleteObjectRequestInterface>(
    '/:bucketName/*',
    {
      schema,
    },
    async (request, response) => {
      const { bucketName } = request.params
      const objectName = request.params['*']

      if (!isValidKey(objectName) || !isValidKey(bucketName)) {
        return response
          .status(400)
          .send(createResponse('The key contains invalid characters', '400', 'Invalid key'))
      }

      const objectResponse = await request.postgrest
        .from<Obj>('objects')
        .delete()
        .match({
          name: objectName,
          bucket_id: bucketName,
        })
        .single()

      if (objectResponse.error) {
        const { error, status } = objectResponse
        request.log.error({ error }, 'error object')
        return response.status(400).send(transformPostgrestError(error, status))
      }
      const { data: results } = objectResponse
      request.log.info({ results }, 'results')

      // if successfully deleted, delete from s3 too
      const s3Key = `${request.tenantId}/${bucketName}/${objectName}`
      await storageBackend.deleteObject(globalS3Bucket, s3Key)

      return response.status(200).send(createResponse('Successfully deleted'))
    }
  )
}
Example #15
Source File: base-mercurius.module.ts    From nestjs-mercurius with MIT License 5 votes vote down vote up
protected async registerFastify(mercuriusOptions: Opts) {
    const mercurius = loadPackage('mercurius', 'MercuriusModule', () =>
      require('mercurius'),
    );

    const httpAdapter = this.httpAdapterHost.httpAdapter;
    const app: FastifyInstance = httpAdapter.getInstance();

    const options = {
      ...mercuriusOptions,
      path: this.getNormalizedPath(mercuriusOptions),
    };

    if (mercuriusOptions.uploads) {
      const mercuriusUpload = loadPackage(
        'mercurius-upload',
        'MercuriusModule',
        () => require('mercurius-upload'),
      );
      await app.register(
        mercuriusUpload,
        typeof mercuriusOptions.uploads !== 'boolean'
          ? mercuriusOptions.uploads
          : undefined,
      );
    }

    if (mercuriusOptions.altair) {
      const altairPlugin = loadPackage(
        'altair-fastify-plugin',
        'MercuriusModule',
        () => require('altair-fastify-plugin'),
      );

      options.graphiql = false;
      options.ide = false;

      await app.register(altairPlugin, {
        baseURL: '/altair/',
        path: '/altair',
        ...(typeof mercuriusOptions.altair !== 'boolean' &&
          mercuriusOptions.altair),
        endpointURL: options.path,
      });
    }

    await app.register(mercurius, options);

    this.addHooks(app);
  }
Example #16
Source File: admin-app.ts    From storage-api with Apache License 2.0 5 votes vote down vote up
build = (opts: FastifyServerOptions = {}): FastifyInstance => {
  const app = fastify(opts)
  app.register(tenantRoutes, { prefix: 'tenants' })
  app.register(underPressure, { exposeStatusRoute: true, maxEventLoopUtilization: 0.99 })
  return app
}
Example #17
Source File: base-mercurius.module.ts    From nestjs-mercurius with MIT License 5 votes vote down vote up
protected addHooks(app: FastifyInstance) {
    const hooks = this.hookExplorerService.explore();

    hooks.forEach((hook) => {
      app.graphql.addHook(hook.name as any, hook.callback as any);
    });
  }
Example #18
Source File: node.ts    From hubble-contracts with MIT License 5 votes vote down vote up
public static async init(config: ClientConfig, fast: FastifyInstance) {
        await mcl.init();
        const genesis = await Genesis.fromConfig(config.genesisPath);

        const provider = new ethers.providers.JsonRpcProvider(
            config.providerUrl,
            genesis.auxiliary.chainid
        );
        provider.on("error", err => {
            console.error(err);
        });

        const { MAX_DEPTH } = genesis.parameters;
        const storageManager = await storageManagerFactory({
            stateTreeDepth: MAX_DEPTH,
            pubkeyTreeDepth: MAX_DEPTH
        });

        const signer = provider.getSigner();
        const api = CoreAPI.new(storageManager, genesis, provider, signer);

        const syncer = new SyncerService(api);

        let transferPool;
        let packer;
        let bidder;

        const modes = this.getNodeModes(config);
        if (modes.isProposer) {
            const { feeReceivers, willingnessToBid, maxPendingTransactions } =
                config.proposer || {};
            if (!feeReceivers) {
                throw new MissingConfigPropError("proposer.feeRecievers");
            }
            if (!feeReceivers.length) {
                throw new EmptyConfigPropError("proposer.feeRecievers");
            }
            if (!willingnessToBid) {
                throw new MissingConfigPropError("proposer.willingnessToBid");
            }

            transferPool = new TransferPool(
                storageManager.state,
                feeReceivers,
                maxPendingTransactions
            );

            packer = new Packer(api, transferPool);
            bidder = await Bidder.new(
                BigNumber.from(willingnessToBid),
                api.contracts.burnAuction
            );
        }
        if (modes.isWatcher) {
            throw new Error("watcher is currently not supported");
        }

        fast.addHook("onRequest", async (_request, reply) => {
            if (syncer.getMode() === SyncMode.INITIAL_SYNCING) {
                return reply.status(503).send({
                    message: "Initial sync incomplete",
                    error: "RPC unavailable",
                    statusCode: 503
                });
            }
        });

        const rpc = new RPC(api, fast, transferPool);
        return new this(
            modes,
            provider,
            api.eventEmitter,
            syncer,
            packer,
            bidder,
            rpc
        );
    }
Example #19
Source File: moveObject.ts    From storage-api with Apache License 2.0 5 votes vote down vote up
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export default async function routes(fastify: FastifyInstance) {
  const summary = 'Moves an object'

  const schema = createDefaultSchema(successResponseSchema, {
    body: moveObjectsBodySchema,
    summary,
    tags: ['object'],
  })

  fastify.post<moveObjectRequestInterface>(
    '/move',
    {
      schema,
    },
    async (request, response) => {
      const { destinationKey, sourceKey, bucketId } = request.body

      if (!isValidKey(destinationKey)) {
        return response
          .status(400)
          .send(
            createResponse('The destination key contains invalid characters', '400', 'Invalid key')
          )
      }

      const objectResponse = await request.postgrest
        .from<Obj>('objects')
        .update({
          last_accessed_at: new Date().toISOString(),
          name: destinationKey,
        })
        .match({ bucket_id: bucketId, name: sourceKey })
        .single()

      if (objectResponse.error) {
        const { status, error } = objectResponse
        request.log.error({ error }, 'error object')
        return response.status(400).send(transformPostgrestError(error, status))
      }

      // if successfully updated, copy and delete object from s3
      const oldS3Key = `${request.tenantId}/${bucketId}/${sourceKey}`
      const newS3Key = `${request.tenantId}/${bucketId}/${destinationKey}`

      // @todo what happens if one of these fail?
      await storageBackend.copyObject(globalS3Bucket, oldS3Key, newS3Key)
      await storageBackend.deleteObject(globalS3Bucket, oldS3Key)

      return response.status(200).send(createResponse('Successfully moved'))
    }
  )
}
Example #20
Source File: pub-sub-host.ts    From nestjs-mercurius with MIT License 5 votes vote down vote up
getInstance(): PubSub | undefined {
    return this.httpAdapterHost.httpAdapter.getInstance<FastifyInstance>()
      .graphql?.pubsub;
  }
Example #21
Source File: getPublicObject.ts    From storage-api with Apache License 2.0 5 votes vote down vote up
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export default async function routes(fastify: FastifyInstance) {
  const summary = 'Retrieve an object from a public bucket'
  fastify.get<getObjectRequestInterface>(
    '/public/:bucketName/*',
    {
      // @todo add success response schema here
      schema: {
        params: getPublicObjectParamsSchema,
        summary,
        response: { '4xx': { $ref: 'errorSchema#' } },
        tags: ['object'],
      },
    },
    async (request, response) => {
      const { bucketName } = request.params
      const objectName = request.params['*']

      const { error, status } = await request.superUserPostgrest
        .from<Bucket>('buckets')
        .select('id, public')
        .eq('id', bucketName)
        .eq('public', true)
        .single()

      if (error) {
        request.log.error({ error }, 'error finding public bucket')
        return response.status(400).send(transformPostgrestError(error, status))
      }

      const s3Key = `${request.tenantId}/${bucketName}/${objectName}`
      request.log.info(s3Key)
      try {
        const data = await storageBackend.getObject(globalS3Bucket, s3Key, {
          ifModifiedSince: request.headers['if-modified-since'],
          ifNoneMatch: request.headers['if-none-match'],
          range: request.headers.range,
        })
        response
          .status(data.metadata.httpStatusCode ?? 200)
          .header('Accept-Ranges', 'bytes')
          .header('Content-Type', normalizeContentType(data.metadata.mimetype))
          .header('Cache-Control', data.metadata.cacheControl)
          .header('Content-Length', data.metadata.contentLength)
          .header('ETag', data.metadata.eTag)
          .header('Last-Modified', data.metadata.lastModified)
        if (data.metadata.contentRange) {
          response.header('Content-Range', data.metadata.contentRange)
        }
        return response.send(data.body)
      } catch (err: any) {
        if (err.$metadata?.httpStatusCode === 304) {
          return response.status(304).send()
        }
        request.log.error(err)
        if (err.$metadata?.httpStatusCode === 404) {
          return response.status(404).send()
        } else {
          return response.status(400).send({
            message: err.message,
            statusCode: '400',
            error: err.message,
          })
        }
      }
    }
  )
}
Example #22
Source File: code-first.spec.ts    From nestjs-mercurius with MIT License 5 votes vote down vote up
gqlSuite('subscriber should work', async ({ app }) => {
  return new Promise<void>((resolve, reject) => {
    app.listen(0, (err) => {
      if (err) {
        return reject(err);
      }
      const port = app.getHttpServer().address().port;
      const fastifyApp = app.getHttpAdapter().getInstance() as FastifyInstance;

      const ws = new Websocket(`ws://localhost:${port}/graphql`, 'graphql-ws');

      const client = Websocket.createWebSocketStream(ws, {
        encoding: 'utf8',
        objectMode: true,
      });
      client.setEncoding('utf8');
      client.write(
        JSON.stringify({
          type: 'connection_init',
        }),
      );

      client.write(
        JSON.stringify({
          id: 1,
          type: 'start',
          payload: {
            query: `
          subscription {
            onCatSub {
              id
              lives
              name
              hasFur
            }
          }
        `,
          },
        }),
      );

      client.on('data', (chunk) => {
        const data = JSON.parse(chunk);

        if (data.type === 'connection_ack') {
          fastifyApp.graphql.pubsub.publish({
            topic: 'CAT_SUB_TOPIC',
            payload: cats[0],
          });
        } else if (data.id === 1) {
          const expectedCat = expectedCats[0];
          const receivedCat = data.payload.data?.onCatSub;
          assert.ok(receivedCat);
          assert.equal(expectedCat.id, receivedCat.id);
          assert.type(receivedCat.hasFur, 'boolean');

          client.end();
        }
      });

      client.on('end', () => {
        client.destroy();
        app.close().then(resolve).catch(reject);
      });
    });
  });
});
Example #23
Source File: listObjects.ts    From storage-api with Apache License 2.0 5 votes vote down vote up
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export default async function routes(fastify: FastifyInstance) {
  const summary = 'Search for objects under a prefix'

  const schema = createDefaultSchema(successResponseSchema, {
    body: searchRequestBodySchema,
    params: searchRequestParamsSchema,
    summary,
    tags: ['object'],
  })

  fastify.post<searchRequestInterface>(
    '/list/:bucketName',
    {
      schema,
    },
    async (request, response) => {
      const { bucketName } = request.params
      const { limit, offset, sortBy, search } = request.body
      let sortColumn, sortOrder
      if (sortBy?.column) {
        sortColumn = sortBy.column
        sortOrder = sortBy.order ?? 'asc'
      } else {
        sortColumn = 'name'
        sortOrder = 'asc'
      }
      let { prefix } = request.body
      if (prefix.length > 0 && !prefix.endsWith('/')) {
        // assuming prefix is always a folder
        prefix = `${prefix}/`
      }
      request.log.info(request.body)
      request.log.info(`searching for %s`, prefix)

      const {
        data: results,
        error,
        status,
      } = await request.postgrest.rpc('search', {
        prefix,
        bucketname: bucketName,
        limits: limit,
        offsets: offset,
        levels: prefix.split('/').length,
        search,
        sortcolumn: sortColumn,
        sortorder: sortOrder,
      })

      if (error) {
        request.log.error({ error }, 'search rpc')
        return response.status(status).send(transformPostgrestError(error, status))
      }
      request.log.info({ results }, 'results')

      response.status(200).send(results)
    }
  )
}
Example #24
Source File: router.ts    From iplocate with MIT License 5 votes vote down vote up
export default async function router(fastify: FastifyInstance) {
  fastify.register(ipLocate, { prefix: "/ip" });
}
Example #25
Source File: construction-metadata-api.test.ts    From cardano-rosetta with Apache License 2.0 5 votes vote down vote up
describe(CONSTRUCTION_METADATA_ENDPOINT, () => {
  let database: Pool;
  let server: FastifyInstance;

  beforeAll(async () => {
    database = setupOfflineDatabase();
    server = setupServer(database);
  });

  afterAll(async () => {
    await database.end();
  });

  beforeAll(async () => {
    database = setupDatabase();
    server = setupServer(database);
  });

  test('Should return a valid TTL when the parameters are valid', async () => {
    const relativeTtl = 100;
    const response = await server.inject({
      method: 'post',
      url: CONSTRUCTION_METADATA_ENDPOINT,
      payload: generateMetadataPayload('cardano', 'mainnet', relativeTtl)
    });
    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json()).toEqual({
      metadata: {
        ttl: (latestBlockSlot + relativeTtl).toString()
      },
      suggested_fee: [
        {
          currency: {
            decimals: 6,
            symbol: 'ADA'
          },
          // ttl is encoded as 5 bytes but metadata comes with one already
          value: (
            (TRANSACTION_SIZE_IN_BYTES + 4) * linearFeeParameters.minFeeA +
            linearFeeParameters.minFeeB
          ).toString()
        }
      ]
    });
  });

  testInvalidNetworkParameters(
    CONSTRUCTION_METADATA_ENDPOINT,
    (blockchain, network) => generateMetadataPayload(blockchain, network, 100),
    () => server
  );
});
Example #26
Source File: http.ts    From walletconnect-v2-monorepo with Apache License 2.0 5 votes vote down vote up
public app: FastifyInstance;
Example #27
Source File: block-transactions-api.test.ts    From cardano-rosetta with Apache License 2.0 4 votes vote down vote up
describe('/block/transactions endpoint', () => {
  let database: Pool;
  let server: FastifyInstance;
  beforeAll(async () => {
    database = setupDatabase();
    server = setupServer(database);
  });

  afterAll(async () => {
    await database.end();
  });

  const BLOCK_TRANSACTION_ENDPOINT = '/block/transaction';
  test('should return the transaction if a valid hash is sent', async () => {
    const { index, hash } = block23236WithTransactions.block.block_identifier;
    const [transaction] = block23236WithTransactions.block.transactions;
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(index, hash),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction.transaction_identifier.hash
        }
      }
    });

    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json()).toEqual({ transaction });
  });

  test('should return an error if the transaction doesnt exist', async () => {
    const { index, hash } = block23236WithTransactions.block.block_identifier;
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(index, hash),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          // Last digit was changed from 4 to 5
          hash: 'abbeb108ebc3990c7f031113bcb8ce8f306a1eec8f313acffcdcd256379208f5'
        }
      }
    });

    expect(response.statusCode).toEqual(StatusCodes.INTERNAL_SERVER_ERROR);
    expect(response.json()).toEqual({ code: 4006, message: TRANSACTION_NOT_FOUND, retriable: false });
  });
  test('should fail if incorrect network identifier is sent', async () => {
    const { index, hash } = block23236WithTransactions.block.block_identifier;
    const [transaction] = block23236WithTransactions.block.transactions;
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(index, hash),
        // eslint-disable-next-line camelcase
        network_identifier: {
          blockchain: 'cardano',
          network: 'testnet'
        },
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction.transaction_identifier.hash
        }
      }
    });

    expect(response.statusCode).toEqual(StatusCodes.INTERNAL_SERVER_ERROR);
    expect(response.json()).toEqual({ message: 'Network not found', code: 4002, retriable: false });
  });
  test('should fail if incorrect blockchain identifier is sent', async () => {
    const { index, hash } = block23236WithTransactions.block.block_identifier;
    const [transaction] = block23236WithTransactions.block.transactions;
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(index, hash),
        // eslint-disable-next-line camelcase
        network_identifier: {
          blockchain: 'incorrect',
          network: 'mainnet'
        },
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction.transaction_identifier.hash
        }
      }
    });

    expect(response.statusCode).toEqual(StatusCodes.INTERNAL_SERVER_ERROR);
    expect(response.json()).toEqual({ message: 'Invalid blockchain', code: 4004, retriable: false });
  });

  test('should fail if requested block index does not correspond to requested block hash', async () => {
    const { hash } = block23236WithTransactions.block.block_identifier;
    const [transaction] = block23236WithTransactions.block.transactions;
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(1234, hash),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction.transaction_identifier.hash
        }
      }
    });

    expect(response.statusCode).toEqual(StatusCodes.INTERNAL_SERVER_ERROR);
    expect(response.json()).toEqual({ message: TRANSACTION_NOT_FOUND, code: 4006, retriable: false });
  });
  test('should fail if requested block hash does not correspond to requested block index', async () => {
    const { index } = block23236WithTransactions.block.block_identifier;
    const [transaction] = block23236WithTransactions.block.transactions;
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(index, 'fakeHash'),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction.transaction_identifier.hash
        }
      }
    });
    expect(response.statusCode).toEqual(StatusCodes.INTERNAL_SERVER_ERROR);
    expect(response.json()).toEqual({ message: TRANSACTION_NOT_FOUND, code: 4006, retriable: false });
  });

  test('should return transaction for genesis block when requested', async () => {
    const genesisIndex = 0;
    const genesisHash = '5f20df933584822601f9e3f8c024eb5eb252fe8cefb24d1317dc3d432e940ebb';
    const transaction = '927edb96f3386ab91b5f5d85d84cb4253c65b1c2f65fa7df25f81fab1d62987a';
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(genesisIndex, genesisHash),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction
        }
      }
    });

    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json()).toEqual(transaction987aOnGenesis);
  });

  test('should return transaction withdrawals', async () => {
    const transaction = '2974845ecc7e02e86285d32961c69f3945662a80d5e2caae8a1086e652936f42';
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(4597861, 'e73be90cd5e2b0bf3acb86e3bed575931ab0ff1e7d5bfca94cff6166ef010060'),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction
        }
      }
    });
    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json()).toEqual(transactionBlock4597861WithWithdrawals);
  });

  test('should return transaction registrations', async () => {
    const transaction = '91f88c21679fdc95cb0712dc8a755eab20fdf9e919871c3c668515c830572090';
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(4490558, '600fc0fc8b9d4bcb777536cd9168703d0645ab4986fe8d3bdae4011ad0ee5919'),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction
        }
      }
    });

    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json()).toEqual(transactionBlock4490558WithRegistrations);
  });

  test('should return transaction delegations', async () => {
    const transaction = 'f0024159d124a128db522031c4a3e7b255ee511600afa92ff52b2504702e4e1d';
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(4490559, 'd5c4088f55024cb5a087c1588ff362d6c5c1a95ada0608044192c320b41c5987'),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction
        }
      }
    });
    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json()).toEqual(transactionBlock4490559WithDelegation);
  });

  test('should return transaction deregistrations', async () => {
    const transaction = '5fe53eece38ff4eb102c33c6cbdf34947c8232eefaae0731fdf8f746b81763fc';
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(4853177, '6713e3dbea2a037f0be9401744a8b2be4c6190294a23c496165c212972a82f61'),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction
        }
      }
    });
    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json()).toEqual(transactionBlock4853177WithDeregistration);
  });

  test('should return a pool retirement transaction', async () => {
    const transaction = '896cf8fefad1eaf0fa056ba3adf28bfb26b06d1beed64cf790deb595dcb2687a';
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(4491210, 'ddb008b4a1cad00db90f524b5ba94da94f84b2aabe7de6ff4a0d27d89ed222dd'),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction
        }
      }
    });
    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json()).toEqual(transactionBlock4853177WithPoolRetirement);
  });

  test('should be able to return multiasset token transactions with several tokens in the bundle', async () => {
    const transaction = '8d67291066037f46f092bfc098241cc7143fa1ec2b14b6c23b945878ccf9fe0f';
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(5407534, '6d48a3e7af71698268ea3efaf67a2f012e237b19e10131eb77cd22448fd4183c'),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction
        }
      }
    });
    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json()).toEqual({ transaction: transaction5407534WithTokenBundle });
  });

  test('should return transaction pool registrations', async () => {
    const transaction = '29a76dd58c6309cd9cde855c0c50d81d63f921959359b1e544401ac1dbc9b472';
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(4597779, '8839b697618eb1b3167bcd2658e10008d9c1d11bd32b305abf497371cd79dafa'),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction
        }
      }
    });
    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json()).toEqual(transactionWithPoolRegistration);
  });

  test('should return transaction pool registrations with multiple owners', async () => {
    const transaction = '51d67e194d749df2abf4e2e11cea63ca6e1c630042a366f555939e795a6ddecf';
    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(4490593, 'a5f1a0e14e1ca218fd07e1601792545945c8cb552d7978967e230d6d3b2710fd'),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: transaction
        }
      }
    });
    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json()).toEqual(transactionWithPoolRegistrationWithMultipleOwners);
  });

  // TODO: deprecated. pending to be implemented
  // test('should return operation status as invalid when there is an invalid transaction', async () => {
  //   const invalidTxHash = '0c2d516c9eaf0d9f641506f1f64be3f660a49e622f4651ed1b19d6edeaefaf4c';
  //   const blockNumber = 25050;
  //   const blockHash = '1f58250b82bc7c7c408028ba01173bdfa37fc82dde34060c5b49a3ea644d9439';

  //   const response = await serverWithAlonzoSupport.inject({
  //     method: 'post',
  //     url: BLOCK_TRANSACTION_ENDPOINT,
  //     payload: {
  //       ...generatePayload(blockNumber, blockHash),
  //       // eslint-disable-next-line camelcase
  //       transaction_identifier: {
  //         hash: invalidTxHash
  //       }
  //     }
  //   });

  //   expect(response.statusCode).toEqual(StatusCodes.OK);
  //   expect(response.json()).toEqual(invalidAlonzoTransaction);
  // });

  test('should return vote registration operations', async () => {
    const txHash = 'adeb7b6845f3f4b0e74275588412cf00912b615e4bbf76d111326ce899260c59';
    const blockNumber = 5593749;
    const blockHash = '1c42fd317888b2aafe9f84787fdd3b90b95be06687a217cf4e6ca95130157eb5';

    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(blockNumber, blockHash),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: txHash
        }
      }
    });
    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json()).toEqual(transactionWithVoteOperation);
  });

  test('should not return a vote registration operation when it is bad formed', async () => {
    const txHash = 'cacbc12afa3a1d2ec0186971d5c9035c79bfa1250ca7a6af580d1b8d9e04db8c';
    const blockNumber = 5406810;
    const blockHash = '0cea06f7b3003a5c0efc27fff117fa9e2a08603e1b0049c3b5c719abf6a617f1';

    const response = await server.inject({
      method: 'post',
      url: BLOCK_TRANSACTION_ENDPOINT,
      payload: {
        ...generatePayload(blockNumber, blockHash),
        // eslint-disable-next-line camelcase
        transaction_identifier: {
          hash: txHash
        }
      }
    });
    expect(response.statusCode).toEqual(StatusCodes.OK);
    expect(response.json()).toEqual(transactionWithBadFormedVote);
  });
});
Example #28
Source File: rpc.ts    From hubble-contracts with MIT License 4 votes vote down vote up
constructor(
        { l2Storage }: CoreAPI,
        fastify: FastifyInstance,
        transferPool?: ITransferPool
    ) {
        fastify.register(cors, {
            origin: "*"
        });
        fastify.get<{ Params: { stateID: number } }>(
            "/user/state/:stateID",
            async function(request, reply) {
                try {
                    const { stateID } = request.params;
                    const state = await l2Storage.state.get(stateID);
                    return state.toJSON();
                } catch (error) {
                    if (error.name === "NotFoundError") {
                        return reply
                            .status(404)
                            .send({ error: "pubkey not found" });
                    } else {
                        console.error(error);
                        return reply.status(500);
                    }
                }
            }
        );
        fastify.get<{ Params: { pubkeyHash: string } }>(
            "/user/state/pubkey/:pubkeyHash",
            async function(request, reply) {
                try {
                    const { pubkeyHash } = request.params;
                    const stateIndices = await Pubkey2StatesDB.getStates(
                        pubkeyHash
                    );
                    let data = stateIndices.map(async id => {
                        let state = await l2Storage.state.get(Number(id));
                        return {
                            stateId: id,
                            balance: state.balance.toString(),
                            tokenId: state.tokenID.toString(),
                            nonce: state.nonce.toString()
                        };
                    });
                    return { states: await Promise.all(data) };
                } catch (error) {
                    if (error.name === "NotFoundError") {
                        return reply
                            .status(404)
                            .send({ error: "pubkey not found" });
                    } else {
                        console.error(error);
                        return reply.status(500);
                    }
                }
            }
        );
        fastify.get<{ Params: { pubkeyID: number } }>(
            "/user/pubkey/hash/:pubkeyID",
            async function(request, reply) {
                try {
                    const { pubkeyID } = request.params;
                    const pubkey = await l2Storage.pubkey.get(pubkeyID);
                    return { hash: pubkey.hash() };
                } catch (error) {
                    return reply
                        .status(404)
                        .send({ error: "pubkey not found" });
                }
            }
        );
        fastify.get<{ Params: { pubkeyHash: string } }>(
            "/user/pubkey/id/:pubkeyHash",
            async function(request, reply) {
                try {
                    const { pubkeyHash } = request.params;
                    const stateIndices = await Pubkey2StatesDB.getStates(
                        pubkeyHash
                    );
                    let data = await l2Storage.state.get(
                        Number(stateIndices[0])
                    );
                    return { id: data.pubkeyID.toNumber() };
                } catch (error) {
                    if (error.name === "NotFoundError") {
                        return reply
                            .status(404)
                            .send({ error: "pubkey not found" });
                    } else {
                        console.error(error);
                        return reply.status(500);
                    }
                }
            }
        );
        fastify.post<{ Body: { bytes: string } }>(
            "/tx",
            tx,
            async (request, reply) => {
                try {
                    if (!transferPool) {
                        reply.status(409).send("not a proposer");
                        return;
                    }

                    const bytes = arrayify(request.body.bytes);
                    const transfer = TransferOffchainTx.deserialize(bytes);
                    await transferPool.push(transfer);
                    await l2Storage.transactions.pending(transfer);
                    return { txHash: transfer.hash() };
                } catch (error) {
                    console.error(error);
                    return reply.status(500);
                }
            }
        );
        fastify.get<{ Params: { txMsg: string } }>(
            "/tx/:txMsg",
            async (request, reply) => {
                const { txMsg } = request.params;
                const txStatus = await l2Storage.transactions.get(txMsg);
                if (!txStatus) {
                    reply.status(404).send(`${txMsg} not found`);
                    return;
                }
                // In the future, we may want to clean up
                // this JSON serialization to something more minimal.
                return JSON.stringify({
                    status: txStatus.status,
                    l1BlockIncluded: txStatus.l1BlockIncluded,
                    l1TxnHash: txStatus.l1TxnHash
                });
            }
        );
    }
Example #29
Source File: index.ts    From mercurius-typescript with MIT License 4 votes vote down vote up
export async function codegenMercurius(
  app: FastifyInstance,
  {
    disable = process.env.NODE_ENV === 'production',
    targetPath,
    silent,
    codegenConfig,
    preImportCode,
    operationsGlob,
    watchOptions,
    outputSchema = false,
  }: CodegenMercuriusOptions
): Promise<{
  closeWatcher: () => Promise<boolean>
  watcher: Promise<FSWatcher | undefined>
}> {
  const noopCloseWatcher = async () => false
  if (disable) {
    return {
      closeWatcher: noopCloseWatcher,
      watcher: Promise.resolve(undefined),
    }
  }

  await app.ready()

  if (typeof app.graphql !== 'function') {
    throw Error('Mercurius is not registered in Fastify Instance!')
  }

  const { generateCode, writeGeneratedCode } = await import('./code')
  const { writeOutputSchema } = await import('./outputSchema')

  return new Promise((resolve, reject) => {
    const log = (...message: Parameters<typeof console['log']>) =>
      silent ? undefined : console.log(...message)

    setImmediate(() => {
      const schema = app.graphql.schema

      async function watchExecute() {
        const {
          enabled: watchEnabled = false,
          chokidarOptions,
          uniqueWatch = true,
        } = watchOptions || {}

        if (watchEnabled && operationsGlob) {
          const { watch } = await import('chokidar')

          let watcherPromise = deferredPromise<FSWatcher | undefined>()

          const watcher = watch(
            operationsGlob,
            Object.assign(
              {
                useFsEvents: false,
              } as ChokidarOptions,
              chokidarOptions
            )
          )

          let isReady = false

          watcher.on('ready', () => {
            isReady = true
            log(`[mercurius-codegen] Watching for changes in ${operationsGlob}`)
            watcherPromise.resolve(watcher)
          })

          watcher.on('error', watcherPromise.reject)

          let closed = false

          const closeWatcher = async () => {
            if (closed) return false

            closed = true
            await watcher.close()
            return true
          }

          if (uniqueWatch) {
            if (typeof global.mercuriusOperationsWatchCleanup === 'function') {
              global.mercuriusOperationsWatchCleanup()
            }

            global.mercuriusOperationsWatchCleanup = closeWatcher
          }

          const listener = (
            eventName: 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir',
            changedPath: string
          ) => {
            if (!isReady) return

            log(
              `[mercurius-codegen] ${changedPath} ${eventName}, re-generating...`
            )

            generateCode(
              schema,
              codegenConfig,
              preImportCode,
              silent,
              operationsGlob
            ).then((code) => {
              writeGeneratedCode({
                code,
                targetPath,
              }).then((absoluteTargetPath) => {
                log(
                  `[mercurius-codegen] Code re-generated at ${absoluteTargetPath}`
                )
              }, console.error)
            }, console.error)
          }
          watcher.on('all', listener)

          return {
            closeWatcher,
            watcher: watcherPromise.promise,
          }
        }

        return {
          closeWatcher: noopCloseWatcher,
          watcher: Promise.resolve(undefined),
        }
      }

      writeOutputSchema(app, outputSchema).catch(reject)

      generateCode(
        schema,
        codegenConfig,
        preImportCode,
        silent,
        operationsGlob
      ).then((code) => {
        writeGeneratedCode({
          code,
          targetPath,
        }).then((absoluteTargetPath) => {
          log(`[mercurius-codegen] Code generated at ${absoluteTargetPath}`)

          watchExecute().then((watchResult) => {
            resolve(watchResult)
          }, reject)
        }, reject)
      }, reject)
    })
  })
}