@shopware-ag/app-server-sdk 1.0.1 → 1.1.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 (130) hide show
  1. package/README.md +52 -41
  2. package/dist/commonjs/context-resolver.test.d.ts +2 -0
  3. package/dist/commonjs/context-resolver.test.d.ts.map +1 -0
  4. package/dist/commonjs/context-resolver.test.js +81 -0
  5. package/dist/commonjs/context-resolver.test.js.map +1 -0
  6. package/dist/commonjs/helper/app-actions.test.d.ts +2 -0
  7. package/dist/commonjs/helper/app-actions.test.d.ts.map +1 -0
  8. package/dist/commonjs/helper/app-actions.test.js +31 -0
  9. package/dist/commonjs/helper/app-actions.test.js.map +1 -0
  10. package/dist/commonjs/http-client.test.d.ts +2 -0
  11. package/dist/commonjs/http-client.test.d.ts.map +1 -0
  12. package/dist/commonjs/http-client.test.js +71 -0
  13. package/dist/commonjs/http-client.test.js.map +1 -0
  14. package/dist/commonjs/integration/bun-sqlite.d.ts +11 -0
  15. package/dist/commonjs/integration/bun-sqlite.d.ts.map +1 -0
  16. package/dist/commonjs/integration/bun-sqlite.js +60 -0
  17. package/dist/commonjs/integration/bun-sqlite.js.map +1 -0
  18. package/dist/commonjs/integration/bun-sqlite.test.d.ts +2 -0
  19. package/dist/commonjs/integration/bun-sqlite.test.d.ts.map +1 -0
  20. package/dist/commonjs/integration/bun-sqlite.test.js +24 -0
  21. package/dist/commonjs/integration/bun-sqlite.test.js.map +1 -0
  22. package/dist/commonjs/integration/cloudflare-kv.d.ts +20 -0
  23. package/dist/commonjs/integration/cloudflare-kv.d.ts.map +1 -0
  24. package/dist/commonjs/integration/cloudflare-kv.js +49 -0
  25. package/dist/commonjs/integration/cloudflare-kv.js.map +1 -0
  26. package/dist/commonjs/integration/cloudflare.test.d.ts +2 -0
  27. package/dist/commonjs/integration/cloudflare.test.d.ts.map +1 -0
  28. package/dist/commonjs/integration/cloudflare.test.js +39 -0
  29. package/dist/commonjs/integration/cloudflare.test.js.map +1 -0
  30. package/dist/commonjs/integration/deno-kv.d.ts +18 -0
  31. package/dist/commonjs/integration/deno-kv.d.ts.map +1 -0
  32. package/dist/commonjs/integration/deno-kv.js +52 -0
  33. package/dist/commonjs/integration/deno-kv.js.map +1 -0
  34. package/dist/commonjs/integration/deno.test.d.ts +2 -0
  35. package/dist/commonjs/integration/deno.test.d.ts.map +1 -0
  36. package/dist/commonjs/integration/deno.test.js +48 -0
  37. package/dist/commonjs/integration/deno.test.js.map +1 -0
  38. package/dist/commonjs/integration/dynamodb.d.ts +13 -0
  39. package/dist/commonjs/integration/dynamodb.d.ts.map +1 -0
  40. package/dist/commonjs/integration/dynamodb.js +73 -0
  41. package/dist/commonjs/integration/dynamodb.js.map +1 -0
  42. package/dist/commonjs/integration/dynamodb.test.d.ts +2 -0
  43. package/dist/commonjs/integration/dynamodb.test.d.ts.map +1 -0
  44. package/dist/commonjs/integration/dynamodb.test.js +132 -0
  45. package/dist/commonjs/integration/dynamodb.test.js.map +1 -0
  46. package/dist/commonjs/integration/hono.d.ts +29 -0
  47. package/dist/commonjs/integration/hono.d.ts.map +1 -0
  48. package/dist/commonjs/integration/hono.js +105 -0
  49. package/dist/commonjs/integration/hono.js.map +1 -0
  50. package/dist/commonjs/integration/hono.test.d.ts +2 -0
  51. package/dist/commonjs/integration/hono.test.d.ts.map +1 -0
  52. package/dist/commonjs/integration/hono.test.js +86 -0
  53. package/dist/commonjs/integration/hono.test.js.map +1 -0
  54. package/dist/commonjs/registration.test.d.ts +2 -0
  55. package/dist/commonjs/registration.test.d.ts.map +1 -0
  56. package/dist/commonjs/registration.test.js +59 -0
  57. package/dist/commonjs/registration.test.js.map +1 -0
  58. package/dist/commonjs/repository.test.d.ts +2 -0
  59. package/dist/commonjs/repository.test.d.ts.map +1 -0
  60. package/dist/commonjs/repository.test.js +32 -0
  61. package/dist/commonjs/repository.test.js.map +1 -0
  62. package/dist/commonjs/signer.test.d.ts +2 -0
  63. package/dist/commonjs/signer.test.d.ts.map +1 -0
  64. package/dist/commonjs/signer.test.js +25 -0
  65. package/dist/commonjs/signer.test.js.map +1 -0
  66. package/dist/esm/context-resolver.test.d.ts +2 -0
  67. package/dist/esm/context-resolver.test.d.ts.map +1 -0
  68. package/dist/esm/context-resolver.test.js +79 -0
  69. package/dist/esm/context-resolver.test.js.map +1 -0
  70. package/dist/esm/helper/app-actions.test.d.ts +2 -0
  71. package/dist/esm/helper/app-actions.test.d.ts.map +1 -0
  72. package/dist/esm/helper/app-actions.test.js +29 -0
  73. package/dist/esm/helper/app-actions.test.js.map +1 -0
  74. package/dist/esm/http-client.test.d.ts +2 -0
  75. package/dist/esm/http-client.test.d.ts.map +1 -0
  76. package/dist/esm/http-client.test.js +69 -0
  77. package/dist/esm/http-client.test.js.map +1 -0
  78. package/dist/esm/integration/bun-sqlite.d.ts +11 -0
  79. package/dist/esm/integration/bun-sqlite.d.ts.map +1 -0
  80. package/dist/esm/integration/bun-sqlite.js +56 -0
  81. package/dist/esm/integration/bun-sqlite.js.map +1 -0
  82. package/dist/esm/integration/bun-sqlite.test.d.ts +2 -0
  83. package/dist/esm/integration/bun-sqlite.test.d.ts.map +1 -0
  84. package/dist/esm/integration/bun-sqlite.test.js +22 -0
  85. package/dist/esm/integration/bun-sqlite.test.js.map +1 -0
  86. package/dist/esm/integration/cloudflare-kv.d.ts +20 -0
  87. package/dist/esm/integration/cloudflare-kv.d.ts.map +1 -0
  88. package/dist/esm/integration/cloudflare-kv.js +45 -0
  89. package/dist/esm/integration/cloudflare-kv.js.map +1 -0
  90. package/dist/esm/integration/cloudflare.test.d.ts +2 -0
  91. package/dist/esm/integration/cloudflare.test.d.ts.map +1 -0
  92. package/dist/esm/integration/cloudflare.test.js +37 -0
  93. package/dist/esm/integration/cloudflare.test.js.map +1 -0
  94. package/dist/esm/integration/deno-kv.d.ts +18 -0
  95. package/dist/esm/integration/deno-kv.d.ts.map +1 -0
  96. package/dist/esm/integration/deno-kv.js +48 -0
  97. package/dist/esm/integration/deno-kv.js.map +1 -0
  98. package/dist/esm/integration/deno.test.d.ts +2 -0
  99. package/dist/esm/integration/deno.test.d.ts.map +1 -0
  100. package/dist/esm/integration/deno.test.js +46 -0
  101. package/dist/esm/integration/deno.test.js.map +1 -0
  102. package/dist/esm/integration/dynamodb.d.ts +13 -0
  103. package/dist/esm/integration/dynamodb.d.ts.map +1 -0
  104. package/dist/esm/integration/dynamodb.js +69 -0
  105. package/dist/esm/integration/dynamodb.js.map +1 -0
  106. package/dist/esm/integration/dynamodb.test.d.ts +2 -0
  107. package/dist/esm/integration/dynamodb.test.d.ts.map +1 -0
  108. package/dist/esm/integration/dynamodb.test.js +130 -0
  109. package/dist/esm/integration/dynamodb.test.js.map +1 -0
  110. package/dist/esm/integration/hono.d.ts +29 -0
  111. package/dist/esm/integration/hono.d.ts.map +1 -0
  112. package/dist/esm/integration/hono.js +102 -0
  113. package/dist/esm/integration/hono.js.map +1 -0
  114. package/dist/esm/integration/hono.test.d.ts +2 -0
  115. package/dist/esm/integration/hono.test.d.ts.map +1 -0
  116. package/dist/esm/integration/hono.test.js +84 -0
  117. package/dist/esm/integration/hono.test.js.map +1 -0
  118. package/dist/esm/registration.test.d.ts +2 -0
  119. package/dist/esm/registration.test.d.ts.map +1 -0
  120. package/dist/esm/registration.test.js +57 -0
  121. package/dist/esm/registration.test.js.map +1 -0
  122. package/dist/esm/repository.test.d.ts +2 -0
  123. package/dist/esm/repository.test.d.ts.map +1 -0
  124. package/dist/esm/repository.test.js +30 -0
  125. package/dist/esm/repository.test.js.map +1 -0
  126. package/dist/esm/signer.test.d.ts +2 -0
  127. package/dist/esm/signer.test.d.ts.map +1 -0
  128. package/dist/esm/signer.test.js +23 -0
  129. package/dist/esm/signer.test.js.map +1 -0
  130. package/package.json +142 -63
