{"id":22796283,"url":"https://github.com/makerxstudio/node-common","last_synced_at":"2026-05-09T02:17:25.537Z","repository":{"id":177159393,"uuid":"530860641","full_name":"MakerXStudio/node-common","owner":"MakerXStudio","description":"A set of MakerX core NodeJS types and utilities","archived":false,"fork":false,"pushed_at":"2024-02-14T19:03:28.000Z","size":996,"stargazers_count":0,"open_issues_count":6,"forks_count":0,"subscribers_count":12,"default_branch":"main","last_synced_at":"2024-03-14T21:23:11.923Z","etag":null,"topics":["node-common","npm","package","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MakerXStudio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-30T22:59:51.000Z","updated_at":"2024-05-09T05:27:27.366Z","dependencies_parsed_at":null,"dependency_job_id":"cfcb743f-1b95-4936-afe8-64c2c14cd297","html_url":"https://github.com/MakerXStudio/node-common","commit_stats":null,"previous_names":["makerxstudio/node-common"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MakerXStudio%2Fnode-common","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MakerXStudio%2Fnode-common/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MakerXStudio%2Fnode-common/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MakerXStudio%2Fnode-common/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MakerXStudio","download_url":"https://codeload.github.com/MakerXStudio/node-common/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246358321,"owners_count":20764366,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["node-common","npm","package","typescript"],"created_at":"2024-12-12T05:11:48.260Z","updated_at":"2025-10-16T17:28:58.797Z","avatar_url":"https://github.com/MakerXStudio.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿# Node Common\n\nA set of MakerX core NodeJS types and utilities.\n\n## Environment\n\nThis module standardises minimal environment definitions based on the NODE_ENV environment variable.\n\n| NODE_ENV   | Description                                                                                                                          |\n| ---------- | ------------------------------------------------------------------------------------------------------------------------------------ |\n| localdev   | Indicates a local development setup, code can expect to have `devDependencies` installed, logging is expected to be more verbose etc |\n| dev        | Indicates a deployed environment with non-production data and behaviour                                                              |\n| production | Indicates the live production environment with real data and optimised behaviour                                                     |\n\n- `environment` returns process.env.NODE_ENV\n- `isLocalDev` indicates whether the environment is `localdev`\n- `isDev` indicates whether the environment is `dev`\n- `isProduction` indicates whether the environment is `production`\n\n## Logger\n\nThis type can be used to optionally emit logging from packages without taking a dependency on any specific logging framework.\n\n```ts\nexport type Logger = {\n  error(message: string, ...optionalParams: unknown[]): void\n  warn(message: string, ...optionalParams: unknown[]): void\n  info(message: string, ...optionalParams: unknown[]): void\n  verbose(message: string, ...optionalParams: unknown[]): void\n  debug(message: string, ...optionalParams: unknown[]): void\n}\n```\n\nExample usage:\n\n```ts\nlogger?.verbose('About to do something')\nconst result = doSomething()\nlogger?.info('Did something', { result })\n```\n\nThe `Logger` representation is compatible with [Winston](https://github.com/winstonjs/winston).\n\nOr, if you want console output, you could use:\n\n```ts\nconst logger: Logger = {\n  error: (message: string, ...params: unknown[]) =\u003e console.error\n  warn: (message: string, ...params: unknown[]) =\u003e console.warn\n  info: (message: string, ...params: unknown[]) =\u003e console.info\n  verbose: (message: string, ...params: unknown[]) =\u003e console.trace\n  debug: (message: string, ...params: unknown[]) =\u003e console.debug\n}\n```\n\n## HTTP\n\n### HttpClient\n\n`HttpClient` is a class wrapping `fetch` to make calling Web API endpoints slightly easier:\n\n- supports setting a base URL so relative paths can be used\n- supports providing an function to set an authorization header on every request\n- provides individual GET POST PUT PATCH DELETE methods\n- provides default behaviour of reading the response body as JSON\n- supports a form-urlencoded body POST via `postForm` method\n- extracts some response info into an thrown error for non-200 responses to make error responses visible in logs\n\nExample:\n\n```ts\nexport class ThingClient extends HttpClient\u003cBaseContext\u003e {\n  constructor(options: HttpClientOptions\u003cBaseContext\u003e) {\n    super(options)\n  }\n\n  public things(): Promise\u003cThing[]\u003e {\n    return this.get\u003cThing[]\u003e(`things`)\n  }\n\n  public thing(id: string): Promise\u003cThing\u003e {\n    return this.get\u003cThing\u003e(`things/${id}`)\n  }\n\n  public async createThing(thingInput: { name: string; date: Date }): Promise\u003cThing\u003e {\n    const thing = await this.post\u003cThing\u003e(`things`, { data: thingInput })\n    this.options.logger.info('Created a thing', { thingInput, thing })\n  }\n}\n\nconst onBehalfOfAuthFactory: HttpAuthFactory\u003cBaseContext\u003e = async ({ user }) =\u003e {\n  const { access_token, expires_in } = await getOnBehalfOfToken({ ...oboConfig, assertionToken })\n  return { authorization: `Bearer ${access_token}` }\n}\n\nexport const createServices = (context: BaseContext): Services =\u003e {\n  const httpClientOptions = {\n    requestContext: context,\n    logger: context.logger,\n    correlationId: context.requestInfo.correlationId,\n  }\n  return {\n    thingClient: new ThingClient({\n      ...httpClientOptions,\n      baseUrl,\n      authFactory: onBehalfOfAuthFactory,\n    }),\n  }\n}\n```\n\n### makeHttpRequest\n\nIf the `HttpClient` class is too opinionated for your use case, or you simply want a stateless wrapper for the fetch api with some sensible defaults; we export the function `makeHttpRequest` which is what `HttpClient` uses internally. This function takes care of request logging but leaves request encoding and response decoding to the consumer which offers a higher degree of flexibility.\n\n```ts\nimport { makeHttpRequest } from './http'\n\nconst usersResponse = await makeHttpRequest({\n  url: 'https://localhost:8080/api/users',\n  method: 'GET',\n  headers: {\n    Authorization: 'Bearer abc123def',\n  },\n  ensureSuccessStatusCode: false,\n  logger: myLogger,\n  requestLogLovel: 'debug',\n  logContext: {\n    service: 'My Service Name',\n    version: '1.0.0',\n  },\n  accept: 'application/json',\n  fetchInit: {\n    redirect: 'manual',\n  },\n})\n\nif (usersResponse.ok) {\n  const users = await usersResponse.json()\n} else if (usersResponse.status === 302) {\n  const redirectLocation = usersResponse.headers.get('location')\n} else {\n  // Do something with error code???\n}\n```\n\n### HttpResponseError\n\nA custom Error class which includes a `responseInfo` field to make investigating HTTP errors (via logs etc) a little easier.\n\nA static `create` async factory will attempt to read the response body (as json, then text) and add it to the error.\n\n```ts\nconst response = await fetch('https://broken.io/error', {\n  method: 'POST',\n  body,\n})\n\nif (!response.ok) throw await HttpResponseError.create(response, 'POST failed')\n```\n\n### Polyfilling fetch for NodeJS v16\n\nWhen using NodeJS v16 or below, you must polyfill the global `fetch` function. We recommend using [node-fetch](https://github.com/node-fetch/node-fetch?tab=readme-ov-file#providing-global-access) as a drop-in polyfill choice. **Note:** Due to node 16 and earlier versions no longer being maintained, we also strongly recommend the project be updated to the current LTS version.\n\n## Authorisation\n\nA number of authorisation functions and `HttpAuthFactory` wrappers are exported:\n\n### Client-Credentials flow\n\n- `getClientCredentialsToken`: posts a client-credentials auth request to a token endpoint and returns an `AccessToken` response.\n- `createClientCredentialsAuthFactory`: calls `getClientCredentialsToken` and returns an authorization header, caching the `AccessToken` response until it expires, when it will fetch a new token.\n\n### On-Behalf-Of flow\n\n- `getOnBehalfOfToken`: posts an on-behalf-of auth request to a token endpoint and returns an `AccessToken` response\n- `createClientCredentialsAuthFactory`: calls `createOnBehalfOfAuthFactory` using an `assertionToken` and returns an authorization header.\n\n### Basic auth\n\n- `getBasicAuthHeader`: returns a `Basic {value}` auth header string based on the supplied username and password.\n- `createBasicAuthFactory`: calls `getBasicAuthHeader` and returns an authorization header.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakerxstudio%2Fnode-common","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmakerxstudio%2Fnode-common","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmakerxstudio%2Fnode-common/lists"}