@unifiedcommerce/core 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/types.d.ts +2 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/interfaces/mcp/tools/analytics.d.ts +1 -1
- package/dist/interfaces/mcp/tools/catalog.d.ts +1 -1
- package/dist/interfaces/mcp/tools/webhooks.d.ts +1 -1
- package/dist/interfaces/rest/index.d.ts.map +1 -1
- package/dist/interfaces/rest/index.js +17 -0
- package/dist/interfaces/rest/routes/entity-aliases.d.ts +18 -0
- package/dist/interfaces/rest/routes/entity-aliases.d.ts.map +1 -0
- package/dist/interfaces/rest/routes/entity-aliases.js +39 -0
- package/dist/runtime/server.d.ts.map +1 -1
- package/dist/runtime/server.js +12 -1
- package/package.json +1 -1
- package/src/interfaces/rest/index.ts +4 -32
- package/src/interfaces/rest/routes/entity-aliases.ts +29 -326
- package/src/runtime/server.ts +33 -0
package/dist/config/types.d.ts
CHANGED
|
@@ -41,6 +41,8 @@ export interface EntityConfig {
|
|
|
41
41
|
variants: EntityVariantConfig;
|
|
42
42
|
fulfillment: string;
|
|
43
43
|
hooks?: EntityHooks;
|
|
44
|
+
/** Optional URL alias. Generates ergonomic CRUD routes at `/api/{alias}` that delegate to the catalog service with `type` pre-injected. E.g., `alias: "products"` creates `GET /api/products`, `POST /api/products`, etc. */
|
|
45
|
+
alias?: string;
|
|
44
46
|
}
|
|
45
47
|
/**
|
|
46
48
|
* A predefined API key scope — a named set of permissions, prefix, and rate limit.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACpD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEhG,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,WAAW,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,WAAW,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,WAAW,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,SAAS,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,SAAS,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAChC,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACpD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,CAAC;AAEhG,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,WAAW,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,WAAW,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,WAAW,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,SAAS,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,SAAS,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAChC,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,6NAA6N;IAC7N,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,2FAA2F;IAC3F,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACtC,sDAAsD;IACtD,SAAS,CAAC,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,mCAAmC;QACnC,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7E,SAAS,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC9D,OAAO,CAAC,EAAE;QACR,OAAO,EAAE,OAAO,CAAC;QACjB,qEAAqE;QACrE,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;KAC/B,CAAC;IACF,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACvC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IACrD;;;;;OAKG;IACH,SAAS,CAAC,EAAE;QACV,wFAAwF;QACxF,OAAO,EAAE,CAAC,MAAM,EAAE;YAAE,WAAW,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/F,wFAAwF;QACxF,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE;YAAE,WAAW,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QACxG,8BAA8B;QAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,uDAAuD;QACvD,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,4FAA4F;QAC5F,oBAAoB,CAAC,EAAE;YACrB,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,CAAC;YAC9C,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,CAAC;SAC/C,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE;QACN,aAAa,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,YAAY,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,gBAAgB,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,eAAe,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;QACvC,oBAAoB,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,mBAAmB,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;KAC5C,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACrC,WAAW,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;KACpC,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACrC,WAAW,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,kBAAkB,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3C,iBAAiB,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,QAAQ,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;KACtC,CAAC;IACF;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE;QACN,WAAW,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;KACpC,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,cAAc,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,kBAAkB,CAAC,EAAE;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,OAAO,CAAC;QAAE,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CAC5E;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,MAAM,EAAE,cAAc,KACnB,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;AAE9C,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE;QACR,QAAQ,EAAE,YAAY,CAAC;QACvB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,CAAC;IACF,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACxC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,KAAK,EAAE;YACV,QAAQ,EAAE,MAAM,CAAC;YACjB,EAAE,EAAE,MAAM,CAAC;YACX,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SAChC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACnB,CAAC;IACF,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,GAAG,CAAC,EAAE;QACJ,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,yDAAyD;QACzD,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;KACjC,CAAC;IACF,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,WAAW,CAAC;QACtB,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;QACzB,OAAO,CAAC,EAAE;YACR,OAAO,EAAE,OAAO,CAAC;YACjB,UAAU,CAAC,EAAE,MAAM,CAAC;SACrB,CAAC;KACH,CAAC;IACF;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxC,6EAA6E;IAC7E,aAAa,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC;IAC/D,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACjC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACnD,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,EAAE,CAAC;IAC1C,yDAAyD;IACzD,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;IACnE;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,+BAA+B;IAC/B,UAAU,CAAC,EAAE;QACX,yDAAyD;QACzD,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,2DAA2D;QAC3D,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,oDAAoD;QACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,iBAAkB,SAAQ,cAAc;CAAG;AAE5D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC1B,CAAC;IACF,OAAO,EAAE;QACP,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACrC,sBAAsB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACxC,CAAC;CACH;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB"}
|
|
@@ -6,9 +6,9 @@ export declare const analyticsQuery: ToolDefinition<z.ZodObject<{
|
|
|
6
6
|
timeDimensions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
7
7
|
dimension: z.ZodString;
|
|
8
8
|
granularity: z.ZodOptional<z.ZodEnum<{
|
|
9
|
+
month: "month";
|
|
9
10
|
day: "day";
|
|
10
11
|
week: "week";
|
|
11
|
-
month: "month";
|
|
12
12
|
year: "year";
|
|
13
13
|
}>>;
|
|
14
14
|
dateRange: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodTuple<[z.ZodString, z.ZodString], null>]>>;
|
|
@@ -23,10 +23,10 @@ export declare const catalogGet: ToolDefinition<z.ZodObject<{
|
|
|
23
23
|
}, z.core.$strip>>;
|
|
24
24
|
export declare const catalogManage: ToolDefinition<z.ZodObject<{
|
|
25
25
|
action: z.ZodEnum<{
|
|
26
|
-
update: "update";
|
|
27
26
|
delete: "delete";
|
|
28
27
|
publish: "publish";
|
|
29
28
|
archive: "archive";
|
|
29
|
+
update: "update";
|
|
30
30
|
discontinue: "discontinue";
|
|
31
31
|
set_attributes: "set_attributes";
|
|
32
32
|
assign_category: "assign_category";
|
|
@@ -2,8 +2,8 @@ import { z } from "zod";
|
|
|
2
2
|
import type { ToolDefinition } from "./registry.js";
|
|
3
3
|
export declare const webhooksManage: ToolDefinition<z.ZodObject<{
|
|
4
4
|
action: z.ZodEnum<{
|
|
5
|
-
create: "create";
|
|
6
5
|
delete: "delete";
|
|
6
|
+
create: "create";
|
|
7
7
|
list: "list";
|
|
8
8
|
}>;
|
|
9
9
|
url: z.ZodOptional<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/interfaces/rest/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/interfaces/rest/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAiBzC,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,gCAqF9C"}
|
|
@@ -15,6 +15,7 @@ import { searchRoutes } from "./routes/search.js";
|
|
|
15
15
|
import { auditRoutes } from "./routes/audit.js";
|
|
16
16
|
import { adminJobRoutes } from "./routes/admin-jobs.js";
|
|
17
17
|
import { customerRoutes } from "./routes/customers.js";
|
|
18
|
+
import { registerEntityAliases } from "./routes/entity-aliases.js";
|
|
18
19
|
export function createRestRoutes(kernel) {
|
|
19
20
|
const router = new OpenAPIHono({
|
|
20
21
|
// Standardize Zod validation error responses across all routes
|
|
@@ -61,6 +62,22 @@ export function createRestRoutes(kernel) {
|
|
|
61
62
|
router.route("/customers", customerRoutes(kernel));
|
|
62
63
|
router.route("/audit", auditRoutes(kernel));
|
|
63
64
|
router.route("/admin", adminJobRoutes(kernel));
|
|
65
|
+
// ─── Aliases ────────────────────────────────────────────────
|
|
66
|
+
// Entity aliases: /api/{alias} → /api/catalog/entities?type={type}
|
|
67
|
+
registerEntityAliases(router, kernel);
|
|
68
|
+
// Static aliases: shorter paths for catalog sub-resources
|
|
69
|
+
for (const [shortcut, target] of [["categories", "catalog/categories"], ["brands", "catalog/brands"]]) {
|
|
70
|
+
router.all(`/${shortcut}`, (c) => {
|
|
71
|
+
const url = new URL(c.req.url);
|
|
72
|
+
url.pathname = `/api/${target}`;
|
|
73
|
+
return router.fetch(new Request(url.toString(), c.req.raw));
|
|
74
|
+
});
|
|
75
|
+
router.all(`/${shortcut}/*`, (c) => {
|
|
76
|
+
const url = new URL(c.req.url);
|
|
77
|
+
url.pathname = url.pathname.replace(`/api/${shortcut}`, `/api/${target}`);
|
|
78
|
+
return router.fetch(new Request(url.toString(), c.req.raw));
|
|
79
|
+
});
|
|
80
|
+
}
|
|
64
81
|
// API Reference (Scalar) — disabled in production unless config.exposeOpenApiSpec is true
|
|
65
82
|
const exposeSpec = kernel.config.exposeOpenApiSpec ?? (process.env.NODE_ENV !== "production");
|
|
66
83
|
if (exposeSpec) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
+
import type { Kernel } from "../../../runtime/kernel.js";
|
|
3
|
+
import type { AppEnv } from "../utils.js";
|
|
4
|
+
/**
|
|
5
|
+
* Register URL rewrite aliases for entity types that define `alias` in config.
|
|
6
|
+
*
|
|
7
|
+
* E.g., `entities.product.alias = "products"` rewrites:
|
|
8
|
+
* /api/products → /api/catalog/entities?type=product
|
|
9
|
+
* /api/products/:id → /api/catalog/entities/:id
|
|
10
|
+
* /api/products/:id/... → /api/catalog/entities/:id/...
|
|
11
|
+
*
|
|
12
|
+
* This is a thin rewrite layer — no handler duplication. The original
|
|
13
|
+
* catalog routes handle all logic, validation, and OpenAPI schema.
|
|
14
|
+
*
|
|
15
|
+
* The `type` filter is injected automatically on list requests.
|
|
16
|
+
*/
|
|
17
|
+
export declare function registerEntityAliases(router: OpenAPIHono<AppEnv>, kernel: Kernel): void;
|
|
18
|
+
//# sourceMappingURL=entity-aliases.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-aliases.d.ts","sourceRoot":"","sources":["../../../../src/interfaces/rest/routes/entity-aliases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,EAC3B,MAAM,EAAE,MAAM,GACb,IAAI,CA4BN"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register URL rewrite aliases for entity types that define `alias` in config.
|
|
3
|
+
*
|
|
4
|
+
* E.g., `entities.product.alias = "products"` rewrites:
|
|
5
|
+
* /api/products → /api/catalog/entities?type=product
|
|
6
|
+
* /api/products/:id → /api/catalog/entities/:id
|
|
7
|
+
* /api/products/:id/... → /api/catalog/entities/:id/...
|
|
8
|
+
*
|
|
9
|
+
* This is a thin rewrite layer — no handler duplication. The original
|
|
10
|
+
* catalog routes handle all logic, validation, and OpenAPI schema.
|
|
11
|
+
*
|
|
12
|
+
* The `type` filter is injected automatically on list requests.
|
|
13
|
+
*/
|
|
14
|
+
export function registerEntityAliases(router, kernel) {
|
|
15
|
+
const entities = kernel.config.entities ?? {};
|
|
16
|
+
for (const [entityType, entityConfig] of Object.entries(entities)) {
|
|
17
|
+
if (!entityConfig.alias)
|
|
18
|
+
continue;
|
|
19
|
+
const alias = entityConfig.alias;
|
|
20
|
+
// /api/{alias} → /api/catalog/entities?type={entityType}
|
|
21
|
+
router.all(`/${alias}`, (c) => {
|
|
22
|
+
const url = new URL(c.req.url);
|
|
23
|
+
url.pathname = "/api/catalog/entities";
|
|
24
|
+
// Inject type filter for list requests
|
|
25
|
+
if (c.req.method === "GET") {
|
|
26
|
+
url.searchParams.set("type", entityType);
|
|
27
|
+
}
|
|
28
|
+
const newReq = new Request(url.toString(), c.req.raw);
|
|
29
|
+
return router.fetch(newReq);
|
|
30
|
+
});
|
|
31
|
+
// /api/{alias}/:rest → /api/catalog/entities/:rest
|
|
32
|
+
router.all(`/${alias}/*`, (c) => {
|
|
33
|
+
const url = new URL(c.req.url);
|
|
34
|
+
url.pathname = url.pathname.replace(`/api/${alias}`, "/api/catalog/entities");
|
|
35
|
+
const newReq = new Request(url.toString(), c.req.raw);
|
|
36
|
+
return router.fetch(newReq);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/runtime/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKhD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAOzD,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtE,KAAK,SAAS,GAAG;IACf,SAAS,EAAE;QACT,IAAI,EAAE,YAAY,CAAC;QACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,cAAc;;;;;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/runtime/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAKhD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAOzD,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtE,KAAK,SAAS,GAAG;IACf,SAAS,EAAE;QACT,IAAI,EAAE,YAAY,CAAC;QACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,cAAc;;;;;GAuWxD"}
|
package/dist/runtime/server.js
CHANGED
|
@@ -208,8 +208,15 @@ export async function createServer(config) {
|
|
|
208
208
|
description: "Headless commerce engine REST API. Includes core and plugin endpoints.",
|
|
209
209
|
},
|
|
210
210
|
tags: [
|
|
211
|
+
// ── Entity aliases (generated from config.entities[type].alias) ──
|
|
212
|
+
...Object.entries(config.entities ?? {})
|
|
213
|
+
.filter(([, cfg]) => cfg.alias)
|
|
214
|
+
.map(([type, cfg]) => {
|
|
215
|
+
const name = cfg.alias.charAt(0).toUpperCase() + cfg.alias.slice(1);
|
|
216
|
+
return { name, description: `Ergonomic alias for ${type} entities — CRUD, variants, attributes` };
|
|
217
|
+
}),
|
|
211
218
|
// ── Storefront ──
|
|
212
|
-
{ name: "Catalog", description: "Products, categories, brands, variants, and option types" },
|
|
219
|
+
{ name: "Catalog", description: "Products, categories, brands, variants, and option types (unified entity API)" },
|
|
213
220
|
{ name: "Search", description: "Full-text search and typeahead suggestions" },
|
|
214
221
|
{ name: "Pricing", description: "Base prices, price modifiers, and customer group pricing" },
|
|
215
222
|
{ name: "Carts", description: "Shopping cart lifecycle — create, add items, update quantities" },
|
|
@@ -228,7 +235,11 @@ export async function createServer(config) {
|
|
|
228
235
|
],
|
|
229
236
|
});
|
|
230
237
|
// Serve enriched spec with x-tagGroups vendor extension (Scalar/Redocly sidebar grouping)
|
|
238
|
+
const aliasTags = Object.values(config.entities ?? {})
|
|
239
|
+
.filter((cfg) => cfg.alias)
|
|
240
|
+
.map((cfg) => cfg.alias.charAt(0).toUpperCase() + cfg.alias.slice(1));
|
|
231
241
|
const tagGroups = [
|
|
242
|
+
...(aliasTags.length > 0 ? [{ name: "Quick Access", tags: aliasTags }] : []),
|
|
232
243
|
{ name: "Storefront", tags: ["Catalog", "Search", "Pricing", "Carts", "Checkout", "Promotions"] },
|
|
233
244
|
{ name: "Admin", tags: ["Orders", "Customers", "Inventory", "Media", "Payments"] },
|
|
234
245
|
{ name: "Operations", tags: ["Webhooks", "Audit", "Admin Jobs"] },
|
package/package.json
CHANGED
|
@@ -17,7 +17,8 @@ import { searchRoutes } from "./routes/search.js";
|
|
|
17
17
|
import { auditRoutes } from "./routes/audit.js";
|
|
18
18
|
import { adminJobRoutes } from "./routes/admin-jobs.js";
|
|
19
19
|
import { customerRoutes } from "./routes/customers.js";
|
|
20
|
-
|
|
20
|
+
// Entity aliases are registered in server.ts on the top-level app (not this sub-router)
|
|
21
|
+
// because internal re-dispatch requires app.fetch(), not router.fetch().
|
|
21
22
|
|
|
22
23
|
export function createRestRoutes(kernel: Kernel) {
|
|
23
24
|
const router = new OpenAPIHono<AppEnv>({
|
|
@@ -67,37 +68,8 @@ export function createRestRoutes(kernel: Kernel) {
|
|
|
67
68
|
router.route("/audit", auditRoutes(kernel));
|
|
68
69
|
router.route("/admin", adminJobRoutes(kernel));
|
|
69
70
|
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
const aliasPath = (aliasRouter as unknown as Record<string, string>).__aliasPath;
|
|
73
|
-
if (aliasPath) {
|
|
74
|
-
router.route(`/${aliasPath}`, aliasRouter);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// ─── Static shortcut aliases ───────────────────────────────
|
|
79
|
-
// /api/categories → forwards to /api/catalog/categories
|
|
80
|
-
router.all("/categories/*", (c) => {
|
|
81
|
-
const url = new URL(c.req.url);
|
|
82
|
-
url.pathname = url.pathname.replace("/api/categories", "/api/catalog/categories");
|
|
83
|
-
return router.fetch(new Request(url.toString(), c.req.raw));
|
|
84
|
-
});
|
|
85
|
-
router.all("/categories", (c) => {
|
|
86
|
-
const url = new URL(c.req.url);
|
|
87
|
-
url.pathname = "/api/catalog/categories";
|
|
88
|
-
return router.fetch(new Request(url.toString(), c.req.raw));
|
|
89
|
-
});
|
|
90
|
-
// /api/brands → forwards to /api/catalog/brands
|
|
91
|
-
router.all("/brands/*", (c) => {
|
|
92
|
-
const url = new URL(c.req.url);
|
|
93
|
-
url.pathname = url.pathname.replace("/api/brands", "/api/catalog/brands");
|
|
94
|
-
return router.fetch(new Request(url.toString(), c.req.raw));
|
|
95
|
-
});
|
|
96
|
-
router.all("/brands", (c) => {
|
|
97
|
-
const url = new URL(c.req.url);
|
|
98
|
-
url.pathname = "/api/catalog/brands";
|
|
99
|
-
return router.fetch(new Request(url.toString(), c.req.raw));
|
|
100
|
-
});
|
|
71
|
+
// Aliases (entity + categories/brands) are registered in server.ts on the
|
|
72
|
+
// top-level app, not here, because re-dispatch requires app.fetch().
|
|
101
73
|
|
|
102
74
|
// API Reference (Scalar) — disabled in production unless config.exposeOpenApiSpec is true
|
|
103
75
|
const exposeSpec = kernel.config.exposeOpenApiSpec ?? (process.env.NODE_ENV !== "production");
|
|
@@ -1,346 +1,49 @@
|
|
|
1
1
|
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
-
import { z, createRoute } from "@hono/zod-openapi";
|
|
3
2
|
import type { Kernel } from "../../../runtime/kernel.js";
|
|
4
|
-
import type {
|
|
5
|
-
import {
|
|
6
|
-
type AppEnv,
|
|
7
|
-
mapErrorToResponse,
|
|
8
|
-
mapErrorToStatus,
|
|
9
|
-
parseInclude,
|
|
10
|
-
parsePagination,
|
|
11
|
-
parseSort,
|
|
12
|
-
} from "../utils.js";
|
|
13
|
-
import { errorResponses } from "../schemas/shared.js";
|
|
3
|
+
import type { AppEnv } from "../utils.js";
|
|
14
4
|
|
|
15
5
|
/**
|
|
16
|
-
*
|
|
6
|
+
* Register URL rewrite aliases for entity types that define `alias` in config.
|
|
17
7
|
*
|
|
18
|
-
* E.g.,
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* PATCH /api/products/:id
|
|
23
|
-
* DELETE /api/products/:id
|
|
24
|
-
* POST /api/products/:id/publish
|
|
25
|
-
* POST /api/products/:id/archive
|
|
26
|
-
* GET /api/products/:id/variants
|
|
27
|
-
* POST /api/products/:id/variants
|
|
28
|
-
* GET /api/products/:id/options
|
|
29
|
-
* GET /api/products/:id/attributes/:locale
|
|
30
|
-
* PUT /api/products/:id/attributes/:locale
|
|
8
|
+
* E.g., `entities.product.alias = "products"` rewrites:
|
|
9
|
+
* /api/products → /api/catalog/entities?type=product
|
|
10
|
+
* /api/products/:id → /api/catalog/entities/:id
|
|
11
|
+
* /api/products/:id/... → /api/catalog/entities/:id/...
|
|
31
12
|
*
|
|
32
|
-
*
|
|
13
|
+
* This is a thin rewrite layer — no handler duplication. The original
|
|
14
|
+
* catalog routes handle all logic, validation, and OpenAPI schema.
|
|
15
|
+
*
|
|
16
|
+
* The `type` filter is injected automatically on list requests.
|
|
33
17
|
*/
|
|
34
|
-
export function
|
|
35
|
-
|
|
18
|
+
export function registerEntityAliases(
|
|
19
|
+
router: OpenAPIHono<AppEnv>,
|
|
20
|
+
kernel: Kernel,
|
|
21
|
+
): void {
|
|
36
22
|
const entities = kernel.config.entities ?? {};
|
|
37
23
|
|
|
38
24
|
for (const [entityType, entityConfig] of Object.entries(entities)) {
|
|
39
25
|
if (!entityConfig.alias) continue;
|
|
40
26
|
|
|
41
27
|
const alias = entityConfig.alias;
|
|
42
|
-
const tag = alias.charAt(0).toUpperCase() + alias.slice(1);
|
|
43
|
-
const router = new OpenAPIHono<AppEnv>();
|
|
44
|
-
|
|
45
|
-
// ─── LIST ─────────────────────────────────────────────────
|
|
46
|
-
const listRoute = createRoute({
|
|
47
|
-
method: "get",
|
|
48
|
-
path: "/",
|
|
49
|
-
tags: [tag],
|
|
50
|
-
summary: `List ${alias}`,
|
|
51
|
-
description: `Alias for GET /api/catalog/entities?type=${entityType}`,
|
|
52
|
-
request: {
|
|
53
|
-
query: z.object({
|
|
54
|
-
status: z.string().optional(),
|
|
55
|
-
category: z.string().optional(),
|
|
56
|
-
brand: z.string().optional(),
|
|
57
|
-
include: z.string().optional(),
|
|
58
|
-
sort: z.string().optional(),
|
|
59
|
-
page: z.string().optional(),
|
|
60
|
-
limit: z.string().optional(),
|
|
61
|
-
}),
|
|
62
|
-
},
|
|
63
|
-
responses: {
|
|
64
|
-
200: {
|
|
65
|
-
content: { "application/json": { schema: z.object({ data: z.array(z.record(z.string(), z.unknown())), meta: z.record(z.string(), z.unknown()) }) } },
|
|
66
|
-
description: `${tag} list`,
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
// @ts-expect-error -- openapi handler union return type
|
|
72
|
-
router.openapi(listRoute, async (c) => {
|
|
73
|
-
const include = parseInclude(c.req.query("include"));
|
|
74
|
-
const pagination = parsePagination(c.req.query());
|
|
75
|
-
const filter: Record<string, string> = { type: entityType };
|
|
76
|
-
const status = c.req.query("status");
|
|
77
|
-
const category = c.req.query("category");
|
|
78
|
-
const brand = c.req.query("brand");
|
|
79
|
-
if (status) filter.status = status;
|
|
80
|
-
if (category) filter.category = category;
|
|
81
|
-
if (brand) filter.brand = brand;
|
|
82
|
-
|
|
83
|
-
const payload: Record<string, unknown> = { filter, pagination };
|
|
84
|
-
const sort = parseSort(c.req.query("sort"));
|
|
85
|
-
if (sort) payload.sort = sort;
|
|
86
28
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
includeVariants: include.has("variants"),
|
|
95
|
-
includeOptionTypes: include.has("optionTypes"),
|
|
96
|
-
includeCategories: include.has("categories"),
|
|
97
|
-
includeBrands: include.has("brands"),
|
|
98
|
-
includeMedia: include.has("media"),
|
|
99
|
-
includeInventory: include.has("inventory"),
|
|
100
|
-
includePricing: include.has("pricing"),
|
|
101
|
-
};
|
|
102
|
-
items = await Promise.all(
|
|
103
|
-
items.map(async (item) => {
|
|
104
|
-
const full = await kernel.services.catalog.getById(item.id, opts);
|
|
105
|
-
return full.ok ? full.value : item;
|
|
106
|
-
}),
|
|
107
|
-
);
|
|
29
|
+
// /api/{alias} → /api/catalog/entities?type={entityType}
|
|
30
|
+
router.all(`/${alias}`, (c) => {
|
|
31
|
+
const url = new URL(c.req.url);
|
|
32
|
+
url.pathname = "/api/catalog/entities";
|
|
33
|
+
// Inject type filter for list requests
|
|
34
|
+
if (c.req.method === "GET") {
|
|
35
|
+
url.searchParams.set("type", entityType);
|
|
108
36
|
}
|
|
109
|
-
|
|
110
|
-
return
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// ─── GET BY ID/SLUG ───────────────────────────────────────
|
|
114
|
-
const getRoute = createRoute({
|
|
115
|
-
method: "get",
|
|
116
|
-
path: "/{idOrSlug}",
|
|
117
|
-
tags: [tag],
|
|
118
|
-
summary: `Get ${alias.slice(0, -1)} by ID or slug`,
|
|
119
|
-
request: {
|
|
120
|
-
params: z.object({ idOrSlug: z.string() }),
|
|
121
|
-
query: z.object({ include: z.string().optional() }),
|
|
122
|
-
},
|
|
123
|
-
responses: {
|
|
124
|
-
200: { content: { "application/json": { schema: z.object({ data: z.record(z.string(), z.unknown()) }) } }, description: `${tag} detail` },
|
|
125
|
-
...errorResponses,
|
|
126
|
-
},
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
// @ts-expect-error -- openapi handler union return type
|
|
130
|
-
router.openapi(getRoute, async (c) => {
|
|
131
|
-
const idOrSlug = c.req.valid("param").idOrSlug;
|
|
132
|
-
const include = parseInclude(c.req.query("include"));
|
|
133
|
-
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(idOrSlug);
|
|
134
|
-
const opts = {
|
|
135
|
-
includeAttributes: include.has("attributes"),
|
|
136
|
-
includeVariants: include.has("variants"),
|
|
137
|
-
includeOptionTypes: include.has("optionTypes"),
|
|
138
|
-
includeCategories: include.has("categories"),
|
|
139
|
-
includeBrands: include.has("brands"),
|
|
140
|
-
includeMedia: include.has("media"),
|
|
141
|
-
includeInventory: include.has("inventory"),
|
|
142
|
-
includePricing: include.has("pricing"),
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
const result = isUUID
|
|
146
|
-
? await kernel.services.catalog.getById(idOrSlug, opts)
|
|
147
|
-
: await kernel.services.catalog.getBySlug(idOrSlug, opts);
|
|
148
|
-
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
149
|
-
return c.json({ data: result.value });
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// ─── CREATE ───────────────────────────────────────────────
|
|
153
|
-
const createEntityRoute = createRoute({
|
|
154
|
-
method: "post",
|
|
155
|
-
path: "/",
|
|
156
|
-
tags: [tag],
|
|
157
|
-
summary: `Create ${alias.slice(0, -1)}`,
|
|
158
|
-
request: {
|
|
159
|
-
body: { content: { "application/json": { schema: z.object({ slug: z.string().optional(), title: z.string().optional(), description: z.string().optional(), metadata: z.record(z.string(), z.unknown()).optional() }).openapi(`Create${tag}Request`) } } },
|
|
160
|
-
},
|
|
161
|
-
responses: {
|
|
162
|
-
201: { content: { "application/json": { schema: z.object({ data: z.record(z.string(), z.unknown()) }) } }, description: `${tag} created` },
|
|
163
|
-
...errorResponses,
|
|
164
|
-
},
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
// @ts-expect-error -- openapi handler union return type
|
|
168
|
-
router.openapi(createEntityRoute, async (c) => {
|
|
169
|
-
const body = c.req.valid("json");
|
|
170
|
-
const input: CreateEntityInput = { type: entityType, ...body };
|
|
171
|
-
const result = await kernel.services.catalog.create(input, c.get("actor"));
|
|
172
|
-
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
173
|
-
return c.json({ data: result.value }, 201);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
// ─── UPDATE ───────────────────────────────────────────────
|
|
177
|
-
const updateRoute = createRoute({
|
|
178
|
-
method: "patch",
|
|
179
|
-
path: "/{id}",
|
|
180
|
-
tags: [tag],
|
|
181
|
-
summary: `Update ${alias.slice(0, -1)}`,
|
|
182
|
-
request: {
|
|
183
|
-
params: z.object({ id: z.string().uuid() }),
|
|
184
|
-
body: { content: { "application/json": { schema: z.object({ slug: z.string().optional(), title: z.string().optional(), description: z.string().optional(), metadata: z.record(z.string(), z.unknown()).optional() }).openapi(`Update${tag}Request`) } } },
|
|
185
|
-
},
|
|
186
|
-
responses: {
|
|
187
|
-
200: { content: { "application/json": { schema: z.object({ data: z.record(z.string(), z.unknown()) }) } }, description: `${tag} updated` },
|
|
188
|
-
...errorResponses,
|
|
189
|
-
},
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
// @ts-expect-error -- openapi handler union return type
|
|
193
|
-
router.openapi(updateRoute, async (c) => {
|
|
194
|
-
const { id } = c.req.valid("param");
|
|
195
|
-
const body = c.req.valid("json");
|
|
196
|
-
const input: UpdateEntityInput = { ...body };
|
|
197
|
-
const result = await kernel.services.catalog.update(id, input, c.get("actor"));
|
|
198
|
-
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
199
|
-
return c.json({ data: result.value });
|
|
37
|
+
const newReq = new Request(url.toString(), c.req.raw);
|
|
38
|
+
return router.fetch(newReq);
|
|
200
39
|
});
|
|
201
40
|
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
request: { params: z.object({ id: z.string().uuid() }) },
|
|
209
|
-
responses: {
|
|
210
|
-
200: { content: { "application/json": { schema: z.object({ data: z.object({ deleted: z.literal(true) }) }) } }, description: "Deleted" },
|
|
211
|
-
...errorResponses,
|
|
212
|
-
},
|
|
41
|
+
// /api/{alias}/:rest → /api/catalog/entities/:rest
|
|
42
|
+
router.all(`/${alias}/*`, (c) => {
|
|
43
|
+
const url = new URL(c.req.url);
|
|
44
|
+
url.pathname = url.pathname.replace(`/api/${alias}`, "/api/catalog/entities");
|
|
45
|
+
const newReq = new Request(url.toString(), c.req.raw);
|
|
46
|
+
return router.fetch(newReq);
|
|
213
47
|
});
|
|
214
|
-
|
|
215
|
-
// @ts-expect-error -- openapi handler union return type
|
|
216
|
-
router.openapi(deleteRoute, async (c) => {
|
|
217
|
-
const { id } = c.req.valid("param");
|
|
218
|
-
const result = await kernel.services.catalog.delete(id, c.get("actor"));
|
|
219
|
-
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
220
|
-
return c.json({ data: { deleted: true as const } });
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
// ─── PUBLISH / ARCHIVE ────────────────────────────────────
|
|
224
|
-
for (const action of ["publish", "archive"] as const) {
|
|
225
|
-
const actionRoute = createRoute({
|
|
226
|
-
method: "post",
|
|
227
|
-
path: `/{id}/${action}`,
|
|
228
|
-
tags: [tag],
|
|
229
|
-
summary: `${action.charAt(0).toUpperCase() + action.slice(1)} ${alias.slice(0, -1)}`,
|
|
230
|
-
request: { params: z.object({ id: z.string().uuid() }) },
|
|
231
|
-
responses: {
|
|
232
|
-
200: { content: { "application/json": { schema: z.object({ data: z.record(z.string(), z.unknown()) }) } }, description: `${tag} ${action}ed` },
|
|
233
|
-
...errorResponses,
|
|
234
|
-
},
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
// @ts-expect-error -- openapi handler union return type
|
|
238
|
-
router.openapi(actionRoute, async (c) => {
|
|
239
|
-
const { id } = c.req.valid("param");
|
|
240
|
-
const result = await kernel.services.catalog[action](id, c.get("actor"));
|
|
241
|
-
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
242
|
-
return c.json({ data: result.value });
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// ─── ATTRIBUTES ───────────────────────────────────────────
|
|
247
|
-
const getAttrsRoute = createRoute({
|
|
248
|
-
method: "get",
|
|
249
|
-
path: "/{id}/attributes/{locale}",
|
|
250
|
-
tags: [tag],
|
|
251
|
-
summary: `Get ${alias.slice(0, -1)} attributes`,
|
|
252
|
-
request: { params: z.object({ id: z.string().uuid(), locale: z.string() }) },
|
|
253
|
-
responses: {
|
|
254
|
-
200: { content: { "application/json": { schema: z.object({ data: z.record(z.string(), z.unknown()) }) } }, description: "Attributes" },
|
|
255
|
-
...errorResponses,
|
|
256
|
-
},
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
// @ts-expect-error -- openapi handler union return type
|
|
260
|
-
router.openapi(getAttrsRoute, async (c) => {
|
|
261
|
-
const { id, locale } = c.req.valid("param");
|
|
262
|
-
const result = await kernel.services.catalog.getAttributes(id, locale);
|
|
263
|
-
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
264
|
-
return c.json({ data: result.value });
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
const setAttrsRoute = createRoute({
|
|
268
|
-
method: "put",
|
|
269
|
-
path: "/{id}/attributes/{locale}",
|
|
270
|
-
tags: [tag],
|
|
271
|
-
summary: `Set ${alias.slice(0, -1)} attributes`,
|
|
272
|
-
request: {
|
|
273
|
-
params: z.object({ id: z.string().uuid(), locale: z.string() }),
|
|
274
|
-
body: { content: { "application/json": { schema: z.record(z.string(), z.unknown()).openapi(`Set${tag}AttributesRequest`) } } },
|
|
275
|
-
},
|
|
276
|
-
responses: {
|
|
277
|
-
200: { content: { "application/json": { schema: z.object({ data: z.object({ updated: z.literal(true) }) }) } }, description: "Attributes set" },
|
|
278
|
-
...errorResponses,
|
|
279
|
-
},
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
// @ts-expect-error -- openapi handler union return type
|
|
283
|
-
router.openapi(setAttrsRoute, async (c) => {
|
|
284
|
-
const { id, locale } = c.req.valid("param");
|
|
285
|
-
const body = c.req.valid("json");
|
|
286
|
-
const result = await kernel.services.catalog.setAttributes(id, locale, body);
|
|
287
|
-
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
288
|
-
return c.json({ data: { updated: true as const } });
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
// ─── VARIANTS ─────────────────────────────────────────────
|
|
292
|
-
if (entityConfig.variants.enabled) {
|
|
293
|
-
const createVariantRoute = createRoute({
|
|
294
|
-
method: "post",
|
|
295
|
-
path: "/{id}/variants",
|
|
296
|
-
tags: [tag],
|
|
297
|
-
summary: `Create variant for ${alias.slice(0, -1)}`,
|
|
298
|
-
request: {
|
|
299
|
-
params: z.object({ id: z.string().uuid() }),
|
|
300
|
-
body: { content: { "application/json": { schema: z.object({ sku: z.string().optional(), options: z.record(z.string(), z.string()).optional(), metadata: z.record(z.string(), z.unknown()).optional() }).openapi(`Create${tag}VariantRequest`) } } },
|
|
301
|
-
},
|
|
302
|
-
responses: {
|
|
303
|
-
201: { content: { "application/json": { schema: z.object({ data: z.record(z.string(), z.unknown()) }) } }, description: "Variant created" },
|
|
304
|
-
...errorResponses,
|
|
305
|
-
},
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
// @ts-expect-error -- openapi handler union return type
|
|
309
|
-
router.openapi(createVariantRoute, async (c) => {
|
|
310
|
-
const { id } = c.req.valid("param");
|
|
311
|
-
const body = c.req.valid("json");
|
|
312
|
-
const result = await kernel.services.catalog.createVariant({ entityId: id, ...body }, c.get("actor"));
|
|
313
|
-
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
314
|
-
return c.json({ data: result.value }, 201);
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
const listOptionsRoute = createRoute({
|
|
318
|
-
method: "get",
|
|
319
|
-
path: "/{id}/options",
|
|
320
|
-
tags: [tag],
|
|
321
|
-
summary: `List option types for ${alias.slice(0, -1)}`,
|
|
322
|
-
request: { params: z.object({ id: z.string().uuid() }) },
|
|
323
|
-
responses: {
|
|
324
|
-
200: { content: { "application/json": { schema: z.object({ data: z.array(z.record(z.string(), z.unknown())) }) } }, description: "Option types" },
|
|
325
|
-
...errorResponses,
|
|
326
|
-
},
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
// @ts-expect-error -- openapi handler union return type
|
|
330
|
-
router.openapi(listOptionsRoute, async (c) => {
|
|
331
|
-
const { id } = c.req.valid("param");
|
|
332
|
-
const result = await kernel.services.catalog.getById(id, { includeOptionTypes: true });
|
|
333
|
-
if (!result.ok) return c.json(mapErrorToResponse(result.error), mapErrorToStatus(result.error));
|
|
334
|
-
return c.json({ data: result.value.optionTypes ?? [] });
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Store alias → entityType for the tag group
|
|
339
|
-
(router as unknown as Record<string, string>).__aliasTag = tag;
|
|
340
|
-
(router as unknown as Record<string, string>).__aliasPath = alias;
|
|
341
|
-
|
|
342
|
-
routers.push(router);
|
|
343
48
|
}
|
|
344
|
-
|
|
345
|
-
return routers;
|
|
346
49
|
}
|
package/src/runtime/server.ts
CHANGED
|
@@ -253,6 +253,39 @@ export async function createServer(config: CommerceConfig) {
|
|
|
253
253
|
app.route("/mcp", createMCPHandler(kernel));
|
|
254
254
|
app.route("/api/me", createCustomerPortalRoutes(kernel));
|
|
255
255
|
|
|
256
|
+
// ─── Entity aliases (e.g., /api/products → /api/catalog/entities?type=product) ──
|
|
257
|
+
for (const [entityType, entityConfig] of Object.entries(config.entities ?? {})) {
|
|
258
|
+
if (!entityConfig.alias) continue;
|
|
259
|
+
const alias = entityConfig.alias;
|
|
260
|
+
// List: inject type filter
|
|
261
|
+
app.all(`/api/${alias}`, async (c) => {
|
|
262
|
+
const url = new URL(c.req.url);
|
|
263
|
+
url.pathname = "/api/catalog/entities";
|
|
264
|
+
if (c.req.method === "GET") url.searchParams.set("type", entityType);
|
|
265
|
+
return app.fetch(new Request(url.toString(), c.req.raw));
|
|
266
|
+
});
|
|
267
|
+
// Sub-paths: rewrite /api/{alias}/... → /api/catalog/entities/...
|
|
268
|
+
app.all(`/api/${alias}/:rest{.+}`, async (c) => {
|
|
269
|
+
const url = new URL(c.req.url);
|
|
270
|
+
url.pathname = url.pathname.replace(`/api/${alias}`, "/api/catalog/entities");
|
|
271
|
+
return app.fetch(new Request(url.toString(), c.req.raw));
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Static aliases
|
|
276
|
+
for (const [shortcut, target] of [["categories", "catalog/categories"], ["brands", "catalog/brands"]] as const) {
|
|
277
|
+
app.all(`/api/${shortcut}`, (c) => {
|
|
278
|
+
const url = new URL(c.req.url);
|
|
279
|
+
url.pathname = `/api/${target}`;
|
|
280
|
+
return app.fetch(new Request(url.toString(), c.req.raw));
|
|
281
|
+
});
|
|
282
|
+
app.all(`/api/${shortcut}/:rest{.+}`, (c) => {
|
|
283
|
+
const url = new URL(c.req.url);
|
|
284
|
+
url.pathname = url.pathname.replace(`/api/${shortcut}`, `/api/${target}`);
|
|
285
|
+
return app.fetch(new Request(url.toString(), c.req.raw));
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
256
289
|
if (config.routes) {
|
|
257
290
|
config.routes(app, kernel);
|
|
258
291
|
}
|