# backend-js-packages

application_family: permissions-platform

Monorepo for our shared javascript npm packages for backend. It is built with [pnpm](https://pnpm.io) and [changesets](https://github.com/atlassian/changesets).

## Setup

Follow this guide to get your environment set up to work with private packages.
<https://www.notion.so/Javascript-Package-Management-Setup-9553d5d491c94835aa787fdf0fc4838d>

### Install pnpm using corepack

We are currently on **version 10** of pnpm.

```bash
corepack enable
```

### Install dependencies using pnpm

```bash
pnpm install
```

## Managing the repo

Working with this repo is slightly different than other js/ts based PDE projects. Since there are many sub projects and they are interconnected we need a better tooling than yarn. yarn has the notion of workspaces, but it has some big drawbacks. One of them is that you have to repeat dev-dependencies and dependencies for every package. And it makes it hard to ensure all packages are using the same library, e.g jest.

**pnpm** is a package manager that is specifically tailored to handle monorepos.

- Define your dev-dependencies at the root. All packages will use the same.
- Run commands across all packages with inter-dependencies in mind.
- Works perfect with changeset.
- Very fast
- Used by big companies, like Microsoft. ( It's the basis for their rushjs.io tooling )

### Root scripts for building, testing and deployment

All the scripts in the root package.json runs the command against every package in the repo.

#### `pnpm [cmd]`

Runs a script defined in every `/packages/*/package.json` files.

If there is no matching script, it will be skipped. However, for consistency when adding a new package, you should make sure scripts are included for:

- build
- build:esm
- build:cjs
- clean
- format
- format:check
- lint
- test:unit

##### Examples

```bash

# build and run all unit tests and linters for changed packages ( it's what the PR job does )
pnpm test:changed

# run all unit tests
pnpm test:unit

# run all linters
pnpm lint

# run unit tests just for one package
pnpm --filter @theorchard/backend-m2m-token-manager test:unit

# run unit tests just for packages matching pattern
pnpm --filter "*graphql" test:unit

# build all suite packages
pnpm --filter "*suite*" build

# run a script only defined for your package(s)
# the -r argument tells pnpm to look for this script in all packages.
pnpm -r my-script

# Add a dependency for one package
pnpm add --filter @theorchard/backend-m2m-token-manager zod@^3.25.0

# Update a dependency for one package
pnpm up --filter @theorchard/backend-m2m-token-manager zod

# Remove a dependency from one package
pnpm rm --filter @theorchard/backend-m2m-token-manager zod

# Update a shared / global dev dependency
pnpm up @biomejs/biome
```

There are more ways to filter your commands to target specific packages. <https://pnpm.io/filtering>

## Managing a package

### Creating a new package

#### Naming Convention

- The package directory should be named `backend-<thing>`, where `<thing>` is kebab-lowercase
- Package name, as listed in the package.json file should be `@theorchard/<package-directory>`.

`@theorchard` indicates the private NPM registry.

`backend-` prefix helps folks know that the codebase for this package is located in _this_ monorepo as opposed in the [`orchard-suite` monorepo](https://github.com/theorchard/orchard-suite).

#### Directory structure

In the `packages` directory, add a new directory for your package. Be sure to include:

- README.md
- package.json
- src/ directory containing code
- jest.config.js
- tsconfig.cjs.json
- tsconfig.esm.json

### Package Versioning

In short:

- Make your changes and stage with `git add <file1> <file2>`
- Make sure your tests are passing running `pnpm test:changed`.
- Run at the root: `pnpm new-version`.
- Follow the changeset instructions.
- Commit your changes and create a PR.
- The new package(s) will be published once your PR is merged.

**DO NOT run the `pnpm publish` command locally.**
This will publish the packages without your changes being merged to the master branch.

#### Reverting changes

If you published a new package that you want to revert; you have two options.

1. Create a new PR with the reverted changes, but keep the changelog and bump the version. The "bad" version will still be around, so a simple github revert PR wont do.
2. If you published a very bad version that nobody should ever use, create a normal github revert PR and a devops ticket to delete the package from the registry.

#### Patching previous major versions ( figure out how to do this within @theorchard/monorepo-cli )

It is currently [hard-coded to suite-apps](https://github.com/theorchard/orchard-suite/blob/067b827021353e5d2bdb04d9ced66eafbb1c7bee/packages/monorepo-cli/src/tasks/patch/index.ts#L12-L19).

#### Testing a new package

If you are making changes to an backend-js-package and you want to test changes to the package, you can build the package and reference it in a client that imports the package.

Example: I have made changes to `backend-m2m-token-manager` but now I need to test those changes. How do I do that?

1. Make your changes.
2. From `backend-js-packages`, `cd packages/backend-m2m-token-manager`.
3. Run `pnpm build && pnpm pack`. This will build and zip the package as `theorchard-backend-m2m-token-manager-[version].tgz`

4. Go into the client that uses this package. In the client's `package.json` update the dependency to point to either the relative or absolute path of the `.tgz`. Then run `yarn install --force` to re-install your package.

For example:

```json
    "dependencies": {
        ...
        "@theorchard/backend-m2m-token-manager": "^0.1.0",
        ...
    }
```

becomes

```json
    "dependencies": {
        ...
        "@theorchard/backend-m2m-token-manager": "file:/Users/jchung/code/backend-js-packages/packages/backend-m2m-token-manager/theorchard-backend-m2m-token-manager-0.1.2.tgz",
        ...
    }
```
