diff --git a/.yarn/cache/@aws-crypto-crc32-npm-5.2.0-a834040f6d-1ddf7ec3fc.zip b/.yarn/cache/@aws-crypto-crc32-npm-5.2.0-a834040f6d-1ddf7ec3fc.zip new file mode 100644 index 0000000000..2499461a9d Binary files /dev/null and b/.yarn/cache/@aws-crypto-crc32-npm-5.2.0-a834040f6d-1ddf7ec3fc.zip differ diff --git a/.yarn/cache/@aws-crypto-crc32c-npm-5.2.0-e4a77c7012-0b399de860.zip b/.yarn/cache/@aws-crypto-crc32c-npm-5.2.0-e4a77c7012-0b399de860.zip new file mode 100644 index 0000000000..d41ebde0c2 Binary files /dev/null and b/.yarn/cache/@aws-crypto-crc32c-npm-5.2.0-e4a77c7012-0b399de860.zip differ diff --git a/.yarn/cache/@aws-crypto-sha1-browser-npm-5.2.0-1973da1a70-8b04af601d.zip b/.yarn/cache/@aws-crypto-sha1-browser-npm-5.2.0-1973da1a70-8b04af601d.zip new file mode 100644 index 0000000000..f5d78db98a Binary files /dev/null and b/.yarn/cache/@aws-crypto-sha1-browser-npm-5.2.0-1973da1a70-8b04af601d.zip differ diff --git a/.yarn/cache/@aws-crypto-sha256-browser-npm-5.2.0-5e8b02b82a-773f12f202.zip b/.yarn/cache/@aws-crypto-sha256-browser-npm-5.2.0-5e8b02b82a-773f12f202.zip new file mode 100644 index 0000000000..6b73b76b0a Binary files /dev/null and b/.yarn/cache/@aws-crypto-sha256-browser-npm-5.2.0-5e8b02b82a-773f12f202.zip differ diff --git a/.yarn/cache/@aws-crypto-sha256-js-npm-5.2.0-fbe0f9fbf6-007fbe0436.zip b/.yarn/cache/@aws-crypto-sha256-js-npm-5.2.0-fbe0f9fbf6-007fbe0436.zip new file mode 100644 index 0000000000..a03c0152bb Binary files /dev/null and b/.yarn/cache/@aws-crypto-sha256-js-npm-5.2.0-fbe0f9fbf6-007fbe0436.zip differ diff --git a/.yarn/cache/@aws-crypto-supports-web-crypto-npm-5.2.0-37acf6e569-6ffc21de48.zip b/.yarn/cache/@aws-crypto-supports-web-crypto-npm-5.2.0-37acf6e569-6ffc21de48.zip new file mode 100644 index 0000000000..ab216e2cb5 Binary files /dev/null and b/.yarn/cache/@aws-crypto-supports-web-crypto-npm-5.2.0-37acf6e569-6ffc21de48.zip differ diff --git a/.yarn/cache/@aws-crypto-util-npm-5.2.0-67e90fb04c-f0f81d9d27.zip b/.yarn/cache/@aws-crypto-util-npm-5.2.0-67e90fb04c-f0f81d9d27.zip new file mode 100644 index 0000000000..c6ae7971f6 Binary files /dev/null and b/.yarn/cache/@aws-crypto-util-npm-5.2.0-67e90fb04c-f0f81d9d27.zip differ diff --git a/.yarn/cache/@aws-sdk-client-s3-npm-3.670.0-3996ccedf6-64e78b5d1c.zip b/.yarn/cache/@aws-sdk-client-s3-npm-3.670.0-3996ccedf6-64e78b5d1c.zip new file mode 100644 index 0000000000..e9d580a0e8 Binary files /dev/null and b/.yarn/cache/@aws-sdk-client-s3-npm-3.670.0-3996ccedf6-64e78b5d1c.zip differ diff --git a/.yarn/cache/@aws-sdk-client-sso-npm-3.670.0-6239db1c59-226bb40e8b.zip b/.yarn/cache/@aws-sdk-client-sso-npm-3.670.0-6239db1c59-226bb40e8b.zip new file mode 100644 index 0000000000..3e30e2e424 Binary files /dev/null and b/.yarn/cache/@aws-sdk-client-sso-npm-3.670.0-6239db1c59-226bb40e8b.zip differ diff --git a/.yarn/cache/@aws-sdk-client-sso-oidc-npm-3.670.0-764aaf8b08-3f3f10daab.zip b/.yarn/cache/@aws-sdk-client-sso-oidc-npm-3.670.0-764aaf8b08-3f3f10daab.zip new file mode 100644 index 0000000000..0afc93ea66 Binary files /dev/null and b/.yarn/cache/@aws-sdk-client-sso-oidc-npm-3.670.0-764aaf8b08-3f3f10daab.zip differ diff --git a/.yarn/cache/@aws-sdk-client-sts-npm-3.670.0-24db3935e6-3cd0a8a5db.zip b/.yarn/cache/@aws-sdk-client-sts-npm-3.670.0-24db3935e6-3cd0a8a5db.zip new file mode 100644 index 0000000000..f97a6f0c01 Binary files /dev/null and b/.yarn/cache/@aws-sdk-client-sts-npm-3.670.0-24db3935e6-3cd0a8a5db.zip differ diff --git a/.yarn/cache/@aws-sdk-core-npm-3.667.0-379380dc92-da4d0e3971.zip b/.yarn/cache/@aws-sdk-core-npm-3.667.0-379380dc92-da4d0e3971.zip new file mode 100644 index 0000000000..f488521919 Binary files /dev/null and b/.yarn/cache/@aws-sdk-core-npm-3.667.0-379380dc92-da4d0e3971.zip differ diff --git a/.yarn/cache/@aws-sdk-credential-provider-env-npm-3.667.0-c847a82230-d077c5370b.zip b/.yarn/cache/@aws-sdk-credential-provider-env-npm-3.667.0-c847a82230-d077c5370b.zip new file mode 100644 index 0000000000..f3cac1e874 Binary files /dev/null and b/.yarn/cache/@aws-sdk-credential-provider-env-npm-3.667.0-c847a82230-d077c5370b.zip differ diff --git a/.yarn/cache/@aws-sdk-credential-provider-http-npm-3.667.0-0a6d639e5f-9f300ca39a.zip b/.yarn/cache/@aws-sdk-credential-provider-http-npm-3.667.0-0a6d639e5f-9f300ca39a.zip new file mode 100644 index 0000000000..4ad9d973e1 Binary files /dev/null and b/.yarn/cache/@aws-sdk-credential-provider-http-npm-3.667.0-0a6d639e5f-9f300ca39a.zip differ diff --git a/.yarn/cache/@aws-sdk-credential-provider-ini-npm-3.670.0-ac33082e72-63afbf4a8d.zip b/.yarn/cache/@aws-sdk-credential-provider-ini-npm-3.670.0-ac33082e72-63afbf4a8d.zip new file mode 100644 index 0000000000..6fa51232c2 Binary files /dev/null and b/.yarn/cache/@aws-sdk-credential-provider-ini-npm-3.670.0-ac33082e72-63afbf4a8d.zip differ diff --git a/.yarn/cache/@aws-sdk-credential-provider-node-npm-3.670.0-daa727f5e0-b25c6ca674.zip b/.yarn/cache/@aws-sdk-credential-provider-node-npm-3.670.0-daa727f5e0-b25c6ca674.zip new file mode 100644 index 0000000000..cfef4cfbfc Binary files /dev/null and b/.yarn/cache/@aws-sdk-credential-provider-node-npm-3.670.0-daa727f5e0-b25c6ca674.zip differ diff --git a/.yarn/cache/@aws-sdk-credential-provider-process-npm-3.667.0-db207f78a0-eab090d81c.zip b/.yarn/cache/@aws-sdk-credential-provider-process-npm-3.667.0-db207f78a0-eab090d81c.zip new file mode 100644 index 0000000000..a43659eb6a Binary files /dev/null and b/.yarn/cache/@aws-sdk-credential-provider-process-npm-3.667.0-db207f78a0-eab090d81c.zip differ diff --git a/.yarn/cache/@aws-sdk-credential-provider-sso-npm-3.670.0-0c7519b89c-cb86ce737a.zip b/.yarn/cache/@aws-sdk-credential-provider-sso-npm-3.670.0-0c7519b89c-cb86ce737a.zip new file mode 100644 index 0000000000..667d7efabd Binary files /dev/null and b/.yarn/cache/@aws-sdk-credential-provider-sso-npm-3.670.0-0c7519b89c-cb86ce737a.zip differ diff --git a/.yarn/cache/@aws-sdk-credential-provider-web-identity-npm-3.667.0-7e1b2280db-02dff83f72.zip b/.yarn/cache/@aws-sdk-credential-provider-web-identity-npm-3.667.0-7e1b2280db-02dff83f72.zip new file mode 100644 index 0000000000..5d423c7f02 Binary files /dev/null and b/.yarn/cache/@aws-sdk-credential-provider-web-identity-npm-3.667.0-7e1b2280db-02dff83f72.zip differ diff --git a/.yarn/cache/@aws-sdk-middleware-bucket-endpoint-npm-3.667.0-db866204ab-b67c9438fc.zip b/.yarn/cache/@aws-sdk-middleware-bucket-endpoint-npm-3.667.0-db866204ab-b67c9438fc.zip new file mode 100644 index 0000000000..cd8416e6eb Binary files /dev/null and b/.yarn/cache/@aws-sdk-middleware-bucket-endpoint-npm-3.667.0-db866204ab-b67c9438fc.zip differ diff --git a/.yarn/cache/@aws-sdk-middleware-expect-continue-npm-3.667.0-57383659ac-c5da94a95b.zip b/.yarn/cache/@aws-sdk-middleware-expect-continue-npm-3.667.0-57383659ac-c5da94a95b.zip new file mode 100644 index 0000000000..20d07abb12 Binary files /dev/null and b/.yarn/cache/@aws-sdk-middleware-expect-continue-npm-3.667.0-57383659ac-c5da94a95b.zip differ diff --git a/.yarn/cache/@aws-sdk-middleware-flexible-checksums-npm-3.669.0-7be517d907-65fc21716e.zip b/.yarn/cache/@aws-sdk-middleware-flexible-checksums-npm-3.669.0-7be517d907-65fc21716e.zip new file mode 100644 index 0000000000..4c072280a2 Binary files /dev/null and b/.yarn/cache/@aws-sdk-middleware-flexible-checksums-npm-3.669.0-7be517d907-65fc21716e.zip differ diff --git a/.yarn/cache/@aws-sdk-middleware-host-header-npm-3.667.0-123a27e3a9-e545c3f218.zip b/.yarn/cache/@aws-sdk-middleware-host-header-npm-3.667.0-123a27e3a9-e545c3f218.zip new file mode 100644 index 0000000000..15338cedc2 Binary files /dev/null and b/.yarn/cache/@aws-sdk-middleware-host-header-npm-3.667.0-123a27e3a9-e545c3f218.zip differ diff --git a/.yarn/cache/@aws-sdk-middleware-location-constraint-npm-3.667.0-19a922664f-bd92e6cb7a.zip b/.yarn/cache/@aws-sdk-middleware-location-constraint-npm-3.667.0-19a922664f-bd92e6cb7a.zip new file mode 100644 index 0000000000..571d71f432 Binary files /dev/null and b/.yarn/cache/@aws-sdk-middleware-location-constraint-npm-3.667.0-19a922664f-bd92e6cb7a.zip differ diff --git a/.yarn/cache/@aws-sdk-middleware-logger-npm-3.667.0-5b3a302823-47d7c9fa8f.zip b/.yarn/cache/@aws-sdk-middleware-logger-npm-3.667.0-5b3a302823-47d7c9fa8f.zip new file mode 100644 index 0000000000..217458926d Binary files /dev/null and b/.yarn/cache/@aws-sdk-middleware-logger-npm-3.667.0-5b3a302823-47d7c9fa8f.zip differ diff --git a/.yarn/cache/@aws-sdk-middleware-recursion-detection-npm-3.667.0-5f5aaf00fc-80b4f28b76.zip b/.yarn/cache/@aws-sdk-middleware-recursion-detection-npm-3.667.0-5f5aaf00fc-80b4f28b76.zip new file mode 100644 index 0000000000..7f7777b062 Binary files /dev/null and b/.yarn/cache/@aws-sdk-middleware-recursion-detection-npm-3.667.0-5f5aaf00fc-80b4f28b76.zip differ diff --git a/.yarn/cache/@aws-sdk-middleware-sdk-s3-npm-3.669.0-00e9527c6c-9137a0d670.zip b/.yarn/cache/@aws-sdk-middleware-sdk-s3-npm-3.669.0-00e9527c6c-9137a0d670.zip new file mode 100644 index 0000000000..7d9f98ecc5 Binary files /dev/null and b/.yarn/cache/@aws-sdk-middleware-sdk-s3-npm-3.669.0-00e9527c6c-9137a0d670.zip differ diff --git a/.yarn/cache/@aws-sdk-middleware-ssec-npm-3.667.0-6cd2c4c7b0-16210a33fb.zip b/.yarn/cache/@aws-sdk-middleware-ssec-npm-3.667.0-6cd2c4c7b0-16210a33fb.zip new file mode 100644 index 0000000000..63c9cd557b Binary files /dev/null and b/.yarn/cache/@aws-sdk-middleware-ssec-npm-3.667.0-6cd2c4c7b0-16210a33fb.zip differ diff --git a/.yarn/cache/@aws-sdk-middleware-user-agent-npm-3.669.0-c2653fe7b1-c1295321b7.zip b/.yarn/cache/@aws-sdk-middleware-user-agent-npm-3.669.0-c2653fe7b1-c1295321b7.zip new file mode 100644 index 0000000000..2a940531d8 Binary files /dev/null and b/.yarn/cache/@aws-sdk-middleware-user-agent-npm-3.669.0-c2653fe7b1-c1295321b7.zip differ diff --git a/.yarn/cache/@aws-sdk-region-config-resolver-npm-3.667.0-11686b714e-be102ae253.zip b/.yarn/cache/@aws-sdk-region-config-resolver-npm-3.667.0-11686b714e-be102ae253.zip new file mode 100644 index 0000000000..571798dd65 Binary files /dev/null and b/.yarn/cache/@aws-sdk-region-config-resolver-npm-3.667.0-11686b714e-be102ae253.zip differ diff --git a/.yarn/cache/@aws-sdk-s3-request-presigner-npm-3.670.0-69132c52b2-25916ce05f.zip b/.yarn/cache/@aws-sdk-s3-request-presigner-npm-3.670.0-69132c52b2-25916ce05f.zip new file mode 100644 index 0000000000..0ec2907c41 Binary files /dev/null and b/.yarn/cache/@aws-sdk-s3-request-presigner-npm-3.670.0-69132c52b2-25916ce05f.zip differ diff --git a/.yarn/cache/@aws-sdk-signature-v4-multi-region-npm-3.669.0-93c9c8c4b9-b8f6e28ffb.zip b/.yarn/cache/@aws-sdk-signature-v4-multi-region-npm-3.669.0-93c9c8c4b9-b8f6e28ffb.zip new file mode 100644 index 0000000000..6bd456490b Binary files /dev/null and b/.yarn/cache/@aws-sdk-signature-v4-multi-region-npm-3.669.0-93c9c8c4b9-b8f6e28ffb.zip differ diff --git a/.yarn/cache/@aws-sdk-token-providers-npm-3.667.0-88bf74de22-cd783b95f3.zip b/.yarn/cache/@aws-sdk-token-providers-npm-3.667.0-88bf74de22-cd783b95f3.zip new file mode 100644 index 0000000000..de4ce3948b Binary files /dev/null and b/.yarn/cache/@aws-sdk-token-providers-npm-3.667.0-88bf74de22-cd783b95f3.zip differ diff --git a/.yarn/cache/@aws-sdk-types-npm-3.667.0-ffe6d09ec3-54471245c8.zip b/.yarn/cache/@aws-sdk-types-npm-3.667.0-ffe6d09ec3-54471245c8.zip new file mode 100644 index 0000000000..c0504c5f6e Binary files /dev/null and b/.yarn/cache/@aws-sdk-types-npm-3.667.0-ffe6d09ec3-54471245c8.zip differ diff --git a/.yarn/cache/@aws-sdk-util-arn-parser-npm-3.568.0-8b1427ba0d-e3c45e5d52.zip b/.yarn/cache/@aws-sdk-util-arn-parser-npm-3.568.0-8b1427ba0d-e3c45e5d52.zip new file mode 100644 index 0000000000..e7d2a2591b Binary files /dev/null and b/.yarn/cache/@aws-sdk-util-arn-parser-npm-3.568.0-8b1427ba0d-e3c45e5d52.zip differ diff --git a/.yarn/cache/@aws-sdk-util-endpoints-npm-3.667.0-f25b8eb95b-c9e2baccba.zip b/.yarn/cache/@aws-sdk-util-endpoints-npm-3.667.0-f25b8eb95b-c9e2baccba.zip new file mode 100644 index 0000000000..d4aa3fa16d Binary files /dev/null and b/.yarn/cache/@aws-sdk-util-endpoints-npm-3.667.0-f25b8eb95b-c9e2baccba.zip differ diff --git a/.yarn/cache/@aws-sdk-util-format-url-npm-3.667.0-a92e3b8a15-4f687d3478.zip b/.yarn/cache/@aws-sdk-util-format-url-npm-3.667.0-a92e3b8a15-4f687d3478.zip new file mode 100644 index 0000000000..794700a574 Binary files /dev/null and b/.yarn/cache/@aws-sdk-util-format-url-npm-3.667.0-a92e3b8a15-4f687d3478.zip differ diff --git a/.yarn/cache/@aws-sdk-util-locate-window-npm-3.568.0-c00d9c0c7c-354db5187b.zip b/.yarn/cache/@aws-sdk-util-locate-window-npm-3.568.0-c00d9c0c7c-354db5187b.zip new file mode 100644 index 0000000000..1a691f0c56 Binary files /dev/null and b/.yarn/cache/@aws-sdk-util-locate-window-npm-3.568.0-c00d9c0c7c-354db5187b.zip differ diff --git a/.yarn/cache/@aws-sdk-util-user-agent-browser-npm-3.670.0-c0fb3b320d-70c4b8374b.zip b/.yarn/cache/@aws-sdk-util-user-agent-browser-npm-3.670.0-c0fb3b320d-70c4b8374b.zip new file mode 100644 index 0000000000..5e4911727c Binary files /dev/null and b/.yarn/cache/@aws-sdk-util-user-agent-browser-npm-3.670.0-c0fb3b320d-70c4b8374b.zip differ diff --git a/.yarn/cache/@aws-sdk-util-user-agent-node-npm-3.669.0-9b383b0f77-89af069147.zip b/.yarn/cache/@aws-sdk-util-user-agent-node-npm-3.669.0-9b383b0f77-89af069147.zip new file mode 100644 index 0000000000..b6d080dccf Binary files /dev/null and b/.yarn/cache/@aws-sdk-util-user-agent-node-npm-3.669.0-9b383b0f77-89af069147.zip differ diff --git a/.yarn/cache/@aws-sdk-xml-builder-npm-3.662.0-32ceda7d13-4571dfe225.zip b/.yarn/cache/@aws-sdk-xml-builder-npm-3.662.0-32ceda7d13-4571dfe225.zip new file mode 100644 index 0000000000..2e170364c4 Binary files /dev/null and b/.yarn/cache/@aws-sdk-xml-builder-npm-3.662.0-32ceda7d13-4571dfe225.zip differ diff --git a/.yarn/cache/@smithy-abort-controller-npm-3.1.5-9d37a61a65-538c88d6df.zip b/.yarn/cache/@smithy-abort-controller-npm-3.1.5-9d37a61a65-538c88d6df.zip new file mode 100644 index 0000000000..9287e7a87a Binary files /dev/null and b/.yarn/cache/@smithy-abort-controller-npm-3.1.5-9d37a61a65-538c88d6df.zip differ diff --git a/.yarn/cache/@smithy-chunked-blob-reader-native-npm-3.0.0-3b387a57fd-f97c0c0ce5.zip b/.yarn/cache/@smithy-chunked-blob-reader-native-npm-3.0.0-3b387a57fd-f97c0c0ce5.zip new file mode 100644 index 0000000000..c4e8074af0 Binary files /dev/null and b/.yarn/cache/@smithy-chunked-blob-reader-native-npm-3.0.0-3b387a57fd-f97c0c0ce5.zip differ diff --git a/.yarn/cache/@smithy-chunked-blob-reader-npm-3.0.0-4eeb81fd25-6f520884ad.zip b/.yarn/cache/@smithy-chunked-blob-reader-npm-3.0.0-4eeb81fd25-6f520884ad.zip new file mode 100644 index 0000000000..3740f77f7c Binary files /dev/null and b/.yarn/cache/@smithy-chunked-blob-reader-npm-3.0.0-4eeb81fd25-6f520884ad.zip differ diff --git a/.yarn/cache/@smithy-config-resolver-npm-3.0.9-8437e02d06-87e61be2ae.zip b/.yarn/cache/@smithy-config-resolver-npm-3.0.9-8437e02d06-87e61be2ae.zip new file mode 100644 index 0000000000..3783b0439a Binary files /dev/null and b/.yarn/cache/@smithy-config-resolver-npm-3.0.9-8437e02d06-87e61be2ae.zip differ diff --git a/.yarn/cache/@smithy-core-npm-2.4.8-a774305796-ab9e635f16.zip b/.yarn/cache/@smithy-core-npm-2.4.8-a774305796-ab9e635f16.zip new file mode 100644 index 0000000000..714b4fc377 Binary files /dev/null and b/.yarn/cache/@smithy-core-npm-2.4.8-a774305796-ab9e635f16.zip differ diff --git a/.yarn/cache/@smithy-credential-provider-imds-npm-3.2.4-5a13aa609c-d416f85450.zip b/.yarn/cache/@smithy-credential-provider-imds-npm-3.2.4-5a13aa609c-d416f85450.zip new file mode 100644 index 0000000000..3c86224ced Binary files /dev/null and b/.yarn/cache/@smithy-credential-provider-imds-npm-3.2.4-5a13aa609c-d416f85450.zip differ diff --git a/.yarn/cache/@smithy-eventstream-codec-npm-3.1.6-4f5b360d61-9b7ec78dd0.zip b/.yarn/cache/@smithy-eventstream-codec-npm-3.1.6-4f5b360d61-9b7ec78dd0.zip new file mode 100644 index 0000000000..63e80b82b5 Binary files /dev/null and b/.yarn/cache/@smithy-eventstream-codec-npm-3.1.6-4f5b360d61-9b7ec78dd0.zip differ diff --git a/.yarn/cache/@smithy-eventstream-serde-browser-npm-3.0.10-dda1281f42-292382ae41.zip b/.yarn/cache/@smithy-eventstream-serde-browser-npm-3.0.10-dda1281f42-292382ae41.zip new file mode 100644 index 0000000000..57f9187a53 Binary files /dev/null and b/.yarn/cache/@smithy-eventstream-serde-browser-npm-3.0.10-dda1281f42-292382ae41.zip differ diff --git a/.yarn/cache/@smithy-eventstream-serde-config-resolver-npm-3.0.7-d75c40f39a-c1762b21c6.zip b/.yarn/cache/@smithy-eventstream-serde-config-resolver-npm-3.0.7-d75c40f39a-c1762b21c6.zip new file mode 100644 index 0000000000..dd672588cb Binary files /dev/null and b/.yarn/cache/@smithy-eventstream-serde-config-resolver-npm-3.0.7-d75c40f39a-c1762b21c6.zip differ diff --git a/.yarn/cache/@smithy-eventstream-serde-node-npm-3.0.9-e5f8fddb0d-3f5dd21636.zip b/.yarn/cache/@smithy-eventstream-serde-node-npm-3.0.9-e5f8fddb0d-3f5dd21636.zip new file mode 100644 index 0000000000..cc075885b9 Binary files /dev/null and b/.yarn/cache/@smithy-eventstream-serde-node-npm-3.0.9-e5f8fddb0d-3f5dd21636.zip differ diff --git a/.yarn/cache/@smithy-eventstream-serde-universal-npm-3.0.9-d04c4d738f-d247fdb915.zip b/.yarn/cache/@smithy-eventstream-serde-universal-npm-3.0.9-d04c4d738f-d247fdb915.zip new file mode 100644 index 0000000000..5d9986ac63 Binary files /dev/null and b/.yarn/cache/@smithy-eventstream-serde-universal-npm-3.0.9-d04c4d738f-d247fdb915.zip differ diff --git a/.yarn/cache/@smithy-fetch-http-handler-npm-3.2.9-56214dc8b1-3b8eed12bf.zip b/.yarn/cache/@smithy-fetch-http-handler-npm-3.2.9-56214dc8b1-3b8eed12bf.zip new file mode 100644 index 0000000000..9e7c60b854 Binary files /dev/null and b/.yarn/cache/@smithy-fetch-http-handler-npm-3.2.9-56214dc8b1-3b8eed12bf.zip differ diff --git a/.yarn/cache/@smithy-hash-blob-browser-npm-3.1.6-bfded9314a-4807ad388f.zip b/.yarn/cache/@smithy-hash-blob-browser-npm-3.1.6-bfded9314a-4807ad388f.zip new file mode 100644 index 0000000000..f64548ee63 Binary files /dev/null and b/.yarn/cache/@smithy-hash-blob-browser-npm-3.1.6-bfded9314a-4807ad388f.zip differ diff --git a/.yarn/cache/@smithy-hash-node-npm-3.0.7-56f26ccb5a-7a3b432e49.zip b/.yarn/cache/@smithy-hash-node-npm-3.0.7-56f26ccb5a-7a3b432e49.zip new file mode 100644 index 0000000000..77b27371fe Binary files /dev/null and b/.yarn/cache/@smithy-hash-node-npm-3.0.7-56f26ccb5a-7a3b432e49.zip differ diff --git a/.yarn/cache/@smithy-hash-stream-node-npm-3.1.6-d363941106-e6427f7865.zip b/.yarn/cache/@smithy-hash-stream-node-npm-3.1.6-d363941106-e6427f7865.zip new file mode 100644 index 0000000000..173417a7d2 Binary files /dev/null and b/.yarn/cache/@smithy-hash-stream-node-npm-3.1.6-d363941106-e6427f7865.zip differ diff --git a/.yarn/cache/@smithy-invalid-dependency-npm-3.0.7-6c6b2721d1-6ccfd99568.zip b/.yarn/cache/@smithy-invalid-dependency-npm-3.0.7-6c6b2721d1-6ccfd99568.zip new file mode 100644 index 0000000000..aa8729903c Binary files /dev/null and b/.yarn/cache/@smithy-invalid-dependency-npm-3.0.7-6c6b2721d1-6ccfd99568.zip differ diff --git a/.yarn/cache/@smithy-is-array-buffer-npm-2.2.0-108320772d-cd12c2e278.zip b/.yarn/cache/@smithy-is-array-buffer-npm-2.2.0-108320772d-cd12c2e278.zip new file mode 100644 index 0000000000..8b514d6bb7 Binary files /dev/null and b/.yarn/cache/@smithy-is-array-buffer-npm-2.2.0-108320772d-cd12c2e278.zip differ diff --git a/.yarn/cache/@smithy-is-array-buffer-npm-3.0.0-8e8215ad1c-ce7440fcb1.zip b/.yarn/cache/@smithy-is-array-buffer-npm-3.0.0-8e8215ad1c-ce7440fcb1.zip new file mode 100644 index 0000000000..cb1d871125 Binary files /dev/null and b/.yarn/cache/@smithy-is-array-buffer-npm-3.0.0-8e8215ad1c-ce7440fcb1.zip differ diff --git a/.yarn/cache/@smithy-md5-js-npm-3.0.7-e9c4411b50-d9badbd536.zip b/.yarn/cache/@smithy-md5-js-npm-3.0.7-e9c4411b50-d9badbd536.zip new file mode 100644 index 0000000000..eea8e4c9a6 Binary files /dev/null and b/.yarn/cache/@smithy-md5-js-npm-3.0.7-e9c4411b50-d9badbd536.zip differ diff --git a/.yarn/cache/@smithy-middleware-content-length-npm-3.0.9-89c2cf8ddc-0299e25739.zip b/.yarn/cache/@smithy-middleware-content-length-npm-3.0.9-89c2cf8ddc-0299e25739.zip new file mode 100644 index 0000000000..298e1fba93 Binary files /dev/null and b/.yarn/cache/@smithy-middleware-content-length-npm-3.0.9-89c2cf8ddc-0299e25739.zip differ diff --git a/.yarn/cache/@smithy-middleware-endpoint-npm-3.1.4-f3b7aac970-34cc4115fc.zip b/.yarn/cache/@smithy-middleware-endpoint-npm-3.1.4-f3b7aac970-34cc4115fc.zip new file mode 100644 index 0000000000..dbb0ac0c44 Binary files /dev/null and b/.yarn/cache/@smithy-middleware-endpoint-npm-3.1.4-f3b7aac970-34cc4115fc.zip differ diff --git a/.yarn/cache/@smithy-middleware-retry-npm-3.0.23-677d873343-8d991ce755.zip b/.yarn/cache/@smithy-middleware-retry-npm-3.0.23-677d873343-8d991ce755.zip new file mode 100644 index 0000000000..282a90347d Binary files /dev/null and b/.yarn/cache/@smithy-middleware-retry-npm-3.0.23-677d873343-8d991ce755.zip differ diff --git a/.yarn/cache/@smithy-middleware-serde-npm-3.0.7-820eb913ea-6ec3a00004.zip b/.yarn/cache/@smithy-middleware-serde-npm-3.0.7-820eb913ea-6ec3a00004.zip new file mode 100644 index 0000000000..df1a557506 Binary files /dev/null and b/.yarn/cache/@smithy-middleware-serde-npm-3.0.7-820eb913ea-6ec3a00004.zip differ diff --git a/.yarn/cache/@smithy-middleware-stack-npm-3.0.7-0f70aeb1dc-f29af8abb5.zip b/.yarn/cache/@smithy-middleware-stack-npm-3.0.7-0f70aeb1dc-f29af8abb5.zip new file mode 100644 index 0000000000..273c685902 Binary files /dev/null and b/.yarn/cache/@smithy-middleware-stack-npm-3.0.7-0f70aeb1dc-f29af8abb5.zip differ diff --git a/.yarn/cache/@smithy-node-config-provider-npm-3.1.8-153e528dfa-20b6d0e5e2.zip b/.yarn/cache/@smithy-node-config-provider-npm-3.1.8-153e528dfa-20b6d0e5e2.zip new file mode 100644 index 0000000000..0dac9aa808 Binary files /dev/null and b/.yarn/cache/@smithy-node-config-provider-npm-3.1.8-153e528dfa-20b6d0e5e2.zip differ diff --git a/.yarn/cache/@smithy-node-http-handler-npm-3.2.4-a35b04a246-6589343669.zip b/.yarn/cache/@smithy-node-http-handler-npm-3.2.4-a35b04a246-6589343669.zip new file mode 100644 index 0000000000..ee20661b1a Binary files /dev/null and b/.yarn/cache/@smithy-node-http-handler-npm-3.2.4-a35b04a246-6589343669.zip differ diff --git a/.yarn/cache/@smithy-property-provider-npm-3.1.7-5bc7673e75-c0b9fdbfeb.zip b/.yarn/cache/@smithy-property-provider-npm-3.1.7-5bc7673e75-c0b9fdbfeb.zip new file mode 100644 index 0000000000..4e1eb488e2 Binary files /dev/null and b/.yarn/cache/@smithy-property-provider-npm-3.1.7-5bc7673e75-c0b9fdbfeb.zip differ diff --git a/.yarn/cache/@smithy-protocol-http-npm-4.1.4-34c565d0e2-c0655e2031.zip b/.yarn/cache/@smithy-protocol-http-npm-4.1.4-34c565d0e2-c0655e2031.zip new file mode 100644 index 0000000000..b61fc0bc63 Binary files /dev/null and b/.yarn/cache/@smithy-protocol-http-npm-4.1.4-34c565d0e2-c0655e2031.zip differ diff --git a/.yarn/cache/@smithy-querystring-builder-npm-3.0.7-493dba1da6-0c41ce1993.zip b/.yarn/cache/@smithy-querystring-builder-npm-3.0.7-493dba1da6-0c41ce1993.zip new file mode 100644 index 0000000000..1533c2be25 Binary files /dev/null and b/.yarn/cache/@smithy-querystring-builder-npm-3.0.7-493dba1da6-0c41ce1993.zip differ diff --git a/.yarn/cache/@smithy-querystring-parser-npm-3.0.7-beac0ab729-5ef80af89f.zip b/.yarn/cache/@smithy-querystring-parser-npm-3.0.7-beac0ab729-5ef80af89f.zip new file mode 100644 index 0000000000..e40b73e706 Binary files /dev/null and b/.yarn/cache/@smithy-querystring-parser-npm-3.0.7-beac0ab729-5ef80af89f.zip differ diff --git a/.yarn/cache/@smithy-service-error-classification-npm-3.0.7-815301ce4d-a6370ee348.zip b/.yarn/cache/@smithy-service-error-classification-npm-3.0.7-815301ce4d-a6370ee348.zip new file mode 100644 index 0000000000..66256053a8 Binary files /dev/null and b/.yarn/cache/@smithy-service-error-classification-npm-3.0.7-815301ce4d-a6370ee348.zip differ diff --git a/.yarn/cache/@smithy-shared-ini-file-loader-npm-3.1.8-fe61a4ac22-0ad620cb4a.zip b/.yarn/cache/@smithy-shared-ini-file-loader-npm-3.1.8-fe61a4ac22-0ad620cb4a.zip new file mode 100644 index 0000000000..45db7ef5c5 Binary files /dev/null and b/.yarn/cache/@smithy-shared-ini-file-loader-npm-3.1.8-fe61a4ac22-0ad620cb4a.zip differ diff --git a/.yarn/cache/@smithy-signature-v4-npm-4.2.0-a4d03e78cf-edf0fa3ee5.zip b/.yarn/cache/@smithy-signature-v4-npm-4.2.0-a4d03e78cf-edf0fa3ee5.zip new file mode 100644 index 0000000000..a199ea925d Binary files /dev/null and b/.yarn/cache/@smithy-signature-v4-npm-4.2.0-a4d03e78cf-edf0fa3ee5.zip differ diff --git a/.yarn/cache/@smithy-smithy-client-npm-3.4.0-e70f9c17e7-4eb8387ca1.zip b/.yarn/cache/@smithy-smithy-client-npm-3.4.0-e70f9c17e7-4eb8387ca1.zip new file mode 100644 index 0000000000..652574cf90 Binary files /dev/null and b/.yarn/cache/@smithy-smithy-client-npm-3.4.0-e70f9c17e7-4eb8387ca1.zip differ diff --git a/.yarn/cache/@smithy-types-npm-3.5.0-34faf744cc-5d29700554.zip b/.yarn/cache/@smithy-types-npm-3.5.0-34faf744cc-5d29700554.zip new file mode 100644 index 0000000000..8911786c6b Binary files /dev/null and b/.yarn/cache/@smithy-types-npm-3.5.0-34faf744cc-5d29700554.zip differ diff --git a/.yarn/cache/@smithy-url-parser-npm-3.0.7-6dc4402348-b0e4939c95.zip b/.yarn/cache/@smithy-url-parser-npm-3.0.7-6dc4402348-b0e4939c95.zip new file mode 100644 index 0000000000..66226b1b4c Binary files /dev/null and b/.yarn/cache/@smithy-url-parser-npm-3.0.7-6dc4402348-b0e4939c95.zip differ diff --git a/.yarn/cache/@smithy-util-base64-npm-3.0.0-38fc40fa27-413f26046a.zip b/.yarn/cache/@smithy-util-base64-npm-3.0.0-38fc40fa27-413f26046a.zip new file mode 100644 index 0000000000..bf7673c335 Binary files /dev/null and b/.yarn/cache/@smithy-util-base64-npm-3.0.0-38fc40fa27-413f26046a.zip differ diff --git a/.yarn/cache/@smithy-util-body-length-browser-npm-3.0.0-868397df97-b01d8258b9.zip b/.yarn/cache/@smithy-util-body-length-browser-npm-3.0.0-868397df97-b01d8258b9.zip new file mode 100644 index 0000000000..80737d80d6 Binary files /dev/null and b/.yarn/cache/@smithy-util-body-length-browser-npm-3.0.0-868397df97-b01d8258b9.zip differ diff --git a/.yarn/cache/@smithy-util-body-length-node-npm-3.0.0-9d33ec493b-da1baf4790.zip b/.yarn/cache/@smithy-util-body-length-node-npm-3.0.0-9d33ec493b-da1baf4790.zip new file mode 100644 index 0000000000..99c4423552 Binary files /dev/null and b/.yarn/cache/@smithy-util-body-length-node-npm-3.0.0-9d33ec493b-da1baf4790.zip differ diff --git a/.yarn/cache/@smithy-util-buffer-from-npm-2.2.0-0ef5989125-424c5b7368.zip b/.yarn/cache/@smithy-util-buffer-from-npm-2.2.0-0ef5989125-424c5b7368.zip new file mode 100644 index 0000000000..07ca3d219e Binary files /dev/null and b/.yarn/cache/@smithy-util-buffer-from-npm-2.2.0-0ef5989125-424c5b7368.zip differ diff --git a/.yarn/cache/@smithy-util-buffer-from-npm-3.0.0-7f54bf03c3-1bfc4ab093.zip b/.yarn/cache/@smithy-util-buffer-from-npm-3.0.0-7f54bf03c3-1bfc4ab093.zip new file mode 100644 index 0000000000..cf02c92b1c Binary files /dev/null and b/.yarn/cache/@smithy-util-buffer-from-npm-3.0.0-7f54bf03c3-1bfc4ab093.zip differ diff --git a/.yarn/cache/@smithy-util-config-provider-npm-3.0.0-f3b040d73b-fc0f5f57d3.zip b/.yarn/cache/@smithy-util-config-provider-npm-3.0.0-f3b040d73b-fc0f5f57d3.zip new file mode 100644 index 0000000000..a6f2878448 Binary files /dev/null and b/.yarn/cache/@smithy-util-config-provider-npm-3.0.0-f3b040d73b-fc0f5f57d3.zip differ diff --git a/.yarn/cache/@smithy-util-defaults-mode-browser-npm-3.0.23-8e8d044c81-8b95eddff6.zip b/.yarn/cache/@smithy-util-defaults-mode-browser-npm-3.0.23-8e8d044c81-8b95eddff6.zip new file mode 100644 index 0000000000..bc0ce373ea Binary files /dev/null and b/.yarn/cache/@smithy-util-defaults-mode-browser-npm-3.0.23-8e8d044c81-8b95eddff6.zip differ diff --git a/.yarn/cache/@smithy-util-defaults-mode-node-npm-3.0.23-7f73218fae-6e961b50a1.zip b/.yarn/cache/@smithy-util-defaults-mode-node-npm-3.0.23-7f73218fae-6e961b50a1.zip new file mode 100644 index 0000000000..5e67540963 Binary files /dev/null and b/.yarn/cache/@smithy-util-defaults-mode-node-npm-3.0.23-7f73218fae-6e961b50a1.zip differ diff --git a/.yarn/cache/@smithy-util-endpoints-npm-2.1.3-e84fc435be-63a362e1b5.zip b/.yarn/cache/@smithy-util-endpoints-npm-2.1.3-e84fc435be-63a362e1b5.zip new file mode 100644 index 0000000000..a0cc94b5df Binary files /dev/null and b/.yarn/cache/@smithy-util-endpoints-npm-2.1.3-e84fc435be-63a362e1b5.zip differ diff --git a/.yarn/cache/@smithy-util-hex-encoding-npm-3.0.0-55c86ac7d0-dd32fd71e9.zip b/.yarn/cache/@smithy-util-hex-encoding-npm-3.0.0-55c86ac7d0-dd32fd71e9.zip new file mode 100644 index 0000000000..7c8c16ad11 Binary files /dev/null and b/.yarn/cache/@smithy-util-hex-encoding-npm-3.0.0-55c86ac7d0-dd32fd71e9.zip differ diff --git a/.yarn/cache/@smithy-util-middleware-npm-3.0.7-d57fadc553-ed1f9751d6.zip b/.yarn/cache/@smithy-util-middleware-npm-3.0.7-d57fadc553-ed1f9751d6.zip new file mode 100644 index 0000000000..89a797a1e4 Binary files /dev/null and b/.yarn/cache/@smithy-util-middleware-npm-3.0.7-d57fadc553-ed1f9751d6.zip differ diff --git a/.yarn/cache/@smithy-util-retry-npm-3.0.7-f085ce455f-8af7ed849a.zip b/.yarn/cache/@smithy-util-retry-npm-3.0.7-f085ce455f-8af7ed849a.zip new file mode 100644 index 0000000000..a4440e1a2e Binary files /dev/null and b/.yarn/cache/@smithy-util-retry-npm-3.0.7-f085ce455f-8af7ed849a.zip differ diff --git a/.yarn/cache/@smithy-util-stream-npm-3.1.9-3c37633105-4a97777420.zip b/.yarn/cache/@smithy-util-stream-npm-3.1.9-3c37633105-4a97777420.zip new file mode 100644 index 0000000000..77672a8bc9 Binary files /dev/null and b/.yarn/cache/@smithy-util-stream-npm-3.1.9-3c37633105-4a97777420.zip differ diff --git a/.yarn/cache/@smithy-util-uri-escape-npm-3.0.0-aa29683710-d7ee01c978.zip b/.yarn/cache/@smithy-util-uri-escape-npm-3.0.0-aa29683710-d7ee01c978.zip new file mode 100644 index 0000000000..2fcf8cd7d4 Binary files /dev/null and b/.yarn/cache/@smithy-util-uri-escape-npm-3.0.0-aa29683710-d7ee01c978.zip differ diff --git a/.yarn/cache/@smithy-util-utf8-npm-2.3.0-9dcba0d35f-00e55d4b4e.zip b/.yarn/cache/@smithy-util-utf8-npm-2.3.0-9dcba0d35f-00e55d4b4e.zip new file mode 100644 index 0000000000..754531dd65 Binary files /dev/null and b/.yarn/cache/@smithy-util-utf8-npm-2.3.0-9dcba0d35f-00e55d4b4e.zip differ diff --git a/.yarn/cache/@smithy-util-utf8-npm-3.0.0-1695d28ad7-d97be17489.zip b/.yarn/cache/@smithy-util-utf8-npm-3.0.0-1695d28ad7-d97be17489.zip new file mode 100644 index 0000000000..caae6eb178 Binary files /dev/null and b/.yarn/cache/@smithy-util-utf8-npm-3.0.0-1695d28ad7-d97be17489.zip differ diff --git a/.yarn/cache/@smithy-util-waiter-npm-3.1.6-0957b0160d-8375e3530c.zip b/.yarn/cache/@smithy-util-waiter-npm-3.1.6-0957b0160d-8375e3530c.zip new file mode 100644 index 0000000000..3c552efeb4 Binary files /dev/null and b/.yarn/cache/@smithy-util-waiter-npm-3.1.6-0957b0160d-8375e3530c.zip differ diff --git a/.yarn/cache/bowser-npm-2.11.0-33664d9063-29c3f01f22.zip b/.yarn/cache/bowser-npm-2.11.0-33664d9063-29c3f01f22.zip new file mode 100644 index 0000000000..7860319da0 Binary files /dev/null and b/.yarn/cache/bowser-npm-2.11.0-33664d9063-29c3f01f22.zip differ diff --git a/apps/web/package.json b/apps/web/package.json index dc690b17e2..ea7689ec52 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -31,6 +31,8 @@ "@serlo/katex-styles": "1.0.1" }, "dependencies": { + "@aws-sdk/client-s3": "^3.670.0", + "@aws-sdk/s3-request-presigner": "^3.670.0", "@cortex-js/compute-engine": "^0.22.0", "@fortawesome/fontawesome-svg-core": "6.5.2", "@fortawesome/free-brands-svg-icons": "6.5.2", diff --git a/apps/web/src/pages/api/media/presigned-url.ts b/apps/web/src/pages/api/media/presigned-url.ts new file mode 100644 index 0000000000..c2e614125d --- /dev/null +++ b/apps/web/src/pages/api/media/presigned-url.ts @@ -0,0 +1,77 @@ +import { + PutObjectCommand, + PutObjectCommandInput, + S3Client, +} from '@aws-sdk/client-s3' +import { getSignedUrl } from '@aws-sdk/s3-request-presigner' +import { NextApiRequest, NextApiResponse } from 'next/types' +import { v1 as uuidv1 } from 'uuid' + +const supportedMimeTypes = [ + 'image/gif', + 'image/jpeg', + 'image/png', + 'image/svg+xml', + 'image/webp', +] as const +type SupportedMimeType = (typeof supportedMimeTypes)[number] + +// minIO test credentials as fallback +const bucket = process.env.BUCKET_NAME ?? 'serlo-test-bucket' + +const s3Client = new S3Client({ + region: process.env.BUCKET_REGION ?? 'us-east-1', + credentials: { + accessKeyId: process.env.BUCKET_ACCESS_KEY_ID ?? 'Q3AM3UQ867SPQQA43P2F', + secretAccessKey: + process.env.BUCKET_SECRET_ACCESS_KEY ?? + 'zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG', + }, + endpoint: process.env.BUCKET_ENDPOINT ?? 'https://play.min.io:9000', + forcePathStyle: true, // test, maybe only set on dev +}) + +const srcPrefix = + process.env.BUCKET_PUBLIC_SRC_PREFIX ?? `https://play.min.io:9000/${bucket}/` + +export const getPresignedUrl = async (mimeType: SupportedMimeType) => { + const fileHash = uuidv1() + const fileExtension = + mimeType === 'image/svg+xml' ? 'svg' : mimeType.replace('image/', '') + const fileName = `${fileHash}.${fileExtension}` + + const params: PutObjectCommandInput = { + Key: `${fileHash}.${fileExtension}`, + Bucket: bucket, + ContentType: mimeType, + Metadata: { 'Content-Type': mimeType }, + } + + const command = new PutObjectCommand(params) + const signedUrl = await getSignedUrl(s3Client, command, { expiresIn: 3600 }) + const imgSrc = `${srcPrefix}${fileName}` + return { signedUrl, imgSrc } +} + +export function isValidMimeType( + mimeType: string +): mimeType is SupportedMimeType { + if (typeof mimeType !== 'string') return false + return supportedMimeTypes.includes(mimeType as SupportedMimeType) +} + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + const mimeType = decodeURIComponent(String(req.query.mimeType)) + + if (!isValidMimeType(mimeType)) { + return res.send( + 'Missing or invalid query parameter mimeType. Please provide one of: gif, jpeg, png, svg+xml, webp' + ) + } + + const response = await getPresignedUrl(mimeType) + res.send(response) +} diff --git a/apps/web/src/serlo-editor-integration/create-plugins.tsx b/apps/web/src/serlo-editor-integration/create-plugins.tsx index df59c9c269..19733d1af6 100644 --- a/apps/web/src/serlo-editor-integration/create-plugins.tsx +++ b/apps/web/src/serlo-editor-integration/create-plugins.tsx @@ -11,6 +11,7 @@ import { exercisePlugin } from '@editor/plugins/exercise' import { exerciseGroupPlugin } from '@editor/plugins/exercise-group' import { geoGebraPlugin } from '@editor/plugins/geogebra' import { createHighlightPlugin } from '@editor/plugins/highlight' +import { createImagePlugin } from '@editor/plugins/image' import { createImageGalleryPlugin } from '@editor/plugins/image-gallery' import { injectionPlugin } from '@editor/plugins/injection' import { createInputExercisePlugin } from '@editor/plugins/input-exercise' @@ -44,7 +45,6 @@ import { TemplatePluginType } from '@editor/types/template-plugin-type' import { Instance } from '@/fetcher/graphql-types/operations' import { isProduction } from '@/helper/is-production' import { H5pPlugin } from '@/serlo-editor-integration/h5p' -import { imagePlugin } from '@/serlo-editor-integration/image-with-serlo-config' export function createPlugins({ lang }: { lang: Instance }): PluginsWithData { const plugins = [ @@ -98,7 +98,7 @@ export function createPlugins({ lang }: { lang: Instance }): PluginsWithData { const allPlugins = [ { type: EditorPluginType.Text, plugin: createTextPlugin({}) }, - { type: EditorPluginType.Image, plugin: imagePlugin }, + { type: EditorPluginType.Image, plugin: createImagePlugin({}) }, { type: EditorPluginType.ImageGallery, plugin: createImageGalleryPlugin() }, { type: EditorPluginType.Multimedia, diff --git a/apps/web/src/serlo-editor-integration/image-with-serlo-config.ts b/apps/web/src/serlo-editor-integration/image-with-serlo-config.ts deleted file mode 100644 index 5590b1101a..0000000000 --- a/apps/web/src/serlo-editor-integration/image-with-serlo-config.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { LoadedFile, UploadValidator } from '@editor/plugin' -import { createImagePlugin } from '@editor/plugins/image' -import { gql } from 'graphql-request' - -import { createAuthAwareGraphqlFetch } from '@/api/graphql-fetch' -import { getAuthPayloadFromSession } from '@/auth/auth-provider' -import { fetchAndPersistAuthSession } from '@/auth/cookie/fetch-and-persist-auth-session' -import { MediaType, MediaUploadQuery } from '@/fetcher/graphql-types/operations' -import { showToastNotice } from '@/helper/show-toast-notice' - -const maxFileSize = 2 * 1024 * 1024 -const allowedExtensions = ['gif', 'jpg', 'jpeg', 'png', 'svg', 'webp'] -const supportedMimeTypes = [ - 'image/gif', - 'image/jpeg', - 'image/png', - 'image/svg+xml', - 'image/webp', -] as const - -type SupportedMimeType = (typeof supportedMimeTypes)[number] - -const mimeTypesToMediaType: Record = { - 'image/gif': MediaType.ImageGif, - 'image/jpeg': MediaType.ImageJpeg, - 'image/png': MediaType.ImagePng, - 'image/svg+xml': MediaType.ImageSvgXml, - 'image/webp': MediaType.ImageWebp, -} - -enum FileErrorCode { - TOO_MANY_FILES, - NO_FILE_SELECTED, - BAD_EXTENSION, - FILE_TOO_BIG, - UPLOAD_FAILED, -} - -export interface FileError { - errorCode: FileErrorCode - message: string -} - -const validateFile: UploadValidator = (file) => { - let uploadErrors: FileErrorCode[] = [] - - if (!file) { - uploadErrors = [...uploadErrors, FileErrorCode.NO_FILE_SELECTED] - } else if (!matchesAllowedExtensions(file.name)) { - uploadErrors = [...uploadErrors, FileErrorCode.BAD_EXTENSION] - } else if (file.size > maxFileSize) { - uploadErrors = [...uploadErrors, FileErrorCode.FILE_TOO_BIG] - } else { - return { valid: true } - } - - return { valid: false, errors: handleErrors(uploadErrors) } -} - -export const imagePlugin = createImagePlugin({ - upload: createUploadImageHandler(), - validate: validateFile, -}) - -function createUploadImageHandler() { - const readFile = createReadFile() - return async function uploadImageHandler(file: File): Promise { - const validation = validateFile(file) - if (!validation.valid) { - onError(validation.errors) - return Promise.reject(validation.errors) - } - - return (await readFile(file)).dataUrl - } -} - -export function createReadFile() { - return async function readFile(file: File): Promise { - return new Promise((resolve, reject) => { - fetchAndPersistAuthSession() - .then((session) => { - const gqlFetch = createAuthAwareGraphqlFetch( - getAuthPayloadFromSession(session) - ) - const args = JSON.stringify({ - query: uploadUrlQuery, - variables: { - mediaType: mimeTypesToMediaType[file.type as SupportedMimeType], - }, - }) - - async function runFetch() { - const data = (await gqlFetch(args)) as MediaUploadQuery - const reader = new FileReader() - - reader.onload = async function (e: ProgressEvent) { - if (!e.target) return - - try { - const response = await fetch(data.media.newUpload.uploadUrl, { - method: 'PUT', - headers: { 'Content-Type': file.type }, - body: file, - }) - - if (response.status !== 200) reject() - resolve({ - file, - dataUrl: data.media.newUpload.urlAfterUpload, - }) - } catch { - reject() - } - } - - reader.readAsDataURL(file) - } - - void runFetch() - }) - .catch(() => { - reject() - }) - }) - } -} - -function matchesAllowedExtensions(fileName: string) { - const extension = fileName.toLowerCase().slice(fileName.lastIndexOf('.') + 1) - return allowedExtensions.includes(extension) -} - -function handleErrors(errors: FileErrorCode[]): FileError[] { - return errors.map((error) => ({ - errorCode: error, - message: errorCodeToMessage(error), - })) -} - -function onError(errors: FileError[]): void { - showToastNotice(errors.map((error) => error.message).join('\n'), 'warning') -} - -function errorCodeToMessage(error: FileErrorCode) { - switch (error) { - case FileErrorCode.TOO_MANY_FILES: - return 'You can only upload one file' - case FileErrorCode.NO_FILE_SELECTED: - return 'No file selected' - case FileErrorCode.BAD_EXTENSION: - return 'Not an accepted file type' - case FileErrorCode.FILE_TOO_BIG: - return 'Filesize is too big' - case FileErrorCode.UPLOAD_FAILED: - return 'Error while uploading' - } -} - -const uploadUrlQuery = gql` - query mediaUpload($mediaType: MediaType!) { - media { - newUpload(mediaType: $mediaType) { - uploadUrl - urlAfterUpload - } - } - } -` diff --git a/packages/editor-web-component/src/editor-web-component.tsx b/packages/editor-web-component/src/editor-web-component.tsx index 64d0297fb0..6ba22619a9 100644 --- a/packages/editor-web-component/src/editor-web-component.tsx +++ b/packages/editor-web-component/src/editor-web-component.tsx @@ -30,8 +30,6 @@ export class EditorWebComponent extends HTMLElement { private _initialState: InitialState = exampleInitialState private _currentState: unknown - private _testingSecret: string | null = null - private _editorVariant: EditorVariant = 'unknown' // By default, we are NOT attaching it to the shadow DOM @@ -113,14 +111,6 @@ export class EditorWebComponent extends HTMLElement { return this._history } - get testingSecret(): string | null { - return this._testingSecret - } - - set testingSecret(newTestingSecret) { - if (newTestingSecret) this.setAttribute('testing-secret', newTestingSecret) - } - get editorVariant(): EditorVariant { return this._editorVariant } @@ -167,7 +157,6 @@ export class EditorWebComponent extends HTMLElement { mountReactComponent() { const initialStateAttr = this.getAttribute('initial-state') - const testingSecretAttr = this.getAttribute('testing-secret') // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const initialState: InitialState = initialStateAttr @@ -193,7 +182,6 @@ export class EditorWebComponent extends HTMLElement { { this._currentState = newState this.broadcastNewState(newState) diff --git a/packages/editor/src/editor-integration/create-basic-plugins.tsx b/packages/editor/src/editor-integration/create-basic-plugins.tsx index 654026873a..5a5c5bf0d9 100644 --- a/packages/editor/src/editor-integration/create-basic-plugins.tsx +++ b/packages/editor/src/editor-integration/create-basic-plugins.tsx @@ -6,6 +6,7 @@ import { equationsPlugin } from '@editor/plugins/equations' import { exercisePlugin } from '@editor/plugins/exercise' import { geoGebraPlugin } from '@editor/plugins/geogebra' import { createHighlightPlugin } from '@editor/plugins/highlight' +import { createImagePlugin } from '@editor/plugins/image' import { createImageGalleryPlugin } from '@editor/plugins/image-gallery' import { createInputExercisePlugin } from '@editor/plugins/input-exercise' import { createMultimediaPlugin } from '@editor/plugins/multimedia' @@ -23,37 +24,22 @@ import { unsupportedPlugin } from '@editor/plugins/unsupported' import { EditorPluginType } from '@editor/types/editor-plugin-type' import { TemplatePluginType } from '@editor/types/template-plugin-type' -import { createTestingImagePlugin } from './image-with-testing-config' - export function createBasicPlugins( - plugins: (EditorPluginType | TemplatePluginType)[], - testingSecret?: string | null + plugins: (EditorPluginType | TemplatePluginType)[] ) { - if (plugins.includes(EditorPluginType.Image) && !testingSecret) { - /* eslint-disable no-console */ - console.log( - 'The image plugin needs the `testingSecret` but it is missing. Image plugin was disabled. Either provide it or deactivate the image plugin in the editor API.' - ) - plugins = plugins.filter((plugin) => plugin !== EditorPluginType.Image) - } - const allPlugins = [ { type: EditorPluginType.Text, plugin: createTextPlugin({}), }, - ...(testingSecret - ? [ - { - type: EditorPluginType.Image, - plugin: createTestingImagePlugin(testingSecret), - }, - { - type: EditorPluginType.ImageGallery, - plugin: createImageGalleryPlugin(), - }, - ] - : []), + { + type: EditorPluginType.Image, + plugin: createImagePlugin({}), + }, + { + type: EditorPluginType.ImageGallery, + plugin: createImageGalleryPlugin(), + }, { type: EditorPluginType.Multimedia, plugin: createMultimediaPlugin(plugins), diff --git a/packages/editor/src/editor-integration/image-with-testing-config.ts b/packages/editor/src/editor-integration/image-with-testing-config.ts deleted file mode 100644 index 52635f2dbf..0000000000 --- a/packages/editor/src/editor-integration/image-with-testing-config.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { showToastNotice } from '@editor/editor-ui/show-toast-notice' -import type { LoadedFile, UploadValidator } from '@editor/plugin' -import { createImagePlugin } from '@editor/plugins/image' - -interface MediaUploadQuery { - __typename?: 'Query' - media: { - __typename?: 'MediaQuery' - newUpload: { - __typename?: 'MediaUpload' - uploadUrl: string - urlAfterUpload: string - } - } -} - -enum MediaType { - ImageGif = 'IMAGE_GIF', - ImageJpeg = 'IMAGE_JPEG', - ImagePng = 'IMAGE_PNG', - ImageSvgXml = 'IMAGE_SVG_XML', - ImageWebp = 'IMAGE_WEBP', -} - -const maxFileSize = 2 * 1024 * 1024 -const allowedExtensions = ['gif', 'jpg', 'jpeg', 'png', 'svg', 'webp'] -const supportedMimeTypes = [ - 'image/gif', - 'image/jpeg', - 'image/png', - 'image/svg+xml', - 'image/webp', -] as const - -type SupportedMimeType = (typeof supportedMimeTypes)[number] - -const mimeTypesToMediaType: Record = { - 'image/gif': MediaType.ImageGif, - 'image/jpeg': MediaType.ImageJpeg, - 'image/png': MediaType.ImagePng, - 'image/svg+xml': MediaType.ImageSvgXml, - 'image/webp': MediaType.ImageWebp, -} - -enum FileErrorCode { - TOO_MANY_FILES, - NO_FILE_SELECTED, - BAD_EXTENSION, - FILE_TOO_BIG, - UPLOAD_FAILED, -} - -export interface FileError { - errorCode: FileErrorCode - message: string -} - -const validateFile: UploadValidator = (file) => { - let uploadErrors: FileErrorCode[] = [] - - if (!file) { - uploadErrors = [...uploadErrors, FileErrorCode.NO_FILE_SELECTED] - } else if (!matchesAllowedExtensions(file.name)) { - uploadErrors = [...uploadErrors, FileErrorCode.BAD_EXTENSION] - } else if (file.size > maxFileSize) { - uploadErrors = [...uploadErrors, FileErrorCode.FILE_TOO_BIG] - } else { - return { valid: true } - } - - return { valid: false, errors: handleErrors(uploadErrors) } -} - -export const createTestingImagePlugin = (secret: string) => { - return createImagePlugin({ - upload: createUploadImageHandler(secret), - validate: validateFile, - }) -} - -function createUploadImageHandler(secret: string) { - const readFile = createReadFile(secret) - return async function uploadImageHandler(file: File): Promise { - const validation = validateFile(file) - if (!validation.valid) { - onError(validation.errors) - return Promise.reject(validation.errors) - } - - return (await readFile(file)).dataUrl - } -} - -export function createReadFile(secret: string) { - return async function readFile(file: File): Promise { - return new Promise((resolve, reject) => { - async function runFetch() { - const endpoint = 'https://api.serlo-staging.dev/graphql' - const response = await fetch(endpoint, { - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - 'X-SERLO-EDITOR-TESTING': secret, - }, - method: 'POST', - body: JSON.stringify({ - query: uploadUrlQuery, - variables: { - mediaType: mimeTypesToMediaType[file.type as SupportedMimeType], - }, - }), - }) - const { data } = (await response.json()) as { data: MediaUploadQuery } - const reader = new FileReader() - - reader.onload = async function (e: ProgressEvent) { - if (!e.target) return - - try { - const response = await fetch(data.media.newUpload.uploadUrl, { - method: 'PUT', - headers: { 'Content-Type': file.type }, - body: file, - }) - - if (response.status !== 200) reject() - resolve({ - file, - dataUrl: data.media.newUpload.urlAfterUpload, - }) - } catch { - reject() - } - } - - reader.readAsDataURL(file) - } - - void runFetch() - }) - } -} - -function matchesAllowedExtensions(fileName: string) { - const extension = fileName.toLowerCase().slice(fileName.lastIndexOf('.') + 1) - return allowedExtensions.includes(extension) -} - -function handleErrors(errors: FileErrorCode[]): FileError[] { - return errors.map((error) => ({ - errorCode: error, - message: errorCodeToMessage(error), - })) -} - -function onError(errors: FileError[]): void { - showToastNotice(errors.map((error) => error.message).join('\n'), 'warning') -} - -function errorCodeToMessage(error: FileErrorCode) { - switch (error) { - case FileErrorCode.TOO_MANY_FILES: - return 'You can only upload one file' - case FileErrorCode.NO_FILE_SELECTED: - return 'No file selected' - case FileErrorCode.BAD_EXTENSION: - return 'Not an accepted file type' - case FileErrorCode.FILE_TOO_BIG: - return 'Filesize is too big' - case FileErrorCode.UPLOAD_FAILED: - return 'Error while uploading' - } -} - -/** - * This marker is used by https://github.com/serlo/unused-graphql-properties - * to detect graphql statements. - */ -function gql(strings: TemplateStringsArray, ...expr: string[]): string { - return strings.reduce((result, str, i) => { - return result + expr[i - 1] + str - }) -} - -const uploadUrlQuery = gql` - query mediaUpload($mediaType: MediaType!) { - media { - newUpload(mediaType: $mediaType) { - uploadUrl - urlAfterUpload - } - } - } -` diff --git a/packages/editor/src/package/editor.tsx b/packages/editor/src/package/editor.tsx index 1b79cb73fc..2ee41d58c6 100644 --- a/packages/editor/src/package/editor.tsx +++ b/packages/editor/src/package/editor.tsx @@ -31,21 +31,12 @@ export interface SerloEditorProps { onChange?: (state: StorageFormat) => void language?: SupportedLanguage editorVariant: EditorVariant - _testingSecret?: string | null _ltik?: string } /** For exporting the editor */ export function SerloEditor(props: SerloEditorProps) { - const { - children, - editorVariant, - onChange, - language, - plugins, - _testingSecret, - _ltik, - } = { + const { children, editorVariant, onChange, language, plugins, _ltik } = { ...defaultSerloEditorProps, ...props, } @@ -62,7 +53,7 @@ export function SerloEditor(props: SerloEditorProps) { const { staticStrings, editStrings } = editorData[language] - const allPlugins = createBasicPlugins(plugins, _testingSecret) + const allPlugins = createBasicPlugins(plugins) editorPlugins.init(allPlugins) const basicRenderers = createRenderers() diff --git a/packages/editor/src/plugins/image/controls/upload-button.tsx b/packages/editor/src/plugins/image/controls/upload-button.tsx index 33dda7c6c0..833dd55385 100644 --- a/packages/editor/src/plugins/image/controls/upload-button.tsx +++ b/packages/editor/src/plugins/image/controls/upload-button.tsx @@ -10,6 +10,7 @@ import { import { useState } from 'react' import type { ImageProps } from '..' +import { uploadFile } from '../utils/upload-file' interface UploadButtonProps { config: ImageProps['config'] @@ -64,7 +65,7 @@ export function UploadButton({ const filesArray = Array.from(target.files) // Upload the first file like normal - void src.upload(filesArray[0], config.upload) + void src.upload(filesArray[0], uploadFile) // If multiple upload is allowed, call the multiple upload callback // with the remaining files @@ -82,7 +83,7 @@ export function UploadButton({