@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
@@ -0,0 +1,102 @@
1
+ import { AppServer } from "../app.js";
2
+ /**
3
+ * Configure the Hono server to handle the app registration and context resolution
4
+ */
5
+ export function configureAppServer(hono, cfg) {
6
+ let app = null;
7
+ cfg.registrationUrl = cfg.registrationUrl || "/app/register";
8
+ cfg.registerConfirmationUrl =
9
+ cfg.registerConfirmationUrl || "/app/register/confirm";
10
+ cfg.appActivateUrl = cfg.appActivateUrl || "/app/activate";
11
+ cfg.appDeactivateUrl = cfg.appDeactivateUrl || "/app/deactivate";
12
+ cfg.appDeleteUrl = cfg.appDeleteUrl || "/app/delete";
13
+ cfg.appPath = cfg.appPath || "/app/*";
14
+ hono.use("*", async (ctx, next) => {
15
+ if (app === null) {
16
+ const appUrl = cfg.appUrl || buildBaseUrl(ctx.req.url);
17
+ if (typeof cfg.shopRepository === "function") {
18
+ cfg.shopRepository = cfg.shopRepository(ctx);
19
+ }
20
+ if (typeof cfg.appName === "function") {
21
+ cfg.appName = cfg.appName(ctx);
22
+ }
23
+ if (typeof cfg.appSecret === "function") {
24
+ cfg.appSecret = cfg.appSecret(ctx);
25
+ }
26
+ app = new AppServer({
27
+ appName: cfg.appName,
28
+ appSecret: cfg.appSecret,
29
+ authorizeCallbackUrl: appUrl + cfg.registerConfirmationUrl,
30
+ }, cfg.shopRepository);
31
+ }
32
+ // @ts-ignore
33
+ ctx.set("app", app);
34
+ await next();
35
+ });
36
+ hono.use(cfg.appPath, async (ctx, next) => {
37
+ // @ts-ignore
38
+ const app = ctx.get("app");
39
+ // Don't validate signature for registration
40
+ if (ctx.req.path === cfg.registrationUrl ||
41
+ ctx.req.path === cfg.registerConfirmationUrl ||
42
+ ctx.req.path === cfg.appActivateUrl ||
43
+ ctx.req.path === cfg.appDeactivateUrl ||
44
+ ctx.req.path === cfg.appDeleteUrl) {
45
+ await next();
46
+ return;
47
+ }
48
+ let context;
49
+ try {
50
+ context =
51
+ ctx.req.method === "GET"
52
+ ? await app.contextResolver.fromBrowser(ctx.req.raw)
53
+ : await app.contextResolver.fromAPI(ctx.req.raw);
54
+ }
55
+ catch (_e) {
56
+ return jsonResponse({ message: "Invalid request" }, 400);
57
+ }
58
+ // @ts-ignore
59
+ ctx.set("shop", context.shop);
60
+ // @ts-ignore
61
+ ctx.set("context", context);
62
+ await next();
63
+ const cloned = ctx.res.clone();
64
+ await ctx
65
+ .get("app")
66
+ .signer.signResponse(cloned, ctx.get("shop").getShopSecret());
67
+ ctx.header("shopware-app-signature", cloned.headers.get("shopware-app-signature"));
68
+ });
69
+ hono.get(cfg.registrationUrl, async (ctx) => {
70
+ const app = ctx.get("app");
71
+ return await app.registration.authorize(ctx.req.raw);
72
+ });
73
+ hono.post(cfg.registerConfirmationUrl, async (ctx) => {
74
+ const app = ctx.get("app");
75
+ return await app.registration.authorizeCallback(ctx.req.raw);
76
+ });
77
+ hono.post(cfg.appActivateUrl, async (ctx) => {
78
+ const app = ctx.get("app");
79
+ return await app.registration.activate(ctx.req.raw);
80
+ });
81
+ hono.post(cfg.appDeactivateUrl, async (ctx) => {
82
+ const app = ctx.get("app");
83
+ return await app.registration.deactivate(ctx.req.raw);
84
+ });
85
+ hono.post(cfg.appDeleteUrl, async (ctx) => {
86
+ const app = ctx.get("app");
87
+ return await app.registration.delete(ctx.req.raw);
88
+ });
89
+ }
90
+ function jsonResponse(body, status = 200) {
91
+ return new Response(JSON.stringify(body), {
92
+ status,
93
+ headers: {
94
+ "Content-Type": "application/json",
95
+ },
96
+ });
97
+ }
98
+ function buildBaseUrl(url) {
99
+ const u = new URL(url);
100
+ return `${u.protocol}//${u.host}`;
101
+ }
102
+ //# sourceMappingURL=hono.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hono.js","sourceRoot":"","sources":["../../../src/integration/hono.ts"],"names":[],"mappings":"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","sourcesContent":["import { AppServer } from \"../app.js\";\nimport type { Context } from \"../context-resolver.js\";\nimport type { ShopInterface, ShopRepositoryInterface } from \"../repository.js\";\n\nimport type { Hono, Context as HonoContext } from \"hono\";\n\ndeclare module \"hono\" {\n\tinterface ContextVariableMap {\n\t\t// @ts-ignore\n\t\tapp: AppServer<ShopInterface>;\n\t\tshop: ShopInterface;\n\t\t// @ts-ignore\n\t\tcontext: Context<ShopInterface, unknown>;\n\t}\n}\n\ninterface MiddlewareConfig {\n\tappName: string | ((c: HonoContext) => string);\n\tappSecret: string | ((c: HonoContext) => string);\n\tappUrl?: string | null;\n\tregistrationUrl?: string | null;\n\tregisterConfirmationUrl?: string | null;\n\tappActivateUrl?: string | null;\n\tappDeactivateUrl?: string | null;\n\tappDeleteUrl?: string | null;\n\tappPath?: string | null;\n\tshopRepository:\n\t\t| ShopRepositoryInterface\n\t\t| ((c: HonoContext) => ShopRepositoryInterface);\n}\n\n/**\n * Configure the Hono server to handle the app registration and context resolution\n */\nexport function configureAppServer(hono: Hono, cfg: MiddlewareConfig) {\n\tlet app: AppServer | null = null;\n\n\tcfg.registrationUrl = cfg.registrationUrl || \"/app/register\";\n\tcfg.registerConfirmationUrl =\n\t\tcfg.registerConfirmationUrl || \"/app/register/confirm\";\n\tcfg.appActivateUrl = cfg.appActivateUrl || \"/app/activate\";\n\tcfg.appDeactivateUrl = cfg.appDeactivateUrl || \"/app/deactivate\";\n\tcfg.appDeleteUrl = cfg.appDeleteUrl || \"/app/delete\";\n\tcfg.appPath = cfg.appPath || \"/app/*\";\n\n\thono.use(\"*\", async (ctx, next) => {\n\t\tif (app === null) {\n\t\t\tconst appUrl = cfg.appUrl || buildBaseUrl(ctx.req.url);\n\n\t\t\tif (typeof cfg.shopRepository === \"function\") {\n\t\t\t\tcfg.shopRepository = cfg.shopRepository(ctx);\n\t\t\t}\n\n\t\t\tif (typeof cfg.appName === \"function\") {\n\t\t\t\tcfg.appName = cfg.appName(ctx);\n\t\t\t}\n\n\t\t\tif (typeof cfg.appSecret === \"function\") {\n\t\t\t\tcfg.appSecret = cfg.appSecret(ctx);\n\t\t\t}\n\n\t\t\tapp = new AppServer(\n\t\t\t\t{\n\t\t\t\t\tappName: cfg.appName,\n\t\t\t\t\tappSecret: cfg.appSecret,\n\t\t\t\t\tauthorizeCallbackUrl: appUrl + cfg.registerConfirmationUrl,\n\t\t\t\t},\n\t\t\t\tcfg.shopRepository,\n\t\t\t);\n\t\t}\n\n\t\t// @ts-ignore\n\t\tctx.set(\"app\", app);\n\n\t\tawait next();\n\t});\n\n\thono.use(cfg.appPath, async (ctx, next) => {\n\t\t// @ts-ignore\n\t\tconst app = ctx.get(\"app\") as AppServer;\n\n\t\t// Don't validate signature for registration\n\t\tif (\n\t\t\tctx.req.path === cfg.registrationUrl ||\n\t\t\tctx.req.path === cfg.registerConfirmationUrl ||\n\t\t\tctx.req.path === cfg.appActivateUrl ||\n\t\t\tctx.req.path === cfg.appDeactivateUrl ||\n\t\t\tctx.req.path === cfg.appDeleteUrl\n\t\t) {\n\t\t\tawait next();\n\t\t\treturn;\n\t\t}\n\n\t\tlet context: Context<ShopInterface, unknown>;\n\t\ttry {\n\t\t\tcontext =\n\t\t\t\tctx.req.method === \"GET\"\n\t\t\t\t\t? await app.contextResolver.fromBrowser(ctx.req.raw)\n\t\t\t\t\t: await app.contextResolver.fromAPI(ctx.req.raw);\n\t\t} catch (_e) {\n\t\t\treturn jsonResponse({ message: \"Invalid request\" }, 400);\n\t\t}\n\n\t\t// @ts-ignore\n\t\tctx.set(\"shop\", context.shop);\n\t\t// @ts-ignore\n\t\tctx.set(\"context\", context);\n\n\t\tawait next();\n\n\t\tconst cloned = ctx.res.clone();\n\n\t\tawait ctx\n\t\t\t.get(\"app\")\n\t\t\t.signer.signResponse(cloned, ctx.get(\"shop\").getShopSecret());\n\n\t\tctx.header(\n\t\t\t\"shopware-app-signature\",\n\t\t\tcloned.headers.get(\"shopware-app-signature\") as string,\n\t\t);\n\t});\n\n\thono.get(cfg.registrationUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.authorize(ctx.req.raw);\n\t});\n\n\thono.post(cfg.registerConfirmationUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.authorizeCallback(ctx.req.raw);\n\t});\n\n\thono.post(cfg.appActivateUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.activate(ctx.req.raw);\n\t});\n\n\thono.post(cfg.appDeactivateUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.deactivate(ctx.req.raw);\n\t});\n\n\thono.post(cfg.appDeleteUrl, async (ctx) => {\n\t\tconst app = ctx.get(\"app\");\n\n\t\treturn await app.registration.delete(ctx.req.raw);\n\t});\n}\n\nfunction jsonResponse(body: object, status = 200): Response {\n\treturn new Response(JSON.stringify(body), {\n\t\tstatus,\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t});\n}\n\nfunction buildBaseUrl(url: string): string {\n\tconst u = new URL(url);\n\n\treturn `${u.protocol}//${u.host}`;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hono.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hono.test.d.ts","sourceRoot":"","sources":["../../../src/integration/hono.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,84 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { Hono } from "hono";
3
+ import { InMemoryShopRepository } from "../repository.js";
4
+ import { configureAppServer } from "./hono.js";
5
+ describe("Hono", async () => {
6
+ const repo = new InMemoryShopRepository();
7
+ await repo.createShop("a", "a", "a");
8
+ test("configre by functions", async () => {
9
+ const hono = new Hono();
10
+ configureAppServer(hono, {
11
+ appName: () => "test",
12
+ appSecret: () => "test",
13
+ shopRepository: () => repo,
14
+ });
15
+ const resp = await hono.fetch(new Request("http://localhost/app/register"));
16
+ expect(resp.status).toBe(400);
17
+ });
18
+ test("register", async () => {
19
+ const hono = new Hono();
20
+ configureAppServer(hono, {
21
+ appName: "test",
22
+ appSecret: "test",
23
+ shopRepository: repo,
24
+ });
25
+ const resp = await hono.fetch(new Request("http://localhost/app/register"));
26
+ expect(resp.status).toBe(400);
27
+ });
28
+ test("register: success", async () => {
29
+ const hono = new Hono();
30
+ configureAppServer(hono, {
31
+ appName: "My App",
32
+ appSecret: "my-secret",
33
+ shopRepository: repo,
34
+ });
35
+ const resp = await hono.fetch(new Request("http://localhost/app/register?shop-id=123&shop-url=https://my-shop.com&timestamp=1234567890", {
36
+ headers: new Headers({
37
+ "shopware-app-signature": "96c91f86c822e11444b7a57b54ef125ed86b1a639c5360d45c5397daa8c3f70b",
38
+ }),
39
+ }));
40
+ expect(resp.status).toBe(200);
41
+ const body = (await resp.json());
42
+ expect(body).toBeObject();
43
+ expect(body.proof).not.toBeNull();
44
+ });
45
+ test("registerConfirm", async () => {
46
+ const hono = new Hono();
47
+ configureAppServer(hono, {
48
+ appName: "test",
49
+ appSecret: "test",
50
+ shopRepository: repo,
51
+ });
52
+ const resp = await hono.fetch(new Request("http://localhost/app/register/confirm", {
53
+ method: "POST",
54
+ body: "{}",
55
+ }));
56
+ expect(resp.status).toBe(400);
57
+ });
58
+ test("signature failure", async () => {
59
+ const hono = new Hono();
60
+ configureAppServer(hono, {
61
+ appName: "test",
62
+ appSecret: "test",
63
+ shopRepository: repo,
64
+ });
65
+ hono.get("/app/test", (c) => c.text("ok"));
66
+ const resp = await hono.fetch(new Request("http://localhost/app/test?shopware-shop-signature=invalid&shop-id=a"));
67
+ expect(resp.status).toBe(400);
68
+ expect(await resp.text()).toBe('{"message":"Invalid request"}');
69
+ });
70
+ test("signature success", async () => {
71
+ const hono = new Hono();
72
+ configureAppServer(hono, {
73
+ appName: "test",
74
+ appSecret: "test",
75
+ shopRepository: repo,
76
+ });
77
+ hono.get("/app/test", (c) => c.text("ok"));
78
+ const resp = await hono.fetch(new Request("http://localhost/app/test?shopware-shop-signature=8b523d99aeef5b456288fcec48236c3367a914c6b2c9fded63d81257ac019b25&shop-id=a"));
79
+ expect(resp.status).toBe(200);
80
+ expect(await resp.text()).toBe("ok");
81
+ expect(resp.headers.get("shopware-app-signature")).toBe("4a43a105ccce57e8e38d4a1f7b3565d743b1e15fb1fec36f41fdf20164fa1c8b");
82
+ });
83
+ });
84
+ //# sourceMappingURL=hono.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hono.test.js","sourceRoot":"","sources":["../../../src/integration/hono.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, test } from \"bun:test\";\nimport { Hono } from \"hono\";\nimport { InMemoryShopRepository } from \"../repository.js\";\nimport { configureAppServer } from \"./hono.js\";\n\ndescribe(\"Hono\", async () => {\n\tconst repo = new InMemoryShopRepository();\n\n\tawait repo.createShop(\"a\", \"a\", \"a\");\n\n\ttest(\"configre by functions\", async () => {\n\t\tconst hono = new Hono();\n\n\t\tconfigureAppServer(hono, {\n\t\t\tappName: () => \"test\",\n\t\t\tappSecret: () => \"test\",\n\t\t\tshopRepository: () => repo,\n\t\t});\n\n\t\tconst resp = await hono.fetch(new Request(\"http://localhost/app/register\"));\n\n\t\texpect(resp.status).toBe(400);\n\t});\n\n\ttest(\"register\", async () => {\n\t\tconst hono = new Hono();\n\n\t\tconfigureAppServer(hono, {\n\t\t\tappName: \"test\",\n\t\t\tappSecret: \"test\",\n\t\t\tshopRepository: repo,\n\t\t});\n\n\t\tconst resp = await hono.fetch(new Request(\"http://localhost/app/register\"));\n\n\t\texpect(resp.status).toBe(400);\n\t});\n\n\ttest(\"register: success\", async () => {\n\t\tconst hono = new Hono();\n\n\t\tconfigureAppServer(hono, {\n\t\t\tappName: \"My App\",\n\t\t\tappSecret: \"my-secret\",\n\t\t\tshopRepository: repo,\n\t\t});\n\n\t\tconst resp = await hono.fetch(\n\t\t\tnew Request(\n\t\t\t\t\"http://localhost/app/register?shop-id=123&shop-url=https://my-shop.com&timestamp=1234567890\",\n\t\t\t\t{\n\t\t\t\t\theaders: new Headers({\n\t\t\t\t\t\t\"shopware-app-signature\":\n\t\t\t\t\t\t\t\"96c91f86c822e11444b7a57b54ef125ed86b1a639c5360d45c5397daa8c3f70b\",\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t),\n\t\t);\n\n\t\texpect(resp.status).toBe(200);\n\n\t\tconst body = (await resp.json()) as { proof: string };\n\n\t\texpect(body).toBeObject();\n\n\t\texpect(body.proof).not.toBeNull();\n\t});\n\n\ttest(\"registerConfirm\", async () => {\n\t\tconst hono = new Hono();\n\n\t\tconfigureAppServer(hono, {\n\t\t\tappName: \"test\",\n\t\t\tappSecret: \"test\",\n\t\t\tshopRepository: repo,\n\t\t});\n\n\t\tconst resp = await hono.fetch(\n\t\t\tnew Request(\"http://localhost/app/register/confirm\", {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tbody: \"{}\",\n\t\t\t}),\n\t\t);\n\n\t\texpect(resp.status).toBe(400);\n\t});\n\n\ttest(\"signature failure\", async () => {\n\t\tconst hono = new Hono();\n\n\t\tconfigureAppServer(hono, {\n\t\t\tappName: \"test\",\n\t\t\tappSecret: \"test\",\n\t\t\tshopRepository: repo,\n\t\t});\n\n\t\thono.get(\"/app/test\", (c) => c.text(\"ok\"));\n\n\t\tconst resp = await hono.fetch(\n\t\t\tnew Request(\n\t\t\t\t\"http://localhost/app/test?shopware-shop-signature=invalid&shop-id=a\",\n\t\t\t),\n\t\t);\n\n\t\texpect(resp.status).toBe(400);\n\t\texpect(await resp.text()).toBe('{\"message\":\"Invalid request\"}');\n\t});\n\n\ttest(\"signature success\", async () => {\n\t\tconst hono = new Hono();\n\n\t\tconfigureAppServer(hono, {\n\t\t\tappName: \"test\",\n\t\t\tappSecret: \"test\",\n\t\t\tshopRepository: repo,\n\t\t});\n\n\t\thono.get(\"/app/test\", (c) => c.text(\"ok\"));\n\n\t\tconst resp = await hono.fetch(\n\t\t\tnew Request(\n\t\t\t\t\"http://localhost/app/test?shopware-shop-signature=8b523d99aeef5b456288fcec48236c3367a914c6b2c9fded63d81257ac019b25&shop-id=a\",\n\t\t\t),\n\t\t);\n\n\t\texpect(resp.status).toBe(200);\n\t\texpect(await resp.text()).toBe(\"ok\");\n\t\texpect(resp.headers.get(\"shopware-app-signature\")).toBe(\n\t\t\t\"4a43a105ccce57e8e38d4a1f7b3565d743b1e15fb1fec36f41fdf20164fa1c8b\",\n\t\t);\n\t});\n});\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=registration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration.test.d.ts","sourceRoot":"","sources":["../../src/registration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,57 @@
1
+ import { describe, expect, jest, test } from "bun:test";
2
+ import { AppServer } from "../src/app.js";
3
+ import { InMemoryShopRepository } from "../src/repository.js";
4
+ describe("Registration", async () => {
5
+ const app = new AppServer({ appName: "test", appSecret: "test", authorizeCallbackUrl: "test" }, new InMemoryShopRepository());
6
+ test("authorize: invalid request", async () => {
7
+ const resp = await app.registration.authorize(new Request("http://localhost"));
8
+ expect(resp.status).toBe(400);
9
+ });
10
+ test("authorize: invalid signature", async () => {
11
+ const resp = await app.registration.authorize(new Request("http://localhost?shop-url=test&shop-id=test&timestamp=test", { headers: new Headers({ "shopware-app-signature": "test" }) }));
12
+ expect(resp.status).toBe(401);
13
+ });
14
+ test("authorize: valid request", async () => {
15
+ app.signer.verify = jest.fn().mockResolvedValue(true);
16
+ const resp = await app.registration.authorize(new Request("http://localhost?shop-url=test&shop-id=test&timestamp=test", { headers: new Headers({ "shopware-app-signature": "test" }) }));
17
+ expect(resp.status).toBe(200);
18
+ });
19
+ test("authorizeCallback: invalid request", async () => {
20
+ const resp = await app.registration.authorizeCallback(new Request("http://localhost", { body: "{}" }));
21
+ expect(resp.status).toBe(400);
22
+ });
23
+ test("authorizeCallback: shop does not exist", async () => {
24
+ const resp = await app.registration.authorizeCallback(new Request("http://localhost", {
25
+ body: '{"shopId": "test", "apiKey": "test", "secretKey": "test"}',
26
+ }));
27
+ expect(resp.status).toBe(400);
28
+ });
29
+ test("activateShop", async () => {
30
+ await app.repository.createShop("1", "http://localhost", "test");
31
+ const shop = await app.repository.getShopById("1");
32
+ shop?.setShopActive(false);
33
+ app.contextResolver.fromAPI = jest.fn().mockResolvedValue({ shop });
34
+ const resp = await app.registration.activate(new Request("http://localhost", { body: '{"source": {"shopId": "1"}}' }));
35
+ expect(resp.status).toBe(204);
36
+ expect(shop?.getShopActive()).toBe(true);
37
+ });
38
+ test("deactivateShop", async () => {
39
+ await app.repository.createShop("1", "http://localhost", "test");
40
+ const shop = await app.repository.getShopById("1");
41
+ shop?.setShopActive(true);
42
+ app.contextResolver.fromAPI = jest.fn().mockResolvedValue({ shop });
43
+ const resp = await app.registration.deactivate(new Request("http://localhost", { body: '{"source": {"shopId": "1"}}' }));
44
+ expect(resp.status).toBe(204);
45
+ expect(shop?.getShopActive()).toBe(false);
46
+ });
47
+ test("deletedShop", async () => {
48
+ await app.repository.createShop("1", "http://localhost", "test");
49
+ const shop = await app.repository.getShopById("1");
50
+ expect(shop).not.toBeNull();
51
+ app.contextResolver.fromAPI = jest.fn().mockResolvedValue({ shop });
52
+ const resp = await app.registration.delete(new Request("http://localhost", { body: '{"source": {"shopId": "1"}}' }));
53
+ expect(resp.status).toBe(204);
54
+ expect(app.repository.getShopById("1")).resolves.toBeNull();
55
+ });
56
+ });
57
+ //# sourceMappingURL=registration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration.test.js","sourceRoot":"","sources":["../../src/registration.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, jest, test } from \"bun:test\";\nimport { AppServer } from \"../src/app.js\";\nimport { InMemoryShopRepository, SimpleShop } from \"../src/repository.js\";\n\ndescribe(\"Registration\", async () => {\n\tconst app = new AppServer(\n\t\t{ appName: \"test\", appSecret: \"test\", authorizeCallbackUrl: \"test\" },\n\t\tnew InMemoryShopRepository(),\n\t);\n\n\ttest(\"authorize: invalid request\", async () => {\n\t\tconst resp = await app.registration.authorize(\n\t\t\tnew Request(\"http://localhost\"),\n\t\t);\n\n\t\texpect(resp.status).toBe(400);\n\t});\n\n\ttest(\"authorize: invalid signature\", async () => {\n\t\tconst resp = await app.registration.authorize(\n\t\t\tnew Request(\n\t\t\t\t\"http://localhost?shop-url=test&shop-id=test&timestamp=test\",\n\t\t\t\t{ headers: new Headers({ \"shopware-app-signature\": \"test\" }) },\n\t\t\t),\n\t\t);\n\n\t\texpect(resp.status).toBe(401);\n\t});\n\n\ttest(\"authorize: valid request\", async () => {\n\t\tapp.signer.verify = jest.fn().mockResolvedValue(true);\n\n\t\tconst resp = await app.registration.authorize(\n\t\t\tnew Request(\n\t\t\t\t\"http://localhost?shop-url=test&shop-id=test&timestamp=test\",\n\t\t\t\t{ headers: new Headers({ \"shopware-app-signature\": \"test\" }) },\n\t\t\t),\n\t\t);\n\n\t\texpect(resp.status).toBe(200);\n\t});\n\n\ttest(\"authorizeCallback: invalid request\", async () => {\n\t\tconst resp = await app.registration.authorizeCallback(\n\t\t\tnew Request(\"http://localhost\", { body: \"{}\" }),\n\t\t);\n\n\t\texpect(resp.status).toBe(400);\n\t});\n\n\ttest(\"authorizeCallback: shop does not exist\", async () => {\n\t\tconst resp = await app.registration.authorizeCallback(\n\t\t\tnew Request(\"http://localhost\", {\n\t\t\t\tbody: '{\"shopId\": \"test\", \"apiKey\": \"test\", \"secretKey\": \"test\"}',\n\t\t\t}),\n\t\t);\n\n\t\texpect(resp.status).toBe(400);\n\t});\n\n\ttest(\"activateShop\", async () => {\n\t\tawait app.repository.createShop(\"1\", \"http://localhost\", \"test\");\n\n\t\tconst shop = await app.repository.getShopById(\"1\");\n\n\t\tshop?.setShopActive(false);\n\n\t\tapp.contextResolver.fromAPI = jest.fn().mockResolvedValue({ shop });\n\n\t\tconst resp = await app.registration.activate(\n\t\t\tnew Request(\"http://localhost\", { body: '{\"source\": {\"shopId\": \"1\"}}' }),\n\t\t);\n\n\t\texpect(resp.status).toBe(204);\n\n\t\texpect(shop?.getShopActive()).toBe(true);\n\t});\n\n\ttest(\"deactivateShop\", async () => {\n\t\tawait app.repository.createShop(\"1\", \"http://localhost\", \"test\");\n\n\t\tconst shop = await app.repository.getShopById(\"1\");\n\n\t\tshop?.setShopActive(true);\n\n\t\tapp.contextResolver.fromAPI = jest.fn().mockResolvedValue({ shop });\n\n\t\tconst resp = await app.registration.deactivate(\n\t\t\tnew Request(\"http://localhost\", { body: '{\"source\": {\"shopId\": \"1\"}}' }),\n\t\t);\n\n\t\texpect(resp.status).toBe(204);\n\n\t\texpect(shop?.getShopActive()).toBe(false);\n\t});\n\n\ttest(\"deletedShop\", async () => {\n\t\tawait app.repository.createShop(\"1\", \"http://localhost\", \"test\");\n\n\t\tconst shop = await app.repository.getShopById(\"1\");\n\n\t\texpect(shop).not.toBeNull();\n\n\t\tapp.contextResolver.fromAPI = jest.fn().mockResolvedValue({ shop });\n\n\t\tconst resp = await app.registration.delete(\n\t\t\tnew Request(\"http://localhost\", { body: '{\"source\": {\"shopId\": \"1\"}}' }),\n\t\t);\n\n\t\texpect(resp.status).toBe(204);\n\n\t\texpect(app.repository.getShopById(\"1\")).resolves.toBeNull();\n\t});\n});\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=repository.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.test.d.ts","sourceRoot":"","sources":["../../src/repository.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,30 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { InMemoryShopRepository, SimpleShop } from "../src/repository.js";
3
+ describe("Repository", async () => {
4
+ test("SimpleShop", async () => {
5
+ const shop = new SimpleShop("test", "test", "test");
6
+ expect(shop.getShopId()).toBe("test");
7
+ expect(shop.getShopUrl()).toBe("test");
8
+ expect(shop.getShopSecret()).toBe("test");
9
+ expect(shop.getShopClientId()).toBeNull();
10
+ expect(shop.getShopClientSecret()).toBeNull();
11
+ expect(shop.getShopActive()).toBe(true);
12
+ shop.setShopActive(false);
13
+ expect(shop.getShopActive()).toBe(false);
14
+ shop.setShopCredentials("test", "test");
15
+ expect(shop.getShopClientId()).toBe("test");
16
+ expect(shop.getShopClientSecret()).toBe("test");
17
+ });
18
+ test("InMemoryShopRepository", async () => {
19
+ const shop = new SimpleShop("test", "test", "test");
20
+ const repository = new InMemoryShopRepository();
21
+ expect(repository.getShopById("test")).resolves.toBeNull();
22
+ await repository.createShop("test", "test", "test");
23
+ expect(repository.getShopById("test")).resolves.toBeInstanceOf(SimpleShop);
24
+ await repository.deleteShop("test");
25
+ expect(repository.getShopById("test")).resolves.toBeNull();
26
+ await repository.updateShop(shop);
27
+ expect(repository.getShopById("test")).resolves.toBe(shop);
28
+ });
29
+ });
30
+ //# sourceMappingURL=repository.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.test.js","sourceRoot":"","sources":["../../src/repository.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAE1E,QAAQ,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;IACjC,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;QAC7B,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAEpD,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAExC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAE1B,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEzC,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAExC,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAEpD,MAAM,UAAU,GAAG,IAAI,sBAAsB,EAAE,CAAC;QAEhD,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAE3D,MAAM,UAAU,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAEpD,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QAE3E,MAAM,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAEpC,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAE3D,MAAM,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAElC,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, test } from \"bun:test\";\nimport { InMemoryShopRepository, SimpleShop } from \"../src/repository.js\";\n\ndescribe(\"Repository\", async () => {\n\ttest(\"SimpleShop\", async () => {\n\t\tconst shop = new SimpleShop(\"test\", \"test\", \"test\");\n\n\t\texpect(shop.getShopId()).toBe(\"test\");\n\t\texpect(shop.getShopUrl()).toBe(\"test\");\n\t\texpect(shop.getShopSecret()).toBe(\"test\");\n\t\texpect(shop.getShopClientId()).toBeNull();\n\t\texpect(shop.getShopClientSecret()).toBeNull();\n\t\texpect(shop.getShopActive()).toBe(true);\n\n\t\tshop.setShopActive(false);\n\n\t\texpect(shop.getShopActive()).toBe(false);\n\n\t\tshop.setShopCredentials(\"test\", \"test\");\n\n\t\texpect(shop.getShopClientId()).toBe(\"test\");\n\t\texpect(shop.getShopClientSecret()).toBe(\"test\");\n\t});\n\n\ttest(\"InMemoryShopRepository\", async () => {\n\t\tconst shop = new SimpleShop(\"test\", \"test\", \"test\");\n\n\t\tconst repository = new InMemoryShopRepository();\n\n\t\texpect(repository.getShopById(\"test\")).resolves.toBeNull();\n\n\t\tawait repository.createShop(\"test\", \"test\", \"test\");\n\n\t\texpect(repository.getShopById(\"test\")).resolves.toBeInstanceOf(SimpleShop);\n\n\t\tawait repository.deleteShop(\"test\");\n\n\t\texpect(repository.getShopById(\"test\")).resolves.toBeNull();\n\n\t\tawait repository.updateShop(shop);\n\n\t\texpect(repository.getShopById(\"test\")).resolves.toBe(shop);\n\t});\n});\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=signer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signer.test.d.ts","sourceRoot":"","sources":["../../src/signer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,23 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { WebCryptoHmacSigner } from "../src/signer.js";
3
+ describe("Signer", () => {
4
+ test("signResponse", async () => {
5
+ const signer = new WebCryptoHmacSigner();
6
+ const response = new Response("Hello, World!");
7
+ await signer.signResponse(response, "test");
8
+ expect(response.headers.get("shopware-app-signature")).toBe("52589bd80ccfa4acbb3f9512dfaf4f700fa5195008aae0b77a9e47dcca75beac");
9
+ await signer.signResponse(response, "test");
10
+ expect(response.headers.get("shopware-app-signature")).toBe("52589bd80ccfa4acbb3f9512dfaf4f700fa5195008aae0b77a9e47dcca75beac");
11
+ });
12
+ test("sign", async () => {
13
+ const signer = new WebCryptoHmacSigner();
14
+ expect(await signer.sign("shop-id=blaa", "test")).toBe("f2cb1044ac5a2cb807e1942b06433d23d66bcf7dfad1095b286203e5c1f39cb6");
15
+ });
16
+ test("verifyGetRequest", async () => {
17
+ const signer = new WebCryptoHmacSigner();
18
+ expect(signer.verifyGetRequest(new Request("https://example.com/?shopware-shop-signature=52589bd80ccfa4acbb3f9512dfaf4f700fa5195008aae0b77a9e47dcca75beac"), "test")).rejects.toThrowError("Missing query parameters to verify the GET request");
19
+ expect(signer.verifyGetRequest(new Request("https://example.com/?shopware-shop-signature=52589bd80ccfa4acbb3f9512dfaf4f700fa5195008aae0b77a9e47dcca75beac&a=1"), "test")).rejects.toThrowError("Invalid signature");
20
+ expect(signer.verifyGetRequest(new Request("https://example.com/?shopware-shop-signature=f2cb1044ac5a2cb807e1942b06433d23d66bcf7dfad1095b286203e5c1f39cb6&shop-id=blaa"), "test")).resolves.pass();
21
+ });
22
+ });
23
+ //# sourceMappingURL=signer.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signer.test.js","sourceRoot":"","sources":["../../src/signer.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;IACvB,IAAI,CAAC,cAAc,EAAE,KAAK,IAAI,EAAE;QAC/B,MAAM,MAAM,GAAG,IAAI,mBAAmB,EAAE,CAAC;QAEzC,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC;QAE/C,MAAM,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAE5C,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC,IAAI,CAC1D,kEAAkE,CAClE,CAAC;QAEF,MAAM,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAE5C,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC,IAAI,CAC1D,kEAAkE,CAClE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;QACvB,MAAM,MAAM,GAAG,IAAI,mBAAmB,EAAE,CAAC;QAEzC,MAAM,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CACrD,kEAAkE,CAClE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,MAAM,GAAG,IAAI,mBAAmB,EAAE,CAAC;QAEzC,MAAM,CACL,MAAM,CAAC,gBAAgB,CACtB,IAAI,OAAO,CACV,+GAA+G,CAC/G,EACD,MAAM,CACN,CACD,CAAC,OAAO,CAAC,YAAY,CACrB,oDAAoD,CACpD,CAAC;QACF,MAAM,CACL,MAAM,CAAC,gBAAgB,CACtB,IAAI,OAAO,CACV,mHAAmH,CACnH,EACD,MAAM,CACN,CACD,CAAC,OAAO,CAAC,YAAY,CAAC,mBAAmB,CAAC,CAAC;QAE5C,MAAM,CACL,MAAM,CAAC,gBAAgB,CACtB,IAAI,OAAO,CACV,4HAA4H,CAC5H,EACD,MAAM,CACN,CACD,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, test } from \"bun:test\";\nimport { WebCryptoHmacSigner } from \"../src/signer.js\";\n\ndescribe(\"Signer\", () => {\n\ttest(\"signResponse\", async () => {\n\t\tconst signer = new WebCryptoHmacSigner();\n\n\t\tconst response = new Response(\"Hello, World!\");\n\n\t\tawait signer.signResponse(response, \"test\");\n\n\t\texpect(response.headers.get(\"shopware-app-signature\")).toBe(\n\t\t\t\"52589bd80ccfa4acbb3f9512dfaf4f700fa5195008aae0b77a9e47dcca75beac\",\n\t\t);\n\n\t\tawait signer.signResponse(response, \"test\");\n\n\t\texpect(response.headers.get(\"shopware-app-signature\")).toBe(\n\t\t\t\"52589bd80ccfa4acbb3f9512dfaf4f700fa5195008aae0b77a9e47dcca75beac\",\n\t\t);\n\t});\n\n\ttest(\"sign\", async () => {\n\t\tconst signer = new WebCryptoHmacSigner();\n\n\t\texpect(await signer.sign(\"shop-id=blaa\", \"test\")).toBe(\n\t\t\t\"f2cb1044ac5a2cb807e1942b06433d23d66bcf7dfad1095b286203e5c1f39cb6\",\n\t\t);\n\t});\n\n\ttest(\"verifyGetRequest\", async () => {\n\t\tconst signer = new WebCryptoHmacSigner();\n\n\t\texpect(\n\t\t\tsigner.verifyGetRequest(\n\t\t\t\tnew Request(\n\t\t\t\t\t\"https://example.com/?shopware-shop-signature=52589bd80ccfa4acbb3f9512dfaf4f700fa5195008aae0b77a9e47dcca75beac\",\n\t\t\t\t),\n\t\t\t\t\"test\",\n\t\t\t),\n\t\t).rejects.toThrowError(\n\t\t\t\"Missing query parameters to verify the GET request\",\n\t\t);\n\t\texpect(\n\t\t\tsigner.verifyGetRequest(\n\t\t\t\tnew Request(\n\t\t\t\t\t\"https://example.com/?shopware-shop-signature=52589bd80ccfa4acbb3f9512dfaf4f700fa5195008aae0b77a9e47dcca75beac&a=1\",\n\t\t\t\t),\n\t\t\t\t\"test\",\n\t\t\t),\n\t\t).rejects.toThrowError(\"Invalid signature\");\n\n\t\texpect(\n\t\t\tsigner.verifyGetRequest(\n\t\t\t\tnew Request(\n\t\t\t\t\t\"https://example.com/?shopware-shop-signature=f2cb1044ac5a2cb807e1942b06433d23d66bcf7dfad1095b286203e5c1f39cb6&shop-id=blaa\",\n\t\t\t\t),\n\t\t\t\t\"test\",\n\t\t\t),\n\t\t).resolves.pass();\n\t});\n});\n"]}
package/package.json CHANGED
@@ -1,64 +1,143 @@
1
1
  {
2
- "name": "@shopware-ag/app-server-sdk",
3
- "version": "1.0.1",
4
- "description": "App Server SDK for JavaScript",
5
- "type": "module",
6
- "license": "MIT",
7
- "keywords": [
8
- "shopware",
9
- "app-server"
10
- ],
11
- "exports": {
12
- "./package.json": "./package.json",
13
- ".": {
14
- "import": {
15
- "types": "./dist/esm/mod.d.ts",
16
- "default": "./dist/esm/mod.js"
17
- },
18
- "require": {
19
- "types": "./dist/commonjs/mod.d.ts",
20
- "default": "./dist/commonjs/mod.js"
21
- }
22
- },
23
- "./helper/app-actions": {
24
- "import": {
25
- "types": "./dist/esm/helper/app-actions.d.ts",
26
- "default": "./dist/esm/helper/app-actions.js"
27
- },
28
- "require": {
29
- "types": "./dist/commonjs/helper/app-actions.d.ts",
30
- "default": "./dist/commonjs/helper/app-actions.js"
31
- }
32
- },
33
- "./types": {
34
- "import": {
35
- "types": "./dist/esm/types.d.ts",
36
- "default": "./dist/esm/types.js"
37
- },
38
- "require": {
39
- "types": "./dist/commonjs/types.d.ts",
40
- "default": "./dist/commonjs/types.js"
41
- }
42
- }
43
- },
44
- "main": "./dist/commonjs/mod.js",
45
- "module": "./dist/esm/mod.js",
46
- "types": "./dist/commonjs/mod.d.ts",
47
- "files": [
48
- "dist"
49
- ],
50
- "devDependencies": {
51
- "@biomejs/biome": "1.8.3",
52
- "@types/bun": "^1.1.6",
53
- "tshy": "^3.0.2",
54
- "hono": "^4.5.6"
55
- },
56
- "tshy": {
57
- "exports": {
58
- "./package.json": "./package.json",
59
- ".": "./src/mod.ts",
60
- "./helper/app-actions": "./src/helper/app-actions.ts",
61
- "./types": "./src/types.ts"
62
- }
63
- }
64
- }
2
+ "name": "@shopware-ag/app-server-sdk",
3
+ "version": "1.1.0",
4
+ "description": "App Server SDK for JavaScript",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "keywords": ["shopware", "app-server"],
8
+ "exports": {
9
+ "./package.json": "./package.json",
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/esm/mod.d.ts",
13
+ "default": "./dist/esm/mod.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/commonjs/mod.d.ts",
17
+ "default": "./dist/commonjs/mod.js"
18
+ }
19
+ },
20
+ "./helper/app-actions": {
21
+ "import": {
22
+ "types": "./dist/esm/helper/app-actions.d.ts",
23
+ "default": "./dist/esm/helper/app-actions.js"
24
+ },
25
+ "require": {
26
+ "types": "./dist/commonjs/helper/app-actions.d.ts",
27
+ "default": "./dist/commonjs/helper/app-actions.js"
28
+ }
29
+ },
30
+ "./integration/hono": {
31
+ "import": {
32
+ "types": "./dist/esm/integration/hono.d.ts",
33
+ "default": "./dist/esm/integration/hono.js"
34
+ },
35
+ "require": {
36
+ "types": "./dist/commonjs/integration/hono.d.ts",
37
+ "default": "./dist/commonjs/integration/hono.js"
38
+ }
39
+ },
40
+ "./integration/cloudflare-kv": {
41
+ "import": {
42
+ "types": "./dist/esm/integration/cloudflare-kv.d.ts",
43
+ "default": "./dist/esm/integration/cloudflare-kv.js"
44
+ },
45
+ "require": {
46
+ "types": "./dist/commonjs/integration/cloudflare-kv.d.ts",
47
+ "default": "./dist/commonjs/integration/cloudflare-kv.js"
48
+ }
49
+ },
50
+ "./integration/deno-kv": {
51
+ "import": {
52
+ "types": "./dist/esm/integration/deno-kv.d.ts",
53
+ "default": "./dist/esm/integration/deno-kv.js"
54
+ },
55
+ "require": {
56
+ "types": "./dist/commonjs/integration/deno-kv.d.ts",
57
+ "default": "./dist/commonjs/integration/deno-kv.js"
58
+ }
59
+ },
60
+ "./integration/dynamodb": {
61
+ "import": {
62
+ "types": "./dist/esm/integration/dynamodb.d.ts",
63
+ "default": "./dist/esm/integration/dynamodb.js"
64
+ },
65
+ "require": {
66
+ "types": "./dist/commonjs/integration/dynamodb.d.ts",
67
+ "default": "./dist/commonjs/integration/dynamodb.js"
68
+ }
69
+ },
70
+ "./integration/bun-sqlite": {
71
+ "import": {
72
+ "types": "./dist/esm/integration/bun-sqlite.d.ts",
73
+ "default": "./dist/esm/integration/bun-sqlite.js"
74
+ },
75
+ "require": {
76
+ "types": "./dist/commonjs/integration/bun-sqlite.d.ts",
77
+ "default": "./dist/commonjs/integration/bun-sqlite.js"
78
+ }
79
+ },
80
+ "./types": {
81
+ "import": {
82
+ "types": "./dist/esm/types.d.ts",
83
+ "default": "./dist/esm/types.js"
84
+ },
85
+ "require": {
86
+ "types": "./dist/commonjs/types.d.ts",
87
+ "default": "./dist/commonjs/types.js"
88
+ }
89
+ }
90
+ },
91
+ "main": "./dist/commonjs/mod.js",
92
+ "module": "./dist/esm/mod.js",
93
+ "types": "./dist/commonjs/mod.d.ts",
94
+ "files": ["dist"],
95
+ "publishConfig": {
96
+ "access": "public"
97
+ },
98
+ "peerDependencies": {
99
+ "hono": "^4",
100
+ "@aws-sdk/client-dynamodb": "~3.637",
101
+ "@aws-sdk/lib-dynamodb": "~3.637"
102
+ },
103
+ "peerDependenciesMeta": {
104
+ "hono": {
105
+ "optional": true
106
+ },
107
+ "@aws-sdk/client-dynamodb": {
108
+ "optional": true
109
+ },
110
+ "@aws-sdk/lib-dynamodb": {
111
+ "optional": true
112
+ }
113
+ },
114
+ "devDependencies": {
115
+ "@biomejs/biome": "1.8.3",
116
+ "@types/bun": "^1.1.6",
117
+ "tshy": "^3.0.2",
118
+ "hono": "^4.5.6",
119
+ "@cloudflare/workers-types": "^4.20240821.1",
120
+ "@aws-sdk/client-dynamodb": "~3.637",
121
+ "@aws-sdk/lib-dynamodb": "~3.637"
122
+ },
123
+ "tshy": {
124
+ "exports": {
125
+ "./package.json": "./package.json",
126
+ ".": "./src/mod.ts",
127
+ "./helper/app-actions": "./src/helper/app-actions.ts",
128
+ "./integration/hono": "./src/integration/hono.ts",
129
+ "./integration/cloudflare-kv": "./src/integration/cloudflare-kv.ts",
130
+ "./integration/deno-kv": "./src/integration/deno-kv.ts",
131
+ "./integration/dynamodb": "./src/integration/dynamodb.ts",
132
+ "./integration/bun-sqlite": "./src/integration/bun-sqlite.ts",
133
+ "./types": "./src/types.ts"
134
+ }
135
+ },
136
+ "scripts": {
137
+ "init": "tshy && biome format . --write",
138
+ "lint": "biome ci .",
139
+ "lint:fix": "biome lint . --write && biome format . --write && biome check . --write",
140
+ "typecheck": "tsc --noEmit"
141
+ },
142
+ "trustedDependencies": ["@biomejs/biome"]
143
+ }