π API Maker v2 to v3 repository migration prompt
β Jun 2026 β
Project Directory : /Volumes/Data/code/Git/sava_ecom_be
Below is secret value and you can use that as auth provider name :
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 | Deploy the repo to v3 and commit the regenerated src/assets/schema-types/types.ts. |
| β | 0 | Discover every occurrence | Grep the whole repo for authTokenInfo, IAuthTokenInfo, EAuthTokenType. |
| β | 1 | authTokenInfo β authProviders |
Rename the field, change the cast to <string[]>, drop unused imports. |
| β | 2 | Create the Auth Providers | Extract every inline auth object into a named provider under Auth Providers, de-duplicated. |
| β | 3 | Get Token + headers + WebSocket | Get Token now takes a provider name; each provider type has its own request header. |
| β | 4 | Short folder names β give a name |
7 folder types are now named by their name property instead of ins -- db -- col -- api. |
| β | 4a | Know which items have a name |
Only those 7. Do not invent a name for third party / system / utility items. |
| β | 4b | Put name in the right place |
Schemas + Instance API settings β inside the .config.ts code. Everything else β the .yaml. |
| β | 4c | Rename folder + .yaml + .config.ts together |
A mismatch makes git pull silently skip the item. |
| β | 4d | Set authProvider on every WebSocket event |
v3-only field; leaving it empty falls back to the first provider alphabetically. |
| β | 5 | 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
authProvidersarray) 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.tsin a v2 repo is the old v2 file β it does not yet contain the v3 auth-provider interfaces or theauthProvidersfield. - 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
authTokenInfois nowauthProvidersand 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):
- In v3 it becomes just the list of provider names. Change the cast from
<T.IAuthTokenInfo[]>to<string[]>, and remove any now-unused imports ofT.IAuthTokenInfo/T.EAuthTokenTypeso the code still compiles: - An empty array (
authProviders: <string[]>[]) keeps its v2 meaning: it overrides the default secret so only API Maker's API user token is accepted inx-am-authorization. Create no providers for an empty array. - If
authTokenInfois omitted, omitauthProviderstoo (make zero edits to that file) β it will inherit from the default secret. - Leave
apiAccessTypeexactly where it is. In v2apiAccessType(NO_ACCESS | IS_PUBLIC | TOKEN_ACCESS) is a sibling api-level field next toauthTokenInfo, not part of any token object β it is unrelated to theauthProvidersrename and must not be touched.
Idempotency / guardrails: If a settings file already uses
authProviders(the v2authTokenInfokey 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 Providersfolder, 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 everyauthProvidersarray 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
authTokenTypeand 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
EAuthTokenTypehas exactly these five members:AM,AM_DB,AWS,AZURE. There is noCUSTOMmember and noauthTokenCustomobject in v2 β do not look for them.CUSTOM_TOKEN_GENERATORis a v3-only provider type with no v2 source to migrate.
-
You can check the property details in the
types.tsfile forIAuthTokenAMDB,IAuthTokenGoogle,IAuthTokenAWS,IAuthTokenAzureAD. -
Per-type fields to carry over (verify against
src/assets/schema-types/types.tsandsrc/ajv/mongoose/MongooseAuthProviders_Vali.ts):AM_DBβDB_TOKEN_GENERATOR: carryinstance,database,collection(MongoDB) ortable(SQL),usernameColumn,passwordColumn, and also the two load-bearing columnspasswordChangedAtColumnandgroupsColumn.groupsColumndrives group/role access;passwordChangedAtColumnchanges 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 isappId(documented as the OAuthclient_id), NOTclientId. CarryappId,tenant,audience,issuer,maxRetries.GOOGLE:clientId.
- Groups / roles config (AWS, Azure, Google only): these three providers each also carry the shared
IAuthTokenGroupsPropertiesconfig βsourceFieldOfUniqueId(the token field holding the user's unique id) andgroupsDataSource({ 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. (ForAM_DBthe equivalent is the inlinegroupsColumnfield β there is nogroupsDataSource.) -
expiresInSecondsis v3-only. v2 has no per-tokenexpiresInSeconds(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 Providersfolder, each provider named<name>uses these files:<name>.yamlβ the config file that storesgeneratorType(DB_TOKEN_GENERATOR/CUSTOM_TOKEN_GENERATOR/AWS/GOOGLE/AZURE) and the materialized config fields. This is the source of truth for the provider type, andgeneratorTypeis 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 correctgeneratorTypeinto<name>.yaml; never try to reconstruct the type from which.ts/.tg.ts/.tv.ts/.fg.tsfiles exist.<name>.tsβ basic info / DB token generator code.<name>.tg.tsβ custom token generator code (only forCUSTOM_TOKEN_GENERATOR).<name>.tv.tsβ custom token validator code (only forCUSTOM_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 theAM_DBcolumn 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.tsis always emitted forDB_TOKEN_GENERATOReven when empty, and only when a fields-generator function is set forCUSTOM_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 withoutu/p), andexpiresInSeconds?(optional). Routing is byname:- When
nameis omitted, the request hits the API Maker user path, where the request body'sexpiresInSecondsis honored directly. - When a
nameis supplied, it resolves a DB/Custom auth provider and the token expiry comes from that provider's configuredexpiresInSeconds(the request-body value is ignored on that path).[ { "name": "token_generator_name", "u": "[email protected]", "p": "student1" }, { // When name is not provided, system will generate API Maker User's token "u": "default", "p": "12345", "expiresInSeconds": 259200 } ]
- When
- Get Token only mints tokens for
DB_TOKEN_GENERATORandCUSTOM_TOKEN_GENERATORproviders. 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) plusx-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
authTokenInfoparameter 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
authTokenInfoandauthProvidersare 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-syncandauthTokenInfo=ws-browser-client-syncare unrelated to provider names and must be left exactly as they are.
- Preferred migration: drop the
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
nameproperty. It no longer encodes instance / database / collection / api β those values live only inside the.yamlfile, 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 settingscovers three levels of settings, not one. Database settings and collection settings are not stored in theDatabase hooks/Collection hooksfolders β 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 theirapiId/collectionName:
Settings level Lives in folder Marked by Settings code type Database settings Instance API settingscollectionName=apiId=__DATABASE_SETTINGS__T.IInstanceApiSettingsTypesCollection settings Instance API settingsapiId=__COLLECTION_SETTINGS__T.IInstanceApiSettingsTypesAPI settings Instance API settingsa real apiId, e.g.GEN_GET_ALLT.IInstanceApiSettingsTypesForAPISo all three get their
nameinside the.config.tscode, not in the.yaml. Instance-level settings are the exception: they live inInstance hooks, have no settings code, and takenameas a plain.yamlkey.
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 hooksorUtility classes. They still compose their folder names with--(or withapiId) in v3 β that is not a leftover, it is correct.
4.2 Rules for a name value
nameis optional for all seven folders in group A. An item with nonamekeeps working and uses itsguidas the folder name. So doing nothing is a valid, non-breaking outcome β only rename an item when you are also giving it aname.- 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 anameare 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 eventsare 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.
- take the parts
4.3 Where the name value lives, per item type
This is the part that is easy to get wrong.
Schemasβnamegoes inside the code of<name>.config.ts, as a top-levellet name: string = '...'that is exported alongside the schema. The export line must include it:Instance API settingsβ for all three levels (database / collection / API settings),namegoes inside the code of<name>.config.ts, as a property of the exported settings object. BothT.IInstanceApiSettingsTypes(database & collection level) andT.IInstanceApiSettingsTypesForAPI(API level) accept it:- All hooks (
Instance hooks,Database hooks,Collection hooks,Instance API hooks) andWebSocket eventsβ these have no settings code, sonameis a plain key in the item's<name>.yamlfile. - The
.yamlalso carries anamekey forSchemasandInstance API settings. Keep the two in sync β write the same value in the.yamland in the.config.ts. On save the value from the code wins, and it is only applied when the code actually sets it: deletingnamefrom the code does not clear the stored name (that is deliberate, so old unnamed items keep theirguidfolder), 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 incollectionName/apiIdinside the.yaml. Only the folder gets shorter, vianame.
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 (
SchemasandInstance API settingsonly):<name>.config.ts - β¦and the
namevalue written inside that.yaml/.config.tsmust 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 v3nameis 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
guidis written intonameautomatically, and the folder becomes that guid. That works, but you get a long unreadable folder, so set a real name.
- If you leave it empty, the save does not fail β the event's
- For tree-style custom events the
nameis a path likelevel1/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
ordersandorders/newcannot both exist. - Set the new
authProviderkey. 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. Likename, 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
authProvidernames 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
authProviderfalls 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.
- Use one of the exact provider names created in step 2. An event whose
Idempotency / guardrails: If an item's folder name contains no
--it is already migrated (or is aguid) β leave it alone. If you rename a folder, rename its inner.yaml/.config.tsin the same step and never leave a half-renamed item. Do not invent anameforThird party APIs,Third party API settings,System API settings,System API hooksorUtility classes. Changing nothing is always safe: those items keep using theirguid.
5. After migration β verify
- Make sure every name listed in any
authProvidersarray has a matching auth provider in theAuth Providersfolder. - Confirm the number of distinct auth providers you created equals the number of distinct auth objects in the original v2
authTokenInfoarrays. - Make sure no
authTokenInfofield (orIAuthTokenInfo/EAuthTokenTypereferences / imports) remains anywhere in the migrated repository β except any WebSocket connection URL you deliberately kept it in as a filter, and the twows-local-client-sync/ws-browser-client-syncliterals, both noted in step 3. - Confirm every WebSocket connection URL still carries the token keys themselves (
x-am-authorizationplus the provider-type key) β droppingauthTokenInfois only safe because the token is what identifies the provider. - Confirm every
WebSocket eventsitem has anauthProvidernaming 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
.yamland its.config.ts(where present) all share the exact same name, and that thenameinside the code/yaml matches that folder name too. - For
SchemasandInstance API settings, confirm thenamein the.config.tscode and thenamein the.yamlare identical β the code value wins on save, so a disagreement is a silent rename. - Confirm every
nameyou assigned is unique per item type, that it matches[a-zA-Z0-9 _-](plus/for WebSocket events only), and that everyWebSocket eventsitem has one. - Confirm no folder under
Schemas,Collection hooks,Database hooks,Instance hooks,Instance API hooks,Instance API settingsorWebSocket eventsstill contains--, and that folders underThird party APIs,Third party API settingsandUtility classesstill do. - Confirm you did not add a
nameproperty to anyT.ITPApiSettingsTypes,T.ITPApiSettingsTypesAPILevelorT.ISystemApiSettingsTypessettings object β those interfaces have nonameand it will not typecheck. - Confirm the
Instance API settingsitems whoseapiIdis__DATABASE_SETTINGS__or__COLLECTION_SETTINGS__were renamed too β they are easy to miss because they are "database/collection settings" but live in theInstance API settingsfolder. - If the target repo is a buildable TypeScript project, run its build/lint and confirm it compiles after the cast and import changes.