@shopware-ag/app-server-sdk 1.1.19 → 1.1.21
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/commonjs/app.d.ts +3 -1
- package/dist/commonjs/app.d.ts.map +1 -1
- package/dist/commonjs/app.js +5 -2
- package/dist/commonjs/app.js.map +1 -1
- package/dist/commonjs/context-resolver.d.ts +3 -2
- package/dist/commonjs/context-resolver.d.ts.map +1 -1
- package/dist/commonjs/context-resolver.js +5 -3
- package/dist/commonjs/context-resolver.js.map +1 -1
- package/dist/commonjs/helper/notification.d.ts +10 -0
- package/dist/commonjs/helper/notification.d.ts.map +1 -0
- package/dist/commonjs/helper/notification.js +7 -0
- package/dist/commonjs/helper/notification.js.map +1 -0
- package/dist/commonjs/hooks.d.ts +2 -1
- package/dist/commonjs/hooks.d.ts.map +1 -1
- package/dist/commonjs/hooks.js +3 -3
- package/dist/commonjs/hooks.js.map +1 -1
- package/dist/commonjs/http-client.d.ts +17 -2
- package/dist/commonjs/http-client.d.ts.map +1 -1
- package/dist/commonjs/http-client.js +30 -17
- package/dist/commonjs/http-client.js.map +1 -1
- package/dist/commonjs/integration/hono.d.ts +5 -0
- package/dist/commonjs/integration/hono.d.ts.map +1 -1
- package/dist/commonjs/integration/hono.js +5 -2
- package/dist/commonjs/integration/hono.js.map +1 -1
- package/dist/commonjs/registration.d.ts +9 -0
- package/dist/commonjs/registration.d.ts.map +1 -1
- package/dist/commonjs/registration.js +24 -1
- package/dist/commonjs/registration.js.map +1 -1
- package/dist/esm/app.d.ts +3 -1
- package/dist/esm/app.d.ts.map +1 -1
- package/dist/esm/app.js +5 -2
- package/dist/esm/app.js.map +1 -1
- package/dist/esm/context-resolver.d.ts +3 -2
- package/dist/esm/context-resolver.d.ts.map +1 -1
- package/dist/esm/context-resolver.js +5 -3
- package/dist/esm/context-resolver.js.map +1 -1
- package/dist/esm/helper/notification.d.ts +10 -0
- package/dist/esm/helper/notification.d.ts.map +1 -0
- package/dist/esm/helper/notification.js +4 -0
- package/dist/esm/helper/notification.js.map +1 -0
- package/dist/esm/hooks.d.ts +2 -1
- package/dist/esm/hooks.d.ts.map +1 -1
- package/dist/esm/hooks.js +3 -3
- package/dist/esm/hooks.js.map +1 -1
- package/dist/esm/http-client.d.ts +17 -2
- package/dist/esm/http-client.d.ts.map +1 -1
- package/dist/esm/http-client.js +28 -16
- package/dist/esm/http-client.js.map +1 -1
- package/dist/esm/integration/hono.d.ts +5 -0
- package/dist/esm/integration/hono.d.ts.map +1 -1
- package/dist/esm/integration/hono.js +5 -2
- package/dist/esm/integration/hono.js.map +1 -1
- package/dist/esm/registration.d.ts +9 -0
- package/dist/esm/registration.d.ts.map +1 -1
- package/dist/esm/registration.js +22 -0
- package/dist/esm/registration.js.map +1 -1
- package/package.json +12 -1
package/dist/commonjs/app.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ContextResolver } from "./context-resolver.js";
|
|
2
2
|
import { Hooks } from "./hooks.js";
|
|
3
|
+
import { HttpClientTokenCacheInterface } from "./http-client.js";
|
|
3
4
|
import { Registration } from "./registration.js";
|
|
4
5
|
import type { ShopInterface, ShopRepositoryInterface } from "./repository.js";
|
|
5
6
|
import { WebCryptoHmacSigner } from "./signer.js";
|
|
@@ -9,11 +10,12 @@ import { WebCryptoHmacSigner } from "./signer.js";
|
|
|
9
10
|
export declare class AppServer<Shop extends ShopInterface = ShopInterface> {
|
|
10
11
|
cfg: Configuration;
|
|
11
12
|
repository: ShopRepositoryInterface<Shop>;
|
|
13
|
+
httpClientTokenCache: HttpClientTokenCacheInterface;
|
|
12
14
|
registration: Registration<Shop>;
|
|
13
15
|
contextResolver: ContextResolver<Shop>;
|
|
14
16
|
signer: WebCryptoHmacSigner;
|
|
15
17
|
hooks: Hooks<Shop>;
|
|
16
|
-
constructor(cfg: Configuration, repository: ShopRepositoryInterface<Shop
|
|
18
|
+
constructor(cfg: Configuration, repository: ShopRepositoryInterface<Shop>, httpClientTokenCache?: HttpClientTokenCacheInterface);
|
|
17
19
|
}
|
|
18
20
|
interface Configuration {
|
|
19
21
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD;;GAEG;AACH,qBAAa,SAAS,CAAC,IAAI,SAAS,aAAa,GAAG,aAAa;IAOxD,GAAG,EAAE,aAAa;IAClB,UAAU,EAAE,uBAAuB,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,6BAA6B,EAAgC,MAAM,kBAAkB,CAAC;AAC/F,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD;;GAEG;AACH,qBAAa,SAAS,CAAC,IAAI,SAAS,aAAa,GAAG,aAAa;IAOxD,GAAG,EAAE,aAAa;IAClB,UAAU,EAAE,uBAAuB,CAAC,IAAI,CAAC;IACzC,oBAAoB,EAAE,6BAA6B;IARpD,YAAY,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC;IACjC,eAAe,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAGlB,GAAG,EAAE,aAAa,EAClB,UAAU,EAAE,uBAAuB,CAAC,IAAI,CAAC,EACzC,oBAAoB,GAAE,6BAAkE;CAOhG;AAED,UAAU,aAAa;IACtB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,oBAAoB,EAAE,MAAM,CAAC;CAC7B"}
|
package/dist/commonjs/app.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.AppServer = void 0;
|
|
4
4
|
const context_resolver_js_1 = require("./context-resolver.js");
|
|
5
5
|
const hooks_js_1 = require("./hooks.js");
|
|
6
|
+
const http_client_js_1 = require("./http-client.js");
|
|
6
7
|
const registration_js_1 = require("./registration.js");
|
|
7
8
|
const signer_js_1 = require("./signer.js");
|
|
8
9
|
/**
|
|
@@ -11,15 +12,17 @@ const signer_js_1 = require("./signer.js");
|
|
|
11
12
|
class AppServer {
|
|
12
13
|
cfg;
|
|
13
14
|
repository;
|
|
15
|
+
httpClientTokenCache;
|
|
14
16
|
registration;
|
|
15
17
|
contextResolver;
|
|
16
18
|
signer;
|
|
17
19
|
hooks;
|
|
18
|
-
constructor(cfg, repository) {
|
|
20
|
+
constructor(cfg, repository, httpClientTokenCache = new http_client_js_1.InMemoryHttpClientTokenCache()) {
|
|
19
21
|
this.cfg = cfg;
|
|
20
22
|
this.repository = repository;
|
|
23
|
+
this.httpClientTokenCache = httpClientTokenCache;
|
|
21
24
|
this.registration = new registration_js_1.Registration(this);
|
|
22
|
-
this.contextResolver = new context_resolver_js_1.ContextResolver(this);
|
|
25
|
+
this.contextResolver = new context_resolver_js_1.ContextResolver(this, httpClientTokenCache);
|
|
23
26
|
this.signer = new signer_js_1.WebCryptoHmacSigner();
|
|
24
27
|
this.hooks = new hooks_js_1.Hooks();
|
|
25
28
|
}
|
package/dist/commonjs/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/app.ts"],"names":[],"mappings":";;;AAAA,+DAAwD;AACxD,yCAAmC;AACnC,uDAAiD;AAEjD,2CAAkD;AAElD;;GAEG;AACH,MAAa,SAAS;IAOb;IACA;
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/app.ts"],"names":[],"mappings":";;;AAAA,+DAAwD;AACxD,yCAAmC;AACnC,qDAA+F;AAC/F,uDAAiD;AAEjD,2CAAkD;AAElD;;GAEG;AACH,MAAa,SAAS;IAOb;IACA;IACA;IARD,YAAY,CAAqB;IACjC,eAAe,CAAwB;IACvC,MAAM,CAAsB;IAC5B,KAAK,CAAc;IAE1B,YACQ,GAAkB,EAClB,UAAyC,EACzC,uBAAsD,IAAI,6CAA4B,EAAE;QAFxF,QAAG,GAAH,GAAG,CAAe;QAClB,eAAU,GAAV,UAAU,CAA+B;QACzC,yBAAoB,GAApB,oBAAoB,CAAoE;QAE/F,IAAI,CAAC,YAAY,GAAG,IAAI,8BAAY,CAAO,IAAI,CAAC,CAAC;QACjD,IAAI,CAAC,eAAe,GAAG,IAAI,qCAAe,CAAO,IAAI,EAAE,oBAAoB,CAAC,CAAC;QAC7E,IAAI,CAAC,MAAM,GAAG,IAAI,+BAAmB,EAAE,CAAC;QACxC,IAAI,CAAC,KAAK,GAAG,IAAI,gBAAK,EAAQ,CAAC;IAChC,CAAC;CACD;AAhBD,8BAgBC","sourcesContent":["import { ContextResolver } from \"./context-resolver.js\";\nimport { Hooks } from \"./hooks.js\";\nimport { HttpClientTokenCacheInterface, InMemoryHttpClientTokenCache } from \"./http-client.js\";\nimport { Registration } from \"./registration.js\";\nimport type { ShopInterface, ShopRepositoryInterface } from \"./repository.js\";\nimport { WebCryptoHmacSigner } from \"./signer.js\";\n\n/**\n * AppServer is the main class, this is where you start your app\n */\nexport class AppServer<Shop extends ShopInterface = ShopInterface> {\n\tpublic registration: Registration<Shop>;\n\tpublic contextResolver: ContextResolver<Shop>;\n\tpublic signer: WebCryptoHmacSigner;\n\tpublic hooks: Hooks<Shop>;\n\n\tconstructor(\n\t\tpublic cfg: Configuration,\n\t\tpublic repository: ShopRepositoryInterface<Shop>,\n\t\tpublic httpClientTokenCache: HttpClientTokenCacheInterface = new InMemoryHttpClientTokenCache()\n\t) {\n\t\tthis.registration = new Registration<Shop>(this);\n\t\tthis.contextResolver = new ContextResolver<Shop>(this, httpClientTokenCache);\n\t\tthis.signer = new WebCryptoHmacSigner();\n\t\tthis.hooks = new Hooks<Shop>();\n\t}\n}\n\ninterface Configuration {\n\t/**\n\t * Your app name\n\t */\n\tappName: string;\n\n\t/**\n\t * Your app secret\n\t */\n\tappSecret: string;\n\n\t/**\n\t * URL to authorize callback url\n\t */\n\tauthorizeCallbackUrl: string;\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AppServer } from "./app.js";
|
|
2
|
-
import { HttpClient } from "./http-client.js";
|
|
2
|
+
import { HttpClient, type HttpClientTokenCacheInterface } from "./http-client.js";
|
|
3
3
|
import type { ShopInterface } from "./repository.js";
|
|
4
4
|
/**
|
|
5
5
|
* ContextResolver is a helper class to create a Context object from a request.
|
|
@@ -7,7 +7,8 @@ import type { ShopInterface } from "./repository.js";
|
|
|
7
7
|
*/
|
|
8
8
|
export declare class ContextResolver<Shop extends ShopInterface = ShopInterface> {
|
|
9
9
|
private app;
|
|
10
|
-
|
|
10
|
+
private httpClientTokenCache;
|
|
11
|
+
constructor(app: AppServer<Shop>, httpClientTokenCache: HttpClientTokenCacheInterface);
|
|
11
12
|
/**
|
|
12
13
|
* Create a context from a request body
|
|
13
14
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-resolver.d.ts","sourceRoot":"","sources":["../../src/context-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"context-resolver.d.ts","sourceRoot":"","sources":["../../src/context-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,KAAK,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;GAGG;AACH,qBAAa,eAAe,CAAC,IAAI,SAAS,aAAa,GAAG,aAAa;IAC1D,OAAO,CAAC,GAAG;IAAmB,OAAO,CAAC,oBAAoB;gBAAlD,GAAG,EAAE,SAAS,CAAC,IAAI,CAAC,EAAU,oBAAoB,EAAE,6BAA6B;IAErG;;OAEG;IACU,OAAO,CAAC,OAAO,GAAG,OAAO,EACrC,GAAG,EAAE,OAAO,GACV,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IA0ClC;;;OAGG;IACU,WAAW,CAAC,OAAO,GAAG,OAAO,EACzC,GAAG,EAAE,OAAO,GACV,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;CA6BlC;AAED;;GAEG;AACH,qBAAa,OAAO,CACnB,IAAI,SAAS,aAAa,GAAG,aAAa,EAC1C,OAAO,GAAG,OAAO;IAGT,IAAI,EAAE,IAAI;IACV,OAAO,EAAE,OAAO;IAChB,UAAU,EAAE,UAAU;gBAFtB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,UAAU;CAE9B"}
|
|
@@ -8,8 +8,10 @@ const http_client_js_1 = require("./http-client.js");
|
|
|
8
8
|
*/
|
|
9
9
|
class ContextResolver {
|
|
10
10
|
app;
|
|
11
|
-
|
|
11
|
+
httpClientTokenCache;
|
|
12
|
+
constructor(app, httpClientTokenCache) {
|
|
12
13
|
this.app = app;
|
|
14
|
+
this.httpClientTokenCache = httpClientTokenCache;
|
|
13
15
|
}
|
|
14
16
|
/**
|
|
15
17
|
* Create a context from a request body
|
|
@@ -32,7 +34,7 @@ class ContextResolver {
|
|
|
32
34
|
if (!(await this.app.signer.verify(signature, webHookContent, shop.getShopSecret()))) {
|
|
33
35
|
throw new Error("Invalid signature");
|
|
34
36
|
}
|
|
35
|
-
return new Context(shop, webHookBody, new http_client_js_1.HttpClient(shop));
|
|
37
|
+
return new Context(shop, webHookBody, new http_client_js_1.HttpClient(shop, this.httpClientTokenCache));
|
|
36
38
|
}
|
|
37
39
|
/**
|
|
38
40
|
* Create a context from a request query parameters
|
|
@@ -53,7 +55,7 @@ class ContextResolver {
|
|
|
53
55
|
url.searchParams.forEach((value, key) => {
|
|
54
56
|
paramsObject[key] = value;
|
|
55
57
|
});
|
|
56
|
-
return new Context(shop, paramsObject, new http_client_js_1.HttpClient(shop));
|
|
58
|
+
return new Context(shop, paramsObject, new http_client_js_1.HttpClient(shop, this.httpClientTokenCache));
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
exports.ContextResolver = ContextResolver;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-resolver.js","sourceRoot":"","sources":["../../src/context-resolver.ts"],"names":[],"mappings":";;;AACA,
|
|
1
|
+
{"version":3,"file":"context-resolver.js","sourceRoot":"","sources":["../../src/context-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AppServer } from \"./app.js\";\nimport { HttpClient, type HttpClientTokenCacheInterface } from \"./http-client.js\";\nimport type { ShopInterface } from \"./repository.js\";\n\n/**\n * ContextResolver is a helper class to create a Context object from a request.\n * The context contains the shop, the payload and an instance of the HttpClient\n */\nexport class ContextResolver<Shop extends ShopInterface = ShopInterface> {\n\tconstructor(private app: AppServer<Shop>, private httpClientTokenCache: HttpClientTokenCacheInterface) {}\n\n\t/**\n\t * Create a context from a request body\n\t */\n\tpublic async fromAPI<Payload = unknown>(\n\t\treq: Request,\n\t): Promise<Context<Shop, Payload>> {\n\t\tconst webHookContent = await req.text();\n\t\tconst webHookBody = JSON.parse(webHookContent);\n\n\t\tif (\n\t\t\twebHookBody.source === undefined ||\n\t\t\twebHookBody.source.shopId === undefined\n\t\t) {\n\t\t\tthrow new Error(\"Invalid request\");\n\t\t}\n\n\t\tconst shop = await this.app.repository.getShopById(\n\t\t\twebHookBody.source.shopId,\n\t\t);\n\n\t\tif (shop === null) {\n\t\t\tthrow new Error(`Cannot find shop by id ${webHookBody.source.shopId}`);\n\t\t}\n\n\t\tconst signature = req.headers.get(\"shopware-shop-signature\");\n\n\t\tif (signature === null) {\n\t\t\tthrow new Error(\"Missing shopware-shop-signature header\");\n\t\t}\n\n\t\tif (\n\t\t\t!(await this.app.signer.verify(\n\t\t\t\tsignature,\n\t\t\t\twebHookContent,\n\t\t\t\tshop.getShopSecret(),\n\t\t\t))\n\t\t) {\n\t\t\tthrow new Error(\"Invalid signature\");\n\t\t}\n\n\t\treturn new Context<Shop, Payload>(\n\t\t\tshop as Shop,\n\t\t\twebHookBody,\n\t\t\tnew HttpClient(shop, this.httpClientTokenCache),\n\t\t);\n\t}\n\n\t/**\n\t * Create a context from a request query parameters\n\t * This is usually a module request from the shopware admin\n\t */\n\tpublic async fromBrowser<Payload = unknown>(\n\t\treq: Request,\n\t): Promise<Context<Shop, Payload>> {\n\t\tconst url = new URL(req.url);\n\n\t\tconst shopId = url.searchParams.get(\"shop-id\");\n\n\t\tif (shopId === null) {\n\t\t\tthrow new Error(\"Missing shop-id query parameter\");\n\t\t}\n\n\t\tconst shop = await this.app.repository.getShopById(shopId);\n\n\t\tif (shop === null) {\n\t\t\tthrow new Error(`Cannot find shop by id ${shopId}`);\n\t\t}\n\n\t\tawait this.app.signer.verifyGetRequest(req, shop.getShopSecret());\n\n\t\tconst paramsObject: Record<string, string> = {};\n\n\t\turl.searchParams.forEach((value, key) => {\n\t\t\tparamsObject[key] = value;\n\t\t});\n\n\t\treturn new Context<Shop, Payload>(\n\t\t\tshop as Shop,\n\t\t\tparamsObject as Payload,\n\t\t\tnew HttpClient(shop, this.httpClientTokenCache),\n\t\t);\n\t}\n}\n\n/**\n * Context is the parsed data from the request\n */\nexport class Context<\n\tShop extends ShopInterface = ShopInterface,\n\tPayload = unknown,\n> {\n\tconstructor(\n\t\tpublic shop: Shop,\n\t\tpublic payload: Payload,\n\t\tpublic httpClient: HttpClient,\n\t) {}\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { HttpClient } from "../http-client.js";
|
|
2
|
+
interface NotificationCreateRequest {
|
|
3
|
+
status: 'neutral' | 'info' | 'attention' | 'critical' | 'positive';
|
|
4
|
+
message: string;
|
|
5
|
+
adminOnly?: boolean;
|
|
6
|
+
requiredPrivileges?: string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function sendNotification(httpClient: HttpClient, notification: NotificationCreateRequest): Promise<void>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=notification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification.d.ts","sourceRoot":"","sources":["../../../src/helper/notification.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,UAAU,yBAAyB;IAC/B,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;IACnE,OAAO,EAAE,MAAM,CAAC;IAGhB,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,wBAAsB,gBAAgB,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAErH"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendNotification = sendNotification;
|
|
4
|
+
async function sendNotification(httpClient, notification) {
|
|
5
|
+
await httpClient.post('/notification', notification);
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=notification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification.js","sourceRoot":"","sources":["../../../src/helper/notification.ts"],"names":[],"mappings":";;AAYA,4CAEC;AAFM,KAAK,UAAU,gBAAgB,CAAC,UAAsB,EAAE,YAAuC;IAClG,MAAM,UAAU,CAAC,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,CAAA;AACxD,CAAC","sourcesContent":["import { HttpClient } from \"../http-client.js\";\n\ninterface NotificationCreateRequest {\n status: 'neutral' | 'info' | 'attention' | 'critical' | 'positive';\n message: string;\n \n // Only the admin can see this notification\n adminOnly?: boolean;\n // The user must have these privileges to see this notification\n requiredPrivileges?: string[];\n}\n\nexport async function sendNotification(httpClient: HttpClient, notification: NotificationCreateRequest): Promise<void> {\n await httpClient.post('/notification', notification)\n}\n"]}
|
package/dist/commonjs/hooks.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AppActivateEvent, AppDeactivateEvent, AppInstallEvent, AppUninstallEvent, AppUpdateEvent, ShopAuthorizeEvent } from "./registration.js";
|
|
1
|
+
import type { AppActivateEvent, AppDeactivateEvent, AppInstallEvent, AppUninstallEvent, AppUpdateEvent, ShopAuthorizeEvent, BeforeRegistrationEvent } from "./registration.js";
|
|
2
2
|
import type { ShopInterface } from "./repository.js";
|
|
3
3
|
interface HookRegistry<Shop extends ShopInterface> {
|
|
4
4
|
onAuthorize: (event: ShopAuthorizeEvent<Shop>) => Promise<void>;
|
|
@@ -7,6 +7,7 @@ interface HookRegistry<Shop extends ShopInterface> {
|
|
|
7
7
|
onAppActivate: (event: AppActivateEvent<Shop>) => Promise<void>;
|
|
8
8
|
onAppDeactivate: (event: AppDeactivateEvent<Shop>) => Promise<void>;
|
|
9
9
|
onAppUpdate: (event: AppUpdateEvent<Shop>) => Promise<void>;
|
|
10
|
+
onBeforeRegistrationEvent: (event: BeforeRegistrationEvent) => Promise<void>;
|
|
10
11
|
}
|
|
11
12
|
export declare class Hooks<Shop extends ShopInterface = ShopInterface> {
|
|
12
13
|
private eventListeners;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,UAAU,YAAY,CAAC,IAAI,SAAS,aAAa;IAChD,WAAW,EAAE,CAAC,KAAK,EAAE,kBAAkB,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,YAAY,EAAE,CAAC,KAAK,EAAE,eAAe,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,cAAc,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,aAAa,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,eAAe,EAAE,CAAC,KAAK,EAAE,kBAAkB,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,uBAAuB,EACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,UAAU,YAAY,CAAC,IAAI,SAAS,aAAa;IAChD,WAAW,EAAE,CAAC,KAAK,EAAE,kBAAkB,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,YAAY,EAAE,CAAC,KAAK,EAAE,eAAe,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,cAAc,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,aAAa,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,eAAe,EAAE,CAAC,KAAK,EAAE,kBAAkB,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,yBAAyB,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7E;AAED,qBAAa,KAAK,CAAC,IAAI,SAAS,aAAa,GAAG,aAAa;IAC5D,OAAO,CAAC,cAAc,CAGlB;IAEJ,YAAY,CAAC,KAAK,EAAE,MAAM,YAAY,CAAC,IAAI,CAAC,GAAG,OAAO;IAItD,EAAE,CACD,KAAK,EAAE,MAAM,YAAY,CAAC,IAAI,CAAC,EAC/B,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IAS3C,OAAO,CACZ,KAAK,EAAE,MAAM,YAAY,CAAC,IAAI,CAAC,EAC/B,GAAG,IAAI,EAAE,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,GAC/D,OAAO,CAAC,IAAI,CAAC;CAgBhB"}
|
package/dist/commonjs/hooks.js
CHANGED
|
@@ -13,11 +13,11 @@ class Hooks {
|
|
|
13
13
|
this.eventListeners.get(event)?.push(cb);
|
|
14
14
|
}
|
|
15
15
|
async publish(event, ...args) {
|
|
16
|
-
const
|
|
17
|
-
if (!
|
|
16
|
+
const listeners = this.eventListeners.get(event);
|
|
17
|
+
if (!listeners) {
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
|
-
for (const cb of
|
|
20
|
+
for (const cb of listeners) {
|
|
21
21
|
// @ts-expect-error
|
|
22
22
|
const res = cb(...args);
|
|
23
23
|
if (res instanceof Promise) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/hooks.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/hooks.ts"],"names":[],"mappings":";;;AAqBA,MAAa,KAAK;IACT,cAAc,GAAG,IAAI,GAAG,EAG7B,CAAC;IAEJ,YAAY,CAAC,KAA+B;QAC3C,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,EAAE,CACD,KAA+B,EAC/B,EAAgD;QAEhD,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACpC,CAAC;QAED,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,OAAO,CACZ,KAA+B,EAC/B,GAAG,IAA8D;QAEjE,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAEjD,IAAI,CAAC,SAAS,EAAE,CAAC;YAChB,OAAO;QACR,CAAC;QAED,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;YAC5B,mBAAmB;YACnB,MAAM,GAAG,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;YAExB,IAAI,GAAG,YAAY,OAAO,EAAE,CAAC;gBAC5B,MAAM,GAAG,CAAC;YACX,CAAC;QACF,CAAC;IACF,CAAC;CACD;AAxCD,sBAwCC","sourcesContent":["import type {\n\tAppActivateEvent,\n\tAppDeactivateEvent,\n\tAppInstallEvent,\n\tAppUninstallEvent,\n\tAppUpdateEvent,\n\tShopAuthorizeEvent,\n\tBeforeRegistrationEvent,\n} from \"./registration.js\";\nimport type { ShopInterface } from \"./repository.js\";\n\ninterface HookRegistry<Shop extends ShopInterface> {\n\tonAuthorize: (event: ShopAuthorizeEvent<Shop>) => Promise<void>;\n\tonAppInstall: (event: AppInstallEvent<Shop>) => Promise<void>;\n\tonAppUninstall: (event: AppUninstallEvent<Shop>) => Promise<void>;\n\tonAppActivate: (event: AppActivateEvent<Shop>) => Promise<void>;\n\tonAppDeactivate: (event: AppDeactivateEvent<Shop>) => Promise<void>;\n\tonAppUpdate: (event: AppUpdateEvent<Shop>) => Promise<void>;\n\tonBeforeRegistrationEvent: (event: BeforeRegistrationEvent) => Promise<void>;\n}\n\nexport class Hooks<Shop extends ShopInterface = ShopInterface> {\n\tprivate eventListeners = new Map<\n\t\tkeyof HookRegistry<Shop>,\n\t\tHookRegistry<Shop>[keyof HookRegistry<Shop>][]\n\t>();\n\n\thasListeners(event: keyof HookRegistry<Shop>): boolean {\n\t\treturn this.eventListeners.has(event);\n\t}\n\n\ton(\n\t\tevent: keyof HookRegistry<Shop>,\n\t\tcb: HookRegistry<Shop>[keyof HookRegistry<Shop>],\n\t) {\n\t\tif (!this.eventListeners.has(event)) {\n\t\t\tthis.eventListeners.set(event, []);\n\t\t}\n\n\t\tthis.eventListeners.get(event)?.push(cb);\n\t}\n\n\tasync publish(\n\t\tevent: keyof HookRegistry<Shop>,\n\t\t...args: Parameters<HookRegistry<Shop>[keyof HookRegistry<Shop>]>\n\t): Promise<void> {\n\t\tconst listeners = this.eventListeners.get(event);\n\n\t\tif (!listeners) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const cb of listeners) {\n\t\t\t// @ts-expect-error\n\t\t\tconst res = cb(...args);\n\n\t\t\tif (res instanceof Promise) {\n\t\t\t\tawait res;\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -4,8 +4,8 @@ import type { ShopInterface } from "./repository.js";
|
|
|
4
4
|
*/
|
|
5
5
|
export declare class HttpClient {
|
|
6
6
|
private shop;
|
|
7
|
-
private
|
|
8
|
-
constructor(shop: ShopInterface);
|
|
7
|
+
private tokenCache;
|
|
8
|
+
constructor(shop: ShopInterface, tokenCache?: HttpClientTokenCacheInterface);
|
|
9
9
|
/**
|
|
10
10
|
* Permform a GET request
|
|
11
11
|
*/
|
|
@@ -64,5 +64,20 @@ export declare class ApiClientRequestFailed extends Error {
|
|
|
64
64
|
response: HttpClientResponse<ShopwareErrorResponse>;
|
|
65
65
|
constructor(shopId: string, response: HttpClientResponse<ShopwareErrorResponse>);
|
|
66
66
|
}
|
|
67
|
+
export interface HttpClientTokenCacheItem {
|
|
68
|
+
token: string;
|
|
69
|
+
expiresIn: Date;
|
|
70
|
+
}
|
|
71
|
+
export declare class InMemoryHttpClientTokenCache implements HttpClientTokenCacheInterface {
|
|
72
|
+
private cache;
|
|
73
|
+
getToken(shopId: string): Promise<HttpClientTokenCacheItem | null>;
|
|
74
|
+
setToken(shopId: string, token: HttpClientTokenCacheItem): Promise<void>;
|
|
75
|
+
clearToken(shopId: string): Promise<void>;
|
|
76
|
+
}
|
|
77
|
+
export interface HttpClientTokenCacheInterface {
|
|
78
|
+
getToken(shopId: string): Promise<HttpClientTokenCacheItem | null>;
|
|
79
|
+
setToken(shopId: string, token: HttpClientTokenCacheItem): Promise<void>;
|
|
80
|
+
clearToken(shopId: string): Promise<void>;
|
|
81
|
+
}
|
|
67
82
|
export {};
|
|
68
83
|
//# sourceMappingURL=http-client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../../src/http-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;GAEG;AACH,qBAAa,UAAU;
|
|
1
|
+
{"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../../src/http-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ApiClientRequestFailed = exports.ApiClientAuthenticationFailed = exports.HttpClientResponse = exports.HttpClient = void 0;
|
|
3
|
+
exports.InMemoryHttpClientTokenCache = exports.ApiClientRequestFailed = exports.ApiClientAuthenticationFailed = exports.HttpClientResponse = exports.HttpClient = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* HttpClient is a simple wrapper around the fetch API, pre-configured with the shop's URL and access token
|
|
6
6
|
*/
|
|
7
7
|
class HttpClient {
|
|
8
8
|
shop;
|
|
9
|
-
|
|
10
|
-
constructor(shop) {
|
|
9
|
+
tokenCache;
|
|
10
|
+
constructor(shop, tokenCache = new InMemoryHttpClientTokenCache()) {
|
|
11
11
|
this.shop = shop;
|
|
12
|
-
this.
|
|
13
|
-
token: null,
|
|
14
|
-
expiresIn: null,
|
|
15
|
-
};
|
|
12
|
+
this.tokenCache = tokenCache;
|
|
16
13
|
}
|
|
17
14
|
/**
|
|
18
15
|
* Permform a GET request
|
|
@@ -82,7 +79,7 @@ class HttpClient {
|
|
|
82
79
|
}
|
|
83
80
|
// Obtain new token
|
|
84
81
|
if (!f.ok && f.status === 401) {
|
|
85
|
-
this.
|
|
82
|
+
this.tokenCache.clearToken(this.shop.getShopId());
|
|
86
83
|
return await this.request(method, url, body, headers);
|
|
87
84
|
}
|
|
88
85
|
if (!f.ok) {
|
|
@@ -97,7 +94,8 @@ class HttpClient {
|
|
|
97
94
|
* Obtain a valid bearer token
|
|
98
95
|
*/
|
|
99
96
|
async getToken() {
|
|
100
|
-
|
|
97
|
+
const cachedToken = await this.tokenCache.getToken(this.shop.getShopId());
|
|
98
|
+
if (cachedToken === null) {
|
|
101
99
|
const auth = await globalThis.fetch(`${this.shop.getShopUrl()}/api/oauth/token`, {
|
|
102
100
|
method: "POST",
|
|
103
101
|
redirect: "manual",
|
|
@@ -133,19 +131,21 @@ class HttpClient {
|
|
|
133
131
|
}
|
|
134
132
|
throw new ApiClientAuthenticationFailed(this.shop.getShopId(), new HttpClientResponse(auth.status, body, auth.headers));
|
|
135
133
|
}
|
|
136
|
-
const expireDate = new Date();
|
|
137
134
|
const authBody = (await auth.json());
|
|
138
|
-
|
|
135
|
+
const expireDate = new Date();
|
|
139
136
|
expireDate.setSeconds(expireDate.getSeconds() + authBody.expires_in);
|
|
140
|
-
|
|
141
|
-
|
|
137
|
+
const token = {
|
|
138
|
+
token: authBody.access_token,
|
|
139
|
+
expiresIn: expireDate,
|
|
140
|
+
};
|
|
141
|
+
await this.tokenCache.setToken(this.shop.getShopId(), token);
|
|
142
|
+
return token.token;
|
|
142
143
|
}
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
this.storage.expiresIn = null;
|
|
144
|
+
if (cachedToken.expiresIn.getTime() < new Date().getTime()) {
|
|
145
|
+
await this.tokenCache.clearToken(this.shop.getShopId());
|
|
146
146
|
return await this.getToken();
|
|
147
147
|
}
|
|
148
|
-
return
|
|
148
|
+
return cachedToken.token;
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
exports.HttpClient = HttpClient;
|
|
@@ -186,4 +186,17 @@ class ApiClientRequestFailed extends Error {
|
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
exports.ApiClientRequestFailed = ApiClientRequestFailed;
|
|
189
|
+
class InMemoryHttpClientTokenCache {
|
|
190
|
+
cache = {};
|
|
191
|
+
async getToken(shopId) {
|
|
192
|
+
return this.cache[shopId] || null;
|
|
193
|
+
}
|
|
194
|
+
async setToken(shopId, token) {
|
|
195
|
+
this.cache[shopId] = token;
|
|
196
|
+
}
|
|
197
|
+
async clearToken(shopId) {
|
|
198
|
+
delete this.cache[shopId];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
exports.InMemoryHttpClientTokenCache = InMemoryHttpClientTokenCache;
|
|
189
202
|
//# sourceMappingURL=http-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../src/http-client.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ShopInterface } from \"./repository.js\";\n\n/**\n * HttpClient is a simple wrapper around the fetch API, pre-configured with the shop's URL and access token\n */\nexport class HttpClient {\n\tprivate storage: { expiresIn: Date | null; token: string | null };\n\n\tconstructor(private shop: ShopInterface) {\n\t\tthis.storage = {\n\t\t\ttoken: null,\n\t\t\texpiresIn: null,\n\t\t};\n\t}\n\n\t/**\n\t * Permform a GET request\n\t */\n\tasync get<ResponseType>(\n\t\turl: string,\n\t\theaders: Record<string, string> = {},\n\t): Promise<HttpClientResponse<ResponseType>> {\n\t\treturn await this.request(\"GET\", url, null, headers);\n\t}\n\n\t/**\n\t * Permform a POST request\n\t */\n\tasync post<ResponseType>(\n\t\turl: string,\n\t\tjson: object | FormData | Blob = {},\n\t\theaders: Record<string, string> = {},\n\t): Promise<HttpClientResponse<ResponseType>> {\n\t\tlet data: object | FormData | Blob | string = json;\n\n\t\tif (!(json instanceof Blob) && !(json instanceof FormData)) {\n\t\t\theaders[\"content-type\"] = \"application/json\";\n\t\t\tdata = JSON.stringify(json);\n\t\t}\n\n\t\theaders.accept = \"application/json\";\n\n\t\treturn await this.request(\n\t\t\t\"POST\",\n\t\t\turl,\n\t\t\tdata as FormData | Blob | string,\n\t\t\theaders,\n\t\t);\n\t}\n\n\t/**\n\t * Permform a PUT request\n\t */\n\tasync put<ResponseType>(\n\t\turl: string,\n\t\tjson: object = {},\n\t\theaders: Record<string, string> = {},\n\t): Promise<HttpClientResponse<ResponseType>> {\n\t\theaders[\"content-type\"] = \"application/json\";\n\t\theaders.accept = \"application/json\";\n\n\t\treturn await this.request(\"PUT\", url, JSON.stringify(json), headers);\n\t}\n\n\t/**\n\t * Permform a PATCH request\n\t */\n\tasync patch<ResponseType>(\n\t\turl: string,\n\t\tjson: object = {},\n\t\theaders: Record<string, string> = {},\n\t): Promise<HttpClientResponse<ResponseType>> {\n\t\theaders[\"content-type\"] = \"application/json\";\n\t\theaders.accept = \"application/json\";\n\n\t\treturn await this.request(\"PATCH\", url, JSON.stringify(json), headers);\n\t}\n\n\t/**\n\t * Permform a DELETE request\n\t */\n\tasync delete<ResponseType>(\n\t\turl: string,\n\t\tjson: object = {},\n\t\theaders: Record<string, string> = {},\n\t): Promise<HttpClientResponse<ResponseType>> {\n\t\theaders[\"content-type\"] = \"application/json\";\n\t\theaders.accept = \"application/json\";\n\n\t\treturn await this.request(\"DELETE\", url, JSON.stringify(json), headers);\n\t}\n\n\tprivate getUrl(...parts: string[]): string {\n\t\treturn parts.map(part => part.replace(/^\\/+|\\/+$/g, \"\")).join(\"/\");\n\t}\n\n\tprivate async request<ResponseType>(\n\t\tmethod: string,\n\t\turl: string,\n\t\tbody: string | FormData | Blob | null = \"\",\n\t\theaders: Record<string, string> = {},\n\t): Promise<HttpClientResponse<ResponseType>> {\n\t\tconst f = await globalThis.fetch(this.getUrl(this.shop.getShopUrl(), \"/api\", url), {\n\t\t\tredirect: \"manual\",\n\t\t\tbody,\n\t\t\theaders: Object.assign(\n\t\t\t\t{\n\t\t\t\t\tAuthorization: `Bearer ${await this.getToken()}`,\n\t\t\t\t},\n\t\t\t\theaders,\n\t\t\t),\n\t\t\tmethod,\n\t\t});\n\n\t\tif (f.status === 301 || f.status === 302) {\n\t\t\tthrow new ApiClientRequestFailed(\n\t\t\t\tthis.shop.getShopId(),\n\t\t\t\tnew HttpClientResponse<ShopwareErrorResponse>(\n\t\t\t\t\tf.status,\n\t\t\t\t\t{\n\t\t\t\t\t\terrors: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcode: \"301\",\n\t\t\t\t\t\t\t\tstatus: \"301\",\n\t\t\t\t\t\t\t\ttitle: \"301\",\n\t\t\t\t\t\t\t\tdetail:\n\t\t\t\t\t\t\t\t\t\"Got a redirect response from the URL, the URL should point to the Shop without redirect\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\tf.headers,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\t// Obtain new token\n\t\tif (!f.ok && f.status === 401) {\n\t\t\tthis.storage.expiresIn = null;\n\n\t\t\treturn await this.request(method, url, body, headers);\n\t\t}\n\t\tif (!f.ok) {\n\t\t\tthrow new ApiClientRequestFailed(\n\t\t\t\tthis.shop.getShopId(),\n\t\t\t\tnew HttpClientResponse(f.status, await f.json(), f.headers),\n\t\t\t);\n\t\t}\n\n\t\tif (f.status === 204) {\n\t\t\treturn new HttpClientResponse<ResponseType>(\n\t\t\t\tf.status,\n\t\t\t\t{} as ResponseType,\n\t\t\t\tf.headers,\n\t\t\t);\n\t\t}\n\n\t\treturn new HttpClientResponse(f.status, await f.json(), f.headers);\n\t}\n\n\t/**\n\t * Obtain a valid bearer token\n\t */\n\tasync getToken(): Promise<string> {\n\t\tif (this.storage.expiresIn === null) {\n\t\t\tconst auth = await globalThis.fetch(\n\t\t\t\t`${this.shop.getShopUrl()}/api/oauth/token`,\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tredirect: \"manual\",\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t\t\t},\n\t\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t\tgrant_type: \"client_credentials\",\n\t\t\t\t\t\tclient_id: this.shop.getShopClientId(),\n\t\t\t\t\t\tclient_secret: this.shop.getShopClientSecret(),\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (auth.status === 301 || auth.status === 302) {\n\t\t\t\tthrow new ApiClientRequestFailed(\n\t\t\t\t\tthis.shop.getShopId(),\n\t\t\t\t\tnew HttpClientResponse<ShopwareErrorResponse>(\n\t\t\t\t\t\tauth.status,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terrors: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcode: \"301\",\n\t\t\t\t\t\t\t\t\tstatus: \"301\",\n\t\t\t\t\t\t\t\t\ttitle: \"301\",\n\t\t\t\t\t\t\t\t\tdetail:\n\t\t\t\t\t\t\t\t\t\t\"Got a redirect response from the URL, the URL should point to the Shop without redirect\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t\tauth.headers,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (!auth.ok) {\n\t\t\t\tconst contentType = auth.headers.get(\"content-type\") || \"text/plain\";\n\t\t\t\tlet body = \"\";\n\n\t\t\t\tif (contentType.indexOf(\"application/json\") !== -1) {\n\t\t\t\t\tbody = await auth.json();\n\t\t\t\t} else {\n\t\t\t\t\tbody = await auth.text();\n\t\t\t\t}\n\n\t\t\t\tthrow new ApiClientAuthenticationFailed(\n\t\t\t\t\tthis.shop.getShopId(),\n\t\t\t\t\tnew HttpClientResponse<string>(auth.status, body, auth.headers),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst expireDate = new Date();\n\t\t\tconst authBody = (await auth.json()) as {\n\t\t\t\taccess_token: string;\n\t\t\t\texpires_in: number;\n\t\t\t};\n\t\t\tthis.storage.token = authBody.access_token;\n\t\t\texpireDate.setSeconds(expireDate.getSeconds() + authBody.expires_in);\n\t\t\tthis.storage.expiresIn = expireDate;\n\n\t\t\treturn this.storage.token as string;\n\t\t}\n\n\t\tif (this.storage.expiresIn.getTime() < new Date().getTime()) {\n\t\t\t// Expired\n\n\t\t\tthis.storage.expiresIn = null;\n\n\t\t\treturn await this.getToken();\n\t\t}\n\n\t\treturn this.storage.token as string;\n\t}\n}\n\n/**\n * HttpClientResponse is the response object of the HttpClient\n */\nexport class HttpClientResponse<ResponseType> {\n\tconstructor(\n\t\tpublic statusCode: number,\n\t\tpublic body: ResponseType,\n\t\tpublic headers: Headers,\n\t) {}\n}\n\ntype ShopwareErrorResponse = {\n\terrors: {\n\t\tcode: string;\n\t\tstatus: string;\n\t\ttitle: string;\n\t\tdetail: string;\n\t}[];\n};\n\n/**\n * ApiClientAuthenticationFailed is thrown when the authentication to the shop's API fails\n */\nexport class ApiClientAuthenticationFailed extends Error {\n\tconstructor(\n\t\tshopId: string,\n\t\tpublic response: HttpClientResponse<string>,\n\t) {\n\t\tsuper(\n\t\t\t`The api client authentication to shop with id: ${shopId} with response: ${JSON.stringify(response.body)}`,\n\t\t);\n\t}\n}\n\n/**\n * ApiClientRequestFailed is thrown when the request to the shop's API fails\n */\nexport class ApiClientRequestFailed extends Error {\n\tconstructor(\n\t\tshopId: string,\n\t\tpublic response: HttpClientResponse<ShopwareErrorResponse>,\n\t) {\n\t\tconst message = response.body.errors.map((e) => e.detail).join(\", \");\n\n\t\tsuper(`Request failed with error: ${message} for shop with id: ${shopId}`);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../src/http-client.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ShopInterface } from \"./repository.js\";\n\n/**\n * HttpClient is a simple wrapper around the fetch API, pre-configured with the shop's URL and access token\n */\nexport class HttpClient {\n\tconstructor(private shop: ShopInterface, private tokenCache: HttpClientTokenCacheInterface = new InMemoryHttpClientTokenCache()) {\n\t}\n\n\t/**\n\t * Permform a GET request\n\t */\n\tasync get<ResponseType>(\n\t\turl: string,\n\t\theaders: Record<string, string> = {},\n\t): Promise<HttpClientResponse<ResponseType>> {\n\t\treturn await this.request(\"GET\", url, null, headers);\n\t}\n\n\t/**\n\t * Permform a POST request\n\t */\n\tasync post<ResponseType>(\n\t\turl: string,\n\t\tjson: object | FormData | Blob = {},\n\t\theaders: Record<string, string> = {},\n\t): Promise<HttpClientResponse<ResponseType>> {\n\t\tlet data: object | FormData | Blob | string = json;\n\n\t\tif (!(json instanceof Blob) && !(json instanceof FormData)) {\n\t\t\theaders[\"content-type\"] = \"application/json\";\n\t\t\tdata = JSON.stringify(json);\n\t\t}\n\n\t\theaders.accept = \"application/json\";\n\n\t\treturn await this.request(\n\t\t\t\"POST\",\n\t\t\turl,\n\t\t\tdata as FormData | Blob | string,\n\t\t\theaders,\n\t\t);\n\t}\n\n\t/**\n\t * Permform a PUT request\n\t */\n\tasync put<ResponseType>(\n\t\turl: string,\n\t\tjson: object = {},\n\t\theaders: Record<string, string> = {},\n\t): Promise<HttpClientResponse<ResponseType>> {\n\t\theaders[\"content-type\"] = \"application/json\";\n\t\theaders.accept = \"application/json\";\n\n\t\treturn await this.request(\"PUT\", url, JSON.stringify(json), headers);\n\t}\n\n\t/**\n\t * Permform a PATCH request\n\t */\n\tasync patch<ResponseType>(\n\t\turl: string,\n\t\tjson: object = {},\n\t\theaders: Record<string, string> = {},\n\t): Promise<HttpClientResponse<ResponseType>> {\n\t\theaders[\"content-type\"] = \"application/json\";\n\t\theaders.accept = \"application/json\";\n\n\t\treturn await this.request(\"PATCH\", url, JSON.stringify(json), headers);\n\t}\n\n\t/**\n\t * Permform a DELETE request\n\t */\n\tasync delete<ResponseType>(\n\t\turl: string,\n\t\tjson: object = {},\n\t\theaders: Record<string, string> = {},\n\t): Promise<HttpClientResponse<ResponseType>> {\n\t\theaders[\"content-type\"] = \"application/json\";\n\t\theaders.accept = \"application/json\";\n\n\t\treturn await this.request(\"DELETE\", url, JSON.stringify(json), headers);\n\t}\n\n\tprivate getUrl(...parts: string[]): string {\n\t\treturn parts.map(part => part.replace(/^\\/+|\\/+$/g, \"\")).join(\"/\");\n\t}\n\n\tprivate async request<ResponseType>(\n\t\tmethod: string,\n\t\turl: string,\n\t\tbody: string | FormData | Blob | null = \"\",\n\t\theaders: Record<string, string> = {},\n\t): Promise<HttpClientResponse<ResponseType>> {\n\t\tconst f = await globalThis.fetch(this.getUrl(this.shop.getShopUrl(), \"/api\", url), {\n\t\t\tredirect: \"manual\",\n\t\t\tbody,\n\t\t\theaders: Object.assign(\n\t\t\t\t{\n\t\t\t\t\tAuthorization: `Bearer ${await this.getToken()}`,\n\t\t\t\t},\n\t\t\t\theaders,\n\t\t\t),\n\t\t\tmethod,\n\t\t});\n\n\t\tif (f.status === 301 || f.status === 302) {\n\t\t\tthrow new ApiClientRequestFailed(\n\t\t\t\tthis.shop.getShopId(),\n\t\t\t\tnew HttpClientResponse<ShopwareErrorResponse>(\n\t\t\t\t\tf.status,\n\t\t\t\t\t{\n\t\t\t\t\t\terrors: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcode: \"301\",\n\t\t\t\t\t\t\t\tstatus: \"301\",\n\t\t\t\t\t\t\t\ttitle: \"301\",\n\t\t\t\t\t\t\t\tdetail:\n\t\t\t\t\t\t\t\t\t\"Got a redirect response from the URL, the URL should point to the Shop without redirect\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\tf.headers,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\t// Obtain new token\n\t\tif (!f.ok && f.status === 401) {\n\t\t\tthis.tokenCache.clearToken(this.shop.getShopId());\n\n\t\t\treturn await this.request(method, url, body, headers);\n\t\t}\n\t\tif (!f.ok) {\n\t\t\tthrow new ApiClientRequestFailed(\n\t\t\t\tthis.shop.getShopId(),\n\t\t\t\tnew HttpClientResponse(f.status, await f.json(), f.headers),\n\t\t\t);\n\t\t}\n\n\t\tif (f.status === 204) {\n\t\t\treturn new HttpClientResponse<ResponseType>(\n\t\t\t\tf.status,\n\t\t\t\t{} as ResponseType,\n\t\t\t\tf.headers,\n\t\t\t);\n\t\t}\n\n\t\treturn new HttpClientResponse(f.status, await f.json(), f.headers);\n\t}\n\n\t/**\n\t * Obtain a valid bearer token\n\t */\n\tasync getToken(): Promise<string> {\n\t\tconst cachedToken = await this.tokenCache.getToken(this.shop.getShopId());\n\t\tif (cachedToken === null) {\n\t\t\tconst auth = await globalThis.fetch(\n\t\t\t\t`${this.shop.getShopUrl()}/api/oauth/token`,\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tredirect: \"manual\",\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t\t\t},\n\t\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t\tgrant_type: \"client_credentials\",\n\t\t\t\t\t\tclient_id: this.shop.getShopClientId(),\n\t\t\t\t\t\tclient_secret: this.shop.getShopClientSecret(),\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (auth.status === 301 || auth.status === 302) {\n\t\t\t\tthrow new ApiClientRequestFailed(\n\t\t\t\t\tthis.shop.getShopId(),\n\t\t\t\t\tnew HttpClientResponse<ShopwareErrorResponse>(\n\t\t\t\t\t\tauth.status,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terrors: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcode: \"301\",\n\t\t\t\t\t\t\t\t\tstatus: \"301\",\n\t\t\t\t\t\t\t\t\ttitle: \"301\",\n\t\t\t\t\t\t\t\t\tdetail:\n\t\t\t\t\t\t\t\t\t\t\"Got a redirect response from the URL, the URL should point to the Shop without redirect\",\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t\tauth.headers,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (!auth.ok) {\n\t\t\t\tconst contentType = auth.headers.get(\"content-type\") || \"text/plain\";\n\t\t\t\tlet body = \"\";\n\n\t\t\t\tif (contentType.indexOf(\"application/json\") !== -1) {\n\t\t\t\t\tbody = await auth.json();\n\t\t\t\t} else {\n\t\t\t\t\tbody = await auth.text();\n\t\t\t\t}\n\n\t\t\t\tthrow new ApiClientAuthenticationFailed(\n\t\t\t\t\tthis.shop.getShopId(),\n\t\t\t\t\tnew HttpClientResponse<string>(auth.status, body, auth.headers),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst authBody = (await auth.json()) as {\n\t\t\t\taccess_token: string;\n\t\t\t\texpires_in: number;\n\t\t\t};\n\n\t\t\tconst expireDate = new Date();\n\t\t\texpireDate.setSeconds(expireDate.getSeconds() + authBody.expires_in);\n\n\t\t\tconst token: HttpClientTokenCacheItem = {\n\t\t\t\ttoken: authBody.access_token,\n\t\t\t\texpiresIn: expireDate,\n\t\t\t};\n\n\t\t\tawait this.tokenCache.setToken(this.shop.getShopId(), token);\n\n\t\t\treturn token.token;\n\t\t}\n\n\t\tif (cachedToken.expiresIn.getTime() < new Date().getTime()) {\n\t\t\tawait this.tokenCache.clearToken(this.shop.getShopId());\n\n\t\t\treturn await this.getToken();\n\t\t}\n\n\t\treturn cachedToken.token;\n\t}\n}\n\n/**\n * HttpClientResponse is the response object of the HttpClient\n */\nexport class HttpClientResponse<ResponseType> {\n\tconstructor(\n\t\tpublic statusCode: number,\n\t\tpublic body: ResponseType,\n\t\tpublic headers: Headers,\n\t) {}\n}\n\ntype ShopwareErrorResponse = {\n\terrors: {\n\t\tcode: string;\n\t\tstatus: string;\n\t\ttitle: string;\n\t\tdetail: string;\n\t}[];\n};\n\n/**\n * ApiClientAuthenticationFailed is thrown when the authentication to the shop's API fails\n */\nexport class ApiClientAuthenticationFailed extends Error {\n\tconstructor(\n\t\tshopId: string,\n\t\tpublic response: HttpClientResponse<string>,\n\t) {\n\t\tsuper(\n\t\t\t`The api client authentication to shop with id: ${shopId} with response: ${JSON.stringify(response.body)}`,\n\t\t);\n\t}\n}\n\n/**\n * ApiClientRequestFailed is thrown when the request to the shop's API fails\n */\nexport class ApiClientRequestFailed extends Error {\n\tconstructor(\n\t\tshopId: string,\n\t\tpublic response: HttpClientResponse<ShopwareErrorResponse>,\n\t) {\n\t\tconst message = response.body.errors.map((e) => e.detail).join(\", \");\n\n\t\tsuper(`Request failed with error: ${message} for shop with id: ${shopId}`);\n\t}\n}\n\nexport interface HttpClientTokenCacheItem {\n\ttoken: string;\n\texpiresIn: Date;\n}\n\nexport class InMemoryHttpClientTokenCache implements HttpClientTokenCacheInterface {\n\tprivate cache: Record<string, HttpClientTokenCacheItem> = {};\n\n\tasync getToken(shopId: string): Promise<HttpClientTokenCacheItem | null> {\n\t\treturn this.cache[shopId] || null;\n\t}\n\n\tasync setToken(\n\t\tshopId: string,\n\t\ttoken: HttpClientTokenCacheItem,\n\t): Promise<void> {\n\t\tthis.cache[shopId] = token;\n\t}\n\n\tasync clearToken(shopId: string): Promise<void> {\n\t\tdelete this.cache[shopId];\n\t}\n}\n\nexport interface HttpClientTokenCacheInterface {\n\tgetToken(shopId: string): Promise<HttpClientTokenCacheItem | null>;\n\tsetToken(shopId: string, token: HttpClientTokenCacheItem): Promise<void>;\n\tclearToken(shopId: string): Promise<void>;\n}"]}
|
|
@@ -2,6 +2,7 @@ import { AppServer } from "../app.js";
|
|
|
2
2
|
import { Context } from "../context-resolver.js";
|
|
3
3
|
import type { ShopInterface, ShopRepositoryInterface } from "../repository.js";
|
|
4
4
|
import type { Hono, Context as HonoContext } from "hono";
|
|
5
|
+
import { type HttpClientTokenCacheInterface } from "../http-client.js";
|
|
5
6
|
declare module "hono" {
|
|
6
7
|
interface ContextVariableMap {
|
|
7
8
|
app: AppServer<ShopInterface>;
|
|
@@ -92,6 +93,10 @@ interface MiddlewareConfig {
|
|
|
92
93
|
* The repository to fetch and store the shop data
|
|
93
94
|
*/
|
|
94
95
|
shopRepository: ShopRepositoryInterface | ((c: HonoContext) => ShopRepositoryInterface);
|
|
96
|
+
/**
|
|
97
|
+
* The token cache to use for the HttpClient. This is used to cache the access token for the shopware shop. If you don't provide a token cache, the HttpClient will use an in-memory cache.
|
|
98
|
+
*/
|
|
99
|
+
httpClientTokenCache: HttpClientTokenCacheInterface | ((c: HonoContext) => HttpClientTokenCacheInterface);
|
|
95
100
|
/**
|
|
96
101
|
* A callback to setup the app server. It will be called after the app server is created and before the first request is handled
|
|
97
102
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../../../src/integration/hono.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAE/E,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../../../src/integration/hono.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAE/E,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,MAAM,CAAC;AACzD,OAAO,EAAc,KAAK,6BAA6B,EAAE,MAAM,mBAAmB,CAAC;AAEnF,OAAO,QAAQ,MAAM,CAAC;IACrB,UAAU,kBAAkB;QAE3B,GAAG,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC;QAC9B,IAAI,EAAE,aAAa,CAAC;QAEpB,OAAO,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;KACzC;CACD;AAED,UAAU,gBAAgB;IACzB;;OAEG;IACH,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,WAAW,KAAK,MAAM,CAAC,CAAC;IAC/C;;OAEG;IACH,SAAS,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,WAAW,KAAK,MAAM,CAAC,CAAC;IAEjD;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEvB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEhC;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAExC;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE9B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE/B;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEjC;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE9B;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE5C;;OAEG;IACH,cAAc,EACX,uBAAuB,GACvB,CAAC,CAAC,CAAC,EAAE,WAAW,KAAK,uBAAuB,CAAC,CAAC;IAEjD;;OAEG;IACH,oBAAoB,EAAE,6BAA6B,GAAG,CAAC,CAAC,CAAC,EAAE,WAAW,KAAK,6BAA6B,CAAC,CAAC;IAE1G;;OAEG;IACH,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,CAAC;CACjC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,gBAAgB,QAoMnE"}
|
|
@@ -32,11 +32,14 @@ function configureAppServer(hono, cfg) {
|
|
|
32
32
|
if (typeof cfg.appSecret === "function") {
|
|
33
33
|
cfg.appSecret = cfg.appSecret(ctx);
|
|
34
34
|
}
|
|
35
|
+
if (typeof cfg.httpClientTokenCache === "function") {
|
|
36
|
+
cfg.httpClientTokenCache = cfg.httpClientTokenCache(ctx);
|
|
37
|
+
}
|
|
35
38
|
app = new app_js_1.AppServer({
|
|
36
39
|
appName: cfg.appName,
|
|
37
40
|
appSecret: cfg.appSecret,
|
|
38
41
|
authorizeCallbackUrl: appUrl + cfg.registerConfirmationUrl,
|
|
39
|
-
}, cfg.shopRepository);
|
|
42
|
+
}, cfg.shopRepository, cfg.httpClientTokenCache);
|
|
40
43
|
if (cfg.setup) {
|
|
41
44
|
cfg.setup(app);
|
|
42
45
|
}
|
|
@@ -118,7 +121,7 @@ function configureAppServer(hono, cfg) {
|
|
|
118
121
|
}
|
|
119
122
|
ctx.set("shop", shop);
|
|
120
123
|
// @ts-ignore
|
|
121
|
-
ctx.set("context", new context_resolver_js_1.Context(shop, {}, new http_client_js_1.HttpClient(shop)));
|
|
124
|
+
ctx.set("context", new context_resolver_js_1.Context(shop, {}, new http_client_js_1.HttpClient(shop, ctx.get('app').httpClientTokenCache)));
|
|
122
125
|
await next();
|
|
123
126
|
});
|
|
124
127
|
for (let [path, redirect] of Object.entries(cfg.appIframeRedirects || {})) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono.js","sourceRoot":"","sources":["../../../src/integration/hono.ts"],"names":[],"mappings":"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","sourcesContent":["import { getSignedCookie, setSignedCookie } from \"hono/cookie\";\nimport { AppServer } from \"../app.js\";\nimport { Context } from \"../context-resolver.js\";\nimport type { ShopInterface, ShopRepositoryInterface } from \"../repository.js\";\n\nimport type { Hono, Context as HonoContext } from \"hono\";\nimport { HttpClient } from \"../http-client.js\";\n\ndeclare module \"hono\" {\n\tinterface ContextVariableMap {\n\t\t// @ts-ignore\n\t\tapp: AppServer<ShopInterface>;\n\t\tshop: ShopInterface;\n\t\t// @ts-ignore\n\t\tcontext: Context<ShopInterface, unknown>;\n\t}\n}\n\ninterface MiddlewareConfig {\n\t/**\n\t * The name of the app\n\t */\n\tappName: string | ((c: HonoContext) => string);\n\t/**\n\t * The secret of the app. When the app is published in the Shopware Store, the Shopware Store provides this value.\n\t */\n\tappSecret: string | ((c: HonoContext) => string);\n\n\t/**\n\t * The URL of the app. This is the base URL of the app. This will automatically determined by default\n\t */\n\tappUrl?: string | null;\n\n\t/**\n\t * The relative url of the app registration endpoint\n\t *\n\t * @default \"/app/register\"\n\t */\n\tregistrationUrl?: string | null;\n\n\t/**\n\t * The relative url of the app registration confirmation endpoint\n\t *\n\t * @default \"/app/register/confirm\"\n\t */\n\tregisterConfirmationUrl?: string | null;\n\n\t/**\n\t * The relative url of the app installation lifecycle endpoint\n\t *\n\t * @default \"/app/install\"\n\t */\n\tappInstallUrl?: string | null;\n\n\t/**\n\t * The relative url of the app activation lifecycle endpoint\n\t *\n\t * @default \"/app/activate\"\n\t */\n\tappActivateUrl?: string | null;\n\n\t/**\n\t * The relative url of the app update lifecycle endpoint\n\t *\n\t * @default \"/app/update\"\n\t */\n\tappUpdateUrl?: string | null;\n\n\t/**\n\t * The relative url of the app deactivation lifecycle endpoint\n\t *\n\t * @default \"/app/deactivate\"\n\t */\n\tappDeactivateUrl?: string | null;\n\n\t/**\n\t * The relative url of the app deletion lifecycle endpoint\n\t *\n\t * @default \"/app/delete\"\n\t */\n\tappDeleteUrl?: string | null;\n\n\t/**\n\t * The relative url of the app scope. All requests matching this will be the signature automatically validated and the response will be signed\n\t *\n\t * @default \"/app/*\"\n\t */\n\tappPath?: string | null;\n\n\t/**\n\t * Enable the app iframe integration. This will automatically set a cookie to identifiy the shopware shop and validate the request from a client side application. See appIframeRedirects\n\t */\n\tappIframeEnable?: boolean;\n\n\t/**\n\t * The relative url of the app iframe scope. All requests matching this will require that the request has an cookie set with the shopware shop. This cookie will be automatically set by\n\t *\n\t * @default \"/client-api/*\"\n\t */\n\tappIframePath?: string | null;\n\n\t/**\n\t * A mapping of the app iframe paths to the actual paths. This route will set a cookie automatically before the redirect to the actual path. In that way the client side application can send requests to /app-iframe/* with the cookie set and the server will automatically validate the request and knows which shop the request is for.\n\t *\n\t * @default {\n\t * \"/app/module\": \"https://my-static-client-side-app.com\"\n\t * }\n\t */\n\tappIframeRedirects?: Record<string, string>;\n\n\t/**\n\t * The repository to fetch and store the shop data\n\t */\n\tshopRepository:\n\t\t| ShopRepositoryInterface\n\t\t| ((c: HonoContext) => ShopRepositoryInterface);\n\n\t/**\n\t * A callback to setup the app server. It will be called after the app server is created and before the first request is handled\n\t */\n\tsetup?: (app: AppServer) => void;\n}\n\n/**\n * Configure the Hono server to handle the app registration and context resolution\n */\nexport function configureAppServer(hono: Hono, cfg: MiddlewareConfig) {\n\tlet app: AppServer | null = null;\n\n\tcfg.registrationUrl = cfg.registrationUrl || \"/app/register\";\n\tcfg.registerConfirmationUrl =\n\t\tcfg.registerConfirmationUrl || \"/app/register/confirm\";\n\tcfg.appActivateUrl = cfg.appActivateUrl || \"/app/activate\";\n\tcfg.appDeactivateUrl = cfg.appDeactivateUrl || \"/app/deactivate\";\n\tcfg.appDeleteUrl = cfg.appDeleteUrl || \"/app/delete\";\n\tcfg.appPath = cfg.appPath || \"/app/*\";\n\tcfg.appInstallUrl = cfg.appInstallUrl || \"/app/install\";\n\tcfg.appUpdateUrl = cfg.appUpdateUrl || \"/app/update\";\n\n\tcfg.appIframePath = cfg.appIframePath || \"/client-api/*\";\n\n\thono.use(\"*\", async (ctx, next) => {\n\t\tif (app === null) {\n\t\t\tconst appUrl = cfg.appUrl || buildBaseUrl(ctx.req.url);\n\n\t\t\tif (typeof cfg.shopRepository === \"function\") {\n\t\t\t\tcfg.shopRepository = cfg.shopRepository(ctx);\n\t\t\t}\n\n\t\t\tif (typeof cfg.appName === \"function\") {\n\t\t\t\tcfg.appName = cfg.appName(ctx);\n\t\t\t}\n\n\t\t\tif (typeof cfg.appSecret === \"function\") {\n\t\t\t\tcfg.appSecret = cfg.appSecret(ctx);\n\t\t\t}\n\n\t\t\tapp = new AppServer(\n\t\t\t\t{\n\t\t\t\t\tappName: cfg.appName,\n\t\t\t\t\tappSecret: cfg.appSecret,\n\t\t\t\t\tauthorizeCallbackUrl: appUrl + cfg.registerConfirmationUrl,\n\t\t\t\t},\n\t\t\t\tcfg.shopRepository,\n\t\t\t);\n\n\t\t\tif (cfg.setup) {\n\t\t\t\tcfg.setup(app);\n\t\t\t}\n\t\t}\n\n\t\t// @ts-ignore\n\t\tctx.set(\"app\", app);\n\n\t\tawait next();\n\t});\n\n\thono.use(cfg.appPath, async (ctx, next) => {\n\t\t// @ts-ignore\n\t\tconst app = ctx.get(\"app\") as AppServer;\n\n\t\t// Don't validate signature for registration\n\t\tif (\n\t\t\tctx.req.path === cfg.registrationUrl ||\n\t\t\tctx.req.path === cfg.registerConfirmationUrl ||\n\t\t\tctx.req.path === cfg.appActivateUrl ||\n\t\t\tctx.req.path === cfg.appDeactivateUrl ||\n\t\t\tctx.req.path === cfg.appDeleteUrl\n\t\t) {\n\t\t\tawait next();\n\t\t\treturn;\n\t\t}\n\n\t\tlet context: Context<ShopInterface, unknown>;\n\t\ttry {\n\t\t\tcontext =\n\t\t\t\tctx.req.method === \"GET\"\n\t\t\t\t\t? await app.contextResolver.fromBrowser(ctx.req.raw)\n\t\t\t\t\t: await app.contextResolver.fromAPI(ctx.req.raw);\n\t\t} catch (_e) {\n\t\t\treturn jsonResponse({ message: \"Invalid request\" }, 400);\n\t\t}\n\n\t\t// @ts-ignore\n\t\tctx.set(\"shop\", context.shop);\n\t\t// @ts-ignore\n\t\tctx.set(\"context\", context);\n\n\t\tawait next();\n\n\t\tconst cloned = ctx.res.clone();\n\n\t\tawait ctx\n\t\t\t.get(\"app\")\n\t\t\t.signer.signResponse(cloned, ctx.get(\"shop\").getShopSecret());\n\n\t\tctx.header(\n\t\t\t\"shopware-app-signature\",\n\t\t\tcloned.headers.get(\"shopware-app-signature\") as string,\n\t\t);\n\t});\n\n\thono.get(cfg.registrationUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.authorize(ctx.req.raw);\n\t});\n\n\thono.post(cfg.registerConfirmationUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.authorizeCallback(ctx.req.raw);\n\t});\n\n\thono.post(cfg.appInstallUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.install(ctx.req.raw);\n\t});\n\n\thono.post(cfg.appActivateUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.activate(ctx.req.raw);\n\t});\n\n\thono.post(cfg.appUpdateUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.update(ctx.req.raw);\n\t});\n\n\thono.post(cfg.appDeactivateUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.deactivate(ctx.req.raw);\n\t});\n\n\thono.post(cfg.appDeleteUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.delete(ctx.req.raw);\n\t});\n\n\tif (cfg.appIframeEnable) {\n\t\thono.use(cfg.appIframePath, async (ctx, next) => {\n\t\t\tconst shopId = await getSignedCookie(\n\t\t\t\tctx,\n\t\t\t\tctx.get(\"app\").cfg.appSecret,\n\t\t\t\t\"shop\",\n\t\t\t);\n\n\t\t\tif (!shopId) {\n\t\t\t\treturn ctx.json({ message: \"Shop not found\" }, { status: 400 });\n\t\t\t}\n\n\t\t\tconst shop = await ctx.get(\"app\").repository.getShopById(shopId);\n\n\t\t\tif (!shop) {\n\t\t\t\treturn ctx.json({ message: \"Shop not found\" }, { status: 400 });\n\t\t\t}\n\n\t\t\tctx.set(\"shop\", shop);\n\t\t\t// @ts-ignore\n\t\t\tctx.set(\"context\", new Context(shop, {}, new HttpClient(shop)));\n\n\t\t\tawait next();\n\t\t});\n\n\t\tfor (let [path, redirect] of Object.entries(cfg.appIframeRedirects || {})) {\n\t\t\thono.get(path, async (ctx) => {\n\t\t\t\tconst url = new URL(ctx.req.url);\n\n\t\t\t\tif (redirect.startsWith(\"/\")) {\n\t\t\t\t\turl.pathname = redirect;\n\t\t\t\t\tredirect = url.toString();\n\t\t\t\t} else {\n\t\t\t\t\tconst newUrl = new URL(redirect);\n\n\t\t\t\t\tfor (const [key, value] of url.searchParams) {\n\t\t\t\t\t\tnewUrl.searchParams.set(key, value);\n\t\t\t\t\t}\n\n\t\t\t\t\tredirect = newUrl.toString();\n\t\t\t\t}\n\n\t\t\t\tawait setSignedCookie(\n\t\t\t\t\tctx,\n\t\t\t\t\t\"shop\",\n\t\t\t\t\tctx.get(\"shop\").getShopId(),\n\t\t\t\t\tctx.get(\"app\").cfg.appSecret,\n\t\t\t\t);\n\n\t\t\t\treturn ctx.redirect(redirect);\n\t\t\t});\n\t\t}\n\t}\n}\n\nfunction jsonResponse(body: object, status = 200): Response {\n\treturn new Response(JSON.stringify(body), {\n\t\tstatus,\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t});\n}\n\nfunction buildBaseUrl(url: string): string {\n\tconst u = new URL(url);\n\n\tlet protocol = u.protocol;\n\n\tif (typeof process !== \"undefined\" && process.env?.SHOPWARE_APP_SDK_FORCE_HTTPS) {\n\t\tprotocol = \"https:\";\n\t}\n\n\treturn `${protocol}//${u.host}`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"hono.js","sourceRoot":"","sources":["../../../src/integration/hono.ts"],"names":[],"mappings":"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","sourcesContent":["import { getSignedCookie, setSignedCookie } from \"hono/cookie\";\nimport { AppServer } from \"../app.js\";\nimport { Context } from \"../context-resolver.js\";\nimport type { ShopInterface, ShopRepositoryInterface } from \"../repository.js\";\n\nimport type { Hono, Context as HonoContext } from \"hono\";\nimport { HttpClient, type HttpClientTokenCacheInterface } from \"../http-client.js\";\n\ndeclare module \"hono\" {\n\tinterface ContextVariableMap {\n\t\t// @ts-ignore\n\t\tapp: AppServer<ShopInterface>;\n\t\tshop: ShopInterface;\n\t\t// @ts-ignore\n\t\tcontext: Context<ShopInterface, unknown>;\n\t}\n}\n\ninterface MiddlewareConfig {\n\t/**\n\t * The name of the app\n\t */\n\tappName: string | ((c: HonoContext) => string);\n\t/**\n\t * The secret of the app. When the app is published in the Shopware Store, the Shopware Store provides this value.\n\t */\n\tappSecret: string | ((c: HonoContext) => string);\n\n\t/**\n\t * The URL of the app. This is the base URL of the app. This will automatically determined by default\n\t */\n\tappUrl?: string | null;\n\n\t/**\n\t * The relative url of the app registration endpoint\n\t *\n\t * @default \"/app/register\"\n\t */\n\tregistrationUrl?: string | null;\n\n\t/**\n\t * The relative url of the app registration confirmation endpoint\n\t *\n\t * @default \"/app/register/confirm\"\n\t */\n\tregisterConfirmationUrl?: string | null;\n\n\t/**\n\t * The relative url of the app installation lifecycle endpoint\n\t *\n\t * @default \"/app/install\"\n\t */\n\tappInstallUrl?: string | null;\n\n\t/**\n\t * The relative url of the app activation lifecycle endpoint\n\t *\n\t * @default \"/app/activate\"\n\t */\n\tappActivateUrl?: string | null;\n\n\t/**\n\t * The relative url of the app update lifecycle endpoint\n\t *\n\t * @default \"/app/update\"\n\t */\n\tappUpdateUrl?: string | null;\n\n\t/**\n\t * The relative url of the app deactivation lifecycle endpoint\n\t *\n\t * @default \"/app/deactivate\"\n\t */\n\tappDeactivateUrl?: string | null;\n\n\t/**\n\t * The relative url of the app deletion lifecycle endpoint\n\t *\n\t * @default \"/app/delete\"\n\t */\n\tappDeleteUrl?: string | null;\n\n\t/**\n\t * The relative url of the app scope. All requests matching this will be the signature automatically validated and the response will be signed\n\t *\n\t * @default \"/app/*\"\n\t */\n\tappPath?: string | null;\n\n\t/**\n\t * Enable the app iframe integration. This will automatically set a cookie to identifiy the shopware shop and validate the request from a client side application. See appIframeRedirects\n\t */\n\tappIframeEnable?: boolean;\n\n\t/**\n\t * The relative url of the app iframe scope. All requests matching this will require that the request has an cookie set with the shopware shop. This cookie will be automatically set by\n\t *\n\t * @default \"/client-api/*\"\n\t */\n\tappIframePath?: string | null;\n\n\t/**\n\t * A mapping of the app iframe paths to the actual paths. This route will set a cookie automatically before the redirect to the actual path. In that way the client side application can send requests to /app-iframe/* with the cookie set and the server will automatically validate the request and knows which shop the request is for.\n\t *\n\t * @default {\n\t * \"/app/module\": \"https://my-static-client-side-app.com\"\n\t * }\n\t */\n\tappIframeRedirects?: Record<string, string>;\n\n\t/**\n\t * The repository to fetch and store the shop data\n\t */\n\tshopRepository:\n\t\t| ShopRepositoryInterface\n\t\t| ((c: HonoContext) => ShopRepositoryInterface);\n\n\t/**\n\t * The token cache to use for the HttpClient. This is used to cache the access token for the shopware shop. If you don't provide a token cache, the HttpClient will use an in-memory cache.\n\t */\n\thttpClientTokenCache: HttpClientTokenCacheInterface | ((c: HonoContext) => HttpClientTokenCacheInterface);\n\n\t/**\n\t * A callback to setup the app server. It will be called after the app server is created and before the first request is handled\n\t */\n\tsetup?: (app: AppServer) => void;\n}\n\n/**\n * Configure the Hono server to handle the app registration and context resolution\n */\nexport function configureAppServer(hono: Hono, cfg: MiddlewareConfig) {\n\tlet app: AppServer | null = null;\n\n\tcfg.registrationUrl = cfg.registrationUrl || \"/app/register\";\n\tcfg.registerConfirmationUrl =\n\t\tcfg.registerConfirmationUrl || \"/app/register/confirm\";\n\tcfg.appActivateUrl = cfg.appActivateUrl || \"/app/activate\";\n\tcfg.appDeactivateUrl = cfg.appDeactivateUrl || \"/app/deactivate\";\n\tcfg.appDeleteUrl = cfg.appDeleteUrl || \"/app/delete\";\n\tcfg.appPath = cfg.appPath || \"/app/*\";\n\tcfg.appInstallUrl = cfg.appInstallUrl || \"/app/install\";\n\tcfg.appUpdateUrl = cfg.appUpdateUrl || \"/app/update\";\n\n\tcfg.appIframePath = cfg.appIframePath || \"/client-api/*\";\n\n\thono.use(\"*\", async (ctx, next) => {\n\t\tif (app === null) {\n\t\t\tconst appUrl = cfg.appUrl || buildBaseUrl(ctx.req.url);\n\n\t\t\tif (typeof cfg.shopRepository === \"function\") {\n\t\t\t\tcfg.shopRepository = cfg.shopRepository(ctx);\n\t\t\t}\n\n\t\t\tif (typeof cfg.appName === \"function\") {\n\t\t\t\tcfg.appName = cfg.appName(ctx);\n\t\t\t}\n\n\t\t\tif (typeof cfg.appSecret === \"function\") {\n\t\t\t\tcfg.appSecret = cfg.appSecret(ctx);\n\t\t\t}\n\n\t\t\tif (typeof cfg.httpClientTokenCache === \"function\") {\n\t\t\t\tcfg.httpClientTokenCache = cfg.httpClientTokenCache(ctx);\n\t\t\t}\n\n\t\t\tapp = new AppServer(\n\t\t\t\t{\n\t\t\t\t\tappName: cfg.appName,\n\t\t\t\t\tappSecret: cfg.appSecret,\n\t\t\t\t\tauthorizeCallbackUrl: appUrl + cfg.registerConfirmationUrl,\n\t\t\t\t},\n\t\t\t\tcfg.shopRepository,\n\t\t\t\tcfg.httpClientTokenCache,\n\t\t\t);\n\n\t\t\tif (cfg.setup) {\n\t\t\t\tcfg.setup(app);\n\t\t\t}\n\t\t}\n\n\t\t// @ts-ignore\n\t\tctx.set(\"app\", app);\n\n\t\tawait next();\n\t});\n\n\thono.use(cfg.appPath, async (ctx, next) => {\n\t\t// @ts-ignore\n\t\tconst app = ctx.get(\"app\") as AppServer;\n\n\t\t// Don't validate signature for registration\n\t\tif (\n\t\t\tctx.req.path === cfg.registrationUrl ||\n\t\t\tctx.req.path === cfg.registerConfirmationUrl ||\n\t\t\tctx.req.path === cfg.appActivateUrl ||\n\t\t\tctx.req.path === cfg.appDeactivateUrl ||\n\t\t\tctx.req.path === cfg.appDeleteUrl\n\t\t) {\n\t\t\tawait next();\n\t\t\treturn;\n\t\t}\n\n\t\tlet context: Context<ShopInterface, unknown>;\n\t\ttry {\n\t\t\tcontext =\n\t\t\t\tctx.req.method === \"GET\"\n\t\t\t\t\t? await app.contextResolver.fromBrowser(ctx.req.raw)\n\t\t\t\t\t: await app.contextResolver.fromAPI(ctx.req.raw);\n\t\t} catch (_e) {\n\t\t\treturn jsonResponse({ message: \"Invalid request\" }, 400);\n\t\t}\n\n\t\t// @ts-ignore\n\t\tctx.set(\"shop\", context.shop);\n\t\t// @ts-ignore\n\t\tctx.set(\"context\", context);\n\n\t\tawait next();\n\n\t\tconst cloned = ctx.res.clone();\n\n\t\tawait ctx\n\t\t\t.get(\"app\")\n\t\t\t.signer.signResponse(cloned, ctx.get(\"shop\").getShopSecret());\n\n\t\tctx.header(\n\t\t\t\"shopware-app-signature\",\n\t\t\tcloned.headers.get(\"shopware-app-signature\") as string,\n\t\t);\n\t});\n\n\thono.get(cfg.registrationUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.authorize(ctx.req.raw);\n\t});\n\n\thono.post(cfg.registerConfirmationUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.authorizeCallback(ctx.req.raw);\n\t});\n\n\thono.post(cfg.appInstallUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.install(ctx.req.raw);\n\t});\n\n\thono.post(cfg.appActivateUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.activate(ctx.req.raw);\n\t});\n\n\thono.post(cfg.appUpdateUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.update(ctx.req.raw);\n\t});\n\n\thono.post(cfg.appDeactivateUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.deactivate(ctx.req.raw);\n\t});\n\n\thono.post(cfg.appDeleteUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.delete(ctx.req.raw);\n\t});\n\n\tif (cfg.appIframeEnable) {\n\t\thono.use(cfg.appIframePath, async (ctx, next) => {\n\t\t\tconst shopId = await getSignedCookie(\n\t\t\t\tctx,\n\t\t\t\tctx.get(\"app\").cfg.appSecret,\n\t\t\t\t\"shop\",\n\t\t\t);\n\n\t\t\tif (!shopId) {\n\t\t\t\treturn ctx.json({ message: \"Shop not found\" }, { status: 400 });\n\t\t\t}\n\n\t\t\tconst shop = await ctx.get(\"app\").repository.getShopById(shopId);\n\n\t\t\tif (!shop) {\n\t\t\t\treturn ctx.json({ message: \"Shop not found\" }, { status: 400 });\n\t\t\t}\n\n\t\t\tctx.set(\"shop\", shop);\n\t\t\t// @ts-ignore\n\t\t\tctx.set(\"context\", new Context(shop, {}, new HttpClient(shop, ctx.get('app').httpClientTokenCache)));\n\n\t\t\tawait next();\n\t\t});\n\n\t\tfor (let [path, redirect] of Object.entries(cfg.appIframeRedirects || {})) {\n\t\t\thono.get(path, async (ctx) => {\n\t\t\t\tconst url = new URL(ctx.req.url);\n\n\t\t\t\tif (redirect.startsWith(\"/\")) {\n\t\t\t\t\turl.pathname = redirect;\n\t\t\t\t\tredirect = url.toString();\n\t\t\t\t} else {\n\t\t\t\t\tconst newUrl = new URL(redirect);\n\n\t\t\t\t\tfor (const [key, value] of url.searchParams) {\n\t\t\t\t\t\tnewUrl.searchParams.set(key, value);\n\t\t\t\t\t}\n\n\t\t\t\t\tredirect = newUrl.toString();\n\t\t\t\t}\n\n\t\t\t\tawait setSignedCookie(\n\t\t\t\t\tctx,\n\t\t\t\t\t\"shop\",\n\t\t\t\t\tctx.get(\"shop\").getShopId(),\n\t\t\t\t\tctx.get(\"app\").cfg.appSecret,\n\t\t\t\t);\n\n\t\t\t\treturn ctx.redirect(redirect);\n\t\t\t});\n\t\t}\n\t}\n}\n\nfunction jsonResponse(body: object, status = 200): Response {\n\treturn new Response(JSON.stringify(body), {\n\t\tstatus,\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t});\n}\n\nfunction buildBaseUrl(url: string): string {\n\tconst u = new URL(url);\n\n\tlet protocol = u.protocol;\n\n\tif (typeof process !== \"undefined\" && process.env?.SHOPWARE_APP_SDK_FORCE_HTTPS) {\n\t\tprotocol = \"https:\";\n\t}\n\n\treturn `${protocol}//${u.host}`;\n}\n"]}
|
|
@@ -92,4 +92,13 @@ export declare class AppUninstallEvent<Shop extends ShopInterface = ShopInterfac
|
|
|
92
92
|
keepUserData: boolean | null;
|
|
93
93
|
constructor(request: Request, shop: Shop, keepUserData?: boolean | null);
|
|
94
94
|
}
|
|
95
|
+
export declare class BeforeRegistrationEvent<Shop extends ShopInterface = ShopInterface> {
|
|
96
|
+
request: Request;
|
|
97
|
+
shopId: string;
|
|
98
|
+
shopUrl: string;
|
|
99
|
+
private cancellationReason;
|
|
100
|
+
constructor(request: Request, shopId: string, shopUrl: string);
|
|
101
|
+
rejectRegistration(reason: string): void;
|
|
102
|
+
get reason(): string | null;
|
|
103
|
+
}
|
|
95
104
|
//# sourceMappingURL=registration.d.ts.map
|