# API Maker v2 to v3 repository migration prompt

> It contains AI prompt to migration any repository from API Maker v2 to v3

Source: https://docs.apimaker.dev/v1/docs/blog/release-notes/v2-to-v3-prompt.html

## Jun 2026

Project Directory : `/Volumes/Data/code/Git/sava_ecom_be`
Below is secret value and you can use that as auth provider name :

```typescript
authTokenInfo_SAVA_ECom: <T.IAuthTokenInfo[]>[{
    "authTokenType": "AM_DB",
    "authTokenAMDB": {
        "instance": "mongodb",
        "database": "sava_ecom",
        "collection": "users",
        "usernameColumn": "username",
        "passwordColumn": "password",
        "expiresInSeconds": 259200
    }
}]
```

## ✅ Migration checklist (summary)

| Done | # | Step | In one line |
| --- | --- | --- | --- |
| ☐ | M | [Manual — deploy to v3 first](https://docs.apimaker.dev/v1/docs/blog/release-notes/v2-to-v3-prompt.html#manual-task-do-this-first-yourself) | Deploy the repo to v3 and commit the regenerated `src/assets/schema-types/types.ts`. |
| ☐ | 0 | [Discover every occurrence](https://docs.apimaker.dev/v1/docs/blog/release-notes/v2-to-v3-prompt.html#0-discover-every-occurrence-first) | Grep the whole repo for `authTokenInfo`, `IAuthTokenInfo`, `EAuthTokenType`. |
| ☐ | 1 | [`authTokenInfo` → `authProviders`](https://docs.apimaker.dev/v1/docs/blog/release-notes/v2-to-v3-prompt.html#1-authtokeninfo-authproviders) | Rename the field, change the cast to `<string[]>`, drop unused imports. |
| ☐ | 2 | [Create the Auth Providers](https://docs.apimaker.dev/v1/docs/blog/release-notes/v2-to-v3-prompt.html#2-create-the-auth-providers-from-each-object) | Extract every inline auth object into a named provider under `Auth Providers`, de-duplicated. |
| ☐ | 3 | [Get Token + headers + WebSocket](https://docs.apimaker.dev/v1/docs/blog/release-notes/v2-to-v3-prompt.html#3-get-token) | Get Token now takes a provider `name`; each provider type has its own request header. |
| ☐ | 4 | [Short folder names — give a `name`](https://docs.apimaker.dev/v1/docs/blog/release-notes/v2-to-v3-prompt.html#4-short-folder-names-give-a-name-to-instance-keyed-items) | 7 folder types are now named by their `name` property instead of `ins -- db -- col -- api`. |
| ☐ | 4a | [Know which items have a `name`](https://docs.apimaker.dev/v1/docs/blog/release-notes/v2-to-v3-prompt.html#41-which-items-have-a-name-and-which-do-not) | Only those 7. Do **not** invent a `name` for third party / system / utility items. |
| ☐ | 4b | [Put `name` in the right place](https://docs.apimaker.dev/v1/docs/blog/release-notes/v2-to-v3-prompt.html#43-where-the-name-value-lives-per-item-type) | Schemas + Instance API settings → inside the `.config.ts` code. Everything else → the `.yaml`. |
| ☐ | 4c | [Rename folder + `.yaml` + `.config.ts` together](https://docs.apimaker.dev/v1/docs/blog/release-notes/v2-to-v3-prompt.html#44-renaming-a-folder-three-names-must-change-together) | A mismatch makes git pull silently skip the item. |
| ☐ | 4d | [Set `authProvider` on every WebSocket event](https://docs.apimaker.dev/v1/docs/blog/release-notes/v2-to-v3-prompt.html#45-websocket-events-extra-rules) | v3-only field; leaving it empty falls back to the first provider alphabetically. |
| ☐ | 5 | [Verify](https://docs.apimaker.dev/v1/docs/blog/release-notes/v2-to-v3-prompt.html#5-after-migration-verify) | Providers resolve, no `authTokenInfo` left, no ` -- ` left in the 7 renamed folders. |

---

- API Maker is a framework and it has it's own standard way of organizing backend code.
- In project directory which uses API Maker v2 and we want to migrate that repository to API Maker V3.
- Do NOT change any business logic or code other than what is described below.
- Once you assign a name to a newly-created auth provider, use that exact same name everywhere it is referenced (in every `authProviders` array) so the references stay consistent.
- You need to make below changes.

## 🔧 Manual task (do this first, yourself)

> This step is **manual** — do it yourself before handing the rest of this prompt to an AI agent.

- **Deploy the repository to API Maker v3 first.** The `types.ts` in a v2 repo is the **old** v2 file — it does not yet contain the v3 auth-provider interfaces or the `authProviders` field.
- After deploying to v3, **commit only the regenerated `src/assets/schema-types/types.ts`** (the type interfaces referenced below live in that file).
- Do this before any of the migration steps below, otherwise the new code will not reference the right symbols or typecheck.

---

## 🤖 Automated migration steps (for the AI agent)

### 0. Discover every occurrence first

- Before editing anything, grep the **entire repository** for all v2 auth-field forms and enumerate every occurrence: `authTokenInfo`, `IAuthTokenInfo`, `EAuthTokenType`.
- The settings categories in step 1 are a **guide, not an exhaustive file list** — migrate every occurrence you find.
- Note that **third party API settings exist at TWO levels** — version-level (`T.ITPApiSettingsTypes`) and per-API level (`T.ITPApiSettingsTypesAPILevel`) — and **both** carry the auth field, so both must be migrated.
- The type interfaces referenced below live in `src/assets/schema-types/types.ts`.

### 1. `authTokenInfo` → `authProviders`

- `authTokenInfo` is now `authProviders` and it takes an **array of strings** (the names of the auth providers to use).
- Make this change in **instance**, **database**, **collection**, **API settings** files, **system API settings**, **third party API settings** (both version-level and per-API level), **custom API settings**, and in **secrets** (the default secret also holds `authProviders`).
- In v2 the auth config was written **inline** as an array of objects (there was no auth master). In v3 those objects move out into named auth providers (step 2) and the settings file only keeps the list of names.
- In v2 the field looked like this (array of objects):
```typescript
authTokenInfo: <T.IAuthTokenInfo[]>[
    {
        authTokenType: T.EAuthTokenType.AM_DB,
        authTokenAMDB: { instance: "...", database: "...", collection: "...", usernameColumn: "...", passwordColumn: "..." }
    }
]
```
- In v3 it becomes just the list of provider names. Change the cast from `<T.IAuthTokenInfo[]>` to `<string[]>`, and remove any now-unused imports of `T.IAuthTokenInfo` / `T.EAuthTokenType` so the code still compiles:
```typescript
authProviders: <string[]>["my_db_login", "my_google_login"]
```
- An empty array (`authProviders: <string[]>[]`) keeps its v2 meaning: it overrides the default secret so only API Maker's API user token is accepted in `x-am-authorization`. Create **no** providers for an empty array.
- If `authTokenInfo` is omitted, **omit `authProviders` too** (make zero edits to that file) — it will inherit from the default secret.
- Leave `apiAccessType` exactly where it is. In v2 `apiAccessType` (`NO_ACCESS | IS_PUBLIC | TOKEN_ACCESS`) is a **sibling** api-level field next to `authTokenInfo`, **not** part of any token object — it is unrelated to the `authProviders` rename and must not be touched.

> **Idempotency / guardrails:** If a settings file already uses `authProviders` (the v2 `authTokenInfo` key is not present), leave it untouched and create no duplicate providers. If a file contains neither key, make no edits to it. Always preserve existing formatting, comments, key order, and all unrelated fields. Re-running this prompt must be a no-op.

### 2. Create the Auth Providers from each object

- In v2 there was **no auth master** — the auth config was defined **inline** as the array of objects inside each settings file, and those objects had **no name**.
- In v3 auth is a master: every object must be extracted into one **separate auth provider** (a named master record) inside the new **`Auth Providers`** folder, and settings reference it by name.
- **De-duplicate across files:** if the *same* inline auth object (same type and same data values) appears in more than one settings file, create **only ONE** shared provider and reference it by the same name from every file that used it. Two objects that differ in any value are distinct and each gets its own provider.
- Since v2 objects have no name, assign each provider a unique, **descriptive** name derived from its purpose (e.g. `customers_token`, `google_login`). Use that exact name, referenced **verbatim**, in every `authProviders` array of step 1. If two distinct providers would end up with the same name, append a numeric suffix (`_2`, `_3`). Only `@` and `/` are stripped from a provider name when it is written to disk, so avoid those two characters in names.
- Map the v2 `authTokenType` and its data object to the v3 provider type as follows:

  | v2 `authTokenType` | v2 data object | v3 provider type | property reference in `types.ts` |
  | --- | --- | --- | --- |
  | `AM` | `authTokenAM` (`{ u, p }` or `{ refresh_token }`) | *no provider* — this is the API Maker user token; referenced by sending `x-am-authorization`. Do **not** create a provider for it. | `IAuthTokenAM` / `IRefreshTokenAM` |
  | `AM_DB` | `authTokenAMDB` | `DB_TOKEN_GENERATOR` | `IAuthTokenAMDB` |
  | `GOOGLE` | `authTokenGoogle` | `GOOGLE` | `IAuthTokenGoogle` |
  | `AWS` | `authTokenAWS` | `AWS` | `IAuthTokenAWS` |
  | `AZURE` | `authTokenAzureAD` | `AZURE` | `IAuthTokenAzureAD` |

  > v2 `EAuthTokenType` has exactly these five members: `AM`, `AM_DB`, `GOOGLE`, `AWS`, `AZURE`. There is **no** `CUSTOM` member and **no** `authTokenCustom` object in v2 — do not look for them. `CUSTOM_TOKEN_GENERATOR` is a **v3-only** provider type with no v2 source to migrate.

- You can check the property details in the `types.ts` file for `IAuthTokenAMDB`, `IAuthTokenGoogle`, `IAuthTokenAWS`, `IAuthTokenAzureAD`.

- **Per-type fields to carry over** (verify against `src/assets/schema-types/types.ts` and `src/ajv/mongoose/MongooseAuthProviders_Vali.ts`):
    - **`AM_DB` → `DB_TOKEN_GENERATOR`:** carry `instance`, `database`, `collection` (MongoDB) **or** `table` (SQL), `usernameColumn`, `passwordColumn`, and also the two load-bearing columns `passwordChangedAtColumn` and `groupsColumn`. `groupsColumn` drives group/role access; `passwordChangedAtColumn` changes the JWT contents (when set, the password field is not stored in the JWT — this timestamp is stored instead so password changes can be detected).
    - **`AWS`:** `cognitoUserPoolId`, `region`, `tokenUse` (`'access'` | `'id'`), `tokenExpiration` (in milliseconds).
    - **`AZURE`:** the field is **`appId`** (documented as the OAuth `client_id`), **NOT** `clientId`. Carry `appId`, `tenant`, `audience`, `issuer`, `maxRetries`.
    - **`GOOGLE`:** `clientId`.
- **Groups / roles config (AWS, Azure, Google only):** these three providers each also carry the shared `IAuthTokenGroupsProperties` config — `sourceFieldOfUniqueId` (the token field holding the user's unique id) and `groupsDataSource` (`{ instance, database, collection? / table?, targetFieldForUniqueId, groupsColumn, select? }`). **Carry these over** for any AWS/Azure/Google object that defines them, or group/role access for federated tokens will be lost. (For `AM_DB` the equivalent is the inline `groupsColumn` field — there is no `groupsDataSource`.)
- **`expiresInSeconds` is v3-only.** v2 has no per-token `expiresInSeconds` (the AM token lifetime was global, default 3600s). Do not try to migrate it from v2 — set it fresh in v3 if desired, respecting the v3 **minimum of 600**.

- Inside the `Auth Providers` folder, each provider named `<name>` uses these files:
    - `<name>.yaml` — the **config file** that stores `generatorType` (`DB_TOKEN_GENERATOR` / `CUSTOM_TOKEN_GENERATOR` / `AWS` / `GOOGLE` / `AZURE`) and the materialized config fields. **This is the source of truth for the provider type, and `generatorType` is required.** AWS, Azure, Google and DB providers all present on disk as just `<name>.ts` (plus a possibly-empty `<name>.fg.ts`) and are **indistinguishable by file presence** — so you must write the correct `generatorType` into `<name>.yaml`; never try to reconstruct the type from which `.ts`/`.tg.ts`/`.tv.ts`/`.fg.ts` files exist.
    - `<name>.ts` — basic info / DB token generator code.
    - `<name>.tg.ts` — custom token generator code (only for `CUSTOM_TOKEN_GENERATOR`).
    - `<name>.tv.ts` — custom token validator code (only for `CUSTOM_TOKEN_GENERATOR`).
    - `<name>.fg.ts` — fields generator code. **This is a NEW, optional v3 concept** — v2 had no fields generator (which DB columns became token claims was implicit in the `AM_DB` column config). Generate it only if you want to inject specific fields into the token; there is no v2 source to copy from. (On write, `.fg.ts` is always emitted for `DB_TOKEN_GENERATOR` even when empty, and only when a fields-generator function is set for `CUSTOM_TOKEN_GENERATOR`.)

### 3. Get Token

- The **Get Token** API and the call from code is now changed. It just needs the provider **name** and all other information will be picked up automatically from the auth providers master. Please check the example below.
- The request body accepts: `name?` (optional), `u`, `p`, `refresh_token?` (optional — re-issues a token without `u`/`p`), and `expiresInSeconds?` (optional). Routing is by `name`:
    - When `name` is **omitted**, the request hits the API Maker user path, where the request body's `expiresInSeconds` is honored directly.
    - When a `name` is supplied, it resolves a DB/Custom auth provider and the token expiry comes from **that provider's** configured `expiresInSeconds` (the request-body value is ignored on that path).
```typescript
[
    {
        "name": "token_generator_name",
        "u": "student1@gmail.com",
        "p": "student1"
    },
    {
        // When name is not provided, system will generate API Maker User's token
        "u": "default",
        "p": "12345",
        "expiresInSeconds": 259200
    }
]
```
- **Get Token only mints tokens for `DB_TOKEN_GENERATOR` and `CUSTOM_TOKEN_GENERATOR` providers.** For **AWS** (Cognito), **Google**, and **Azure** providers, API Maker does **NOT** issue tokens — the client obtains its own provider-issued token from the external identity provider and sends it to API Maker, which only **validates** it. There is no Get Token login flow for AWS/Google/Azure.
- **Each provider type's token goes in its own request header** — update client call sites accordingly:

  | Provider | Request header |
  | --- | --- |
  | API Maker user/admin token (name-less Get Token result) | `x-am-authorization` |
  | `DB_TOKEN_GENERATOR` | `x-am-user-authorization` |
  | `CUSTOM_TOKEN_GENERATOR` | `x-custom-authorization` |
  | `AWS` | `x-aws-authorization` |
  | `GOOGLE` | `x-google-authorization` |
  | `AZURE` | `x-azure-authorization` |

- **WebSocket note:** a v3 WebSocket connection **does not need to name its auth provider at all**. The client sends its token in the query-string key of that provider's type (the same keys as the header table above — `x-am-user-authorization`, `x-aws-authorization`, `x-google-authorization`, `x-azure-authorization`, `x-custom-authorization`) plus `x-am-authorization`, and API Maker works out which provider the token belongs to: a DB-user token carries its provider's name inside it, and AWS/Google/Azure/custom tokens are matched against the providers of their own type.
    - **Preferred migration:** drop the `authTokenInfo` parameter from WS connection URLs and keep only the token keys.
    - If you keep it, it still works and is now only a **filter** that narrows the connection to the named providers. Both `authTokenInfo` and `authProviders` are accepted as the key, so a rename is safe here too — but a provider you list without sending its token closes the connection, and a token whose provider you left out of the list is not validated.
    - The two internal literals `authTokenInfo=ws-local-client-sync` and `authTokenInfo=ws-browser-client-sync` are unrelated to provider names and must be left exactly as they are.

### 4. Short folder names — give a `name` to instance-keyed items

- In v2 the folder name of these items **encoded their identity**, with ` -- ` as the level separator — e.g. `Instance API settings/mongodb -- test -- default -- GEN_GET_ALL/`. Those paths got very long and hit path-length limits on Windows.
- In v3 the folder name is simply the item's **`name`** property. It no longer encodes instance / database / collection / api — those values live **only inside the `.yaml` file**, which is now the single source of truth for identity.

#### 4.1 Which items have a `name`, and which do not

**A. Newly named in v3 — folder is `{name}`, falling back to `{guid}`.** These are the *only* seven folders affected by this step:

  | Folder | v2 folder name | v3 folder name | `name` is stored in |
  | --- | --- | --- | --- |
  | `Schemas` | `{instance} -- {database} -- {collection}` | `{name}` or `{guid}` | the **code** — `<name>.config.ts` |
  | `Instance API settings` | `{instance} -- {database} -- {collection} -- {apiId}` | `{name}` or `{guid}` | the **code** — `<name>.config.ts` |
  | `Instance hooks` | `{instance}` | `{name}` or `{guid}` | the `.yaml` |
  | `Database hooks` | `{instance} -- {database}` | `{name}` or `{guid}` | the `.yaml` |
  | `Collection hooks` | `{instance} -- {database} -- {collection}` | `{name}` or `{guid}` | the `.yaml` |
  | `Instance API hooks` | `{instance} -- {database} -- {collection} -- {apiId}` | `{name}` or `{guid}` | the `.yaml` |
  | `WebSocket events` | `{Category} -- {identifier}` | `{name}` or `{guid}` | the `.yaml` |

> ⚠️ **`Instance API settings` covers three levels of settings, not one.** Database settings and collection settings are **not** stored in the `Database hooks` / `Collection hooks` folders — those two folders only hold pre-hooks and post-hooks. Database, collection **and** API settings are all rows of the same *Instance API settings* item type, told apart by their `apiId` / `collectionName`:
>
> | Settings level | Lives in folder | Marked by | Settings code type |
> | --- | --- | --- | --- |
> | Database settings | `Instance API settings` | `collectionName` = `apiId` = `__DATABASE_SETTINGS__` | `T.IInstanceApiSettingsTypes` |
> | Collection settings | `Instance API settings` | `apiId` = `__COLLECTION_SETTINGS__` | `T.IInstanceApiSettingsTypes` |
> | API settings | `Instance API settings` | a real `apiId`, e.g. `GEN_GET_ALL` | `T.IInstanceApiSettingsTypesForAPI` |
>
> So all three get their `name` **inside the `.config.ts` code**, not in the `.yaml`. Instance-level settings are the exception: they live in `Instance hooks`, have no settings code, and take `name` as a plain `.yaml` key.

**B. NOT named — leave these completely alone.** They have **no** `name` property at all; adding one to the settings code will not typecheck and renaming their folder will break the repository:

  | Folder | v3 folder name (unchanged) | Why there is no `name` |
  | --- | --- | --- |
  | `Third party API settings` | `{bundleName} -- {apiVersion} -- {apiName}` | Neither `T.ITPApiSettingsTypes` nor `T.ITPApiSettingsTypesAPILevel` has a `name` property. |
  | `Third party APIs` | `{apiBundleName} -- {storeApiVersion}` | Identity is the bundle + version. (The installed APIs *inside* it, under `apis/`, are foldered by their own long-standing `name` — that is not new and needs no change.) |
  | `System API settings` | `{apiId}` | `T.ISystemApiSettingsTypes` has no `name`; the `apiId` is already short. |
  | `System API hooks` | `{apiId}` | Same as above. |
  | `Utility classes` | `{folderPath} -- {ClassName}` | It does have a `name`, but the folder is `name` **plus** `folderPath`, so ` -- ` here is correct and must stay. `/` inside `folderPath` is written as ` - `. |

**C. Already named since v2 — nothing to do.** These masters always required a `name` and were always foldered by it: `Custom APIs`, `Auth Providers`, `Schedulers`, `Events`, `Instances`, `Groups`, `API users`, `Secrets`, `i18ns`, `Log profiles`, `Database migrations`, `Process initializers`, `Test cases`, `DB masters`, `DB master utils`, `UI maker styles`. Do not rename or re-generate their names.

  > **Do NOT touch** `Third party APIs`, `Third party API settings`, `System API settings`, `System API hooks` or `Utility classes`. They still compose their folder names with ` -- ` (or with `apiId`) in v3 — that is not a leftover, it is correct.

#### 4.2 Rules for a `name` value

- **`name` is optional** for all seven folders in group A. An item with no `name` keeps working and uses its **`guid`** as the folder name. So doing nothing is a valid, non-breaking outcome — only rename an item when you are also giving it a `name`.
- It must be **unique per user** across items of the same type. A partial unique index on `{ name, user }` enforces it, so a duplicate is rejected on save. Items without a `name` are excluded from that index, which is why old unnamed items still coexist.
- Allowed characters are **letters, numbers, space, underscore and dash** only — `[a-zA-Z0-9 _-]`. Any other character fails validation. Leading/trailing whitespace is trimmed on save, so do not rely on it.
    - `WebSocket events` are the one exception: they additionally allow `/`, for tree-style custom events (see 4.5).
- Keep it short — shorter paths are the whole point of this change.
- **Default names generated by API Maker** follow this recipe, and matching it keeps things predictable (any valid unique name works, though):
    - take the parts `instance`, `database`, `collection`, `apiId` — skipping the ones that do not apply to the item type;
    - keep the **first 6 characters** of each part, except **`collection`, which keeps up to 22 characters** (the collection name identifies the item the most);
    - strip any disallowed character, then join with `_`;
    - on a collision, append `_2`, then `_3`, and so on.
    - e.g. `mongodb` + `test` + `default` → `mongod_test_default`; `mongodb` + `test` + `default` + `GEN_GET_ALL` → `mongod_test_default_GEN_GE`.

#### 4.3 Where the `name` value lives, per item type

This is the part that is easy to get wrong.

- **`Schemas`** — `name` goes **inside the code** of `<name>.config.ts`, as a top-level `let name: string = '...'` that is exported alongside the schema. The export line must include it:
```typescript
import { ISchemaType, EType, ISchemaProperty, IPropertyValidation } from 'types';
import * as T from 'types';

let name: string = 'mongod_test_default'; // Folder name of this schema in git. It has to be unique.

let schema: ISchemaType = {
    // ... unchanged
};

module.exports = { name, schema };
```
- **`Instance API settings`** — for **all three** levels (database / collection / API settings), `name` goes **inside the code** of `<name>.config.ts`, as a property of the exported settings object. Both `T.IInstanceApiSettingsTypes` (database & collection level) and `T.IInstanceApiSettingsTypesForAPI` (API level) accept it:
```typescript
let instanceColSetting: T.IInstanceApiSettingsTypes = {
    name: 'mongod_test_default', // Folder name of this item in git. It has to be unique.
    enableCaching: false,
    // ... unchanged
};
module.exports = instanceColSetting;
```
- **All hooks** (`Instance hooks`, `Database hooks`, `Collection hooks`, `Instance API hooks`) and **`WebSocket events`** — these have no settings code, so `name` is a plain key in the item's **`<name>.yaml`** file.
- **The `.yaml` also carries a `name` key for `Schemas` and `Instance API settings`.** Keep the two in sync — write the same value in the `.yaml` and in the `.config.ts`. On save the value **from the code wins**, and it is only applied when the code actually sets it: deleting `name` from the code does **not** clear the stored name (that is deliberate, so old unnamed items keep their `guid` folder), it just leaves a stale name behind. Never let the two disagree.
- **Do not change the `__DATABASE_SETTINGS__` / `__COLLECTION_SETTINGS__` values.** They remain exactly as-is in `collectionName` / `apiId` inside the `.yaml`. Only the *folder* gets shorter, via `name`.

#### 4.4 Renaming a folder: three names must change together

Git pull reads the `.yaml` and `.config.ts` **by the folder name**, so a mismatch silently fails to load the item:

- the folder: `<name>/`
- the config file inside it: `<name>.yaml`
- the code file inside it (`Schemas` and `Instance API settings` only): `<name>.config.ts`
- …and the `name` value written *inside* that `.yaml` / `.config.ts` must equal the folder name too.

Hook code files (`pre-hooks/*.ts`, `post-hooks/*.ts`) are named after the hook, not the item — do not rename them.

#### 4.5 `WebSocket events` — extra rules

- **Every WS event should have a `name`.** In v2 only custom WS events had one; instance / custom-API / system / third-party events had none. In v3 `name` is the git folder name for **every** category and must be unique across **all** categories together (not just within one category).
    - If you leave it empty, the save does **not** fail — the event's `guid` is written into `name` automatically, and the folder becomes that guid. That works, but you get a long unreadable folder, so set a real name.
- For tree-style custom events the `name` is a path like `level1/level2/name` — `/` is allowed **only** for these, and it is stripped when the folder is written. Leading and trailing `/` are removed on save.
- For custom (tree) WS events there is an additional constraint: **one event's name may not contain another event's name as a substring** — it would break tree generation. So `orders` and `orders/new` cannot both exist.
- **Set the new `authProvider` key.** This is a **v3-only** field with no v2 source: it names the one auth provider whose token a client must hold to subscribe to that event, and a client connecting with any other provider's token is refused at REGISTER time. Like `name`, it is a plain key in the event's `<name>.yaml` — e.g. `authProvider: customers_token`.
    - Use one of the exact provider names created in step 2. An event whose `authProvider` names a provider that does not exist (or is inactive) is refused at REGISTER time, so a typo here silently breaks subscriptions.
    - **Leaving it empty is the risky outcome, not the safe one.** An event with no `authProvider` falls back to the account's **first** auth provider by name ascending — fine while a repo has exactly one provider, wrong as soon as it has two. Set it explicitly on every WS event whose subscribers log in through a specific provider.
    - Pick the provider the event's clients actually authenticate with. If the v2 client connected with `authTokenInfo=<something>` in its WebSocket URL, the provider you created from that entry in step 2 is the one to use here.

> **Idempotency / guardrails:** If an item's folder name contains no ` -- ` it is already migrated (or is a `guid`) — leave it alone. If you rename a folder, rename its inner `.yaml`/`.config.ts` in the same step and never leave a half-renamed item. Do not invent a `name` for `Third party APIs`, `Third party API settings`, `System API settings`, `System API hooks` or `Utility classes`. Changing nothing is always safe: those items keep using their `guid`.

### 5. After migration — verify

- Make sure every name listed in any `authProviders` array has a matching auth provider in the `Auth Providers` folder.
- Confirm the number of distinct auth providers you created equals the number of distinct auth objects in the original v2 `authTokenInfo` arrays.
- Make sure no `authTokenInfo` field (or `IAuthTokenInfo` / `EAuthTokenType` references / imports) remains anywhere in the migrated repository — except any WebSocket connection URL you deliberately kept it in as a filter, and the two `ws-local-client-sync` / `ws-browser-client-sync` literals, both noted in step 3.
- Confirm every WebSocket connection URL still carries the token keys themselves (`x-am-authorization` plus the provider-type key) — dropping `authTokenInfo` is only safe because the token is what identifies the provider.
- Confirm every `WebSocket events` item has an `authProvider` naming one of the providers created in step 2, and that no event was left to the first-provider fallback by accident.
- For every folder you renamed in step 4, confirm the folder, its `.yaml` and its `.config.ts` (where present) all share the exact same name, and that the `name` inside the code/yaml matches that folder name too.
- For `Schemas` and `Instance API settings`, confirm the `name` in the `.config.ts` code and the `name` in the `.yaml` are identical — the code value wins on save, so a disagreement is a silent rename.
- Confirm every `name` you assigned is unique per item type, that it matches `[a-zA-Z0-9 _-]` (plus `/` for WebSocket events only), and that every `WebSocket events` item has one.
- Confirm no folder under `Schemas`, `Collection hooks`, `Database hooks`, `Instance hooks`, `Instance API hooks`, `Instance API settings` or `WebSocket events` still contains ` -- `, and that folders under `Third party APIs`, `Third party API settings` and `Utility classes` still **do**.
- Confirm you did **not** add a `name` property to any `T.ITPApiSettingsTypes`, `T.ITPApiSettingsTypesAPILevel` or `T.ISystemApiSettingsTypes` settings object — those interfaces have no `name` and it will not typecheck.
- Confirm the `Instance API settings` items whose `apiId` is `__DATABASE_SETTINGS__` or `__COLLECTION_SETTINGS__` were renamed too — they are easy to miss because they are "database/collection settings" but live in the `Instance API settings` folder.
- If the target repo is a buildable TypeScript project, run its build/lint and confirm it compiles after the cast and import changes.