package/README.md CHANGED
@@ -1,51 +1,62 @@
1
- # App Server
1
+ # Shopware App Server SDK in TypeScript
2
2
 
3
- This package can be used to create a Shopware App Backend. It's build independent of any JavaScript framework. It relies on Fetch-standardized Request and Response objects.
3
+ This SDK is written in pure Typescript with portability in mind being able to use it on Node (20+), Deno, Cloudflare Worker or other runtimes.
4
4
 
5
- ## Standalone example with Bun
5
+ ## Features
6
6
 
7
- ```js
8
- import { AppServer, InMemoryShopRepository } from "@shopware-ag/app-server-sdk";
9
- import { ActionButtonRequest } from "@shopware-ag/app-server-sdk/types";
10
- import { createNotificationResponse } from "@shopware-ag/app-server-sdk/helper/app-actions";
7
+ - Provides registration process for app
8
+ - Verify and signing of requests / responses
9
+ - preconfigured API Client
10
+ - Complete Registration Handshake between Shopware and this
11
11
 
12
- const app = new AppServer(
13
- {
14
- appName: "MyApp",
15
- appSecret: "my-secret",
16
- authorizeCallbackUrl: "http://localhost:3000/app/callback",
17
- },
18
- new InMemoryShopRepository(),
19
- );
12
+ ## How to use it?
13
+
14
+ ```bash
15
+ npm install @shopware-ag/app-server-sdk --save
16
+ ```
17
+
18
+ ## Example
19
+
20
+ ```typescript
21
+ import { AppServer, InMemoryShopRepository } from '@shopware-ag/app-server-sdk'
22
+ import { createNotificationResponse } from '@shopware-ag/app-server-sdk/helper/app-actions'
23
+
24
+ const app = new AppServer({
25
+ appName: 'MyApp',
26
+ appSecret: 'my-secret',
27
+ authorizeCallbackUrl: 'http://localhost:3000/authorize/callback',
28
+ }, new InMemoryShopRepository());
20
29
 
21
30
  const server = Bun.serve({
22
- port: 3000,
23
- async fetch(request) {
24
- const { pathname } = new URL(request.url);
25
- if (pathname === "/app/register") {
26
- return app.registration.authorize(request);
27
- } else if (pathname === "/app/callback") {
28
- return app.registration.authorizeCallback(request);
29
- } else if (pathname === "/app/product") {
30
- const context =
31
- await app.contextResolver.fromAPI<ActionButtonRequest>(request);
32
-
33
- // do something with payload, and http client
34
-
35
- const notification = createNotificationResponse(
36
- "success",
37
- "Product created",
38
- );
39
-
40
- // sign the response, with the shop secret
41
- await app.signer.signResponse(notification, context.shop.getShopSecret());
42
-
43
- return notification;
44
- }
45
-
46
- return new Response("Not found", { status: 404 });
47
- },
31
+ port: 3000,
32
+ async fetch(request) {
33
+ const { pathname } = new URL(request.url);
34
+ if (pathname === '/authorize') {
35
+ return app.registration.authorize(request);
36
+ } else if (pathname === '/authorize/callback') {
37
+ return app.registration.authorizeCallback(request);
38
+ } else if (pathname === '/app/product') {
39
+ const context = await app.contextResolver.fromSource(request);
40
+
41
+ // do something with payload, and http client
42
+
43
+ const notification = createNotificationResponse('success', 'Product created');
44
+
45
+ // sign the response, with the shop secret
46
+ await app.signer.signResponse(notification, context.shop.getShopSecret());
47
+
48
+ return resp;
49
+ }
50
+
51
+ return new Response('Not found', { status: 404 });
52
+ },
48
53
  });
