@shopware-ag/app-server-sdk 1.0.0

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.
Files changed (149) hide show
  1. package/README.md +43 -0
  2. package/dist/commonjs/app.d.ts +31 -0
  3. package/dist/commonjs/app.d.ts.map +1 -0
  4. package/dist/commonjs/app.js +25 -0
  5. package/dist/commonjs/app.js.map +1 -0
  6. package/dist/commonjs/context-resolver.d.ts +30 -0
  7. package/dist/commonjs/context-resolver.d.ts.map +1 -0
  8. package/dist/commonjs/context-resolver.js +70 -0
  9. package/dist/commonjs/context-resolver.js.map +1 -0
  10. package/dist/commonjs/framework/hono.d.ts +36 -0
  11. package/dist/commonjs/framework/hono.d.ts.map +1 -0
  12. package/dist/commonjs/framework/hono.js +84 -0
  13. package/dist/commonjs/framework/hono.js.map +1 -0
  14. package/dist/commonjs/helper/app-actions.d.ts +13 -0
  15. package/dist/commonjs/helper/app-actions.d.ts.map +1 -0
  16. package/dist/commonjs/helper/app-actions.js +54 -0
  17. package/dist/commonjs/helper/app-actions.js.map +1 -0
  18. package/dist/commonjs/http-client.d.ts +67 -0
  19. package/dist/commonjs/http-client.d.ts.map +1 -0
  20. package/dist/commonjs/http-client.js +155 -0
  21. package/dist/commonjs/http-client.js.map +1 -0
  22. package/dist/commonjs/mod.d.ts +6 -0
  23. package/dist/commonjs/mod.d.ts.map +1 -0
  24. package/dist/commonjs/mod.js +16 -0
  25. package/dist/commonjs/mod.js.map +1 -0
  26. package/dist/commonjs/package.json +3 -0
  27. package/dist/commonjs/registration.d.ts +18 -0
  28. package/dist/commonjs/registration.d.ts.map +1 -0
  29. package/dist/commonjs/registration.js +89 -0
  30. package/dist/commonjs/registration.js.map +1 -0
  31. package/dist/commonjs/repository.d.ts +51 -0
  32. package/dist/commonjs/repository.d.ts.map +1 -0
  33. package/dist/commonjs/repository.js +68 -0
  34. package/dist/commonjs/repository.js.map +1 -0
  35. package/dist/commonjs/service/cloudflare.d.ts +43 -0
  36. package/dist/commonjs/service/cloudflare.d.ts.map +1 -0
  37. package/dist/commonjs/service/cloudflare.js +45 -0
  38. package/dist/commonjs/service/cloudflare.js.map +1 -0
  39. package/dist/commonjs/service/deno.d.ts +18 -0
  40. package/dist/commonjs/service/deno.d.ts.map +1 -0
  41. package/dist/commonjs/service/deno.js +48 -0
  42. package/dist/commonjs/service/deno.js.map +1 -0
  43. package/dist/commonjs/signer.d.ts +12 -0
  44. package/dist/commonjs/signer.d.ts.map +1 -0
  45. package/dist/commonjs/signer.js +58 -0
  46. package/dist/commonjs/signer.js.map +1 -0
  47. package/dist/commonjs/types.d.ts +28 -0
  48. package/dist/commonjs/types.d.ts.map +1 -0
  49. package/dist/commonjs/types.js +3 -0
  50. package/dist/commonjs/types.js.map +1 -0
  51. package/dist/deno/app.d.ts +31 -0
  52. package/dist/deno/app.d.ts.map +1 -0
  53. package/dist/deno/app.js +21 -0
  54. package/dist/deno/app.js.map +1 -0
  55. package/dist/deno/context-resolver.d.ts +30 -0
  56. package/dist/deno/context-resolver.d.ts.map +1 -0
  57. package/dist/deno/context-resolver.js +65 -0
  58. package/dist/deno/context-resolver.js.map +1 -0
  59. package/dist/deno/framework/hono.d.ts +36 -0
  60. package/dist/deno/framework/hono.d.ts.map +1 -0
  61. package/dist/deno/framework/hono.js +81 -0
  62. package/dist/deno/framework/hono.js.map +1 -0
  63. package/dist/deno/helper/app-actions.d.ts +13 -0
  64. package/dist/deno/helper/app-actions.d.ts.map +1 -0
  65. package/dist/deno/helper/app-actions.js +49 -0
  66. package/dist/deno/helper/app-actions.js.map +1 -0
  67. package/dist/deno/http-client.d.ts +67 -0
  68. package/dist/deno/http-client.d.ts.map +1 -0
  69. package/dist/deno/http-client.js +148 -0
  70. package/dist/deno/http-client.js.map +1 -0
  71. package/dist/deno/mod.d.ts +6 -0
  72. package/dist/deno/mod.d.ts.map +1 -0
  73. package/dist/deno/mod.js +5 -0
  74. package/dist/deno/mod.js.map +1 -0
  75. package/dist/deno/package.json +3 -0
  76. package/dist/deno/registration.d.ts +18 -0
  77. package/dist/deno/registration.d.ts.map +1 -0
  78. package/dist/deno/registration.js +84 -0
  79. package/dist/deno/registration.js.map +1 -0
  80. package/dist/deno/repository.d.ts +51 -0
  81. package/dist/deno/repository.d.ts.map +1 -0
  82. package/dist/deno/repository.js +63 -0
  83. package/dist/deno/repository.js.map +1 -0
  84. package/dist/deno/service/cloudflare.d.ts +43 -0
  85. package/dist/deno/service/cloudflare.d.ts.map +1 -0
  86. package/dist/deno/service/cloudflare.js +41 -0
  87. package/dist/deno/service/cloudflare.js.map +1 -0
  88. package/dist/deno/service/deno.d.ts +18 -0
  89. package/dist/deno/service/deno.d.ts.map +1 -0
  90. package/dist/deno/service/deno.js +44 -0
  91. package/dist/deno/service/deno.js.map +1 -0
  92. package/dist/deno/signer.d.ts +12 -0
  93. package/dist/deno/signer.d.ts.map +1 -0
  94. package/dist/deno/signer.js +54 -0
  95. package/dist/deno/signer.js.map +1 -0
  96. package/dist/deno/types.d.ts +28 -0
  97. package/dist/deno/types.d.ts.map +1 -0
  98. package/dist/deno/types.js +2 -0
  99. package/dist/deno/types.js.map +1 -0
  100. package/dist/esm/app.d.ts +31 -0
  101. package/dist/esm/app.d.ts.map +1 -0
  102. package/dist/esm/app.js +21 -0
  103. package/dist/esm/app.js.map +1 -0
  104. package/dist/esm/context-resolver.d.ts +30 -0
  105. package/dist/esm/context-resolver.d.ts.map +1 -0
  106. package/dist/esm/context-resolver.js +65 -0
  107. package/dist/esm/context-resolver.js.map +1 -0
  108. package/dist/esm/framework/hono.d.ts +36 -0
  109. package/dist/esm/framework/hono.d.ts.map +1 -0
  110. package/dist/esm/framework/hono.js +81 -0
  111. package/dist/esm/framework/hono.js.map +1 -0
  112. package/dist/esm/helper/app-actions.d.ts +13 -0
  113. package/dist/esm/helper/app-actions.d.ts.map +1 -0
  114. package/dist/esm/helper/app-actions.js +49 -0
  115. package/dist/esm/helper/app-actions.js.map +1 -0
  116. package/dist/esm/http-client.d.ts +67 -0
  117. package/dist/esm/http-client.d.ts.map +1 -0
  118. package/dist/esm/http-client.js +148 -0
  119. package/dist/esm/http-client.js.map +1 -0
  120. package/dist/esm/mod.d.ts +6 -0
  121. package/dist/esm/mod.d.ts.map +1 -0
  122. package/dist/esm/mod.js +5 -0
  123. package/dist/esm/mod.js.map +1 -0
  124. package/dist/esm/package.json +3 -0
  125. package/dist/esm/registration.d.ts +18 -0
  126. package/dist/esm/registration.d.ts.map +1 -0
  127. package/dist/esm/registration.js +84 -0
  128. package/dist/esm/registration.js.map +1 -0
  129. package/dist/esm/repository.d.ts +51 -0
  130. package/dist/esm/repository.d.ts.map +1 -0
  131. package/dist/esm/repository.js +63 -0
  132. package/dist/esm/repository.js.map +1 -0
  133. package/dist/esm/service/cloudflare.d.ts +43 -0
  134. package/dist/esm/service/cloudflare.d.ts.map +1 -0
  135. package/dist/esm/service/cloudflare.js +41 -0
  136. package/dist/esm/service/cloudflare.js.map +1 -0
  137. package/dist/esm/service/deno.d.ts +18 -0
  138. package/dist/esm/service/deno.d.ts.map +1 -0
  139. package/dist/esm/service/deno.js +44 -0
  140. package/dist/esm/service/deno.js.map +1 -0
  141. package/dist/esm/signer.d.ts +12 -0
  142. package/dist/esm/signer.d.ts.map +1 -0
  143. package/dist/esm/signer.js +54 -0
  144. package/dist/esm/signer.js.map +1 -0
  145. package/dist/esm/types.d.ts +28 -0
  146. package/dist/esm/types.d.ts.map +1 -0
  147. package/dist/esm/types.js +2 -0
  148. package/dist/esm/types.js.map +1 -0
  149. package/package.json +72 -0
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiClientRequestFailed = exports.ApiClientAuthenticationFailed = exports.HttpClientResponse = exports.HttpClient = void 0;
4
+ /**
5
+ * HttpClient is a simple wrapper around the fetch API, pre-configured with the shop's URL and access token
6
+ */
7
+ class HttpClient {
8
+ shop;
9
+ storage;
10
+ constructor(shop) {
11
+ this.shop = shop;
12
+ this.storage = {
13
+ token: null,
14
+ expiresIn: null,
15
+ };
16
+ }
17
+ /**
18
+ * Permform a GET request
19
+ */
20
+ async get(url, headers = {}) {
21
+ return await this.request("GET", url, null, headers);
22
+ }
23
+ /**
24
+ * Permform a POST request
25
+ */
26
+ async post(url, json = {}, headers = {}) {
27
+ headers["content-type"] = "application/json";
28
+ headers.accept = "application/json";
29
+ return await this.request("POST", url, JSON.stringify(json), headers);
30
+ }
31
+ /**
32
+ * Permform a PUT request
33
+ */
34
+ async put(url, json = {}, headers = {}) {
35
+ headers["content-type"] = "application/json";
36
+ headers.accept = "application/json";
37
+ return await this.request("PUT", url, JSON.stringify(json), headers);
38
+ }
39
+ /**
40
+ * Permform a PATCH request
41
+ */
42
+ async patch(url, json = {}, headers = {}) {
43
+ headers["content-type"] = "application/json";
44
+ headers.accept = "application/json";
45
+ return await this.request("PATCH", url, JSON.stringify(json), headers);
46
+ }
47
+ /**
48
+ * Permform a DELETE request
49
+ */
50
+ async delete(url, json = {}, headers = {}) {
51
+ headers["content-type"] = "application/json";
52
+ headers.accept = "application/json";
53
+ return await this.request("DELETE", url, JSON.stringify(json), headers);
54
+ }
55
+ async request(method, url, body = "", headers = {}) {
56
+ const f = await globalThis.fetch(`${this.shop.getShopUrl()}/api${url}`, {
57
+ body,
58
+ headers: Object.assign({
59
+ Authorization: `Bearer ${await this.getToken()}`,
60
+ }, headers),
61
+ method,
62
+ });
63
+ // Obtain new token
64
+ if (!f.ok && f.status === 401) {
65
+ this.storage.expiresIn = null;
66
+ return await this.request(method, url, body, headers);
67
+ }
68
+ if (!f.ok) {
69
+ throw new ApiClientRequestFailed(this.shop.getShopId(), new HttpClientResponse(f.status, await f.json(), f.headers));
70
+ }
71
+ if (f.status === 204) {
72
+ return new HttpClientResponse(f.status, {}, f.headers);
73
+ }
74
+ return new HttpClientResponse(f.status, await f.json(), f.headers);
75
+ }
76
+ /**
77
+ * Obtain a valid bearer token
78
+ */
79
+ async getToken() {
80
+ if (this.storage.expiresIn === null) {
81
+ const auth = await globalThis.fetch(`${this.shop.getShopUrl()}/api/oauth/token`, {
82
+ method: "POST",
83
+ headers: {
84
+ "content-type": "application/json",
85
+ },
86
+ body: JSON.stringify({
87
+ grant_type: "client_credentials",
88
+ client_id: this.shop.getShopClientId(),
89
+ client_secret: this.shop.getShopClientSecret(),
90
+ }),
91
+ });
92
+ if (!auth.ok) {
93
+ const contentType = auth.headers.get("content-type") || "text/plain";
94
+ let body = "";
95
+ if (contentType.indexOf("application/json") !== -1) {
96
+ body = await auth.json();
97
+ }
98
+ else {
99
+ body = await auth.text();
100
+ }
101
+ throw new ApiClientAuthenticationFailed(this.shop.getShopId(), new HttpClientResponse(auth.status, body, auth.headers));
102
+ }
103
+ const expireDate = new Date();
104
+ const authBody = (await auth.json());
105
+ this.storage.token = authBody.access_token;
106
+ expireDate.setSeconds(expireDate.getSeconds() + authBody.expires_in);
107
+ this.storage.expiresIn = expireDate;
108
+ return this.storage.token;
109
+ }
110
+ if (this.storage.expiresIn.getTime() < new Date().getTime()) {
111
+ // Expired
112
+ this.storage.expiresIn = null;
113
+ return await this.getToken();
114
+ }
115
+ return this.storage.token;
116
+ }
117
+ }
118
+ exports.HttpClient = HttpClient;
119
+ /**
120
+ * HttpClientResponse is the response object of the HttpClient
121
+ */
122
+ class HttpClientResponse {
123
+ statusCode;
124
+ body;
125
+ headers;
126
+ constructor(statusCode, body, headers) {
127
+ this.statusCode = statusCode;
128
+ this.body = body;
129
+ this.headers = headers;
130
+ }
131
+ }
132
+ exports.HttpClientResponse = HttpClientResponse;
133
+ /**
134
+ * ApiClientAuthenticationFailed is thrown when the authentication to the shop's API fails
135
+ */
136
+ class ApiClientAuthenticationFailed extends Error {
137
+ response;
138
+ constructor(shopId, response) {
139
+ super(`The api client authentication to shop with id: ${shopId} with response: ${JSON.stringify(response.body)}`);
140
+ this.response = response;
141
+ }
142
+ }
143
+ exports.ApiClientAuthenticationFailed = ApiClientAuthenticationFailed;
144
+ /**
145
+ * ApiClientRequestFailed is thrown when the request to the shop's API fails
146
+ */
147
+ class ApiClientRequestFailed extends Error {
148
+ response;
149
+ constructor(shopId, response) {
150
+ super(`The api request failed with status code: ${response.statusCode} for shop with id: ${shopId}`);
151
+ this.response = response;
152
+ }
153
+ }
154
+ exports.ApiClientRequestFailed = ApiClientRequestFailed;
155
+ //# sourceMappingURL=http-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../src/http-client.ts"],"names":[],"mappings":";;;AAEA;;GAEG;AACH,MAAa,UAAU;IAGF;IAFZ,OAAO,CAAmD;IAElE,YAAoB,IAAmB;QAAnB,SAAI,GAAJ,IAAI,CAAe;QACtC,IAAI,CAAC,OAAO,GAAG;YACd,KAAK,EAAE,IAAI;YACX,SAAS,EAAE,IAAI;SACf,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CACR,GAAW,EACX,UAAkC,EAAE;QAEpC,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI,CACT,GAAW,EACX,OAAe,EAAE,EACjB,UAAkC,EAAE;QAEpC,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;QAC7C,OAAO,CAAC,MAAM,GAAG,kBAAkB,CAAC;QAEpC,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;IACvE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CACR,GAAW,EACX,OAAe,EAAE,EACjB,UAAkC,EAAE;QAEpC,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;QAC7C,OAAO,CAAC,MAAM,GAAG,kBAAkB,CAAC;QAEpC,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;IACtE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK,CACV,GAAW,EACX,OAAe,EAAE,EACjB,UAAkC,EAAE;QAEpC,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;QAC7C,OAAO,CAAC,MAAM,GAAG,kBAAkB,CAAC;QAEpC,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;IACxE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM,CACX,GAAW,EACX,OAAe,EAAE,EACjB,UAAkC,EAAE;QAEpC,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;QAC7C,OAAO,CAAC,MAAM,GAAG,kBAAkB,CAAC;QAEpC,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;IACzE,CAAC;IAEO,KAAK,CAAC,OAAO,CACpB,MAAc,EACd,GAAW,EACX,OAAsB,EAAE,EACxB,UAAkC,EAAE;QAEpC,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,EAAE,EAAE;YACvE,IAAI;YACJ,OAAO,EAAE,MAAM,CAAC,MAAM,CACrB;gBACC,aAAa,EAAE,UAAU,MAAM,IAAI,CAAC,QAAQ,EAAE,EAAE;aAChD,EACD,OAAO,CACP;YACD,MAAM;SACN,CAAC,CAAC;QAEH,mBAAmB;QACnB,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC/B,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;YAE9B,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACX,MAAM,IAAI,sBAAsB,CAC/B,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EACrB,IAAI,kBAAkB,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAC3D,CAAC;QACH,CAAC;QAED,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACtB,OAAO,IAAI,kBAAkB,CAC5B,CAAC,CAAC,MAAM,EACR,EAAkB,EAClB,CAAC,CAAC,OAAO,CACT,CAAC;QACH,CAAC;QAED,OAAO,IAAI,kBAAkB,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;IACpE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ;QACb,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YACrC,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,KAAK,CAClC,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,kBAAkB,EAC3C;gBACC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACR,cAAc,EAAE,kBAAkB;iBAClC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACpB,UAAU,EAAE,oBAAoB;oBAChC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;oBACtC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE;iBAC9C,CAAC;aACF,CACD,CAAC;YAEF,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACd,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,YAAY,CAAC;gBACrE,IAAI,IAAI,GAAG,EAAE,CAAC;gBAEd,IAAI,WAAW,CAAC,OAAO,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;oBACpD,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC1B,CAAC;qBAAM,CAAC;oBACP,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC1B,CAAC;gBAED,MAAM,IAAI,6BAA6B,CACtC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EACrB,IAAI,kBAAkB,CAAS,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAC/D,CAAC;YACH,CAAC;YAED,MAAM,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAGlC,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,YAAY,CAAC;YAC3C,UAAU,CAAC,UAAU,CAAC,UAAU,CAAC,UAAU,EAAE,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;YACrE,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,UAAU,CAAC;YAEpC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAe,CAAC;QACrC,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;YAC7D,UAAU;YAEV,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;YAE9B,OAAO,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAC,KAAe,CAAC;IACrC,CAAC;CACD;AA/KD,gCA+KC;AAED;;GAEG;AACH,MAAa,kBAAkB;IAEtB;IACA;IACA;IAHR,YACQ,UAAkB,EAClB,IAAkB,EAClB,OAAgB;QAFhB,eAAU,GAAV,UAAU,CAAQ;QAClB,SAAI,GAAJ,IAAI,CAAc;QAClB,YAAO,GAAP,OAAO,CAAS;IACrB,CAAC;CACJ;AAND,gDAMC;AAWD;;GAEG;AACH,MAAa,6BAA8B,SAAQ,KAAK;IAG/C;IAFR,YACC,MAAc,EACP,QAAoC;QAE3C,KAAK,CACJ,kDAAkD,MAAM,mBAAmB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAC1G,CAAC;QAJK,aAAQ,GAAR,QAAQ,CAA4B;IAK5C,CAAC;CACD;AATD,sEASC;AAED;;GAEG;AACH,MAAa,sBAAuB,SAAQ,KAAK;IAGxC;IAFR,YACC,MAAc,EACP,QAAmD;QAE1D,KAAK,CACJ,4CAA4C,QAAQ,CAAC,UAAU,sBAAsB,MAAM,EAAE,CAC7F,CAAC;QAJK,aAAQ,GAAR,QAAQ,CAA2C;IAK3D,CAAC;CACD;AATD,wDASC","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 = {},\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(\"POST\", url, JSON.stringify(json), headers);\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 async request<ResponseType>(\n\t\tmethod: string,\n\t\turl: string,\n\t\tbody: string | null = \"\",\n\t\theaders: Record<string, string> = {},\n\t): Promise<HttpClientResponse<ResponseType>> {\n\t\tconst f = await globalThis.fetch(`${this.shop.getShopUrl()}/api${url}`, {\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\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\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.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\tsuper(\n\t\t\t`The api request failed with status code: ${response.statusCode} for shop with id: ${shopId}`,\n\t\t);\n\t}\n}\n"]}
@@ -0,0 +1,6 @@
1
+ export { AppServer } from "./app.js";
2
+ export { InMemoryShopRepository, SimpleShop } from "./repository.js";
3
+ export type { ShopInterface, ShopRepositoryInterface } from "./repository.js";
4
+ export { HttpClient, HttpClientResponse, ApiClientAuthenticationFailed, ApiClientRequestFailed, } from "./http-client.js";
5
+ export { Context } from "./context-resolver.js";
6
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACrE,YAAY,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EACN,UAAU,EACV,kBAAkB,EAClB,6BAA6B,EAC7B,sBAAsB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Context = exports.ApiClientRequestFailed = exports.ApiClientAuthenticationFailed = exports.HttpClientResponse = exports.HttpClient = exports.SimpleShop = exports.InMemoryShopRepository = exports.AppServer = void 0;
4
+ var app_js_1 = require("./app.js");
5
+ Object.defineProperty(exports, "AppServer", { enumerable: true, get: function () { return app_js_1.AppServer; } });
6
+ var repository_js_1 = require("./repository.js");
7
+ Object.defineProperty(exports, "InMemoryShopRepository", { enumerable: true, get: function () { return repository_js_1.InMemoryShopRepository; } });
8
+ Object.defineProperty(exports, "SimpleShop", { enumerable: true, get: function () { return repository_js_1.SimpleShop; } });
9
+ var http_client_js_1 = require("./http-client.js");
10
+ Object.defineProperty(exports, "HttpClient", { enumerable: true, get: function () { return http_client_js_1.HttpClient; } });
11
+ Object.defineProperty(exports, "HttpClientResponse", { enumerable: true, get: function () { return http_client_js_1.HttpClientResponse; } });
12
+ Object.defineProperty(exports, "ApiClientAuthenticationFailed", { enumerable: true, get: function () { return http_client_js_1.ApiClientAuthenticationFailed; } });
13
+ Object.defineProperty(exports, "ApiClientRequestFailed", { enumerable: true, get: function () { return http_client_js_1.ApiClientRequestFailed; } });
14
+ var context_resolver_js_1 = require("./context-resolver.js");
15
+ Object.defineProperty(exports, "Context", { enumerable: true, get: function () { return context_resolver_js_1.Context; } });
16
+ //# sourceMappingURL=mod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.js","sourceRoot":"","sources":["../../src/mod.ts"],"names":[],"mappings":";;;AAAA,mCAAqC;AAA5B,mGAAA,SAAS,OAAA;AAClB,iDAAqE;AAA5D,uHAAA,sBAAsB,OAAA;AAAE,2GAAA,UAAU,OAAA;AAE3C,mDAK0B;AAJzB,4GAAA,UAAU,OAAA;AACV,oHAAA,kBAAkB,OAAA;AAClB,+HAAA,6BAA6B,OAAA;AAC7B,wHAAA,sBAAsB,OAAA;AAEvB,6DAAgD;AAAvC,8GAAA,OAAO,OAAA","sourcesContent":["export { AppServer } from \"./app.js\";\nexport { InMemoryShopRepository, SimpleShop } from \"./repository.js\";\nexport type { ShopInterface, ShopRepositoryInterface } from \"./repository.js\";\nexport {\n\tHttpClient,\n\tHttpClientResponse,\n\tApiClientAuthenticationFailed,\n\tApiClientRequestFailed,\n} from \"./http-client.js\";\nexport { Context } from \"./context-resolver.js\";\n"]}
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,18 @@
1
+ import type { AppServer } from "./app.js";
2
+ export declare class Registration {
3
+ private app;
4
+ constructor(app: AppServer);
5
+ /**
6
+ * This method checks the request for the handshake with the Shopware Shop.
7
+ * if it's valid a Shop will be created, and a proof will be responded with a confirmation url.
8
+ * then the Shop will call the confirmation url, and this should be handled by the authorizeCallback method to finish the handshake.
9
+ */
10
+ authorize(req: Request): Promise<Response>;
11
+ /**
12
+ * This method is called by the Shopware Shop to confirm the handshake.
13
+ * It will update the shop with the given oauth2 credentials.
14
+ */
15
+ authorizeCallback(req: Request): Promise<Response>;
16
+ }
17
+ export declare function randomString(length?: number): string;
18
+ //# sourceMappingURL=registration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration.d.ts","sourceRoot":"","sources":["../../src/registration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,qBAAa,YAAY;IACZ,OAAO,CAAC,GAAG;gBAAH,GAAG,EAAE,SAAS;IAElC;;;;OAIG;IACU,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IA6CvD;;;OAGG;IACU,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;CAsC/D;AAED,wBAAgB,YAAY,CAAC,MAAM,SAAM,UAUxC"}
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Registration = void 0;
4
+ exports.randomString = randomString;
5
+ class Registration {
6
+ app;
7
+ constructor(app) {
8
+ this.app = app;
9
+ }
10
+ /**
11
+ * This method checks the request for the handshake with the Shopware Shop.
12
+ * if it's valid a Shop will be created, and a proof will be responded with a confirmation url.
13
+ * then the Shop will call the confirmation url, and this should be handled by the authorizeCallback method to finish the handshake.
14
+ */
15
+ async authorize(req) {
16
+ const url = new URL(req.url);
17
+ if (!url.searchParams.has("shop-url") ||
18
+ !req.headers.has("shopware-app-signature") ||
19
+ !url.searchParams.has("shop-id") ||
20
+ !url.searchParams.has("timestamp")) {
21
+ return new InvalidRequestResponse("Invalid Request", 400);
22
+ }
23
+ const v = await this.app.signer.verify(req.headers.get("shopware-app-signature"), `shop-id=${url.searchParams.get("shop-id")}&shop-url=${url.searchParams.get("shop-url")}&timestamp=${url.searchParams.get("timestamp")}`, this.app.cfg.appSecret);
24
+ if (!v) {
25
+ return new InvalidRequestResponse("Cannot validate app signature");
26
+ }
27
+ const shopId = url.searchParams.get("shop-id");
28
+ const shopUrl = url.searchParams.get("shop-url");
29
+ const shopSecret = randomString();
30
+ await this.app.repository.createShop(shopId, shopUrl, shopSecret);
31
+ return new Response(JSON.stringify({
32
+ proof: await this.app.signer.sign(shopId + shopUrl + this.app.cfg.appName, this.app.cfg.appSecret),
33
+ secret: shopSecret,
34
+ confirmation_url: this.app.cfg.authorizeCallbackUrl,
35
+ }), {
36
+ headers: {
37
+ "content-type": "application/json",
38
+ },
39
+ });
40
+ }
41
+ /**
42
+ * This method is called by the Shopware Shop to confirm the handshake.
43
+ * It will update the shop with the given oauth2 credentials.
44
+ */
45
+ async authorizeCallback(req) {
46
+ const bodyContent = await req.text();
47
+ const body = JSON.parse(bodyContent);
48
+ if (typeof body.shopId !== "string" ||
49
+ typeof body.apiKey !== "string" ||
50
+ typeof body.secretKey !== "string" ||
51
+ !req.headers.has("shopware-shop-signature")) {
52
+ return new InvalidRequestResponse("Invalid Request", 400);
53
+ }
54
+ const shop = await this.app.repository.getShopById(body.shopId);
55
+ if (shop === null) {
56
+ return new InvalidRequestResponse("Invalid shop given");
57
+ }
58
+ const v = await this.app.signer.verify(req.headers.get("shopware-shop-signature"), bodyContent, shop.getShopSecret());
59
+ if (!v) {
60
+ // Shop has failed the verify. Delete it from our DB
61
+ await this.app.repository.deleteShop(shop.getShopId());
62
+ return new InvalidRequestResponse("Cannot validate app signature");
63
+ }
64
+ shop.setShopCredentials(body.apiKey, body.secretKey);
65
+ await this.app.repository.updateShop(shop);
66
+ return new Response(null, { status: 204 });
67
+ }
68
+ }
69
+ exports.Registration = Registration;
70
+ function randomString(length = 120) {
71
+ let result = "";
72
+ const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
73
+ const charactersLength = characters.length;
74
+ for (let i = 0; i < length; i++) {
75
+ result += characters.charAt(Math.floor(Math.random() * charactersLength));
76
+ }
77
+ return result;
78
+ }
79
+ class InvalidRequestResponse extends Response {
80
+ constructor(message, status = 401) {
81
+ super(JSON.stringify({ message }), {
82
+ status,
83
+ headers: {
84
+ "content-type": "application/json",
85
+ },
86
+ });
87
+ }
88
+ }
89
+ //# sourceMappingURL=registration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration.js","sourceRoot":"","sources":["../../src/registration.ts"],"names":[],"mappings":";;;AAmGA,oCAUC;AA3GD,MAAa,YAAY;IACJ;IAApB,YAAoB,GAAc;QAAd,QAAG,GAAH,GAAG,CAAW;IAAG,CAAC;IAEtC;;;;OAIG;IACI,KAAK,CAAC,SAAS,CAAC,GAAY;QAClC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAE7B,IACC,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC;YACjC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;YAC1C,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC;YAChC,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EACjC,CAAC;YACF,OAAO,IAAI,sBAAsB,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CACrC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAW,EACnD,WAAW,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,aAAa,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,cAAc,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,EACxI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CACtB,CAAC;QAEF,IAAI,CAAC,CAAC,EAAE,CAAC;YACR,OAAO,IAAI,sBAAsB,CAAC,+BAA+B,CAAC,CAAC;QACpE,CAAC;QAED,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAW,CAAC;QACzD,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAW,CAAC;QAC3D,MAAM,UAAU,GAAG,YAAY,EAAE,CAAC;QAElC,MAAM,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAElE,OAAO,IAAI,QAAQ,CAClB,IAAI,CAAC,SAAS,CAAC;YACd,KAAK,EAAE,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAChC,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EACvC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CACtB;YACD,MAAM,EAAE,UAAU;YAClB,gBAAgB,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,oBAAoB;SACnD,CAAC,EACF;YACC,OAAO,EAAE;gBACR,cAAc,EAAE,kBAAkB;aAClC;SACD,CACD,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,iBAAiB,CAAC,GAAY;QAC1C,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAErC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAErC,IACC,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;YAC/B,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;YAC/B,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ;YAClC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,EAC1C,CAAC;YACF,OAAO,IAAI,sBAAsB,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,MAAgB,CAAC,CAAC;QAE1E,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YACnB,OAAO,IAAI,sBAAsB,CAAC,oBAAoB,CAAC,CAAC;QACzD,CAAC;QAED,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CACrC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAW,EACpD,WAAW,EACX,IAAI,CAAC,aAAa,EAAE,CACpB,CAAC;QACF,IAAI,CAAC,CAAC,EAAE,CAAC;YACR,oDAAoD;YACpD,MAAM,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YAEvD,OAAO,IAAI,sBAAsB,CAAC,+BAA+B,CAAC,CAAC;QACpE,CAAC;QAED,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAErD,MAAM,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAE3C,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5C,CAAC;CACD;AA/FD,oCA+FC;AAED,SAAgB,YAAY,CAAC,MAAM,GAAG,GAAG;IACxC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,MAAM,UAAU,GACf,gEAAgE,CAAC;IAClE,MAAM,gBAAgB,GAAG,UAAU,CAAC,MAAM,CAAC;IAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACjC,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,gBAAgB,CAAC,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED,MAAM,sBAAuB,SAAQ,QAAQ;IAC5C,YAAY,OAAe,EAAE,MAAM,GAAG,GAAG;QACxC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;YAClC,MAAM;YACN,OAAO,EAAE;gBACR,cAAc,EAAE,kBAAkB;aAClC;SACD,CAAC,CAAC;IACJ,CAAC;CACD","sourcesContent":["import type { AppServer } from \"./app.js\";\n\nexport class Registration {\n\tconstructor(private app: AppServer) {}\n\n\t/**\n\t * This method checks the request for the handshake with the Shopware Shop.\n\t * if it's valid a Shop will be created, and a proof will be responded with a confirmation url.\n\t * then the Shop will call the confirmation url, and this should be handled by the authorizeCallback method to finish the handshake.\n\t */\n\tpublic async authorize(req: Request): Promise<Response> {\n\t\tconst url = new URL(req.url);\n\n\t\tif (\n\t\t\t!url.searchParams.has(\"shop-url\") ||\n\t\t\t!req.headers.has(\"shopware-app-signature\") ||\n\t\t\t!url.searchParams.has(\"shop-id\") ||\n\t\t\t!url.searchParams.has(\"timestamp\")\n\t\t) {\n\t\t\treturn new InvalidRequestResponse(\"Invalid Request\", 400);\n\t\t}\n\n\t\tconst v = await this.app.signer.verify(\n\t\t\treq.headers.get(\"shopware-app-signature\") as string,\n\t\t\t`shop-id=${url.searchParams.get(\"shop-id\")}&shop-url=${url.searchParams.get(\"shop-url\")}&timestamp=${url.searchParams.get(\"timestamp\")}`,\n\t\t\tthis.app.cfg.appSecret,\n\t\t);\n\n\t\tif (!v) {\n\t\t\treturn new InvalidRequestResponse(\"Cannot validate app signature\");\n\t\t}\n\n\t\tconst shopId = url.searchParams.get(\"shop-id\") as string;\n\t\tconst shopUrl = url.searchParams.get(\"shop-url\") as string;\n\t\tconst shopSecret = randomString();\n\n\t\tawait this.app.repository.createShop(shopId, shopUrl, shopSecret);\n\n\t\treturn new Response(\n\t\t\tJSON.stringify({\n\t\t\t\tproof: await this.app.signer.sign(\n\t\t\t\t\tshopId + shopUrl + this.app.cfg.appName,\n\t\t\t\t\tthis.app.cfg.appSecret,\n\t\t\t\t),\n\t\t\t\tsecret: shopSecret,\n\t\t\t\tconfirmation_url: this.app.cfg.authorizeCallbackUrl,\n\t\t\t}),\n\t\t\t{\n\t\t\t\theaders: {\n\t\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t}\n\n\t/**\n\t * This method is called by the Shopware Shop to confirm the handshake.\n\t * It will update the shop with the given oauth2 credentials.\n\t */\n\tpublic async authorizeCallback(req: Request): Promise<Response> {\n\t\tconst bodyContent = await req.text();\n\n\t\tconst body = JSON.parse(bodyContent);\n\n\t\tif (\n\t\t\ttypeof body.shopId !== \"string\" ||\n\t\t\ttypeof body.apiKey !== \"string\" ||\n\t\t\ttypeof body.secretKey !== \"string\" ||\n\t\t\t!req.headers.has(\"shopware-shop-signature\")\n\t\t) {\n\t\t\treturn new InvalidRequestResponse(\"Invalid Request\", 400);\n\t\t}\n\n\t\tconst shop = await this.app.repository.getShopById(body.shopId as string);\n\n\t\tif (shop === null) {\n\t\t\treturn new InvalidRequestResponse(\"Invalid shop given\");\n\t\t}\n\n\t\tconst v = await this.app.signer.verify(\n\t\t\treq.headers.get(\"shopware-shop-signature\") as string,\n\t\t\tbodyContent,\n\t\t\tshop.getShopSecret(),\n\t\t);\n\t\tif (!v) {\n\t\t\t// Shop has failed the verify. Delete it from our DB\n\t\t\tawait this.app.repository.deleteShop(shop.getShopId());\n\n\t\t\treturn new InvalidRequestResponse(\"Cannot validate app signature\");\n\t\t}\n\n\t\tshop.setShopCredentials(body.apiKey, body.secretKey);\n\n\t\tawait this.app.repository.updateShop(shop);\n\n\t\treturn new Response(null, { status: 204 });\n\t}\n}\n\nexport function randomString(length = 120) {\n\tlet result = \"\";\n\tconst characters =\n\t\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n\tconst charactersLength = characters.length;\n\tfor (let i = 0; i < length; i++) {\n\t\tresult += characters.charAt(Math.floor(Math.random() * charactersLength));\n\t}\n\n\treturn result;\n}\n\nclass InvalidRequestResponse extends Response {\n\tconstructor(message: string, status = 401) {\n\t\tsuper(JSON.stringify({ message }), {\n\t\t\tstatus,\n\t\t\theaders: {\n\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t},\n\t\t});\n\t}\n}\n"]}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * ShopInterface defines the object that given back from the ShopRepository, it should methods to get the shop data and set them
3
+ */
4
+ export interface ShopInterface {
5
+ getShopId(): string;
6
+ getShopUrl(): string;
7
+ getShopSecret(): string;
8
+ getShopClientId(): string | null;
9
+ getShopClientSecret(): string | null;
10
+ setShopCredentials(clientId: string, clientSecret: string): void;
11
+ }
12
+ /**
13
+ * ShopRepositoryInterface is the storage interface for the shops, you should implement this to save the shop data to your database
14
+ * For testing cases the InMemoryShopRepository can be used
15
+ */
16
+ export interface ShopRepositoryInterface<Shop = ShopInterface> {
17
+ createShop(id: string, url: string, secret: string): Promise<void>;
18
+ getShopById(id: string): Promise<Shop | null>;
19
+ updateShop(shop: Shop): Promise<void>;
20
+ deleteShop(id: string): Promise<void>;
21
+ }
22
+ /**
23
+ * SimpleShop is a simple implementation of the ShopInterface, it stores the shop data in memory
24
+ */
25
+ export declare class SimpleShop implements ShopInterface {
26
+ private shopId;
27
+ private shopUrl;
28
+ private shopSecret;
29
+ private shopClientId;
30
+ private shopClientSecret;
31
+ yes(): void;
32
+ constructor(shopId: string, shopUrl: string, shopSecret: string);
33
+ getShopId(): string;
34
+ getShopUrl(): string;
35
+ getShopSecret(): string;
36
+ getShopClientId(): string | null;
37
+ getShopClientSecret(): string | null;
38
+ setShopCredentials(clientId: string, clientSecret: string): void;
39
+ }
40
+ /**
41
+ * InMemoryShopRepository is a simple implementation of the ShopRepositoryInterface, it stores the shop data in memory
42
+ */
43
+ export declare class InMemoryShopRepository implements ShopRepositoryInterface<SimpleShop> {
44
+ private storage;
45
+ constructor();
46
+ createShop(id: string, secret: string, url: string): Promise<void>;
47
+ getShopById(id: string): Promise<SimpleShop | null>;
48
+ updateShop(shop: SimpleShop): Promise<void>;
49
+ deleteShop(id: string): Promise<void>;
50
+ }
51
+ //# sourceMappingURL=repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/repository.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,SAAS,IAAI,MAAM,CAAC;IACpB,UAAU,IAAI,MAAM,CAAC;IACrB,aAAa,IAAI,MAAM,CAAC;IACxB,eAAe,IAAI,MAAM,GAAG,IAAI,CAAC;IACjC,mBAAmB,IAAI,MAAM,GAAG,IAAI,CAAC;IACrC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACjE;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB,CAAC,IAAI,GAAG,aAAa;IAC5D,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnE,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAE9C,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAED;;GAEG;AACH,qBAAa,UAAW,YAAW,aAAa;IAC/C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,gBAAgB,CAAgB;IAExC,GAAG;gBAES,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAQ/D,SAAS,IAAI,MAAM;IAGnB,UAAU,IAAI,MAAM;IAGpB,aAAa,IAAI,MAAM;IAGvB,eAAe,IAAI,MAAM,GAAG,IAAI;IAGhC,mBAAmB,IAAI,MAAM,GAAG,IAAI;IAGpC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;CAIhE;AAED;;GAEG;AACH,qBAAa,sBACZ,YAAW,uBAAuB,CAAC,UAAU,CAAC;IAE9C,OAAO,CAAC,OAAO,CAA0B;;IAMnC,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAIlD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAUnD,UAAU,CAAC,IAAI,EAAE,UAAU;IAI3B,UAAU,CAAC,EAAE,EAAE,MAAM;CAG3B"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InMemoryShopRepository = exports.SimpleShop = void 0;
4
+ /**
5
+ * SimpleShop is a simple implementation of the ShopInterface, it stores the shop data in memory
6
+ */
7
+ class SimpleShop {
8
+ shopId;
9
+ shopUrl;
10
+ shopSecret;
11
+ shopClientId;
12
+ shopClientSecret;
13
+ yes() { }
14
+ constructor(shopId, shopUrl, shopSecret) {
15
+ this.shopId = shopId;
16
+ this.shopUrl = shopUrl;
17
+ this.shopSecret = shopSecret;
18
+ this.shopClientId = null;
19
+ this.shopClientSecret = null;
20
+ }
21
+ getShopId() {
22
+ return this.shopId;
23
+ }
24
+ getShopUrl() {
25
+ return this.shopUrl;
26
+ }
27
+ getShopSecret() {
28
+ return this.shopSecret;
29
+ }
30
+ getShopClientId() {
31
+ return this.shopClientId;
32
+ }
33
+ getShopClientSecret() {
34
+ return this.shopClientSecret;
35
+ }
36
+ setShopCredentials(clientId, clientSecret) {
37
+ this.shopClientId = clientId;
38
+ this.shopClientSecret = clientSecret;
39
+ }
40
+ }
41
+ exports.SimpleShop = SimpleShop;
42
+ /**
43
+ * InMemoryShopRepository is a simple implementation of the ShopRepositoryInterface, it stores the shop data in memory
44
+ */
45
+ class InMemoryShopRepository {
46
+ storage;
47
+ constructor() {
48
+ this.storage = new Map();
49
+ }
50
+ async createShop(id, secret, url) {
51
+ this.storage.set(id, new SimpleShop(id, url, secret));
52
+ }
53
+ async getShopById(id) {
54
+ const shop = this.storage.get(id);
55
+ if (shop === undefined) {
56
+ return null;
57
+ }
58
+ return shop;
59
+ }
60
+ async updateShop(shop) {
61
+ this.storage.set(shop.getShopId(), shop);
62
+ }
63
+ async deleteShop(id) {
64
+ this.storage.delete(id);
65
+ }
66
+ }
67
+ exports.InMemoryShopRepository = InMemoryShopRepository;
68
+ //# sourceMappingURL=repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/repository.ts"],"names":[],"mappings":";;;AA0BA;;GAEG;AACH,MAAa,UAAU;IACd,MAAM,CAAS;IACf,OAAO,CAAS;IAChB,UAAU,CAAS;IACnB,YAAY,CAAgB;IAC5B,gBAAgB,CAAgB;IAExC,GAAG,KAAI,CAAC;IAER,YAAY,MAAc,EAAE,OAAe,EAAE,UAAkB;QAC9D,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAC9B,CAAC;IAED,SAAS;QACR,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IACD,UAAU;QACT,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IACD,aAAa;QACZ,OAAO,IAAI,CAAC,UAAU,CAAC;IACxB,CAAC;IACD,eAAe;QACd,OAAO,IAAI,CAAC,YAAY,CAAC;IAC1B,CAAC;IACD,mBAAmB;QAClB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC9B,CAAC;IACD,kBAAkB,CAAC,QAAgB,EAAE,YAAoB;QACxD,IAAI,CAAC,YAAY,GAAG,QAAQ,CAAC;QAC7B,IAAI,CAAC,gBAAgB,GAAG,YAAY,CAAC;IACtC,CAAC;CACD;AApCD,gCAoCC;AAED;;GAEG;AACH,MAAa,sBAAsB;IAG1B,OAAO,CAA0B;IAEzC;QACC,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,EAAU,EAAE,MAAc,EAAE,GAAW;QACvD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,UAAU,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,EAAU;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAElC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACb,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAgB;QAChC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,EAAU;QAC1B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC;CACD;AA9BD,wDA8BC","sourcesContent":["/**\n * ShopInterface defines the object that given back from the ShopRepository, it should methods to get the shop data and set them\n */\nexport interface ShopInterface {\n\tgetShopId(): string;\n\tgetShopUrl(): string;\n\tgetShopSecret(): string;\n\tgetShopClientId(): string | null;\n\tgetShopClientSecret(): string | null;\n\tsetShopCredentials(clientId: string, clientSecret: string): void;\n}\n\n/**\n * ShopRepositoryInterface is the storage interface for the shops, you should implement this to save the shop data to your database\n * For testing cases the InMemoryShopRepository can be used\n */\nexport interface ShopRepositoryInterface<Shop = ShopInterface> {\n\tcreateShop(id: string, url: string, secret: string): Promise<void>;\n\n\tgetShopById(id: string): Promise<Shop | null>;\n\n\tupdateShop(shop: Shop): Promise<void>;\n\n\tdeleteShop(id: string): Promise<void>;\n}\n\n/**\n * SimpleShop is a simple implementation of the ShopInterface, it stores the shop data in memory\n */\nexport class SimpleShop implements ShopInterface {\n\tprivate shopId: string;\n\tprivate shopUrl: string;\n\tprivate shopSecret: string;\n\tprivate shopClientId: string | null;\n\tprivate shopClientSecret: string | null;\n\n\tyes() {}\n\n\tconstructor(shopId: string, shopUrl: string, shopSecret: string) {\n\t\tthis.shopId = shopId;\n\t\tthis.shopUrl = shopUrl;\n\t\tthis.shopSecret = shopSecret;\n\t\tthis.shopClientId = null;\n\t\tthis.shopClientSecret = null;\n\t}\n\n\tgetShopId(): string {\n\t\treturn this.shopId;\n\t}\n\tgetShopUrl(): string {\n\t\treturn this.shopUrl;\n\t}\n\tgetShopSecret(): string {\n\t\treturn this.shopSecret;\n\t}\n\tgetShopClientId(): string | null {\n\t\treturn this.shopClientId;\n\t}\n\tgetShopClientSecret(): string | null {\n\t\treturn this.shopClientSecret;\n\t}\n\tsetShopCredentials(clientId: string, clientSecret: string): void {\n\t\tthis.shopClientId = clientId;\n\t\tthis.shopClientSecret = clientSecret;\n\t}\n}\n\n/**\n * InMemoryShopRepository is a simple implementation of the ShopRepositoryInterface, it stores the shop data in memory\n */\nexport class InMemoryShopRepository\n\timplements ShopRepositoryInterface<SimpleShop>\n{\n\tprivate storage: Map<string, SimpleShop>;\n\n\tconstructor() {\n\t\tthis.storage = new Map<string, SimpleShop>();\n\t}\n\n\tasync createShop(id: string, secret: string, url: string) {\n\t\tthis.storage.set(id, new SimpleShop(id, url, secret));\n\t}\n\n\tasync getShopById(id: string): Promise<SimpleShop | null> {\n\t\tconst shop = this.storage.get(id);\n\n\t\tif (shop === undefined) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn shop;\n\t}\n\n\tasync updateShop(shop: SimpleShop) {\n\t\tthis.storage.set(shop.getShopId(), shop);\n\t}\n\n\tasync deleteShop(id: string) {\n\t\tthis.storage.delete(id);\n\t}\n}\n"]}
@@ -0,0 +1,43 @@
1
+ import { SimpleShop } from "../repository.js";
2
+ import type { ShopRepositoryInterface } from "../repository.js";
3
+ /**
4
+ * Cloudflare KV integration
5
+ * @module
6
+ */
7
+ /**
8
+ * Cloudflare KV implementation of the ShopRepositoryInterface
9
+ */
10
+ export declare class CloudflareShopRepository implements ShopRepositoryInterface<SimpleShop> {
11
+ private storage;
12
+ constructor(storage: KVNamespace);
13
+ createShop(id: string, url: string, secret: string): Promise<void>;
14
+ deleteShop(id: string): Promise<void>;
15
+ getShopById(id: string): Promise<SimpleShop | null>;
16
+ updateShop(shop: SimpleShop): Promise<void>;
17
+ protected serializeShop(shop: SimpleShop): string;
18
+ protected deserializeShop(data: string): SimpleShop;
19
+ }
20
+ /**
21
+ * Cloudflare KV
22
+ */
23
+ export declare interface KVNamespace<Key extends string = string> {
24
+ get(key: Key, options?: Partial<KVNamespaceGetOptions<undefined>>): Promise<string | null>;
25
+ put(key: Key, value: string | ArrayBuffer | ArrayBufferView | ReadableStream, options?: KVNamespacePutOptions): Promise<void>;
26
+ delete(key: Key): Promise<void>;
27
+ }
28
+ /**
29
+ * Cloudflare KV get options
30
+ */
31
+ export declare interface KVNamespaceGetOptions<Type> {
32
+ type: Type;
33
+ cacheTtl?: number;
34
+ }
35
+ /**
36
+ * Cloudflare KV put options
37
+ */
38
+ export declare interface KVNamespacePutOptions {
39
+ expiration?: number;
40
+ expirationTtl?: number;
41
+ metadata?: any | null;
42
+ }
43
+ //# sourceMappingURL=cloudflare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../../src/service/cloudflare.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAiB,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAE/E;;;GAGG;AAEH;;GAEG;AACH,qBAAa,wBACZ,YAAW,uBAAuB,CAAC,UAAU,CAAC;IAElC,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,WAAW;IAIlC,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlE,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAUnD,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjD,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM;IAIjD,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU;CAYnD;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,WAAW,WAAW,CAAC,GAAG,SAAS,MAAM,GAAG,MAAM;IAC/D,GAAG,CACF,GAAG,EAAE,GAAG,EACR,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC,GACjD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1B,GAAG,CACF,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,eAAe,GAAG,cAAc,EAC9D,OAAO,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,WAAW,qBAAqB,CAAC,IAAI;IAClD,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,WAAW,qBAAqB;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;CACtB"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CloudflareShopRepository = void 0;
4
+ const repository_js_1 = require("../repository.js");
5
+ /**
6
+ * Cloudflare KV integration
7
+ * @module
8
+ */
9
+ /**
10
+ * Cloudflare KV implementation of the ShopRepositoryInterface
11
+ */
12
+ class CloudflareShopRepository {
13
+ storage;
14
+ constructor(storage) {
15
+ this.storage = storage;
16
+ this.storage = storage;
17
+ }
18
+ async createShop(id, url, secret) {
19
+ await this.storage.put(id, this.serializeShop(new repository_js_1.SimpleShop(id, url, secret)));
20
+ }
21
+ async deleteShop(id) {
22
+ await this.storage.delete(id);
23
+ }
24
+ async getShopById(id) {
25
+ const kvObj = await this.storage.get(id);
26
+ if (kvObj === null) {
27
+ return null;
28
+ }
29
+ return this.deserializeShop(kvObj);
30
+ }
31
+ async updateShop(shop) {
32
+ await this.storage.put(shop.getShopId(), this.serializeShop(shop));
33
+ }
34
+ serializeShop(shop) {
35
+ return JSON.stringify(shop);
36
+ }
37
+ deserializeShop(data) {
38
+ const obj = JSON.parse(data);
39
+ const shop = new repository_js_1.SimpleShop(obj.shopId || "", obj.shopUrl || "", obj.shopSecret || "");
40
+ shop.setShopCredentials(obj.shopClientId || "", obj.shopClientSecret || "");
41
+ return shop;
42
+ }
43
+ }
44
+ exports.CloudflareShopRepository = CloudflareShopRepository;
45
+ //# sourceMappingURL=cloudflare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare.js","sourceRoot":"","sources":["../../../src/service/cloudflare.ts"],"names":[],"mappings":";;;AAAA,oDAA8C;AAG9C;;;GAGG;AAEH;;GAEG;AACH,MAAa,wBAAwB;IAGhB;IAApB,YAAoB,OAAoB;QAApB,YAAO,GAAP,OAAO,CAAa;QACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,EAAU,EAAE,GAAW,EAAE,MAAc;QACvD,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CACrB,EAAE,EACF,IAAI,CAAC,aAAa,CAAC,IAAI,0BAAU,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CACnD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,EAAU;QAC1B,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,EAAU;QAC3B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEzC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACb,CAAC;QAED,OAAO,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAgB;QAChC,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IACpE,CAAC;IAES,aAAa,CAAC,IAAgB;QACvC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAES,eAAe,CAAC,IAAY;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAE7B,MAAM,IAAI,GAAG,IAAI,0BAAU,CAC1B,GAAG,CAAC,MAAM,IAAI,EAAE,EAChB,GAAG,CAAC,OAAO,IAAI,EAAE,EACjB,GAAG,CAAC,UAAU,IAAI,EAAE,CACpB,CAAC;QAEF,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,EAAE,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC;QAC5E,OAAO,IAAI,CAAC;IACb,CAAC;CACD;AAhDD,4DAgDC","sourcesContent":["import { SimpleShop } from \"../repository.js\";\nimport type { ShopInterface, ShopRepositoryInterface } from \"../repository.js\";\n\n/**\n * Cloudflare KV integration\n * @module\n */\n\n/**\n * Cloudflare KV implementation of the ShopRepositoryInterface\n */\nexport class CloudflareShopRepository\n\timplements ShopRepositoryInterface<SimpleShop>\n{\n\tconstructor(private storage: KVNamespace) {\n\t\tthis.storage = storage;\n\t}\n\n\tasync createShop(id: string, url: string, secret: string): Promise<void> {\n\t\tawait this.storage.put(\n\t\t\tid,\n\t\t\tthis.serializeShop(new SimpleShop(id, url, secret)),\n\t\t);\n\t}\n\n\tasync deleteShop(id: string): Promise<void> {\n\t\tawait this.storage.delete(id);\n\t}\n\n\tasync getShopById(id: string): Promise<SimpleShop | null> {\n\t\tconst kvObj = await this.storage.get(id);\n\n\t\tif (kvObj === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.deserializeShop(kvObj);\n\t}\n\n\tasync updateShop(shop: SimpleShop): Promise<void> {\n\t\tawait this.storage.put(shop.getShopId(), this.serializeShop(shop));\n\t}\n\n\tprotected serializeShop(shop: SimpleShop): string {\n\t\treturn JSON.stringify(shop);\n\t}\n\n\tprotected deserializeShop(data: string): SimpleShop {\n\t\tconst obj = JSON.parse(data);\n\n\t\tconst shop = new SimpleShop(\n\t\t\tobj.shopId || \"\",\n\t\t\tobj.shopUrl || \"\",\n\t\t\tobj.shopSecret || \"\",\n\t\t);\n\n\t\tshop.setShopCredentials(obj.shopClientId || \"\", obj.shopClientSecret || \"\");\n\t\treturn shop;\n\t}\n}\n\n/**\n * Cloudflare KV\n */\nexport declare interface KVNamespace<Key extends string = string> {\n\tget(\n\t\tkey: Key,\n\t\toptions?: Partial<KVNamespaceGetOptions<undefined>>,\n\t): Promise<string | null>;\n\tput(\n\t\tkey: Key,\n\t\tvalue: string | ArrayBuffer | ArrayBufferView | ReadableStream,\n\t\toptions?: KVNamespacePutOptions,\n\t): Promise<void>;\n\tdelete(key: Key): Promise<void>;\n}\n\n/**\n * Cloudflare KV get options\n */\nexport declare interface KVNamespaceGetOptions<Type> {\n\ttype: Type;\n\tcacheTtl?: number;\n}\n\n/**\n * Cloudflare KV put options\n */\nexport declare interface KVNamespacePutOptions {\n\texpiration?: number;\n\texpirationTtl?: number;\n\tmetadata?: any | null;\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import { SimpleShop } from "../repository.js";
2
+ import type { ShopRepositoryInterface } from "../repository.js";
3
+ /**
4
+ * Deno KV integration
5
+ * @module
6
+ */
7
+ /**
8
+ * DenoKVRepository is a ShopRepositoryInterface implementation that uses the Deno KV storage to save the shop data
9
+ */
10
+ export declare class DenoKVRepository implements ShopRepositoryInterface<SimpleShop> {
11
+ private namespace;
12
+ constructor(namespace?: string);
13
+ createShop(id: string, url: string, secret: string): Promise<void>;
14
+ getShopById(id: string): Promise<SimpleShop | null>;
15
+ updateShop(shop: SimpleShop): Promise<void>;
16
+ deleteShop(id: string): Promise<void>;
17
+ }
18
+ //# sourceMappingURL=deno.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deno.d.ts","sourceRoot":"","sources":["../../../src/service/deno.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAiB,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAE/E;;;GAGG;AAEH;;GAEG;AACH,qBAAa,gBAAiB,YAAW,uBAAuB,CAAC,UAAU,CAAC;IAC/D,OAAO,CAAC,SAAS;gBAAT,SAAS,SAAU;IAEjC,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlE,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IA2BnD,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3C,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAM3C"}