@adtrackify/at-service-common 3.17.8 → 3.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/__tests__/clients/sqs-bundled-client.spec.d.ts +1 -0
- package/dist/cjs/__tests__/clients/sqs-bundled-client.spec.js +909 -0
- package/dist/cjs/__tests__/clients/sqs-bundled-client.spec.js.map +1 -0
- package/dist/cjs/__tests__/clients/sqs-client.spec.d.ts +1 -1
- package/dist/cjs/__tests__/clients/sqs-client.spec.js +194 -121
- package/dist/cjs/__tests__/clients/sqs-client.spec.js.map +1 -1
- package/dist/cjs/__tests__/clients/sqs-unbundle.spec.d.ts +1 -0
- package/dist/cjs/__tests__/clients/sqs-unbundle.spec.js +788 -0
- package/dist/cjs/__tests__/clients/sqs-unbundle.spec.js.map +1 -0
- package/dist/cjs/__tests__/db/shared-read-db-services.spec.d.ts +1 -1
- package/dist/cjs/__tests__/db/shared-read-db-services.spec.js +89 -89
- package/dist/cjs/__tests__/helpers/account-users-helper.spec.d.ts +1 -1
- package/dist/cjs/__tests__/helpers/account-users-helper.spec.js +220 -220
- package/dist/cjs/__tests__/helpers/api-key-auth-helper.spec.d.ts +1 -1
- package/dist/cjs/__tests__/helpers/api-key-auth-helper.spec.js +74 -74
- package/dist/cjs/__tests__/identity-cache/identity-cache-db-service.spec.d.ts +1 -1
- package/dist/cjs/__tests__/identity-cache/identity-cache-db-service.spec.js +674 -674
- package/dist/cjs/__tests__/identity-cache/trait-merging-and-staleness.spec.d.ts +1 -1
- package/dist/cjs/__tests__/identity-cache/trait-merging-and-staleness.spec.js +588 -588
- package/dist/cjs/__tests__/integration/sqs-bundling-roundtrip.spec.d.ts +1 -0
- package/dist/cjs/__tests__/integration/sqs-bundling-roundtrip.spec.js +582 -0
- package/dist/cjs/__tests__/integration/sqs-bundling-roundtrip.spec.js.map +1 -0
- package/dist/cjs/__tests__/libs/compress-decompress.spec.d.ts +1 -1
- package/dist/cjs/__tests__/libs/compress-decompress.spec.js +16 -16
- package/dist/cjs/__tests__/libs/currency.spec.d.ts +1 -1
- package/dist/cjs/__tests__/libs/currency.spec.js +220 -220
- package/dist/cjs/__tests__/libs/dates.spec.d.ts +1 -1
- package/dist/cjs/__tests__/libs/dates.spec.js +130 -130
- package/dist/cjs/__tests__/libs/domain.spec.d.ts +1 -1
- package/dist/cjs/__tests__/libs/domain.spec.js +107 -107
- package/dist/cjs/__tests__/libs/numbers.spec.d.ts +1 -1
- package/dist/cjs/__tests__/libs/numbers.spec.js +261 -261
- package/dist/cjs/__tests__/s3-client/s3-client.spec.d.ts +1 -1
- package/dist/cjs/__tests__/s3-client/s3-client.spec.js +33 -33
- package/dist/cjs/__tests__/shopify/shopify-graphql-transformer.spec.d.ts +1 -1
- package/dist/cjs/__tests__/shopify/shopify-graphql-transformer.spec.js +35 -35
- package/dist/cjs/__tests__/unit/libs/api-router/public-api-router.spec.d.ts +1 -1
- package/dist/cjs/__tests__/unit/libs/api-router/public-api-router.spec.js +197 -197
- package/dist/cjs/__tests__/unit/libs/api-router/route-matcher.spec.d.ts +1 -1
- package/dist/cjs/__tests__/unit/libs/api-router/route-matcher.spec.js +69 -69
- package/dist/cjs/clients/generic/cognito-client.d.ts +23 -23
- package/dist/cjs/clients/generic/cognito-client.js +209 -209
- package/dist/cjs/clients/generic/dynamodb-client.d.ts +18 -18
- package/dist/cjs/clients/generic/dynamodb-client.js +172 -172
- package/dist/cjs/clients/generic/eventbridge-client.d.ts +14 -14
- package/dist/cjs/clients/generic/eventbridge-client.js +51 -51
- package/dist/cjs/clients/generic/http-client.d.ts +14 -14
- package/dist/cjs/clients/generic/http-client.js +61 -61
- package/dist/cjs/clients/generic/index.d.ts +13 -10
- package/dist/cjs/clients/generic/index.js +29 -26
- package/dist/cjs/clients/generic/index.js.map +1 -1
- package/dist/cjs/clients/generic/lambda-invoke-client.d.ts +10 -10
- package/dist/cjs/clients/generic/lambda-invoke-client.js +39 -39
- package/dist/cjs/clients/generic/location-client.d.ts +8 -8
- package/dist/cjs/clients/generic/location-client.js +31 -31
- package/dist/cjs/clients/generic/redis-client.d.ts +33 -33
- package/dist/cjs/clients/generic/redis-client.js +191 -191
- package/dist/cjs/clients/generic/s3-client.d.ts +23 -23
- package/dist/cjs/clients/generic/s3-client.js +216 -216
- package/dist/cjs/clients/generic/singlestore-db-client.d.ts +14 -14
- package/dist/cjs/clients/generic/singlestore-db-client.js +67 -67
- package/dist/cjs/clients/generic/sqs-bundled-client.d.ts +15 -0
- package/dist/cjs/clients/generic/sqs-bundled-client.js +278 -0
- package/dist/cjs/clients/generic/sqs-bundled-client.js.map +1 -0
- package/dist/cjs/clients/generic/sqs-bundled-client.types.d.ts +52 -0
- package/dist/cjs/clients/generic/sqs-bundled-client.types.js +17 -0
- package/dist/cjs/clients/generic/sqs-bundled-client.types.js.map +1 -0
- package/dist/cjs/clients/generic/sqs-client.d.ts +48 -33
- package/dist/cjs/clients/generic/sqs-client.js +273 -111
- package/dist/cjs/clients/generic/sqs-client.js.map +1 -1
- package/dist/cjs/clients/generic/sqs-unbundle.d.ts +32 -0
- package/dist/cjs/clients/generic/sqs-unbundle.js +145 -0
- package/dist/cjs/clients/generic/sqs-unbundle.js.map +1 -0
- package/dist/cjs/clients/index.d.ts +3 -3
- package/dist/cjs/clients/index.js +19 -19
- package/dist/cjs/clients/internal-api/accounts-client.d.ts +91 -91
- package/dist/cjs/clients/internal-api/accounts-client.js +129 -129
- package/dist/cjs/clients/internal-api/cache-lambda-client.d.ts +26 -26
- package/dist/cjs/clients/internal-api/cache-lambda-client.js +89 -89
- package/dist/cjs/clients/internal-api/db-management-client.d.ts +18 -18
- package/dist/cjs/clients/internal-api/db-management-client.js +36 -36
- package/dist/cjs/clients/internal-api/destinations-client.d.ts +34 -34
- package/dist/cjs/clients/internal-api/destinations-client.js +79 -79
- package/dist/cjs/clients/internal-api/event-collector-client.d.ts +20 -20
- package/dist/cjs/clients/internal-api/event-collector-client.js +36 -36
- package/dist/cjs/clients/internal-api/identity-client.d.ts +31 -31
- package/dist/cjs/clients/internal-api/identity-client.js +91 -91
- package/dist/cjs/clients/internal-api/index.d.ts +9 -9
- package/dist/cjs/clients/internal-api/index.js +25 -25
- package/dist/cjs/clients/internal-api/shopify-app-install-client.d.ts +37 -37
- package/dist/cjs/clients/internal-api/shopify-app-install-client.js +81 -81
- package/dist/cjs/clients/internal-api/subscriptions-client.d.ts +26 -26
- package/dist/cjs/clients/internal-api/subscriptions-client.js +77 -77
- package/dist/cjs/clients/internal-api/users-auth-client.d.ts +35 -35
- package/dist/cjs/clients/internal-api/users-auth-client.js +110 -110
- package/dist/cjs/clients/third-party/emailable-client.d.ts +7 -7
- package/dist/cjs/clients/third-party/emailable-client.js +25 -25
- package/dist/cjs/clients/third-party/exchange-rate-api-client.d.ts +17 -17
- package/dist/cjs/clients/third-party/exchange-rate-api-client.js +19 -19
- package/dist/cjs/clients/third-party/index.d.ts +4 -4
- package/dist/cjs/clients/third-party/index.js +20 -20
- package/dist/cjs/clients/third-party/loops-client.d.ts +10 -10
- package/dist/cjs/clients/third-party/loops-client.js +30 -30
- package/dist/cjs/clients/third-party/shopify/graphql-order-queries.d.ts +25 -25
- package/dist/cjs/clients/third-party/shopify/graphql-order-queries.js +30 -30
- package/dist/cjs/clients/third-party/shopify/graphql-product-queries.d.ts +2 -2
- package/dist/cjs/clients/third-party/shopify/graphql-product-queries.js +180 -180
- package/dist/cjs/clients/third-party/shopify/shopify-graphql-client.d.ts +10 -10
- package/dist/cjs/clients/third-party/shopify/shopify-graphql-client.js +161 -161
- package/dist/cjs/clients/third-party/shopify-client.d.ts +29 -29
- package/dist/cjs/clients/third-party/shopify-client.js +146 -146
- package/dist/cjs/constants/index.d.ts +1 -0
- package/dist/cjs/constants/index.js +18 -0
- package/dist/cjs/constants/index.js.map +1 -0
- package/dist/cjs/constants/sqs.d.ts +11 -0
- package/dist/cjs/constants/sqs.js +15 -0
- package/dist/cjs/constants/sqs.js.map +1 -0
- package/dist/cjs/helpers/account-users-helper.d.ts +2 -2
- package/dist/cjs/helpers/account-users-helper.js +22 -22
- package/dist/cjs/helpers/api-key-auth-helper.d.ts +9 -9
- package/dist/cjs/helpers/api-key-auth-helper.js +40 -40
- package/dist/cjs/helpers/api-key-authorizer-helper.d.ts +36 -36
- package/dist/cjs/helpers/api-key-authorizer-helper.js +85 -85
- package/dist/cjs/helpers/identity-cache-helper.d.ts +21 -21
- package/dist/cjs/helpers/identity-cache-helper.js +156 -156
- package/dist/cjs/helpers/index.d.ts +9 -9
- package/dist/cjs/helpers/index.js +25 -25
- package/dist/cjs/helpers/input-validation-helper.d.ts +3 -3
- package/dist/cjs/helpers/input-validation-helper.js +22 -22
- package/dist/cjs/helpers/logging-helper.d.ts +16 -16
- package/dist/cjs/helpers/logging-helper.js +84 -84
- package/dist/cjs/helpers/response-helper.d.ts +18 -18
- package/dist/cjs/helpers/response-helper.js +43 -43
- package/dist/cjs/helpers/shopify-helper.d.ts +9 -9
- package/dist/cjs/helpers/shopify-helper.js +26 -26
- package/dist/cjs/helpers/sqs-utils.d.ts +6 -6
- package/dist/cjs/helpers/sqs-utils.js +14 -14
- package/dist/cjs/index.d.ts +7 -5
- package/dist/cjs/index.js +23 -21
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/libs/api-router/index.d.ts +2 -2
- package/dist/cjs/libs/api-router/index.js +18 -18
- package/dist/cjs/libs/api-router/public-api-router.d.ts +3 -3
- package/dist/cjs/libs/api-router/public-api-router.js +36 -36
- package/dist/cjs/libs/api-router/route-matcher.d.ts +21 -21
- package/dist/cjs/libs/api-router/route-matcher.js +36 -36
- package/dist/cjs/libs/click-id-parser.d.ts +23 -23
- package/dist/cjs/libs/click-id-parser.js +49 -49
- package/dist/cjs/libs/compression.d.ts +2 -2
- package/dist/cjs/libs/compression.js +33 -33
- package/dist/cjs/libs/cookie.d.ts +17 -17
- package/dist/cjs/libs/cookie.js +76 -76
- package/dist/cjs/libs/crypto.d.ts +4 -4
- package/dist/cjs/libs/crypto.js +25 -25
- package/dist/cjs/libs/csv.d.ts +2 -2
- package/dist/cjs/libs/csv.js +35 -35
- package/dist/cjs/libs/currency.d.ts +1 -1
- package/dist/cjs/libs/currency.js +29 -29
- package/dist/cjs/libs/dates.d.ts +12 -12
- package/dist/cjs/libs/dates.js +96 -96
- package/dist/cjs/libs/domain.d.ts +2 -2
- package/dist/cjs/libs/domain.js +38 -38
- package/dist/cjs/libs/emails.d.ts +6 -6
- package/dist/cjs/libs/emails.js +122 -122
- package/dist/cjs/libs/http-error.d.ts +21 -21
- package/dist/cjs/libs/http-error.js +63 -63
- package/dist/cjs/libs/http-status-codes.d.ts +58 -58
- package/dist/cjs/libs/http-status-codes.js +62 -62
- package/dist/cjs/libs/index.d.ts +18 -18
- package/dist/cjs/libs/index.js +34 -34
- package/dist/cjs/libs/numbers.d.ts +1 -1
- package/dist/cjs/libs/numbers.js +15 -15
- package/dist/cjs/libs/referrer-parser/index.d.ts +2 -2
- package/dist/cjs/libs/referrer-parser/index.js +18 -18
- package/dist/cjs/libs/referrer-parser/referrer-data.d.ts +9 -9
- package/dist/cjs/libs/referrer-parser/referrer-data.js +3307 -3307
- package/dist/cjs/libs/referrer-parser/referrer-parser-util.d.ts +20 -20
- package/dist/cjs/libs/referrer-parser/referrer-parser-util.js +131 -131
- package/dist/cjs/libs/strings.d.ts +3 -3
- package/dist/cjs/libs/strings.js +46 -46
- package/dist/cjs/libs/traits.d.ts +6 -6
- package/dist/cjs/libs/traits.js +65 -65
- package/dist/cjs/libs/url.d.ts +1 -1
- package/dist/cjs/libs/url.js +13 -13
- package/dist/cjs/services/cache/generic-cached-object.d.ts +5 -5
- package/dist/cjs/services/cache/generic-cached-object.js +2 -2
- package/dist/cjs/services/cache/index.d.ts +1 -1
- package/dist/cjs/services/cache/index.js +17 -17
- package/dist/cjs/services/cache/product-cache-service.d.ts +21 -21
- package/dist/cjs/services/cache/product-cache-service.js +76 -76
- package/dist/cjs/services/currency-exchange-rate-lookup-service.d.ts +11 -11
- package/dist/cjs/services/currency-exchange-rate-lookup-service.js +66 -66
- package/dist/cjs/services/db/accounts-db-service.d.ts +9 -9
- package/dist/cjs/services/db/accounts-db-service.js +33 -33
- package/dist/cjs/services/db/api-keys-db-service.d.ts +10 -10
- package/dist/cjs/services/db/api-keys-db-service.js +36 -36
- package/dist/cjs/services/db/currency-exchange-rates-db-service.d.ts +21 -21
- package/dist/cjs/services/db/currency-exchange-rates-db-service.js +39 -39
- package/dist/cjs/services/db/destinations-db-service.d.ts +12 -12
- package/dist/cjs/services/db/destinations-db-service.js +76 -76
- package/dist/cjs/services/db/identity-cache-db-service.d.ts +28 -28
- package/dist/cjs/services/db/identity-cache-db-service.js +320 -320
- package/dist/cjs/services/db/index.d.ts +13 -13
- package/dist/cjs/services/db/index.js +29 -29
- package/dist/cjs/services/db/log-events-db-service.d.ts +11 -11
- package/dist/cjs/services/db/log-events-db-service.js +181 -181
- package/dist/cjs/services/db/pixels-db-service.d.ts +8 -8
- package/dist/cjs/services/db/pixels-db-service.js +35 -35
- package/dist/cjs/services/db/purchasable-contacts-db-service.d.ts +9 -9
- package/dist/cjs/services/db/purchasable-contacts-db-service.js +43 -43
- package/dist/cjs/services/db/purchased-contacts-db-service.d.ts +17 -17
- package/dist/cjs/services/db/purchased-contacts-db-service.js +143 -143
- package/dist/cjs/services/db/shopify-app-installs-db-service.d.ts +8 -8
- package/dist/cjs/services/db/shopify-app-installs-db-service.js +51 -51
- package/dist/cjs/services/db/shopify-products-cache-db-service.d.ts +16 -16
- package/dist/cjs/services/db/shopify-products-cache-db-service.js +73 -73
- package/dist/cjs/services/db/subscriptions-db-service.d.ts +10 -10
- package/dist/cjs/services/db/subscriptions-db-service.js +34 -34
- package/dist/cjs/services/db/tracking-events-db-service.d.ts +20 -20
- package/dist/cjs/services/db/tracking-events-db-service.js +165 -165
- package/dist/cjs/services/eventbridge-integration-service.d.ts +9 -9
- package/dist/cjs/services/eventbridge-integration-service.js +28 -28
- package/dist/cjs/services/events/index.d.ts +3 -3
- package/dist/cjs/services/events/index.js +19 -19
- package/dist/cjs/services/events/log-event-service.d.ts +9 -9
- package/dist/cjs/services/events/log-event-service.js +56 -56
- package/dist/cjs/services/events/metric-event-service.d.ts +9 -9
- package/dist/cjs/services/events/metric-event-service.js +49 -49
- package/dist/cjs/services/events/tracking-event-sqs-service.d.ts +8 -8
- package/dist/cjs/services/events/tracking-event-sqs-service.js +34 -34
- package/dist/cjs/services/generic-cache-service.d.ts +7 -7
- package/dist/cjs/services/generic-cache-service.js +33 -33
- package/dist/cjs/services/index.d.ts +8 -8
- package/dist/cjs/services/index.js +24 -24
- package/dist/cjs/services/ipdata-lookup-service.d.ts +20 -20
- package/dist/cjs/services/ipdata-lookup-service.js +112 -112
- package/dist/cjs/services/shopify/index.d.ts +2 -2
- package/dist/cjs/services/shopify/index.js +18 -18
- package/dist/cjs/services/shopify/products/index.d.ts +1 -1
- package/dist/cjs/services/shopify/products/index.js +17 -17
- package/dist/cjs/services/shopify/products/shopify-products-serviceV2.d.ts +17 -17
- package/dist/cjs/services/shopify/products/shopify-products-serviceV2.js +112 -112
- package/dist/cjs/services/shopify/shopify-graphql-transformer.d.ts +8 -8
- package/dist/cjs/services/shopify/shopify-graphql-transformer.js +141 -141
- package/dist/cjs/types/api-response.d.ts +6 -6
- package/dist/cjs/types/api-response.js +2 -2
- package/dist/cjs/types/index.d.ts +1 -1
- package/dist/cjs/types/index.js +17 -17
- package/dist/cjs/types/internal-events/event-detail-types.d.ts +20 -20
- package/dist/cjs/types/internal-events/event-detail-types.js +27 -27
- package/dist/cjs/types/internal-events/index.d.ts +1 -1
- package/dist/cjs/types/internal-events/index.js +17 -17
- package/dist/cjs/types/shopify-graphql-types/admin.generated.d.ts +123 -123
- package/dist/cjs/types/shopify-graphql-types/admin.generated.js +2 -2
- package/dist/cjs/types/shopify-graphql-types/admin.types.d.ts +26289 -26289
- package/dist/cjs/types/shopify-graphql-types/admin.types.js +5311 -5311
- package/dist/cjs/types/shopify-graphql-types/index.d.ts +2 -2
- package/dist/cjs/types/shopify-graphql-types/index.js +18 -18
- package/dist/cjs/utils/compression.d.ts +35 -0
- package/dist/cjs/utils/compression.js +177 -0
- package/dist/cjs/utils/compression.js.map +1 -0
- package/dist/cjs/utils/index.d.ts +3 -0
- package/dist/cjs/utils/index.js +20 -0
- package/dist/cjs/utils/index.js.map +1 -0
- package/dist/cjs/utils/retry-envelope.d.ts +12 -0
- package/dist/cjs/utils/retry-envelope.js +31 -0
- package/dist/cjs/utils/retry-envelope.js.map +1 -0
- package/dist/cjs/utils/size.d.ts +2 -0
- package/dist/cjs/utils/size.js +49 -0
- package/dist/cjs/utils/size.js.map +1 -0
- package/dist/esm/__tests__/clients/sqs-bundled-client.spec.d.ts +1 -0
- package/dist/esm/__tests__/clients/sqs-bundled-client.spec.js +884 -0
- package/dist/esm/__tests__/clients/sqs-bundled-client.spec.js.map +1 -0
- package/dist/esm/__tests__/clients/sqs-client.spec.d.ts +1 -1
- package/dist/esm/__tests__/clients/sqs-client.spec.js +192 -119
- package/dist/esm/__tests__/clients/sqs-client.spec.js.map +1 -1
- package/dist/esm/__tests__/clients/sqs-unbundle.spec.d.ts +1 -0
- package/dist/esm/__tests__/clients/sqs-unbundle.spec.js +786 -0
- package/dist/esm/__tests__/clients/sqs-unbundle.spec.js.map +1 -0
- package/dist/esm/__tests__/db/shared-read-db-services.spec.d.ts +1 -1
- package/dist/esm/__tests__/db/shared-read-db-services.spec.js +87 -87
- package/dist/esm/__tests__/helpers/account-users-helper.spec.d.ts +1 -1
- package/dist/esm/__tests__/helpers/account-users-helper.spec.js +218 -218
- package/dist/esm/__tests__/helpers/api-key-auth-helper.spec.d.ts +1 -1
- package/dist/esm/__tests__/helpers/api-key-auth-helper.spec.js +72 -72
- package/dist/esm/__tests__/identity-cache/identity-cache-db-service.spec.d.ts +1 -1
- package/dist/esm/__tests__/identity-cache/identity-cache-db-service.spec.js +672 -672
- package/dist/esm/__tests__/identity-cache/trait-merging-and-staleness.spec.d.ts +1 -1
- package/dist/esm/__tests__/identity-cache/trait-merging-and-staleness.spec.js +586 -586
- package/dist/esm/__tests__/integration/sqs-bundling-roundtrip.spec.d.ts +1 -0
- package/dist/esm/__tests__/integration/sqs-bundling-roundtrip.spec.js +580 -0
- package/dist/esm/__tests__/integration/sqs-bundling-roundtrip.spec.js.map +1 -0
- package/dist/esm/__tests__/libs/compress-decompress.spec.d.ts +1 -1
- package/dist/esm/__tests__/libs/compress-decompress.spec.js +14 -14
- package/dist/esm/__tests__/libs/currency.spec.d.ts +1 -1
- package/dist/esm/__tests__/libs/currency.spec.js +218 -218
- package/dist/esm/__tests__/libs/dates.spec.d.ts +1 -1
- package/dist/esm/__tests__/libs/dates.spec.js +128 -128
- package/dist/esm/__tests__/libs/domain.spec.d.ts +1 -1
- package/dist/esm/__tests__/libs/domain.spec.js +105 -105
- package/dist/esm/__tests__/libs/numbers.spec.d.ts +1 -1
- package/dist/esm/__tests__/libs/numbers.spec.js +259 -259
- package/dist/esm/__tests__/s3-client/s3-client.spec.d.ts +1 -1
- package/dist/esm/__tests__/s3-client/s3-client.spec.js +31 -31
- package/dist/esm/__tests__/shopify/shopify-graphql-transformer.spec.d.ts +1 -1
- package/dist/esm/__tests__/shopify/shopify-graphql-transformer.spec.js +33 -33
- package/dist/esm/__tests__/unit/libs/api-router/public-api-router.spec.d.ts +1 -1
- package/dist/esm/__tests__/unit/libs/api-router/public-api-router.spec.js +172 -172
- package/dist/esm/__tests__/unit/libs/api-router/route-matcher.spec.d.ts +1 -1
- package/dist/esm/__tests__/unit/libs/api-router/route-matcher.spec.js +67 -67
- package/dist/esm/clients/generic/cognito-client.d.ts +23 -23
- package/dist/esm/clients/generic/cognito-client.js +204 -204
- package/dist/esm/clients/generic/dynamodb-client.d.ts +18 -18
- package/dist/esm/clients/generic/dynamodb-client.js +168 -168
- package/dist/esm/clients/generic/eventbridge-client.d.ts +14 -14
- package/dist/esm/clients/generic/eventbridge-client.js +47 -47
- package/dist/esm/clients/generic/http-client.d.ts +14 -14
- package/dist/esm/clients/generic/http-client.js +53 -53
- package/dist/esm/clients/generic/index.d.ts +13 -10
- package/dist/esm/clients/generic/index.js +13 -10
- package/dist/esm/clients/generic/index.js.map +1 -1
- package/dist/esm/clients/generic/lambda-invoke-client.d.ts +10 -10
- package/dist/esm/clients/generic/lambda-invoke-client.js +35 -35
- package/dist/esm/clients/generic/location-client.d.ts +8 -8
- package/dist/esm/clients/generic/location-client.js +27 -27
- package/dist/esm/clients/generic/redis-client.d.ts +33 -33
- package/dist/esm/clients/generic/redis-client.js +184 -184
- package/dist/esm/clients/generic/s3-client.d.ts +23 -23
- package/dist/esm/clients/generic/s3-client.js +209 -209
- package/dist/esm/clients/generic/singlestore-db-client.d.ts +14 -14
- package/dist/esm/clients/generic/singlestore-db-client.js +40 -40
- package/dist/esm/clients/generic/sqs-bundled-client.d.ts +15 -0
- package/dist/esm/clients/generic/sqs-bundled-client.js +274 -0
- package/dist/esm/clients/generic/sqs-bundled-client.js.map +1 -0
- package/dist/esm/clients/generic/sqs-bundled-client.types.d.ts +52 -0
- package/dist/esm/clients/generic/sqs-bundled-client.types.js +14 -0
- package/dist/esm/clients/generic/sqs-bundled-client.types.js.map +1 -0
- package/dist/esm/clients/generic/sqs-client.d.ts +48 -33
- package/dist/esm/clients/generic/sqs-client.js +269 -107
- package/dist/esm/clients/generic/sqs-client.js.map +1 -1
- package/dist/esm/clients/generic/sqs-unbundle.d.ts +32 -0
- package/dist/esm/clients/generic/sqs-unbundle.js +138 -0
- package/dist/esm/clients/generic/sqs-unbundle.js.map +1 -0
- package/dist/esm/clients/index.d.ts +3 -3
- package/dist/esm/clients/index.js +3 -3
- package/dist/esm/clients/internal-api/accounts-client.d.ts +91 -91
- package/dist/esm/clients/internal-api/accounts-client.js +125 -125
- package/dist/esm/clients/internal-api/cache-lambda-client.d.ts +26 -26
- package/dist/esm/clients/internal-api/cache-lambda-client.js +85 -85
- package/dist/esm/clients/internal-api/db-management-client.d.ts +18 -18
- package/dist/esm/clients/internal-api/db-management-client.js +32 -32
- package/dist/esm/clients/internal-api/destinations-client.d.ts +34 -34
- package/dist/esm/clients/internal-api/destinations-client.js +75 -75
- package/dist/esm/clients/internal-api/event-collector-client.d.ts +20 -20
- package/dist/esm/clients/internal-api/event-collector-client.js +32 -32
- package/dist/esm/clients/internal-api/identity-client.d.ts +31 -31
- package/dist/esm/clients/internal-api/identity-client.js +87 -87
- package/dist/esm/clients/internal-api/index.d.ts +9 -9
- package/dist/esm/clients/internal-api/index.js +9 -9
- package/dist/esm/clients/internal-api/shopify-app-install-client.d.ts +37 -37
- package/dist/esm/clients/internal-api/shopify-app-install-client.js +77 -77
- package/dist/esm/clients/internal-api/subscriptions-client.d.ts +26 -26
- package/dist/esm/clients/internal-api/subscriptions-client.js +73 -73
- package/dist/esm/clients/internal-api/users-auth-client.d.ts +35 -35
- package/dist/esm/clients/internal-api/users-auth-client.js +106 -106
- package/dist/esm/clients/third-party/emailable-client.d.ts +7 -7
- package/dist/esm/clients/third-party/emailable-client.js +21 -21
- package/dist/esm/clients/third-party/exchange-rate-api-client.d.ts +17 -17
- package/dist/esm/clients/third-party/exchange-rate-api-client.js +15 -15
- package/dist/esm/clients/third-party/index.d.ts +4 -4
- package/dist/esm/clients/third-party/index.js +4 -4
- package/dist/esm/clients/third-party/loops-client.d.ts +10 -10
- package/dist/esm/clients/third-party/loops-client.js +26 -26
- package/dist/esm/clients/third-party/shopify/graphql-order-queries.d.ts +25 -25
- package/dist/esm/clients/third-party/shopify/graphql-order-queries.js +27 -27
- package/dist/esm/clients/third-party/shopify/graphql-product-queries.d.ts +2 -2
- package/dist/esm/clients/third-party/shopify/graphql-product-queries.js +177 -177
- package/dist/esm/clients/third-party/shopify/shopify-graphql-client.d.ts +10 -10
- package/dist/esm/clients/third-party/shopify/shopify-graphql-client.js +157 -157
- package/dist/esm/clients/third-party/shopify-client.d.ts +29 -29
- package/dist/esm/clients/third-party/shopify-client.js +142 -142
- package/dist/esm/constants/index.d.ts +1 -0
- package/dist/esm/constants/index.js +2 -0
- package/dist/esm/constants/index.js.map +1 -0
- package/dist/esm/constants/sqs.d.ts +11 -0
- package/dist/esm/constants/sqs.js +12 -0
- package/dist/esm/constants/sqs.js.map +1 -0
- package/dist/esm/helpers/account-users-helper.d.ts +2 -2
- package/dist/esm/helpers/account-users-helper.js +18 -18
- package/dist/esm/helpers/api-key-auth-helper.d.ts +9 -9
- package/dist/esm/helpers/api-key-auth-helper.js +35 -35
- package/dist/esm/helpers/api-key-authorizer-helper.d.ts +36 -36
- package/dist/esm/helpers/api-key-authorizer-helper.js +81 -81
- package/dist/esm/helpers/identity-cache-helper.d.ts +21 -21
- package/dist/esm/helpers/identity-cache-helper.js +151 -151
- package/dist/esm/helpers/index.d.ts +9 -9
- package/dist/esm/helpers/index.js +9 -9
- package/dist/esm/helpers/input-validation-helper.d.ts +3 -3
- package/dist/esm/helpers/input-validation-helper.js +18 -18
- package/dist/esm/helpers/logging-helper.d.ts +16 -16
- package/dist/esm/helpers/logging-helper.js +56 -56
- package/dist/esm/helpers/response-helper.d.ts +18 -18
- package/dist/esm/helpers/response-helper.js +37 -37
- package/dist/esm/helpers/shopify-helper.d.ts +9 -9
- package/dist/esm/helpers/shopify-helper.js +21 -21
- package/dist/esm/helpers/sqs-utils.d.ts +6 -6
- package/dist/esm/helpers/sqs-utils.js +9 -9
- package/dist/esm/index.d.ts +7 -5
- package/dist/esm/index.js +7 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/libs/api-router/index.d.ts +2 -2
- package/dist/esm/libs/api-router/index.js +2 -2
- package/dist/esm/libs/api-router/public-api-router.d.ts +3 -3
- package/dist/esm/libs/api-router/public-api-router.js +32 -32
- package/dist/esm/libs/api-router/route-matcher.d.ts +21 -21
- package/dist/esm/libs/api-router/route-matcher.js +30 -30
- package/dist/esm/libs/click-id-parser.d.ts +23 -23
- package/dist/esm/libs/click-id-parser.js +45 -45
- package/dist/esm/libs/compression.d.ts +2 -2
- package/dist/esm/libs/compression.js +25 -25
- package/dist/esm/libs/cookie.d.ts +17 -17
- package/dist/esm/libs/cookie.js +70 -70
- package/dist/esm/libs/crypto.d.ts +4 -4
- package/dist/esm/libs/crypto.js +15 -15
- package/dist/esm/libs/csv.d.ts +2 -2
- package/dist/esm/libs/csv.js +30 -30
- package/dist/esm/libs/currency.d.ts +1 -1
- package/dist/esm/libs/currency.js +22 -22
- package/dist/esm/libs/dates.d.ts +12 -12
- package/dist/esm/libs/dates.js +83 -83
- package/dist/esm/libs/domain.d.ts +2 -2
- package/dist/esm/libs/domain.js +33 -33
- package/dist/esm/libs/emails.d.ts +6 -6
- package/dist/esm/libs/emails.js +115 -115
- package/dist/esm/libs/http-error.d.ts +21 -21
- package/dist/esm/libs/http-error.js +59 -59
- package/dist/esm/libs/http-status-codes.d.ts +58 -58
- package/dist/esm/libs/http-status-codes.js +59 -59
- package/dist/esm/libs/index.d.ts +18 -18
- package/dist/esm/libs/index.js +18 -18
- package/dist/esm/libs/numbers.d.ts +1 -1
- package/dist/esm/libs/numbers.js +11 -11
- package/dist/esm/libs/referrer-parser/index.d.ts +2 -2
- package/dist/esm/libs/referrer-parser/index.js +2 -2
- package/dist/esm/libs/referrer-parser/referrer-data.d.ts +9 -9
- package/dist/esm/libs/referrer-parser/referrer-data.js +3304 -3304
- package/dist/esm/libs/referrer-parser/referrer-parser-util.d.ts +20 -20
- package/dist/esm/libs/referrer-parser/referrer-parser-util.js +124 -124
- package/dist/esm/libs/strings.d.ts +3 -3
- package/dist/esm/libs/strings.js +40 -40
- package/dist/esm/libs/traits.d.ts +6 -6
- package/dist/esm/libs/traits.js +54 -54
- package/dist/esm/libs/url.d.ts +1 -1
- package/dist/esm/libs/url.js +9 -9
- package/dist/esm/services/cache/generic-cached-object.d.ts +5 -5
- package/dist/esm/services/cache/generic-cached-object.js +1 -1
- package/dist/esm/services/cache/index.d.ts +1 -1
- package/dist/esm/services/cache/index.js +1 -1
- package/dist/esm/services/cache/product-cache-service.d.ts +21 -21
- package/dist/esm/services/cache/product-cache-service.js +68 -68
- package/dist/esm/services/currency-exchange-rate-lookup-service.d.ts +11 -11
- package/dist/esm/services/currency-exchange-rate-lookup-service.js +62 -62
- package/dist/esm/services/db/accounts-db-service.d.ts +9 -9
- package/dist/esm/services/db/accounts-db-service.js +29 -29
- package/dist/esm/services/db/api-keys-db-service.d.ts +10 -10
- package/dist/esm/services/db/api-keys-db-service.js +32 -32
- package/dist/esm/services/db/currency-exchange-rates-db-service.d.ts +21 -21
- package/dist/esm/services/db/currency-exchange-rates-db-service.js +35 -35
- package/dist/esm/services/db/destinations-db-service.d.ts +12 -12
- package/dist/esm/services/db/destinations-db-service.js +72 -72
- package/dist/esm/services/db/identity-cache-db-service.d.ts +28 -28
- package/dist/esm/services/db/identity-cache-db-service.js +313 -313
- package/dist/esm/services/db/index.d.ts +13 -13
- package/dist/esm/services/db/index.js +13 -13
- package/dist/esm/services/db/log-events-db-service.d.ts +11 -11
- package/dist/esm/services/db/log-events-db-service.js +177 -177
- package/dist/esm/services/db/pixels-db-service.d.ts +8 -8
- package/dist/esm/services/db/pixels-db-service.js +31 -31
- package/dist/esm/services/db/purchasable-contacts-db-service.d.ts +9 -9
- package/dist/esm/services/db/purchasable-contacts-db-service.js +39 -39
- package/dist/esm/services/db/purchased-contacts-db-service.d.ts +17 -17
- package/dist/esm/services/db/purchased-contacts-db-service.js +139 -139
- package/dist/esm/services/db/shopify-app-installs-db-service.d.ts +8 -8
- package/dist/esm/services/db/shopify-app-installs-db-service.js +47 -47
- package/dist/esm/services/db/shopify-products-cache-db-service.d.ts +16 -16
- package/dist/esm/services/db/shopify-products-cache-db-service.js +66 -66
- package/dist/esm/services/db/subscriptions-db-service.d.ts +10 -10
- package/dist/esm/services/db/subscriptions-db-service.js +30 -30
- package/dist/esm/services/db/tracking-events-db-service.d.ts +20 -20
- package/dist/esm/services/db/tracking-events-db-service.js +161 -161
- package/dist/esm/services/eventbridge-integration-service.d.ts +9 -9
- package/dist/esm/services/eventbridge-integration-service.js +24 -24
- package/dist/esm/services/events/index.d.ts +3 -3
- package/dist/esm/services/events/index.js +3 -3
- package/dist/esm/services/events/log-event-service.d.ts +9 -9
- package/dist/esm/services/events/log-event-service.js +52 -52
- package/dist/esm/services/events/metric-event-service.d.ts +9 -9
- package/dist/esm/services/events/metric-event-service.js +45 -45
- package/dist/esm/services/events/tracking-event-sqs-service.d.ts +8 -8
- package/dist/esm/services/events/tracking-event-sqs-service.js +30 -30
- package/dist/esm/services/generic-cache-service.d.ts +7 -7
- package/dist/esm/services/generic-cache-service.js +29 -29
- package/dist/esm/services/index.d.ts +8 -8
- package/dist/esm/services/index.js +8 -8
- package/dist/esm/services/ipdata-lookup-service.d.ts +20 -20
- package/dist/esm/services/ipdata-lookup-service.js +108 -108
- package/dist/esm/services/shopify/index.d.ts +2 -2
- package/dist/esm/services/shopify/index.js +2 -2
- package/dist/esm/services/shopify/products/index.d.ts +1 -1
- package/dist/esm/services/shopify/products/index.js +1 -1
- package/dist/esm/services/shopify/products/shopify-products-serviceV2.d.ts +17 -17
- package/dist/esm/services/shopify/products/shopify-products-serviceV2.js +108 -108
- package/dist/esm/services/shopify/shopify-graphql-transformer.d.ts +8 -8
- package/dist/esm/services/shopify/shopify-graphql-transformer.js +138 -138
- package/dist/esm/types/api-response.d.ts +6 -6
- package/dist/esm/types/api-response.js +1 -1
- package/dist/esm/types/index.d.ts +1 -1
- package/dist/esm/types/index.js +1 -1
- package/dist/esm/types/internal-events/event-detail-types.d.ts +20 -20
- package/dist/esm/types/internal-events/event-detail-types.js +24 -24
- package/dist/esm/types/internal-events/index.d.ts +1 -1
- package/dist/esm/types/internal-events/index.js +1 -1
- package/dist/esm/types/shopify-graphql-types/admin.generated.d.ts +123 -123
- package/dist/esm/types/shopify-graphql-types/admin.generated.js +1 -1
- package/dist/esm/types/shopify-graphql-types/admin.types.d.ts +26289 -26289
- package/dist/esm/types/shopify-graphql-types/admin.types.js +5299 -5299
- package/dist/esm/types/shopify-graphql-types/index.d.ts +2 -2
- package/dist/esm/types/shopify-graphql-types/index.js +2 -2
- package/dist/esm/utils/compression.d.ts +35 -0
- package/dist/esm/utils/compression.js +167 -0
- package/dist/esm/utils/compression.js.map +1 -0
- package/dist/esm/utils/index.d.ts +3 -0
- package/dist/esm/utils/index.js +4 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/esm/utils/retry-envelope.d.ts +12 -0
- package/dist/esm/utils/retry-envelope.js +25 -0
- package/dist/esm/utils/retry-envelope.js.map +1 -0
- package/dist/esm/utils/size.d.ts +2 -0
- package/dist/esm/utils/size.js +44 -0
- package/dist/esm/utils/size.js.map +1 -0
- package/package.json +135 -135
|
@@ -0,0 +1,786 @@
|
|
|
1
|
+
import { unbundleRecords, unbundleMessage, isBundledEnvelope, } from '../../clients/generic/sqs-unbundle';
|
|
2
|
+
import { CompressionAlgorithm, } from '../../clients/generic/sqs-bundled-client.types';
|
|
3
|
+
import { compress, CompressionTimeoutError, CompressionOperation, } from '../../utils/compression';
|
|
4
|
+
jest.mock('../../helpers/logging-helper', () => ({
|
|
5
|
+
Logger: {
|
|
6
|
+
debug: jest.fn(),
|
|
7
|
+
info: jest.fn(),
|
|
8
|
+
warn: jest.fn(),
|
|
9
|
+
error: jest.fn(),
|
|
10
|
+
},
|
|
11
|
+
}));
|
|
12
|
+
function makeTestEvent(id, name = 'test_event', value) {
|
|
13
|
+
return { eventId: id, name, value };
|
|
14
|
+
}
|
|
15
|
+
function makeSqsRecord(body, messageId = 'msg-1') {
|
|
16
|
+
return {
|
|
17
|
+
messageId,
|
|
18
|
+
body: typeof body === 'string' ? body : JSON.stringify(body),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function makeBundledEnvelope(items) {
|
|
22
|
+
return {
|
|
23
|
+
v: 1,
|
|
24
|
+
c: CompressionAlgorithm.NONE,
|
|
25
|
+
n: items.length,
|
|
26
|
+
s: JSON.stringify(items).length,
|
|
27
|
+
p: items,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async function makeCompressedEnvelope(items, level = 3) {
|
|
31
|
+
const json = JSON.stringify(items);
|
|
32
|
+
const compressed = await compress(Buffer.from(json, 'utf8'), CompressionAlgorithm.ZSTD, level);
|
|
33
|
+
const base64 = compressed.toString('base64');
|
|
34
|
+
return {
|
|
35
|
+
v: 1,
|
|
36
|
+
c: CompressionAlgorithm.ZSTD,
|
|
37
|
+
n: items.length,
|
|
38
|
+
s: json.length,
|
|
39
|
+
p: base64,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
describe('isBundledEnvelope', () => {
|
|
43
|
+
it('returns true for valid bundled envelope with NONE compression', () => {
|
|
44
|
+
const envelope = makeBundledEnvelope([makeTestEvent('1')]);
|
|
45
|
+
expect(isBundledEnvelope(envelope)).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
it('returns true for valid bundled envelope with ZSTD compression', async () => {
|
|
48
|
+
const envelope = await makeCompressedEnvelope([makeTestEvent('1')]);
|
|
49
|
+
expect(isBundledEnvelope(envelope)).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
it('returns false for null', () => {
|
|
52
|
+
expect(isBundledEnvelope(null)).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
it('returns false for undefined', () => {
|
|
55
|
+
expect(isBundledEnvelope(undefined)).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
it('returns false for plain object (legacy message)', () => {
|
|
58
|
+
expect(isBundledEnvelope(makeTestEvent('1'))).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
it('returns false for wrong version', () => {
|
|
61
|
+
const envelope = { v: 2, c: 'none', n: 1, p: [] };
|
|
62
|
+
expect(isBundledEnvelope(envelope)).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
it('returns false for invalid compression algorithm', () => {
|
|
65
|
+
const envelope = { v: 1, c: 'gzip', n: 1, p: [] };
|
|
66
|
+
expect(isBundledEnvelope(envelope)).toBe(false);
|
|
67
|
+
});
|
|
68
|
+
it('returns false for missing count', () => {
|
|
69
|
+
const envelope = { v: 1, c: 'none', p: [] };
|
|
70
|
+
expect(isBundledEnvelope(envelope)).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
it('returns false for missing payload', () => {
|
|
73
|
+
const envelope = { v: 1, c: 'none', n: 1 };
|
|
74
|
+
expect(isBundledEnvelope(envelope)).toBe(false);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe('unbundleMessage', () => {
|
|
78
|
+
it('unbundles NONE compression envelope', async () => {
|
|
79
|
+
const items = [makeTestEvent('1'), makeTestEvent('2')];
|
|
80
|
+
const envelope = makeBundledEnvelope(items);
|
|
81
|
+
const result = await unbundleMessage(envelope);
|
|
82
|
+
expect(result).toHaveLength(2);
|
|
83
|
+
expect(result[0].eventId).toBe('1');
|
|
84
|
+
expect(result[1].eventId).toBe('2');
|
|
85
|
+
});
|
|
86
|
+
it('unbundles ZSTD compressed envelope', async () => {
|
|
87
|
+
const items = [makeTestEvent('1'), makeTestEvent('2'), makeTestEvent('3')];
|
|
88
|
+
const envelope = await makeCompressedEnvelope(items);
|
|
89
|
+
const result = await unbundleMessage(envelope);
|
|
90
|
+
expect(result).toHaveLength(3);
|
|
91
|
+
expect(result[0].eventId).toBe('1');
|
|
92
|
+
expect(result[1].eventId).toBe('2');
|
|
93
|
+
expect(result[2].eventId).toBe('3');
|
|
94
|
+
});
|
|
95
|
+
it('unbundles large batches with ZSTD compression', async () => {
|
|
96
|
+
const items = Array.from({ length: 500 }, (_, i) => makeTestEvent(`event-${i}`, `event_${i}`, i * 10));
|
|
97
|
+
const envelope = await makeCompressedEnvelope(items);
|
|
98
|
+
const result = await unbundleMessage(envelope);
|
|
99
|
+
expect(result).toHaveLength(500);
|
|
100
|
+
expect(result[0].eventId).toBe('event-0');
|
|
101
|
+
expect(result[499].eventId).toBe('event-499');
|
|
102
|
+
});
|
|
103
|
+
it('throws on unsupported bundle version', async () => {
|
|
104
|
+
const envelope = { v: 99, c: 'none', n: 1, p: [] };
|
|
105
|
+
await expect(unbundleMessage(envelope)).rejects.toThrow('Unsupported bundle version: 99');
|
|
106
|
+
});
|
|
107
|
+
it('throws on invalid payload type for NONE compression', async () => {
|
|
108
|
+
const envelope = { v: 1, c: 'none', n: 1, p: 'not-an-array' };
|
|
109
|
+
await expect(unbundleMessage(envelope)).rejects.toThrow('Invalid bundle: NONE compression but payload is not an array');
|
|
110
|
+
});
|
|
111
|
+
it('throws on invalid payload type for ZSTD compression', async () => {
|
|
112
|
+
const envelope = { v: 1, c: 'zstd', n: 1, p: [] };
|
|
113
|
+
await expect(unbundleMessage(envelope)).rejects.toThrow('Invalid bundle: zstd compression but payload is not a string');
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe('unbundleRecords', () => {
|
|
117
|
+
describe('legacy (non-bundled) messages', () => {
|
|
118
|
+
it('parses raw JSON message', async () => {
|
|
119
|
+
const event = makeTestEvent('raw-1', 'purchase');
|
|
120
|
+
const record = makeSqsRecord(event);
|
|
121
|
+
const { items, stats, failedMessageIds } = await unbundleRecords([record]);
|
|
122
|
+
expect(items).toHaveLength(1);
|
|
123
|
+
expect(items[0].eventId).toBe('raw-1');
|
|
124
|
+
expect(items[0].name).toBe('purchase');
|
|
125
|
+
expect(stats.legacyRecords).toBe(1);
|
|
126
|
+
expect(stats.bundledRecords).toBe(0);
|
|
127
|
+
expect(failedMessageIds).toHaveLength(0);
|
|
128
|
+
});
|
|
129
|
+
it('parses wrapped messageBody format', async () => {
|
|
130
|
+
const event = makeTestEvent('wrapped-1');
|
|
131
|
+
const record = makeSqsRecord({ messageBody: event });
|
|
132
|
+
const { items, stats } = await unbundleRecords([record]);
|
|
133
|
+
expect(items).toHaveLength(1);
|
|
134
|
+
expect(items[0].eventId).toBe('wrapped-1');
|
|
135
|
+
expect(stats.legacyRecords).toBe(1);
|
|
136
|
+
});
|
|
137
|
+
it('handles multiple legacy records', async () => {
|
|
138
|
+
const records = [
|
|
139
|
+
makeSqsRecord(makeTestEvent('1'), 'msg-1'),
|
|
140
|
+
makeSqsRecord(makeTestEvent('2'), 'msg-2'),
|
|
141
|
+
makeSqsRecord(makeTestEvent('3'), 'msg-3'),
|
|
142
|
+
];
|
|
143
|
+
const { items, stats, recordMap } = await unbundleRecords(records);
|
|
144
|
+
expect(items).toHaveLength(3);
|
|
145
|
+
expect(stats.legacyRecords).toBe(3);
|
|
146
|
+
expect(stats.totalItems).toBe(3);
|
|
147
|
+
expect(recordMap.get(items[0])).toBe('msg-1');
|
|
148
|
+
expect(recordMap.get(items[1])).toBe('msg-2');
|
|
149
|
+
expect(recordMap.get(items[2])).toBe('msg-3');
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
describe('bundled messages (NONE compression)', () => {
|
|
153
|
+
it('unbundles wrapped messageBody envelope', async () => {
|
|
154
|
+
const items = [makeTestEvent('b1'), makeTestEvent('b2')];
|
|
155
|
+
const envelope = makeBundledEnvelope(items);
|
|
156
|
+
const record = makeSqsRecord({ messageBody: envelope });
|
|
157
|
+
const { items: result, stats } = await unbundleRecords([record]);
|
|
158
|
+
expect(result).toHaveLength(2);
|
|
159
|
+
expect(result[0].eventId).toBe('b1');
|
|
160
|
+
expect(result[1].eventId).toBe('b2');
|
|
161
|
+
expect(stats.bundledRecords).toBe(1);
|
|
162
|
+
expect(stats.legacyRecords).toBe(0);
|
|
163
|
+
});
|
|
164
|
+
it('unbundles raw envelope (not wrapped)', async () => {
|
|
165
|
+
const items = [makeTestEvent('r1'), makeTestEvent('r2')];
|
|
166
|
+
const envelope = makeBundledEnvelope(items);
|
|
167
|
+
const record = makeSqsRecord(envelope);
|
|
168
|
+
const { items: result, stats } = await unbundleRecords([record]);
|
|
169
|
+
expect(result).toHaveLength(2);
|
|
170
|
+
expect(stats.bundledRecords).toBe(1);
|
|
171
|
+
});
|
|
172
|
+
it('maps all items from bundle to same messageId', async () => {
|
|
173
|
+
const items = [makeTestEvent('x1'), makeTestEvent('x2'), makeTestEvent('x3')];
|
|
174
|
+
const envelope = makeBundledEnvelope(items);
|
|
175
|
+
const record = makeSqsRecord({ messageBody: envelope }, 'bundle-msg-1');
|
|
176
|
+
const { items: result, recordMap } = await unbundleRecords([record]);
|
|
177
|
+
expect(result).toHaveLength(3);
|
|
178
|
+
expect(recordMap.get(result[0])).toBe('bundle-msg-1');
|
|
179
|
+
expect(recordMap.get(result[1])).toBe('bundle-msg-1');
|
|
180
|
+
expect(recordMap.get(result[2])).toBe('bundle-msg-1');
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
describe('bundled messages (ZSTD compression)', () => {
|
|
184
|
+
it('unbundles ZSTD compressed envelope', async () => {
|
|
185
|
+
const items = [makeTestEvent('z1'), makeTestEvent('z2')];
|
|
186
|
+
const envelope = await makeCompressedEnvelope(items);
|
|
187
|
+
const record = makeSqsRecord({ messageBody: envelope });
|
|
188
|
+
const { items: result, stats } = await unbundleRecords([record]);
|
|
189
|
+
expect(result).toHaveLength(2);
|
|
190
|
+
expect(result[0].eventId).toBe('z1');
|
|
191
|
+
expect(result[1].eventId).toBe('z2');
|
|
192
|
+
expect(stats.bundledRecords).toBe(1);
|
|
193
|
+
});
|
|
194
|
+
it('handles large compressed bundles (500 items)', async () => {
|
|
195
|
+
const items = Array.from({ length: 500 }, (_, i) => makeTestEvent(`item-${i}`));
|
|
196
|
+
const envelope = await makeCompressedEnvelope(items);
|
|
197
|
+
const record = makeSqsRecord({ messageBody: envelope });
|
|
198
|
+
const { items: result, stats } = await unbundleRecords([record]);
|
|
199
|
+
expect(result).toHaveLength(500);
|
|
200
|
+
expect(stats.bundledRecords).toBe(1);
|
|
201
|
+
expect(stats.totalItems).toBe(500);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
describe('mixed message formats', () => {
|
|
205
|
+
it('handles mix of legacy and bundled messages', async () => {
|
|
206
|
+
const legacyEvent = makeTestEvent('legacy-1');
|
|
207
|
+
const bundledItems = [makeTestEvent('bundled-1'), makeTestEvent('bundled-2')];
|
|
208
|
+
const bundleEnvelope = makeBundledEnvelope(bundledItems);
|
|
209
|
+
const records = [
|
|
210
|
+
makeSqsRecord(legacyEvent, 'msg-legacy'),
|
|
211
|
+
makeSqsRecord({ messageBody: bundleEnvelope }, 'msg-bundle'),
|
|
212
|
+
];
|
|
213
|
+
const { items, stats, recordMap } = await unbundleRecords(records);
|
|
214
|
+
expect(items).toHaveLength(3);
|
|
215
|
+
expect(stats.legacyRecords).toBe(1);
|
|
216
|
+
expect(stats.bundledRecords).toBe(1);
|
|
217
|
+
expect(stats.totalItems).toBe(3);
|
|
218
|
+
expect(recordMap.get(items[0])).toBe('msg-legacy');
|
|
219
|
+
expect(recordMap.get(items[1])).toBe('msg-bundle');
|
|
220
|
+
expect(recordMap.get(items[2])).toBe('msg-bundle');
|
|
221
|
+
});
|
|
222
|
+
it('handles mix of NONE and ZSTD compressed bundles', async () => {
|
|
223
|
+
const noneItems = [makeTestEvent('none-1')];
|
|
224
|
+
const zstdItems = [makeTestEvent('zstd-1'), makeTestEvent('zstd-2')];
|
|
225
|
+
const noneEnvelope = makeBundledEnvelope(noneItems);
|
|
226
|
+
const zstdEnvelope = await makeCompressedEnvelope(zstdItems);
|
|
227
|
+
const records = [
|
|
228
|
+
makeSqsRecord({ messageBody: noneEnvelope }, 'msg-none'),
|
|
229
|
+
makeSqsRecord({ messageBody: zstdEnvelope }, 'msg-zstd'),
|
|
230
|
+
];
|
|
231
|
+
const { items, stats } = await unbundleRecords(records);
|
|
232
|
+
expect(items).toHaveLength(3);
|
|
233
|
+
expect(stats.bundledRecords).toBe(2);
|
|
234
|
+
expect(stats.totalItems).toBe(3);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
describe('error handling', () => {
|
|
238
|
+
it('returns failed messageId for invalid JSON', async () => {
|
|
239
|
+
const records = [
|
|
240
|
+
makeSqsRecord('not-valid-json{{{', 'msg-bad'),
|
|
241
|
+
makeSqsRecord(makeTestEvent('good'), 'msg-good'),
|
|
242
|
+
];
|
|
243
|
+
const { items, failedMessageIds, stats } = await unbundleRecords(records);
|
|
244
|
+
expect(items).toHaveLength(1);
|
|
245
|
+
expect(items[0].eventId).toBe('good');
|
|
246
|
+
expect(failedMessageIds).toEqual(['msg-bad']);
|
|
247
|
+
expect(stats.failedRecords).toBe(1);
|
|
248
|
+
expect(stats.legacyRecords).toBe(1);
|
|
249
|
+
});
|
|
250
|
+
it('returns failed messageId for corrupt compressed data', async () => {
|
|
251
|
+
const corruptEnvelope = {
|
|
252
|
+
v: 1,
|
|
253
|
+
c: CompressionAlgorithm.ZSTD,
|
|
254
|
+
n: 10,
|
|
255
|
+
p: 'dGhpcyBpcyBub3QgdmFsaWQgenN0ZA==',
|
|
256
|
+
};
|
|
257
|
+
const records = [
|
|
258
|
+
makeSqsRecord({ messageBody: corruptEnvelope }, 'msg-corrupt'),
|
|
259
|
+
makeSqsRecord(makeTestEvent('valid'), 'msg-valid'),
|
|
260
|
+
];
|
|
261
|
+
const { items, failedMessageIds, stats } = await unbundleRecords(records);
|
|
262
|
+
expect(items).toHaveLength(1);
|
|
263
|
+
expect(items[0].eventId).toBe('valid');
|
|
264
|
+
expect(failedMessageIds).toContain('msg-corrupt');
|
|
265
|
+
expect(stats.failedRecords).toBe(1);
|
|
266
|
+
});
|
|
267
|
+
it('returns empty result for all failed records', async () => {
|
|
268
|
+
const records = [
|
|
269
|
+
makeSqsRecord('invalid-1', 'msg-1'),
|
|
270
|
+
makeSqsRecord('invalid-2', 'msg-2'),
|
|
271
|
+
];
|
|
272
|
+
const { items, failedMessageIds, stats } = await unbundleRecords(records);
|
|
273
|
+
expect(items).toHaveLength(0);
|
|
274
|
+
expect(failedMessageIds).toEqual(['msg-1', 'msg-2']);
|
|
275
|
+
expect(stats.failedRecords).toBe(2);
|
|
276
|
+
expect(stats.totalItems).toBe(0);
|
|
277
|
+
});
|
|
278
|
+
it('handles empty records array', async () => {
|
|
279
|
+
const { items, failedMessageIds, stats } = await unbundleRecords([]);
|
|
280
|
+
expect(items).toHaveLength(0);
|
|
281
|
+
expect(failedMessageIds).toHaveLength(0);
|
|
282
|
+
expect(stats.totalRecords).toBe(0);
|
|
283
|
+
expect(stats.totalItems).toBe(0);
|
|
284
|
+
});
|
|
285
|
+
it('rejects payload exceeding max decompressed size', async () => {
|
|
286
|
+
const largeItems = Array.from({ length: 1000 }, (_, i) => ({
|
|
287
|
+
id: `item-${i}`,
|
|
288
|
+
data: 'x'.repeat(1000),
|
|
289
|
+
}));
|
|
290
|
+
const envelope = await makeCompressedEnvelope(largeItems);
|
|
291
|
+
const record = makeSqsRecord({ messageBody: envelope }, 'msg-too-large');
|
|
292
|
+
const { failedMessageIds, stats } = await unbundleRecords([record], {
|
|
293
|
+
maxDecompressedSizeBytes: 100 * 1024,
|
|
294
|
+
});
|
|
295
|
+
expect(failedMessageIds).toContain('msg-too-large');
|
|
296
|
+
expect(stats.failedRecords).toBe(1);
|
|
297
|
+
});
|
|
298
|
+
it('fails on invalid base64 in compressed payload', async () => {
|
|
299
|
+
const badEnvelope = {
|
|
300
|
+
v: 1,
|
|
301
|
+
c: CompressionAlgorithm.ZSTD,
|
|
302
|
+
n: 1,
|
|
303
|
+
s: 100,
|
|
304
|
+
p: '!!!not-valid-base64!!!',
|
|
305
|
+
};
|
|
306
|
+
const record = makeSqsRecord({ messageBody: badEnvelope }, 'msg-bad-base64');
|
|
307
|
+
const { failedMessageIds } = await unbundleRecords([record]);
|
|
308
|
+
expect(failedMessageIds).toContain('msg-bad-base64');
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
describe('bundle format edge cases', () => {
|
|
312
|
+
it('successfully unbundles even when n does not match actual item count', async () => {
|
|
313
|
+
const envelope = {
|
|
314
|
+
v: 1,
|
|
315
|
+
c: CompressionAlgorithm.NONE,
|
|
316
|
+
n: 5,
|
|
317
|
+
s: 50,
|
|
318
|
+
p: [makeTestEvent('1'), makeTestEvent('2')],
|
|
319
|
+
};
|
|
320
|
+
const record = makeSqsRecord({ messageBody: envelope });
|
|
321
|
+
const { items } = await unbundleRecords([record]);
|
|
322
|
+
expect(items).toHaveLength(2);
|
|
323
|
+
});
|
|
324
|
+
it('treats envelope with unsupported version as legacy message', async () => {
|
|
325
|
+
const badEnvelope = { v: 99, c: 'none', n: 1, s: 10, p: [] };
|
|
326
|
+
const record = makeSqsRecord({ messageBody: badEnvelope }, 'msg-bad-version');
|
|
327
|
+
const { items, stats } = await unbundleRecords([record]);
|
|
328
|
+
expect(items).toHaveLength(1);
|
|
329
|
+
expect(items[0].v).toBe(99);
|
|
330
|
+
expect(stats.legacyRecords).toBe(1);
|
|
331
|
+
expect(stats.bundledRecords).toBe(0);
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
describe('timeout protection', () => {
|
|
335
|
+
it('respects timeoutMs option', async () => {
|
|
336
|
+
const items = [makeTestEvent('1')];
|
|
337
|
+
const envelope = await makeCompressedEnvelope(items);
|
|
338
|
+
const record = makeSqsRecord({ messageBody: envelope });
|
|
339
|
+
const { items: result, failedMessageIds } = await unbundleRecords([record], {
|
|
340
|
+
timeoutMs: 5000,
|
|
341
|
+
});
|
|
342
|
+
expect(result).toHaveLength(1);
|
|
343
|
+
expect(failedMessageIds).toHaveLength(0);
|
|
344
|
+
});
|
|
345
|
+
it('passes timeoutMs through to decompression', async () => {
|
|
346
|
+
const items = [makeTestEvent('1')];
|
|
347
|
+
const envelope = await makeCompressedEnvelope(items);
|
|
348
|
+
const record = makeSqsRecord({ messageBody: envelope });
|
|
349
|
+
await expect(unbundleRecords([record], { timeoutMs: 30000 })).resolves.toBeDefined();
|
|
350
|
+
});
|
|
351
|
+
it('CompressionTimeoutError is properly exported', () => {
|
|
352
|
+
const error = new CompressionTimeoutError(CompressionOperation.DECOMPRESS, 5000);
|
|
353
|
+
expect(error).toBeInstanceOf(Error);
|
|
354
|
+
expect(error.name).toBe('CompressionTimeoutError');
|
|
355
|
+
expect(error.operation).toBe('decompress');
|
|
356
|
+
expect(error.timeoutMs).toBe(5000);
|
|
357
|
+
expect(error.message).toContain('timed out after 5000ms');
|
|
358
|
+
});
|
|
359
|
+
it('includes timeout info in failure logging', async () => {
|
|
360
|
+
const corruptEnvelope = {
|
|
361
|
+
v: 1,
|
|
362
|
+
c: CompressionAlgorithm.ZSTD,
|
|
363
|
+
n: 1,
|
|
364
|
+
s: 100,
|
|
365
|
+
p: 'dGhpcyBpcyBub3QgdmFsaWQgenN0ZA==',
|
|
366
|
+
};
|
|
367
|
+
const record = makeSqsRecord({ messageBody: corruptEnvelope }, 'msg-timeout-test');
|
|
368
|
+
const { failedMessageIds } = await unbundleRecords([record], {
|
|
369
|
+
timeoutMs: 5000,
|
|
370
|
+
});
|
|
371
|
+
expect(failedMessageIds).toContain('msg-timeout-test');
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
describe('end-to-end: producer bundle → consumer unbundle', () => {
|
|
375
|
+
it('simulates full bundle → unbundle flow with compression', async () => {
|
|
376
|
+
const producerItems = Array.from({ length: 100 }, (_, i) => makeTestEvent(`event-${i}`, 'page_view', i * 1.5));
|
|
377
|
+
const envelope = await makeCompressedEnvelope(producerItems, 3);
|
|
378
|
+
const sqsMessageBody = { messageBody: envelope };
|
|
379
|
+
const consumerRecord = makeSqsRecord(sqsMessageBody, 'sqs-message-id-123');
|
|
380
|
+
const { items, recordMap, stats } = await unbundleRecords([consumerRecord]);
|
|
381
|
+
expect(items).toHaveLength(100);
|
|
382
|
+
expect(items[0]).toEqual({ eventId: 'event-0', name: 'page_view', value: 0 });
|
|
383
|
+
expect(items[99]).toEqual({ eventId: 'event-99', name: 'page_view', value: 148.5 });
|
|
384
|
+
expect(stats.bundledRecords).toBe(1);
|
|
385
|
+
expect(stats.legacyRecords).toBe(0);
|
|
386
|
+
expect(stats.totalItems).toBe(100);
|
|
387
|
+
for (const item of items) {
|
|
388
|
+
expect(recordMap.get(item)).toBe('sqs-message-id-123');
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
it('simulates mixed batch with legacy and bundled messages', async () => {
|
|
392
|
+
const legacyRecord1 = makeSqsRecord({ messageBody: makeTestEvent('legacy-1', 'purchase', 99.99) }, 'legacy-msg-1');
|
|
393
|
+
const legacyRecord2 = makeSqsRecord(makeTestEvent('legacy-2', 'add_to_cart', 29.99), 'legacy-msg-2');
|
|
394
|
+
const bundledItems = [
|
|
395
|
+
makeTestEvent('bundled-1', 'page_view'),
|
|
396
|
+
makeTestEvent('bundled-2', 'session_start'),
|
|
397
|
+
makeTestEvent('bundled-3', 'page_end'),
|
|
398
|
+
];
|
|
399
|
+
const envelope = await makeCompressedEnvelope(bundledItems);
|
|
400
|
+
const bundledRecord = makeSqsRecord({ messageBody: envelope }, 'bundled-msg-1');
|
|
401
|
+
const records = [legacyRecord1, bundledRecord, legacyRecord2];
|
|
402
|
+
const { items, stats, recordMap } = await unbundleRecords(records);
|
|
403
|
+
expect(items).toHaveLength(5);
|
|
404
|
+
expect(stats.legacyRecords).toBe(2);
|
|
405
|
+
expect(stats.bundledRecords).toBe(1);
|
|
406
|
+
expect(stats.totalItems).toBe(5);
|
|
407
|
+
expect(recordMap.get(items[0])).toBe('legacy-msg-1');
|
|
408
|
+
expect(recordMap.get(items[1])).toBe('bundled-msg-1');
|
|
409
|
+
expect(recordMap.get(items[2])).toBe('bundled-msg-1');
|
|
410
|
+
expect(recordMap.get(items[3])).toBe('bundled-msg-1');
|
|
411
|
+
expect(recordMap.get(items[4])).toBe('legacy-msg-2');
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
describe('consumer edge cases - real sequences', () => {
|
|
415
|
+
it('handles 500 items in single compressed bundle with exact verification', async () => {
|
|
416
|
+
const originalItems = Array.from({ length: 500 }, (_, i) => ({
|
|
417
|
+
id: `item-${i}`,
|
|
418
|
+
name: `Event ${i}`,
|
|
419
|
+
data: { nested: { value: i * 1.5 } },
|
|
420
|
+
timestamp: Date.now() + i,
|
|
421
|
+
}));
|
|
422
|
+
const envelope = await makeCompressedEnvelope(originalItems);
|
|
423
|
+
const record = makeSqsRecord({ messageBody: envelope }, 'msg-500-items');
|
|
424
|
+
const { items, recordMap, stats } = await unbundleRecords([record]);
|
|
425
|
+
expect(items).toHaveLength(500);
|
|
426
|
+
expect(items[0]).toEqual(originalItems[0]);
|
|
427
|
+
expect(items[249]).toEqual(originalItems[249]);
|
|
428
|
+
expect(items[499]).toEqual(originalItems[499]);
|
|
429
|
+
expect(stats.bundledRecords).toBe(1);
|
|
430
|
+
expect(stats.totalItems).toBe(500);
|
|
431
|
+
for (let i = 0; i < 500; i++) {
|
|
432
|
+
expect(items[i].id).toBe(`item-${i}`);
|
|
433
|
+
expect(items[i].data.nested.value).toBe(i * 1.5);
|
|
434
|
+
}
|
|
435
|
+
for (const item of items) {
|
|
436
|
+
expect(recordMap.get(item)).toBe('msg-500-items');
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
it('handles multiple bundles in single batch with different item counts', async () => {
|
|
440
|
+
const counts = [10, 50, 100, 200, 300];
|
|
441
|
+
const records = [];
|
|
442
|
+
const expectedTotal = counts.reduce((sum, c) => sum + c, 0);
|
|
443
|
+
for (let bundleIdx = 0; bundleIdx < counts.length; bundleIdx++) {
|
|
444
|
+
const count = counts[bundleIdx];
|
|
445
|
+
const items = Array.from({ length: count }, (_, i) => ({
|
|
446
|
+
bundleId: bundleIdx,
|
|
447
|
+
itemIdx: i,
|
|
448
|
+
payload: `bundle-${bundleIdx}-item-${i}`,
|
|
449
|
+
}));
|
|
450
|
+
const envelope = await makeCompressedEnvelope(items);
|
|
451
|
+
records.push(makeSqsRecord({ messageBody: envelope }, `msg-bundle-${bundleIdx}`));
|
|
452
|
+
}
|
|
453
|
+
const { items, recordMap, stats } = await unbundleRecords(records);
|
|
454
|
+
expect(items).toHaveLength(expectedTotal);
|
|
455
|
+
expect(stats.totalItems).toBe(expectedTotal);
|
|
456
|
+
expect(stats.bundledRecords).toBe(5);
|
|
457
|
+
expect(stats.legacyRecords).toBe(0);
|
|
458
|
+
expect(stats.failedRecords).toBe(0);
|
|
459
|
+
const itemsByBundle = new Map();
|
|
460
|
+
for (const item of items) {
|
|
461
|
+
const expectedMsgId = `msg-bundle-${item.bundleId}`;
|
|
462
|
+
expect(recordMap.get(item)).toBe(expectedMsgId);
|
|
463
|
+
itemsByBundle.set(item.bundleId, (itemsByBundle.get(item.bundleId) ?? 0) + 1);
|
|
464
|
+
}
|
|
465
|
+
expect(itemsByBundle.get(0)).toBe(10);
|
|
466
|
+
expect(itemsByBundle.get(1)).toBe(50);
|
|
467
|
+
expect(itemsByBundle.get(2)).toBe(100);
|
|
468
|
+
expect(itemsByBundle.get(3)).toBe(200);
|
|
469
|
+
expect(itemsByBundle.get(4)).toBe(300);
|
|
470
|
+
});
|
|
471
|
+
it('handles realistic 80% bundled / 20% legacy migration ratio', async () => {
|
|
472
|
+
const records = [];
|
|
473
|
+
const totalMessages = 100;
|
|
474
|
+
const bundledCount = 80;
|
|
475
|
+
const legacyCount = 20;
|
|
476
|
+
const itemsPerBundle = 25;
|
|
477
|
+
for (let i = 0; i < bundledCount; i++) {
|
|
478
|
+
const items = Array.from({ length: itemsPerBundle }, (_, j) => ({
|
|
479
|
+
type: 'bundled',
|
|
480
|
+
bundleIdx: i,
|
|
481
|
+
itemIdx: j,
|
|
482
|
+
}));
|
|
483
|
+
const envelope = await makeCompressedEnvelope(items);
|
|
484
|
+
records.push(makeSqsRecord({ messageBody: envelope }, `msg-bundled-${i}`));
|
|
485
|
+
}
|
|
486
|
+
for (let i = 0; i < legacyCount; i++) {
|
|
487
|
+
const legacyEvent = {
|
|
488
|
+
type: 'legacy',
|
|
489
|
+
legacyIdx: i,
|
|
490
|
+
itemIdx: 0,
|
|
491
|
+
};
|
|
492
|
+
records.push(makeSqsRecord(legacyEvent, `msg-legacy-${i}`));
|
|
493
|
+
}
|
|
494
|
+
const shuffled = [...records].sort(() => Math.random() - 0.5);
|
|
495
|
+
const { items, stats, recordMap } = await unbundleRecords(shuffled);
|
|
496
|
+
expect(stats.totalRecords).toBe(totalMessages);
|
|
497
|
+
expect(stats.bundledRecords).toBe(bundledCount);
|
|
498
|
+
expect(stats.legacyRecords).toBe(legacyCount);
|
|
499
|
+
expect(stats.failedRecords).toBe(0);
|
|
500
|
+
expect(items).toHaveLength(bundledCount * itemsPerBundle + legacyCount);
|
|
501
|
+
expect(stats.totalItems).toBe(2020);
|
|
502
|
+
const bundledItems = items.filter((i) => i.type === 'bundled');
|
|
503
|
+
const legacyItems = items.filter((i) => i.type === 'legacy');
|
|
504
|
+
expect(bundledItems).toHaveLength(bundledCount * itemsPerBundle);
|
|
505
|
+
expect(legacyItems).toHaveLength(legacyCount);
|
|
506
|
+
for (const item of bundledItems) {
|
|
507
|
+
expect(recordMap.get(item)).toBe(`msg-bundled-${item.bundleIdx}`);
|
|
508
|
+
}
|
|
509
|
+
for (const item of legacyItems) {
|
|
510
|
+
expect(recordMap.get(item)).toBe(`msg-legacy-${item.legacyIdx}`);
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
it('preserves Unicode characters through ZSTD compression', async () => {
|
|
514
|
+
const unicodeItems = [
|
|
515
|
+
{
|
|
516
|
+
id: 'emoji',
|
|
517
|
+
content: '🎉🚀💻🌍✨ Party time!',
|
|
518
|
+
description: 'Emojis should survive compression',
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
id: 'chinese',
|
|
522
|
+
content: '中文测试:欢迎使用我们的服务',
|
|
523
|
+
description: 'Chinese characters',
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
id: 'arabic',
|
|
527
|
+
content: 'العربية: مرحبا بكم في خدمتنا',
|
|
528
|
+
description: 'Arabic text (RTL)',
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
id: 'math',
|
|
532
|
+
content: '∑∫∂∇ε → ∞ × ∈ ⊆ ∀∃',
|
|
533
|
+
description: 'Mathematical symbols',
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
id: 'mixed',
|
|
537
|
+
content: 'Hello 世界 🌏 مرحبا ∑ Привет',
|
|
538
|
+
description: 'Mixed scripts',
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
id: 'special',
|
|
542
|
+
content: '️️️️️️️️️️️️️️️️',
|
|
543
|
+
description: 'Unicode edge cases',
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
id: 'japanese',
|
|
547
|
+
content: 'こんにちは世界 ひらがな カタカナ 漢字',
|
|
548
|
+
description: 'Japanese hiragana, katakana, kanji',
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
id: 'korean',
|
|
552
|
+
content: '안녕하세요 세계',
|
|
553
|
+
description: 'Korean hangul',
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
id: 'cyrillic',
|
|
557
|
+
content: 'Привет мир! Это тест.',
|
|
558
|
+
description: 'Russian Cyrillic',
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
id: 'combining',
|
|
562
|
+
content: 'e\u0301 n\u0303 c\u0327',
|
|
563
|
+
description: 'Combining diacritical marks',
|
|
564
|
+
},
|
|
565
|
+
];
|
|
566
|
+
const envelope = await makeCompressedEnvelope(unicodeItems);
|
|
567
|
+
const record = makeSqsRecord({ messageBody: envelope }, 'msg-unicode');
|
|
568
|
+
const { items } = await unbundleRecords([record]);
|
|
569
|
+
expect(items).toHaveLength(unicodeItems.length);
|
|
570
|
+
for (let i = 0; i < unicodeItems.length; i++) {
|
|
571
|
+
expect(items[i].id).toBe(unicodeItems[i].id);
|
|
572
|
+
expect(items[i].content).toBe(unicodeItems[i].content);
|
|
573
|
+
expect(items[i].description).toBe(unicodeItems[i].description);
|
|
574
|
+
const originalBytes = Buffer.from(unicodeItems[i].content, 'utf8');
|
|
575
|
+
const recoveredBytes = Buffer.from(items[i].content, 'utf8');
|
|
576
|
+
expect(recoveredBytes.equals(originalBytes)).toBe(true);
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
it('preserves deeply nested structures (10 levels)', async () => {
|
|
580
|
+
function createDeepStructure(depth, maxDepth = 10) {
|
|
581
|
+
const node = {
|
|
582
|
+
level: depth,
|
|
583
|
+
data: `level-${depth}-data-${Math.random().toString(36).slice(2)}`,
|
|
584
|
+
};
|
|
585
|
+
if (depth < maxDepth) {
|
|
586
|
+
node.child = createDeepStructure(depth + 1, maxDepth);
|
|
587
|
+
node.siblings = [
|
|
588
|
+
createDeepStructure(depth + 1, Math.min(depth + 3, maxDepth)),
|
|
589
|
+
createDeepStructure(depth + 1, Math.min(depth + 2, maxDepth)),
|
|
590
|
+
];
|
|
591
|
+
}
|
|
592
|
+
return node;
|
|
593
|
+
}
|
|
594
|
+
const deepItems = Array.from({ length: 10 }, (_, i) => ({
|
|
595
|
+
id: `deep-${i}`,
|
|
596
|
+
nested: createDeepStructure(0, 10),
|
|
597
|
+
arrays: [
|
|
598
|
+
[[[[['deeply', 'nested', 'array']]], [{ inner: { value: i } }]]],
|
|
599
|
+
],
|
|
600
|
+
}));
|
|
601
|
+
const envelope = await makeCompressedEnvelope(deepItems);
|
|
602
|
+
const record = makeSqsRecord({ messageBody: envelope }, 'msg-deep');
|
|
603
|
+
const { items } = await unbundleRecords([record]);
|
|
604
|
+
expect(items).toHaveLength(10);
|
|
605
|
+
for (let i = 0; i < 10; i++) {
|
|
606
|
+
expect(JSON.stringify(items[i])).toBe(JSON.stringify(deepItems[i]));
|
|
607
|
+
expect(items[i].nested.level).toBe(0);
|
|
608
|
+
expect(items[i].nested.child?.level).toBe(1);
|
|
609
|
+
expect(items[i].nested.child?.child?.child?.level).toBe(3);
|
|
610
|
+
expect(items[i].arrays[0][0][0][0][0][0]).toBe('deeply');
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
it('handles binary-like string data (base64 encoded)', async () => {
|
|
614
|
+
const binaryItems = [
|
|
615
|
+
{
|
|
616
|
+
id: 'small-binary',
|
|
617
|
+
base64Data: Buffer.from('Small binary payload').toString('base64'),
|
|
618
|
+
size: 'small',
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
id: 'medium-binary',
|
|
622
|
+
base64Data: Buffer.from('x'.repeat(1000)).toString('base64'),
|
|
623
|
+
size: 'medium',
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
id: 'image-simulation',
|
|
627
|
+
base64Data: Buffer.from([
|
|
628
|
+
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0xff, 0xd8, 0xff, 0xe0,
|
|
629
|
+
]).toString('base64'),
|
|
630
|
+
size: 'binary-header',
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
id: 'random-bytes',
|
|
634
|
+
base64Data: Buffer.from(Array.from({ length: 256 }, () => Math.floor(Math.random() * 256))).toString('base64'),
|
|
635
|
+
size: 'random',
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
id: 'all-byte-values',
|
|
639
|
+
base64Data: Buffer.from(Array.from({ length: 256 }, (_, i) => i)).toString('base64'),
|
|
640
|
+
size: 'full-range',
|
|
641
|
+
},
|
|
642
|
+
];
|
|
643
|
+
const envelope = await makeCompressedEnvelope(binaryItems);
|
|
644
|
+
const record = makeSqsRecord({ messageBody: envelope }, 'msg-binary');
|
|
645
|
+
const { items } = await unbundleRecords([record]);
|
|
646
|
+
expect(items).toHaveLength(binaryItems.length);
|
|
647
|
+
for (let i = 0; i < binaryItems.length; i++) {
|
|
648
|
+
expect(items[i].id).toBe(binaryItems[i].id);
|
|
649
|
+
expect(items[i].base64Data).toBe(binaryItems[i].base64Data);
|
|
650
|
+
const originalDecoded = Buffer.from(binaryItems[i].base64Data, 'base64');
|
|
651
|
+
const recoveredDecoded = Buffer.from(items[i].base64Data, 'base64');
|
|
652
|
+
expect(recoveredDecoded.equals(originalDecoded)).toBe(true);
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
it('handles concurrent unbundling stress test (100 records in parallel)', async () => {
|
|
656
|
+
const recordCount = 100;
|
|
657
|
+
const records = [];
|
|
658
|
+
for (let i = 0; i < recordCount; i++) {
|
|
659
|
+
const itemsInBundle = 10 + (i % 20);
|
|
660
|
+
const items = Array.from({ length: itemsInBundle }, (_, j) => ({
|
|
661
|
+
recordIdx: i,
|
|
662
|
+
itemIdx: j,
|
|
663
|
+
uniqueId: `r${i}-i${j}`,
|
|
664
|
+
timestamp: Date.now() + i * 1000 + j,
|
|
665
|
+
data: `payload-${i}-${j}-${Math.random().toString(36).slice(2)}`,
|
|
666
|
+
}));
|
|
667
|
+
const envelope = await makeCompressedEnvelope(items);
|
|
668
|
+
records.push(makeSqsRecord({ messageBody: envelope }, `stress-msg-${i}`));
|
|
669
|
+
}
|
|
670
|
+
const startTime = Date.now();
|
|
671
|
+
const { items, recordMap, stats, failedMessageIds } = await unbundleRecords(records);
|
|
672
|
+
const duration = Date.now() - startTime;
|
|
673
|
+
expect(failedMessageIds).toHaveLength(0);
|
|
674
|
+
expect(stats.failedRecords).toBe(0);
|
|
675
|
+
expect(stats.bundledRecords).toBe(recordCount);
|
|
676
|
+
const seenUniqueIds = new Set();
|
|
677
|
+
for (const item of items) {
|
|
678
|
+
expect(seenUniqueIds.has(item.uniqueId)).toBe(false);
|
|
679
|
+
seenUniqueIds.add(item.uniqueId);
|
|
680
|
+
const expectedMsgId = `stress-msg-${item.recordIdx}`;
|
|
681
|
+
expect(recordMap.get(item)).toBe(expectedMsgId);
|
|
682
|
+
expect(item.itemIdx).toBeGreaterThanOrEqual(0);
|
|
683
|
+
expect(item.itemIdx).toBeLessThan(30);
|
|
684
|
+
}
|
|
685
|
+
const expectedTotal = Array.from({ length: recordCount }, (_, i) => 10 + (i % 20)).reduce((a, b) => a + b, 0);
|
|
686
|
+
expect(items).toHaveLength(expectedTotal);
|
|
687
|
+
expect(stats.totalItems).toBe(expectedTotal);
|
|
688
|
+
console.log(`Unbundled ${recordCount} records (${stats.totalItems} items) in ${duration}ms`);
|
|
689
|
+
});
|
|
690
|
+
it('handles items with all JSON primitive types', async () => {
|
|
691
|
+
const primitiveItems = [
|
|
692
|
+
{
|
|
693
|
+
id: 'primitives',
|
|
694
|
+
stringVal: 'hello',
|
|
695
|
+
numberVal: 42,
|
|
696
|
+
floatVal: 3.14159265359,
|
|
697
|
+
boolTrue: true,
|
|
698
|
+
boolFalse: false,
|
|
699
|
+
nullVal: null,
|
|
700
|
+
emptyString: '',
|
|
701
|
+
zero: 0,
|
|
702
|
+
negativeNum: -999,
|
|
703
|
+
largeNum: Number.MAX_SAFE_INTEGER,
|
|
704
|
+
smallNum: Number.MIN_SAFE_INTEGER,
|
|
705
|
+
scientificNotation: 1.23e10,
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
id: 'arrays',
|
|
709
|
+
emptyArray: [],
|
|
710
|
+
numberArray: [1, 2, 3],
|
|
711
|
+
mixedArray: [1, 'two', true, null],
|
|
712
|
+
nestedArray: [[1, 2], [3, 4], [[5]]],
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
id: 'objects',
|
|
716
|
+
emptyObject: {},
|
|
717
|
+
nestedObject: { a: { b: { c: 1 } } },
|
|
718
|
+
arrayOfObjects: [{ x: 1 }, { y: 2 }],
|
|
719
|
+
},
|
|
720
|
+
];
|
|
721
|
+
const envelope = await makeCompressedEnvelope(primitiveItems);
|
|
722
|
+
const record = makeSqsRecord({ messageBody: envelope }, 'msg-primitives');
|
|
723
|
+
const { items } = await unbundleRecords([record]);
|
|
724
|
+
expect(items).toHaveLength(3);
|
|
725
|
+
expect(JSON.stringify(items)).toBe(JSON.stringify(primitiveItems));
|
|
726
|
+
});
|
|
727
|
+
it('maintains item order across multiple bundles', async () => {
|
|
728
|
+
const records = [];
|
|
729
|
+
let globalIdx = 0;
|
|
730
|
+
for (let bundleIdx = 0; bundleIdx < 10; bundleIdx++) {
|
|
731
|
+
const itemCount = 10 + bundleIdx * 5;
|
|
732
|
+
const items = Array.from({ length: itemCount }, () => ({
|
|
733
|
+
globalOrder: globalIdx++,
|
|
734
|
+
bundle: bundleIdx,
|
|
735
|
+
}));
|
|
736
|
+
const envelope = await makeCompressedEnvelope(items);
|
|
737
|
+
records.push(makeSqsRecord({ messageBody: envelope }, `order-msg-${bundleIdx}`));
|
|
738
|
+
}
|
|
739
|
+
const { items } = await unbundleRecords(records);
|
|
740
|
+
const bundleGroups = new Map();
|
|
741
|
+
for (const item of items) {
|
|
742
|
+
if (!bundleGroups.has(item.bundle)) {
|
|
743
|
+
bundleGroups.set(item.bundle, []);
|
|
744
|
+
}
|
|
745
|
+
bundleGroups.get(item.bundle)?.push(item.globalOrder);
|
|
746
|
+
}
|
|
747
|
+
for (const [, orders] of bundleGroups) {
|
|
748
|
+
for (let i = 1; i < orders.length; i++) {
|
|
749
|
+
expect(orders[i]).toBeGreaterThan(orders[i - 1]);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
it('handles edge case: single item bundles', async () => {
|
|
754
|
+
const records = await Promise.all(Array.from({ length: 50 }, async (_, i) => {
|
|
755
|
+
const items = [{ id: `single-${i}`, value: i }];
|
|
756
|
+
const envelope = await makeCompressedEnvelope(items);
|
|
757
|
+
return makeSqsRecord({ messageBody: envelope }, `single-msg-${i}`);
|
|
758
|
+
}));
|
|
759
|
+
const { items, stats, recordMap } = await unbundleRecords(records);
|
|
760
|
+
expect(items).toHaveLength(50);
|
|
761
|
+
expect(stats.bundledRecords).toBe(50);
|
|
762
|
+
expect(stats.totalItems).toBe(50);
|
|
763
|
+
for (let i = 0; i < 50; i++) {
|
|
764
|
+
const item = items.find((x) => x.value === i);
|
|
765
|
+
expect(item).toBeDefined();
|
|
766
|
+
if (!item)
|
|
767
|
+
throw new Error(`Expected item with value ${i} to be found`);
|
|
768
|
+
expect(recordMap.get(item)).toMatch(/single-msg-\d+/);
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
it('handles edge case: empty arrays in bundles', async () => {
|
|
772
|
+
const emptyEnvelope = {
|
|
773
|
+
v: 1,
|
|
774
|
+
c: CompressionAlgorithm.NONE,
|
|
775
|
+
n: 0,
|
|
776
|
+
p: [],
|
|
777
|
+
};
|
|
778
|
+
const record = makeSqsRecord({ messageBody: emptyEnvelope }, 'msg-empty');
|
|
779
|
+
const { items, stats } = await unbundleRecords([record]);
|
|
780
|
+
expect(items).toHaveLength(0);
|
|
781
|
+
expect(stats.bundledRecords).toBe(1);
|
|
782
|
+
expect(stats.totalItems).toBe(0);
|
|
783
|
+
});
|
|
784
|
+
});
|
|
785
|
+
});
|
|
786
|
+
//# sourceMappingURL=sqs-unbundle.spec.js.map
|