49
54
 
50
55
  console.log(`Listening on localhost:${server.port}`);
51
56
  ```
57
+
58
+ Checkout the [examples](./examples) folder for more examples using:
59
+
60
+ - [Cloudflare Worker with Hono](./examples/cloudflare-hono)
61
+ - [Deno with Hono](./examples/deno-hono)
62
+ - [Node with Hono](./examples/node-hono)
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=context-resolver.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-resolver.test.d.ts","sourceRoot":"","sources":["../../src/context-resolver.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const bun_test_1 = require("bun:test");
4
+ const app_js_1 = require("../src/app.js");
5
+ const context_resolver_js_1 = require("../src/context-resolver.js");
6
+ const repository_js_1 = require("../src/repository.js");
7
+ (0, bun_test_1.describe)("Context Resolver", async () => {
8
+ const app = new app_js_1.AppServer({
9
+ appName: "test",
10
+ appSecret: "test",
11
+ authorizeCallbackUrl: "test",
12
+ }, new repository_js_1.InMemoryShopRepository());
13
+ await app.repository.createShop("blaa", "test", "test");
14
+ const contextResolver = new context_resolver_js_1.ContextResolver(app);
15
+ (0, bun_test_1.test)("fromBrowser: shop does not exist", async () => {
16
+ (0, bun_test_1.expect)(contextResolver.fromBrowser(new Request("https://example.com/?shop-id=test&shopware-shop-signature=aaa"))).rejects.toThrowError("Cannot find shop by id test");
17
+ });
18
+ (0, bun_test_1.test)("fromBrowser: missing header", async () => {
19
+ (0, bun_test_1.expect)(contextResolver.fromBrowser(new Request("https://example.com/?shop-id=blaa"))).rejects.toThrowError("Missing shopware-shop-signature query parameter");
20
+ });
21
+ (0, bun_test_1.test)("fromBrowser: shop exists", async () => {
22
+ app.signer.verifyGetRequest = bun_test_1.jest.fn().mockResolvedValue(true);
23
+ const context = await contextResolver.fromBrowser(new Request("https://example.com/?shop-id=blaa&shopware-shop-signature=aaa"));
24
+ (0, bun_test_1.expect)(context.payload).toEqual({
25
+ "shop-id": "blaa",
26
+ "shopware-shop-signature": "aaa",
27
+ });
28
+ });
29
+ (0, bun_test_1.test)("fromSource: missing signature header", async () => {
30
+ (0, bun_test_1.expect)(contextResolver.fromAPI(new Request("https://example.com/", {
31
+ body: JSON.stringify({
32
+ source: {
33
+ shopId: "blaa",
34
+ },
35
+ }),
36
+ }))).rejects.toThrowError("Missing shopware-shop-signature header");
37
+ });
38
+ (0, bun_test_1.test)("fromSource: shop does not exists", async () => {
39
+ (0, bun_test_1.expect)(contextResolver.fromAPI(new Request("https://example.com/", {
40
+ headers: {
41
+ "shopware-shop-signature": "aaa",
42
+ },
43
+ body: JSON.stringify({
44
+ source: {
45
+ shopId: "test",
46
+ },
47
+ }),
48
+ }))).rejects.toThrowError("Cannot find shop by id test");
49
+ });
50
+ (0, bun_test_1.test)("fromSource: invalid signature", async () => {
51
+ (0, bun_test_1.expect)(contextResolver.fromAPI(new Request("https://example.com/", {
52
+ headers: {
53
+ "shopware-shop-signature": "aaa",
54
+ },
55
+ body: JSON.stringify({
56
+ source: {
57
+ shopId: "blaa",
58
+ },
59
+ }),
60
+ }))).rejects.toThrowError("Invalid signature");
61
+ });
62
+ (0, bun_test_1.test)("fromSource: resolved", async () => {
63
+ app.signer.verify = bun_test_1.jest.fn().mockResolvedValue(true);
64
+ const ctx = await contextResolver.fromAPI(new Request("https://example.com/", {
65
+ headers: {
66
+ "shopware-shop-signature": "aaa",
67
+ },
68
+ body: JSON.stringify({
69
+ source: {
70
+ shopId: "blaa",
71
+ },
72
+ }),
73
+ }));
74
+ (0, bun_test_1.expect)(ctx.payload).toEqual({
75
+ source: {
76
+ shopId: "blaa",
77
+ },
78
+ });
79
+ });
80
+ });
81
+ //# sourceMappingURL=context-resolver.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-resolver.test.js","sourceRoot":"","sources":["../../src/context-resolver.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, jest, test } from \"bun:test\";\nimport { AppServer } from \"../src/app.js\";\nimport { ContextResolver } from \"../src/context-resolver.js\";\nimport { InMemoryShopRepository, SimpleShop } from \"../src/repository.js\";\n\ndescribe(\"Context Resolver\", async () => {\n\tconst app = new AppServer(\n\t\t{\n\t\t\tappName: \"test\",\n\t\t\tappSecret: \"test\",\n\t\t\tauthorizeCallbackUrl: \"test\",\n\t\t},\n\t\tnew InMemoryShopRepository(),\n\t);\n\n\tawait app.repository.createShop(\"blaa\", \"test\", \"test\");\n\n\tconst contextResolver = new ContextResolver(app);\n\n\ttest(\"fromBrowser: shop does not exist\", async () => {\n\t\texpect(\n\t\t\tcontextResolver.fromBrowser(\n\t\t\t\tnew Request(\n\t\t\t\t\t\"https://example.com/?shop-id=test&shopware-shop-signature=aaa\",\n\t\t\t\t),\n\t\t\t),\n\t\t).rejects.toThrowError(\"Cannot find shop by id test\");\n\t});\n\n\ttest(\"fromBrowser: missing header\", async () => {\n\t\texpect(\n\t\t\tcontextResolver.fromBrowser(\n\t\t\t\tnew Request(\"https://example.com/?shop-id=blaa\"),\n\t\t\t),\n\t\t).rejects.toThrowError(\"Missing shopware-shop-signature query parameter\");\n\t});\n\n\ttest(\"fromBrowser: shop exists\", async () => {\n\t\tapp.signer.verifyGetRequest = jest.fn().mockResolvedValue(true);\n\n\t\tconst context = await contextResolver.fromBrowser(\n\t\t\tnew Request(\n\t\t\t\t\"https://example.com/?shop-id=blaa&shopware-shop-signature=aaa\",\n\t\t\t),\n\t\t);\n\n\t\texpect(context.payload).toEqual({\n\t\t\t\"shop-id\": \"blaa\",\n\t\t\t\"shopware-shop-signature\": \"aaa\",\n\t\t});\n\t});\n\n\ttest(\"fromSource: missing signature header\", async () => {\n\t\texpect(\n\t\t\tcontextResolver.fromAPI(\n\t\t\t\tnew Request(\"https://example.com/\", {\n\t\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t\tsource: {\n\t\t\t\t\t\t\tshopId: \"blaa\",\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t\t),\n\t\t).rejects.toThrowError(\"Missing shopware-shop-signature header\");\n\t});\n\n\ttest(\"fromSource: shop does not exists\", async () => {\n\t\texpect(\n\t\t\tcontextResolver.fromAPI(\n\t\t\t\tnew Request(\"https://example.com/\", {\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"shopware-shop-signature\": \"aaa\",\n\t\t\t\t\t},\n\t\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t\tsource: {\n\t\t\t\t\t\t\tshopId: \"test\",\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t\t),\n\t\t).rejects.toThrowError(\"Cannot find shop by id test\");\n\t});\n\n\ttest(\"fromSource: invalid signature\", async () => {\n\t\texpect(\n\t\t\tcontextResolver.fromAPI(\n\t\t\t\tnew Request(\"https://example.com/\", {\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"shopware-shop-signature\": \"aaa\",\n\t\t\t\t\t},\n\t\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t\tsource: {\n\t\t\t\t\t\t\tshopId: \"blaa\",\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t}),\n\t\t\t),\n\t\t).rejects.toThrowError(\"Invalid signature\");\n\t});\n\n\ttest(\"fromSource: resolved\", async () => {\n\t\tapp.signer.verify = jest.fn().mockResolvedValue(true);\n\n\t\tconst ctx = await contextResolver.fromAPI(\n\t\t\tnew Request(\"https://example.com/\", {\n\t\t\t\theaders: {\n\t\t\t\t\t\"shopware-shop-signature\": \"aaa\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tsource: {\n\t\t\t\t\t\tshopId: \"blaa\",\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t}),\n\t\t);\n\n\t\texpect(ctx.payload).toEqual({\n\t\t\tsource: {\n\t\t\t\tshopId: \"blaa\",\n\t\t\t},\n\t\t});\n\t});\n});\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=app-actions.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-actions.test.d.ts","sourceRoot":"","sources":["../../../src/helper/app-actions.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const bun_test_1 = require("bun:test");
4
+ const app_actions_js_1 = require("../../src/helper/app-actions.js");
5
+ (0, bun_test_1.describe)("AppActions", async () => {
6
+ (0, bun_test_1.test)("createNewTabResponse", async () => {
7
+ const resp = (0, app_actions_js_1.createNewTabResponse)("test");
8
+ (0, bun_test_1.expect)(resp.headers.get("content-type")).toBe("application/json");
9
+ (0, bun_test_1.expect)(await resp.text()).toBe(JSON.stringify({
10
+ actionType: "openNewTab",
11
+ payload: { redirectUrl: "test" },
12
+ }));
13
+ });
14
+ (0, bun_test_1.test)("createNotificationResponse", async () => {
15
+ const resp = (0, app_actions_js_1.createNotificationResponse)("success", "test");
16
+ (0, bun_test_1.expect)(resp.headers.get("content-type")).toBe("application/json");
17
+ (0, bun_test_1.expect)(await resp.text()).toBe(JSON.stringify({
18
+ actionType: "notification",
19
+ payload: { status: "success", message: "test" },
20
+ }));
21
+ });
22
+ (0, bun_test_1.test)("createModalResponse", async () => {
23
+ const resp = (0, app_actions_js_1.createModalResponse)("test", "small", true);
24
+ (0, bun_test_1.expect)(resp.headers.get("content-type")).toBe("application/json");
25
+ (0, bun_test_1.expect)(await resp.text()).toBe(JSON.stringify({
26
+ actionType: "openModal",
27
+ payload: { iframeUrl: "test", size: "small", expand: true },
28
+ }));
29
+ });
30
+ });
31
+ //# sourceMappingURL=app-actions.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-actions.test.js","sourceRoot":"","sources":["../../../src/helper/app-actions.test.ts"],"names":[],"mappings":";;AAAA,uCAAkD;AAClD,oEAIyC;AAEzC,IAAA,mBAAQ,EAAC,YAAY,EAAE,KAAK,IAAI,EAAE;IACjC,IAAA,eAAI,EAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QACvC,MAAM,IAAI,GAAG,IAAA,qCAAoB,EAAC,MAAM,CAAC,CAAC;QAE1C,IAAA,iBAAM,EAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAClE,IAAA,iBAAM,EAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAC7B,IAAI,CAAC,SAAS,CAAC;YACd,UAAU,EAAE,YAAY;YACxB,OAAO,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE;SAChC,CAAC,CACF,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAA,eAAI,EAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,IAAI,GAAG,IAAA,2CAA0B,EAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAE3D,IAAA,iBAAM,EAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAClE,IAAA,iBAAM,EAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAC7B,IAAI,CAAC,SAAS,CAAC;YACd,UAAU,EAAE,cAAc;YAC1B,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE;SAC/C,CAAC,CACF,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAA,eAAI,EAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;QACtC,MAAM,IAAI,GAAG,IAAA,oCAAmB,EAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAExD,IAAA,iBAAM,EAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAClE,IAAA,iBAAM,EAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAC7B,IAAI,CAAC,SAAS,CAAC;YACd,UAAU,EAAE,WAAW;YACvB,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE;SAC3D,CAAC,CACF,CAAC;IACH,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, test } from \"bun:test\";\nimport {\n\tcreateModalResponse,\n\tcreateNewTabResponse,\n\tcreateNotificationResponse,\n} from \"../../src/helper/app-actions.js\";\n\ndescribe(\"AppActions\", async () => {\n\ttest(\"createNewTabResponse\", async () => {\n\t\tconst resp = createNewTabResponse(\"test\");\n\n\t\texpect(resp.headers.get(\"content-type\")).toBe(\"application/json\");\n\t\texpect(await resp.text()).toBe(\n\t\t\tJSON.stringify({\n\t\t\t\tactionType: \"openNewTab\",\n\t\t\t\tpayload: { redirectUrl: \"test\" },\n\t\t\t}),\n\t\t);\n\t});\n\n\ttest(\"createNotificationResponse\", async () => {\n\t\tconst resp = createNotificationResponse(\"success\", \"test\");\n\n\t\texpect(resp.headers.get(\"content-type\")).toBe(\"application/json\");\n\t\texpect(await resp.text()).toBe(\n\t\t\tJSON.stringify({\n\t\t\t\tactionType: \"notification\",\n\t\t\t\tpayload: { status: \"success\", message: \"test\" },\n\t\t\t}),\n\t\t);\n\t});\n\n\ttest(\"createModalResponse\", async () => {\n\t\tconst resp = createModalResponse(\"test\", \"small\", true);\n\n\t\texpect(resp.headers.get(\"content-type\")).toBe(\"application/json\");\n\t\texpect(await resp.text()).toBe(\n\t\t\tJSON.stringify({\n\t\t\t\tactionType: \"openModal\",\n\t\t\t\tpayload: { iframeUrl: \"test\", size: \"small\", expand: true },\n\t\t\t}),\n\t\t);\n\t});\n});\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=http-client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-client.test.d.ts","sourceRoot":"","sources":["../../src/http-client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const bun_test_1 = require("bun:test");
4
+ const http_client_js_1 = require("../src/http-client.js");
5
+ const repository_js_1 = require("../src/repository.js");
6
+ (0, bun_test_1.describe)("HTTP Client", async () => {
7
+ (0, bun_test_1.test)("getToken", async () => {
8
+ const mockFetch = (0, bun_test_1.spyOn)(global, "fetch").mockImplementation(() => Promise.resolve(new Response('{"access_token": "test", "expires_in": 3600}')));
9
+ const client = new http_client_js_1.HttpClient(new repository_js_1.SimpleShop("blaa", "test", "test"));
10
+ (0, bun_test_1.expect)(client.getToken()).resolves.toBe("test");
11
+ // We fetched already once the token, so the second time we should get it from the storage
12
+ await client.getToken();
13
+ (0, bun_test_1.expect)(mockFetch.mock.calls).toBeArrayOfSize(1);
14
+ mockFetch.mockRestore();
15
+ });
16
+ (0, bun_test_1.test)("getToken: failed request", async () => {
17
+ const mockFetch = (0, bun_test_1.spyOn)(global, "fetch").mockImplementation(() => Promise.resolve(new Response('{"error": "invalid_grant"}', { status: 400 })));
18
+ const client = new http_client_js_1.HttpClient(new repository_js_1.SimpleShop("blaa", "test", "test"));
19
+ (0, bun_test_1.expect)(client.getToken()).rejects.toThrowError("The api client authentication to shop with id: blaa");
20
+ mockFetch.mockRestore();
21
+ });
22
+ (0, bun_test_1.test)("getToken: expired refetch", async () => {
23
+ const mockFetch = (0, bun_test_1.spyOn)(global, "fetch").mockImplementation(() => Promise.resolve(new Response('{"access_token": "test", "expires_in": -500}')));
24
+ const client = new http_client_js_1.HttpClient(new repository_js_1.SimpleShop("blaa", "test", "test"));
25
+ (0, bun_test_1.expect)(client.getToken()).resolves.toBe("test");
26
+ (0, bun_test_1.expect)(mockFetch.mock.calls).toBeArrayOfSize(1);
27
+ (0, bun_test_1.expect)(client.getToken()).resolves.toBe("test");
28
+ (0, bun_test_1.expect)(mockFetch.mock.calls).toBeArrayOfSize(2);
29
+ mockFetch.mockRestore();
30
+ });
31
+ (0, bun_test_1.test)("get, post, put, patch, delete", async () => {
32
+ const mockFetch = (0, bun_test_1.spyOn)(global, "fetch").mockImplementationOnce(() => Promise.resolve(new Response('{"access_token": "test", "expires_in": 5000}')));
33
+ const client = new http_client_js_1.HttpClient(new repository_js_1.SimpleShop("blaa", "test", "test"));
34
+ mockFetch.mockImplementation(() => Promise.resolve(new Response('{"data": "test"}')));
35
+ (0, bun_test_1.expect)(client.get("/test")).resolves.toEqual({
36
+ body: { data: "test" },
37
+ headers: new Headers(),
38
+ statusCode: 200,
39
+ });
40
+ (0, bun_test_1.expect)(client.post("/test", { data: "test" })).resolves.toEqual({
41
+ body: { data: "test" },
42
+ headers: new Headers(),
43
+ statusCode: 200,
44
+ });
45
+ (0, bun_test_1.expect)(client.put("/test", { data: "test" })).resolves.toEqual({
46
+ body: { data: "test" },
47
+ headers: new Headers(),
48
+ statusCode: 200,
49
+ });
50
+ (0, bun_test_1.expect)(client.patch("/test", { data: "test" })).resolves.toEqual({
51
+ body: { data: "test" },
52
+ headers: new Headers(),
53
+ statusCode: 200,
54
+ });
55
+ (0, bun_test_1.expect)(client.delete("/test")).resolves.toEqual({
56
+ body: { data: "test" },
57
+ headers: new Headers(),
58
+ statusCode: 200,
59
+ });
60
+ (0, bun_test_1.expect)(mockFetch.mock.calls).toBeArrayOfSize(6);
61
+ mockFetch.mockRestore();
62
+ });
63
+ (0, bun_test_1.test)("get: request failed", async () => {
64
+ const mockFetch = (0, bun_test_1.spyOn)(global, "fetch").mockImplementationOnce(() => Promise.resolve(new Response('{"access_token": "test", "expires_in": 5000}')));
65
+ const client = new http_client_js_1.HttpClient(new repository_js_1.SimpleShop("blaa", "test", "test"));
66
+ mockFetch.mockImplementation(() => Promise.resolve(new Response('{"data": "test"}', { status: 400 })));
67
+ (0, bun_test_1.expect)(client.get("/test")).rejects.toThrowError("The api request failed with status code: 400 for shop with id: blaa");
68
+ mockFetch.mockRestore();
69
+ });
70
+ });
71
+ //# sourceMappingURL=http-client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-client.test.js","sourceRoot":"","sources":["../../src/http-client.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, spyOn, test } from \"bun:test\";\nimport { HttpClient } from \"../src/http-client.js\";\nimport { SimpleShop } from \"../src/repository.js\";\n\ndescribe(\"HTTP Client\", async () => {\n\ttest(\"getToken\", async () => {\n\t\tconst mockFetch = spyOn(global, \"fetch\").mockImplementation(() =>\n\t\t\tPromise.resolve(\n\t\t\t\tnew Response('{\"access_token\": \"test\", \"expires_in\": 3600}'),\n\t\t\t),\n\t\t);\n\n\t\tconst client = new HttpClient(new SimpleShop(\"blaa\", \"test\", \"test\"));\n\t\texpect(client.getToken()).resolves.toBe(\"test\");\n\n\t\t// We fetched already once the token, so the second time we should get it from the storage\n\t\tawait client.getToken();\n\n\t\texpect(mockFetch.mock.calls).toBeArrayOfSize(1);\n\n\t\tmockFetch.mockRestore();\n\t});\n\n\ttest(\"getToken: failed request\", async () => {\n\t\tconst mockFetch = spyOn(global, \"fetch\").mockImplementation(() =>\n\t\t\tPromise.resolve(\n\t\t\t\tnew Response('{\"error\": \"invalid_grant\"}', { status: 400 }),\n\t\t\t),\n\t\t);\n\n\t\tconst client = new HttpClient(new SimpleShop(\"blaa\", \"test\", \"test\"));\n\t\texpect(client.getToken()).rejects.toThrowError(\n\t\t\t\"The api client authentication to shop with id: blaa\",\n\t\t);\n\n\t\tmockFetch.mockRestore();\n\t});\n\n\ttest(\"getToken: expired refetch\", async () => {\n\t\tconst mockFetch = spyOn(global, \"fetch\").mockImplementation(() =>\n\t\t\tPromise.resolve(\n\t\t\t\tnew Response('{\"access_token\": \"test\", \"expires_in\": -500}'),\n\t\t\t),\n\t\t);\n\n\t\tconst client = new HttpClient(new SimpleShop(\"blaa\", \"test\", \"test\"));\n\t\texpect(client.getToken()).resolves.toBe(\"test\");\n\n\t\texpect(mockFetch.mock.calls).toBeArrayOfSize(1);\n\n\t\texpect(client.getToken()).resolves.toBe(\"test\");\n\n\t\texpect(mockFetch.mock.calls).toBeArrayOfSize(2);\n\n\t\tmockFetch.mockRestore();\n\t});\n\n\ttest(\"get, post, put, patch, delete\", async () => {\n\t\tconst mockFetch = spyOn(global, \"fetch\").mockImplementationOnce(() =>\n\t\t\tPromise.resolve(\n\t\t\t\tnew Response('{\"access_token\": \"test\", \"expires_in\": 5000}'),\n\t\t\t),\n\t\t);\n\n\t\tconst client = new HttpClient(new SimpleShop(\"blaa\", \"test\", \"test\"));\n\n\t\tmockFetch.mockImplementation(() =>\n\t\t\tPromise.resolve(new Response('{\"data\": \"test\"}')),\n\t\t);\n\n\t\texpect(client.get(\"/test\")).resolves.toEqual({\n\t\t\tbody: { data: \"test\" },\n\t\t\theaders: new Headers(),\n\t\t\tstatusCode: 200,\n\t\t});\n\t\texpect(client.post(\"/test\", { data: \"test\" })).resolves.toEqual({\n\t\t\tbody: { data: \"test\" },\n\t\t\theaders: new Headers(),\n\t\t\tstatusCode: 200,\n\t\t});\n\t\texpect(client.put(\"/test\", { data: \"test\" })).resolves.toEqual({\n\t\t\tbody: { data: \"test\" },\n\t\t\theaders: new Headers(),\n\t\t\tstatusCode: 200,\n\t\t});\n\t\texpect(client.patch(\"/test\", { data: \"test\" })).resolves.toEqual({\n\t\t\tbody: { data: \"test\" },\n\t\t\theaders: new Headers(),\n\t\t\tstatusCode: 200,\n\t\t});\n\t\texpect(client.delete(\"/test\")).resolves.toEqual({\n\t\t\tbody: { data: \"test\" },\n\t\t\theaders: new Headers(),\n\t\t\tstatusCode: 200,\n\t\t});\n\n\t\texpect(mockFetch.mock.calls).toBeArrayOfSize(6);\n\n\t\tmockFetch.mockRestore();\n\t});\n\n\ttest(\"get: request failed\", async () => {\n\t\tconst mockFetch = spyOn(global, \"fetch\").mockImplementationOnce(() =>\n\t\t\tPromise.resolve(\n\t\t\t\tnew Response('{\"access_token\": \"test\", \"expires_in\": 5000}'),\n\t\t\t),\n\t\t);\n\n\t\tconst client = new HttpClient(new SimpleShop(\"blaa\", \"test\", \"test\"));\n\n\t\tmockFetch.mockImplementation(() =>\n\t\t\tPromise.resolve(new Response('{\"data\": \"test\"}', { status: 400 })),\n\t\t);\n\n\t\texpect(client.get(\"/test\")).rejects.toThrowError(\n\t\t\t\"The api request failed with status code: 400 for shop with id: blaa\",\n\t\t);\n\n\t\tmockFetch.mockRestore();\n\t});\n});\n"]}
@@ -0,0 +1,11 @@
1
+ import { type ShopRepositoryInterface, SimpleShop } from "../repository.js";
2
+ import { Database } from "bun:sqlite";
3
+ export declare class BunSqliteRepository implements ShopRepositoryInterface<SimpleShop> {
4
+ db: Database;
5
+ constructor(fileName: string);
6
+ createShop(id: string, url: string, secret: string): Promise<void>;
7
+ getShopById(id: string): Promise<SimpleShop | null>;
8
+ updateShop(shop: SimpleShop): Promise<void>;
9
+ deleteShop(id: string): Promise<void>;
10
+ }
11
+ //# sourceMappingURL=bun-sqlite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun-sqlite.d.ts","sourceRoot":"","sources":["../../../src/integration/bun-sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,uBAAuB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE5E,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,qBAAa,mBACZ,YAAW,uBAAuB,CAAC,UAAU,CAAC;IAE9C,EAAE,EAAE,QAAQ,CAAC;gBACD,QAAQ,EAAE,MAAM;IActB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAclE,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IA4BnD,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAa3C,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG3C"}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BunSqliteRepository = void 0;
4
+ const repository_js_1 = require("../repository.js");
5
+ const bun_sqlite_1 = require("bun:sqlite");
6
+ class BunSqliteRepository {
7
+ db;
8
+ constructor(fileName) {
9
+ this.db = new bun_sqlite_1.Database(fileName);
10
+ this.db.exec(`
11
+ CREATE TABLE IF NOT EXISTS shop (
12
+ id TEXT PRIMARY KEY,
13
+ active BOOLEAN DEFAULT 1,
14
+ url TEXT NOT NULL,
15
+ secret TEXT NOT NULL,
16
+ client_id TEXT NULL,
17
+ client_secret TEXT NULL
18
+ );
19
+ `);
20
+ }
21
+ async createShop(id, url, secret) {
22
+ const shop = await this.getShopById(id);
23
+ if (shop) {
24
+ return await this.updateShop(shop);
25
+ }
26
+ this.db.exec("INSERT INTO shop (id, url, secret) VALUES (?, ?, ?)", [
27
+ id,
28
+ url,
29
+ secret,
30
+ ]);
31
+ }
32
+ async getShopById(id) {
33
+ const query = this.db.query("SELECT * FROM shop WHERE id = ?");
34
+ const result = query.get(id);
35
+ if (!result) {
36
+ return null;
37
+ }
38
+ const shop = new repository_js_1.SimpleShop(result.id, result.url, result.secret);
39
+ if (result.client_id && result.client_secret) {
40
+ shop.setShopCredentials(result.client_id, result.client_secret);
41
+ }
42
+ shop.setShopActive(result.active);
43
+ return shop;
44
+ }
45
+ async updateShop(shop) {
46
+ this.db.exec("UPDATE shop SET url = ?, secret = ?, client_id = ?, client_secret = ?, active = ? WHERE id = ?", [
47
+ shop.getShopUrl(),
48
+ shop.getShopSecret(),
49
+ shop.getShopClientId(),
50
+ shop.getShopClientSecret(),
51
+ shop.getShopActive(),
52
+ shop.getShopId(),
53
+ ]);
54
+ }
55
+ async deleteShop(id) {
56
+ this.db.exec("DELETE FROM shop where id = ?", [id]);
57
+ }
58
+ }
59
+ exports.BunSqliteRepository = BunSqliteRepository;
60
+ //# sourceMappingURL=bun-sqlite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun-sqlite.js","sourceRoot":"","sources":["../../../src/integration/bun-sqlite.ts"],"names":[],"mappings":";;;AAAA,oDAA4E;AAE5E,2CAAsC;AAEtC,MAAa,mBAAmB;IAG/B,EAAE,CAAW;IACb,YAAY,QAAgB;QAC3B,IAAI,CAAC,EAAE,GAAG,IAAI,qBAAQ,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;OASR,CAAC,CAAC;IACR,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,EAAU,EAAE,GAAW,EAAE,MAAc;QACvD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAExC,IAAI,IAAI,EAAE,CAAC;YACV,OAAO,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC;QAED,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,qDAAqD,EAAE;YACnE,EAAE;YACF,GAAG;YACH,MAAM;SACN,CAAC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,EAAU;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,CAUzB,iCAAiC,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAE7B,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACb,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,0BAAU,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAElE,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YAC9C,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;QACjE,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAElC,OAAO,IAAI,CAAC;IACb,CAAC;IACD,KAAK,CAAC,UAAU,CAAC,IAAgB;QAChC,IAAI,CAAC,EAAE,CAAC,IAAI,CACX,gGAAgG,EAChG;YACC,IAAI,CAAC,UAAU,EAAE;YACjB,IAAI,CAAC,aAAa,EAAE;YACpB,IAAI,CAAC,eAAe,EAAE;YACtB,IAAI,CAAC,mBAAmB,EAAE;YAC1B,IAAI,CAAC,aAAa,EAAE;YACpB,IAAI,CAAC,SAAS,EAAE;SAChB,CACD,CAAC;IACH,CAAC;IACD,KAAK,CAAC,UAAU,CAAC,EAAU;QAC1B,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,+BAA+B,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACrD,CAAC;CACD;AA5ED,kDA4EC","sourcesContent":["import { type ShopRepositoryInterface, SimpleShop } from \"../repository.js\";\n\nimport { Database } from \"bun:sqlite\";\n\nexport class BunSqliteRepository\n\timplements ShopRepositoryInterface<SimpleShop>\n{\n\tdb: Database;\n\tconstructor(fileName: string) {\n\t\tthis.db = new Database(fileName);\n\t\tthis.db.exec(`\n CREATE TABLE IF NOT EXISTS shop (\n id TEXT PRIMARY KEY,\n active BOOLEAN DEFAULT 1,\n url TEXT NOT NULL,\n secret TEXT NOT NULL,\n client_id TEXT NULL,\n client_secret TEXT NULL\n );\n `);\n\t}\n\n\tasync createShop(id: string, url: string, secret: string): Promise<void> {\n\t\tconst shop = await this.getShopById(id);\n\n\t\tif (shop) {\n\t\t\treturn await this.updateShop(shop);\n\t\t}\n\n\t\tthis.db.exec(\"INSERT INTO shop (id, url, secret) VALUES (?, ?, ?)\", [\n\t\t\tid,\n\t\t\turl,\n\t\t\tsecret,\n\t\t]);\n\t}\n\n\tasync getShopById(id: string): Promise<SimpleShop | null> {\n\t\tconst query = this.db.query<\n\t\t\t{\n\t\t\t\tid: string;\n\t\t\t\tactive: boolean;\n\t\t\t\turl: string;\n\t\t\t\tsecret: string;\n\t\t\t\tclient_id?: string;\n\t\t\t\tclient_secret?: string;\n\t\t\t},\n\t\t\tstring\n\t\t>(\"SELECT * FROM shop WHERE id = ?\");\n\t\tconst result = query.get(id);\n\n\t\tif (!result) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst shop = new SimpleShop(result.id, result.url, result.secret);\n\n\t\tif (result.client_id && result.client_secret) {\n\t\t\tshop.setShopCredentials(result.client_id, result.client_secret);\n\t\t}\n\n\t\tshop.setShopActive(result.active);\n\n\t\treturn shop;\n\t}\n\tasync updateShop(shop: SimpleShop): Promise<void> {\n\t\tthis.db.exec(\n\t\t\t\"UPDATE shop SET url = ?, secret = ?, client_id = ?, client_secret = ?, active = ? WHERE id = ?\",\n\t\t\t[\n\t\t\t\tshop.getShopUrl(),\n\t\t\t\tshop.getShopSecret(),\n\t\t\t\tshop.getShopClientId(),\n\t\t\t\tshop.getShopClientSecret(),\n\t\t\t\tshop.getShopActive(),\n\t\t\t\tshop.getShopId(),\n\t\t\t],\n\t\t);\n\t}\n\tasync deleteShop(id: string): Promise<void> {\n\t\tthis.db.exec(\"DELETE FROM shop where id = ?\", [id]);\n\t}\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bun-sqlite.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun-sqlite.test.d.ts","sourceRoot":"","sources":["../../../src/integration/bun-sqlite.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const bun_test_1 = require("bun:test");
4
+ const repository_js_1 = require("../repository.js");
5
+ const bun_sqlite_js_1 = require("./bun-sqlite.js");
6
+ (0, bun_test_1.describe)("Bun SQLite", async () => {
7
+ (0, bun_test_1.test)("createShop", async () => {
8
+ const repo = new bun_sqlite_js_1.BunSqliteRepository(":memory:");
9
+ await repo.createShop("test", "test", "test");
10
+ const shop = await repo.getShopById("test");
11
+ (0, bun_test_1.expect)(shop).not.toBeNull();
12
+ (0, bun_test_1.expect)(shop?.getShopId()).toBe("test");
13
+ (0, bun_test_1.expect)(shop?.getShopUrl()).toBe("test");
14
+ (0, bun_test_1.expect)(shop?.getShopSecret()).toBe("test");
15
+ await repo.deleteShop("test");
16
+ (0, bun_test_1.expect)(repo.getShopById("test")).resolves.toBeNull();
17
+ await repo.createShop("test", "test", "test");
18
+ (0, bun_test_1.expect)(repo.getShopById("test")).resolves.not.toBeNull();
19
+ await repo.updateShop(new repository_js_1.SimpleShop("test", "foo.com", "test"));
20
+ const updatedShop = await repo.getShopById("test");
21
+ (0, bun_test_1.expect)(updatedShop?.getShopUrl()).toBe("foo.com");
22
+ });
23
+ });
24
+ //# sourceMappingURL=bun-sqlite.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun-sqlite.test.js","sourceRoot":"","sources":["../../../src/integration/bun-sqlite.test.ts"],"names":[],"mappings":";;AAAA,uCAAkD;AAClD,oDAA8C;AAC9C,mDAAsD;AAEtD,IAAA,mBAAQ,EAAC,YAAY,EAAE,KAAK,IAAI,EAAE;IACjC,IAAA,eAAI,EAAC,YAAY,EAAE,KAAK,IAAI,EAAE;QAC7B,MAAM,IAAI,GAAG,IAAI,mCAAmB,CAAC,UAAU,CAAC,CAAC;QAEjD,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAE9C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAE5C,IAAA,iBAAM,EAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAE5B,IAAA,iBAAM,EAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,IAAA,iBAAM,EAAC,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxC,IAAA,iBAAM,EAAC,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE3C,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAE9B,IAAA,iBAAM,EAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAErD,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAE9C,IAAA,iBAAM,EAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAEzD,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,0BAAU,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;QAEjE,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAEnD,IAAA,iBAAM,EAAC,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, test } from \"bun:test\";\nimport { SimpleShop } from \"../repository.js\";\nimport { BunSqliteRepository } from \"./bun-sqlite.js\";\n\ndescribe(\"Bun SQLite\", async () => {\n\ttest(\"createShop\", async () => {\n\t\tconst repo = new BunSqliteRepository(\":memory:\");\n\n\t\tawait repo.createShop(\"test\", \"test\", \"test\");\n\n\t\tconst shop = await repo.getShopById(\"test\");\n\n\t\texpect(shop).not.toBeNull();\n\n\t\texpect(shop?.getShopId()).toBe(\"test\");\n\t\texpect(shop?.getShopUrl()).toBe(\"test\");\n\t\texpect(shop?.getShopSecret()).toBe(\"test\");\n\n\t\tawait repo.deleteShop(\"test\");\n\n\t\texpect(repo.getShopById(\"test\")).resolves.toBeNull();\n\n\t\tawait repo.createShop(\"test\", \"test\", \"test\");\n\n\t\texpect(repo.getShopById(\"test\")).resolves.not.toBeNull();\n\n\t\tawait repo.updateShop(new SimpleShop(\"test\", \"foo.com\", \"test\"));\n\n\t\tconst updatedShop = await repo.getShopById(\"test\");\n\n\t\texpect(updatedShop?.getShopUrl()).toBe(\"foo.com\");\n\t});\n});\n"]}
@@ -0,0 +1,20 @@
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
+ //# sourceMappingURL=cloudflare-kv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-kv.d.ts","sourceRoot":"","sources":["../../../src/integration/cloudflare-kv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAEhE;;;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;CAmBnD"}
@@ -0,0 +1,49 @@
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
+ if (obj.shopActive === undefined) {
42
+ obj.shopActive = true;
43
+ }
44
+ shop.setShopActive(obj.shopActive);
45
+ return shop;
46
+ }
47
+ }
48
+ exports.CloudflareShopRepository = CloudflareShopRepository;
49
+ //# sourceMappingURL=cloudflare-kv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-kv.js","sourceRoot":"","sources":["../../../src/integration/cloudflare-kv.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;QAE5E,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAClC,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAEnC,OAAO,IAAI,CAAC;IACb,CAAC;CACD;AAvDD,4DAuDC","sourcesContent":["import { SimpleShop } from \"../repository.js\";\nimport type { 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\n\t\tif (obj.shopActive === undefined) {\n\t\t\tobj.shopActive = true;\n\t\t}\n\n\t\tshop.setShopActive(obj.shopActive);\n\n\t\treturn shop;\n\t}\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cloudflare.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare.test.d.ts","sourceRoot":"","sources":["../../../src/integration/cloudflare.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //
4
+ const bun_test_1 = require("bun:test");
5
+ const cloudflare_kv_js_1 = require("../../src/integration/cloudflare-kv.js");
6
+ const repository_js_1 = require("../../src/repository.js");
7
+ (0, bun_test_1.describe)("Cloudflare", async () => {
8
+ (0, bun_test_1.test)("createShop", async () => {
9
+ const repo = new cloudflare_kv_js_1.CloudflareShopRepository(new MockedKVNamespace());
10
+ await repo.createShop("test", "test", "test");
11
+ const shop = await repo.getShopById("test");
12
+ (0, bun_test_1.expect)(shop).not.toBeNull();
13
+ (0, bun_test_1.expect)(shop?.getShopId()).toBe("test");
14
+ (0, bun_test_1.expect)(shop?.getShopUrl()).toBe("test");
15
+ (0, bun_test_1.expect)(shop?.getShopSecret()).toBe("test");
16
+ await repo.deleteShop("test");
17
+ (0, bun_test_1.expect)(repo.getShopById("test")).resolves.toBeNull();
18
+ await repo.updateShop(new repository_js_1.SimpleShop("test", "test", "test"));
19
+ (0, bun_test_1.expect)(repo.getShopById("test")).resolves.not.toBeNull();
20
+ });
21
+ });
22
+ class MockedKVNamespace {
23
+ storage;
24
+ constructor() {
25
+ this.storage = new Map();
26
+ }
27
+ get(key, options) {
28
+ return Promise.resolve(this.storage.get(key) || null);
29
+ }
30
+ put(key, value, options) {
31
+ this.storage.set(key, value);
32
+ return Promise.resolve();
33
+ }
34
+ delete(key) {
35
+ this.storage.delete(key);
36
+ return Promise.resolve();
37
+ }
38
+ }
39
+ //# sourceMappingURL=cloudflare.test.js.map