@modainteract/moda-interact-shared 5.2.0 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/internationalization.d.ts +2 -2
- package/dist/shopify/index.d.ts +23 -23
- package/dist/shopify/node.d.ts +12 -1
- package/dist/shopify/node.js +38 -4
- package/dist/shopify/node.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@ import { z } from 'zod';
|
|
|
2
2
|
import { PrimitiveType } from 'intl-messageformat';
|
|
3
3
|
|
|
4
4
|
declare const LanguageSourceSchema: z.ZodEnum<{
|
|
5
|
-
shopify: "shopify";
|
|
6
5
|
"customer-explicit": "customer-explicit";
|
|
7
6
|
detected: "detected";
|
|
7
|
+
shopify: "shopify";
|
|
8
8
|
"merchant-default": "merchant-default";
|
|
9
9
|
"platform-default": "platform-default";
|
|
10
10
|
}>;
|
|
@@ -45,9 +45,9 @@ declare const TimeZoneIdSchema: z.ZodPipe<z.ZodString, z.ZodTransform<string, st
|
|
|
45
45
|
declare const InternationalContextSchema: z.ZodObject<{
|
|
46
46
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
47
47
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
48
|
-
shopify: "shopify";
|
|
49
48
|
"customer-explicit": "customer-explicit";
|
|
50
49
|
detected: "detected";
|
|
50
|
+
shopify: "shopify";
|
|
51
51
|
"merchant-default": "merchant-default";
|
|
52
52
|
"platform-default": "platform-default";
|
|
53
53
|
}>>;
|
package/dist/shopify/index.d.ts
CHANGED
|
@@ -389,9 +389,9 @@ declare const ShopifyCheckoutCreatedEventV2Schema: z.ZodObject<{
|
|
|
389
389
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
390
390
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
391
391
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
392
|
-
shopify: "shopify";
|
|
393
392
|
"customer-explicit": "customer-explicit";
|
|
394
393
|
detected: "detected";
|
|
394
|
+
shopify: "shopify";
|
|
395
395
|
"merchant-default": "merchant-default";
|
|
396
396
|
"platform-default": "platform-default";
|
|
397
397
|
}>>;
|
|
@@ -426,9 +426,9 @@ declare const ShopifyCartActivityEventV2Schema: z.ZodObject<{
|
|
|
426
426
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
427
427
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
428
428
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
429
|
-
shopify: "shopify";
|
|
430
429
|
"customer-explicit": "customer-explicit";
|
|
431
430
|
detected: "detected";
|
|
431
|
+
shopify: "shopify";
|
|
432
432
|
"merchant-default": "merchant-default";
|
|
433
433
|
"platform-default": "platform-default";
|
|
434
434
|
}>>;
|
|
@@ -461,9 +461,9 @@ declare const ShopifyCheckoutUpdatedEventV2Schema: z.ZodObject<{
|
|
|
461
461
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
462
462
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
463
463
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
464
|
-
shopify: "shopify";
|
|
465
464
|
"customer-explicit": "customer-explicit";
|
|
466
465
|
detected: "detected";
|
|
466
|
+
shopify: "shopify";
|
|
467
467
|
"merchant-default": "merchant-default";
|
|
468
468
|
"platform-default": "platform-default";
|
|
469
469
|
}>>;
|
|
@@ -495,9 +495,9 @@ declare const ShopifyOrderCompletedEventV2Schema: z.ZodObject<{
|
|
|
495
495
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
496
496
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
497
497
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
498
|
-
shopify: "shopify";
|
|
499
498
|
"customer-explicit": "customer-explicit";
|
|
500
499
|
detected: "detected";
|
|
500
|
+
shopify: "shopify";
|
|
501
501
|
"merchant-default": "merchant-default";
|
|
502
502
|
"platform-default": "platform-default";
|
|
503
503
|
}>>;
|
|
@@ -532,9 +532,9 @@ declare const ShopifyRecoveryEventV2Schema: z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
532
532
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
533
533
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
534
534
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
535
|
-
shopify: "shopify";
|
|
536
535
|
"customer-explicit": "customer-explicit";
|
|
537
536
|
detected: "detected";
|
|
537
|
+
shopify: "shopify";
|
|
538
538
|
"merchant-default": "merchant-default";
|
|
539
539
|
"platform-default": "platform-default";
|
|
540
540
|
}>>;
|
|
@@ -565,9 +565,9 @@ declare const ShopifyRecoveryEventV2Schema: z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
565
565
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
566
566
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
567
567
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
568
|
-
shopify: "shopify";
|
|
569
568
|
"customer-explicit": "customer-explicit";
|
|
570
569
|
detected: "detected";
|
|
570
|
+
shopify: "shopify";
|
|
571
571
|
"merchant-default": "merchant-default";
|
|
572
572
|
"platform-default": "platform-default";
|
|
573
573
|
}>>;
|
|
@@ -600,9 +600,9 @@ declare const ShopifyRecoveryEventV2Schema: z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
600
600
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
601
601
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
602
602
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
603
|
-
shopify: "shopify";
|
|
604
603
|
"customer-explicit": "customer-explicit";
|
|
605
604
|
detected: "detected";
|
|
605
|
+
shopify: "shopify";
|
|
606
606
|
"merchant-default": "merchant-default";
|
|
607
607
|
"platform-default": "platform-default";
|
|
608
608
|
}>>;
|
|
@@ -632,9 +632,9 @@ declare const ShopifyRecoveryEventV2Schema: z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
632
632
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
633
633
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
634
634
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
635
|
-
shopify: "shopify";
|
|
636
635
|
"customer-explicit": "customer-explicit";
|
|
637
636
|
detected: "detected";
|
|
637
|
+
shopify: "shopify";
|
|
638
638
|
"merchant-default": "merchant-default";
|
|
639
639
|
"platform-default": "platform-default";
|
|
640
640
|
}>>;
|
|
@@ -677,7 +677,7 @@ declare function safeParseShopifyRecoveryEventV2(input: unknown): z.ZodSafeParse
|
|
|
677
677
|
};
|
|
678
678
|
internationalContext?: {
|
|
679
679
|
languageTag: string | null;
|
|
680
|
-
languageSource: "
|
|
680
|
+
languageSource: "customer-explicit" | "detected" | "shopify" | "merchant-default" | "platform-default" | null;
|
|
681
681
|
countryCode: string | null;
|
|
682
682
|
currencyCode: string | null;
|
|
683
683
|
timeZone: string | null;
|
|
@@ -704,7 +704,7 @@ declare function safeParseShopifyRecoveryEventV2(input: unknown): z.ZodSafeParse
|
|
|
704
704
|
};
|
|
705
705
|
internationalContext?: {
|
|
706
706
|
languageTag: string | null;
|
|
707
|
-
languageSource: "
|
|
707
|
+
languageSource: "customer-explicit" | "detected" | "shopify" | "merchant-default" | "platform-default" | null;
|
|
708
708
|
countryCode: string | null;
|
|
709
709
|
currencyCode: string | null;
|
|
710
710
|
timeZone: string | null;
|
|
@@ -730,7 +730,7 @@ declare function safeParseShopifyRecoveryEventV2(input: unknown): z.ZodSafeParse
|
|
|
730
730
|
};
|
|
731
731
|
internationalContext?: {
|
|
732
732
|
languageTag: string | null;
|
|
733
|
-
languageSource: "
|
|
733
|
+
languageSource: "customer-explicit" | "detected" | "shopify" | "merchant-default" | "platform-default" | null;
|
|
734
734
|
countryCode: string | null;
|
|
735
735
|
currencyCode: string | null;
|
|
736
736
|
timeZone: string | null;
|
|
@@ -759,7 +759,7 @@ declare function safeParseShopifyRecoveryEventV2(input: unknown): z.ZodSafeParse
|
|
|
759
759
|
};
|
|
760
760
|
internationalContext?: {
|
|
761
761
|
languageTag: string | null;
|
|
762
|
-
languageSource: "
|
|
762
|
+
languageSource: "customer-explicit" | "detected" | "shopify" | "merchant-default" | "platform-default" | null;
|
|
763
763
|
countryCode: string | null;
|
|
764
764
|
currencyCode: string | null;
|
|
765
765
|
timeZone: string | null;
|
|
@@ -803,9 +803,9 @@ declare const ShopifyCheckoutUpdatedEventV3Schema: z.ZodObject<{
|
|
|
803
803
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
804
804
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
805
805
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
806
|
-
shopify: "shopify";
|
|
807
806
|
"customer-explicit": "customer-explicit";
|
|
808
807
|
detected: "detected";
|
|
808
|
+
shopify: "shopify";
|
|
809
809
|
"merchant-default": "merchant-default";
|
|
810
810
|
"platform-default": "platform-default";
|
|
811
811
|
}>>;
|
|
@@ -841,9 +841,9 @@ declare const ShopifyRecoveryEventSchema: z.ZodUnion<readonly [z.ZodDiscriminate
|
|
|
841
841
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
842
842
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
843
843
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
844
|
-
shopify: "shopify";
|
|
845
844
|
"customer-explicit": "customer-explicit";
|
|
846
845
|
detected: "detected";
|
|
846
|
+
shopify: "shopify";
|
|
847
847
|
"merchant-default": "merchant-default";
|
|
848
848
|
"platform-default": "platform-default";
|
|
849
849
|
}>>;
|
|
@@ -874,9 +874,9 @@ declare const ShopifyRecoveryEventSchema: z.ZodUnion<readonly [z.ZodDiscriminate
|
|
|
874
874
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
875
875
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
876
876
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
877
|
-
shopify: "shopify";
|
|
878
877
|
"customer-explicit": "customer-explicit";
|
|
879
878
|
detected: "detected";
|
|
879
|
+
shopify: "shopify";
|
|
880
880
|
"merchant-default": "merchant-default";
|
|
881
881
|
"platform-default": "platform-default";
|
|
882
882
|
}>>;
|
|
@@ -909,9 +909,9 @@ declare const ShopifyRecoveryEventSchema: z.ZodUnion<readonly [z.ZodDiscriminate
|
|
|
909
909
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
910
910
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
911
911
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
912
|
-
shopify: "shopify";
|
|
913
912
|
"customer-explicit": "customer-explicit";
|
|
914
913
|
detected: "detected";
|
|
914
|
+
shopify: "shopify";
|
|
915
915
|
"merchant-default": "merchant-default";
|
|
916
916
|
"platform-default": "platform-default";
|
|
917
917
|
}>>;
|
|
@@ -941,9 +941,9 @@ declare const ShopifyRecoveryEventSchema: z.ZodUnion<readonly [z.ZodDiscriminate
|
|
|
941
941
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
942
942
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
943
943
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
944
|
-
shopify: "shopify";
|
|
945
944
|
"customer-explicit": "customer-explicit";
|
|
946
945
|
detected: "detected";
|
|
946
|
+
shopify: "shopify";
|
|
947
947
|
"merchant-default": "merchant-default";
|
|
948
948
|
"platform-default": "platform-default";
|
|
949
949
|
}>>;
|
|
@@ -976,9 +976,9 @@ declare const ShopifyRecoveryEventSchema: z.ZodUnion<readonly [z.ZodDiscriminate
|
|
|
976
976
|
internationalContext: z.ZodOptional<z.ZodObject<{
|
|
977
977
|
languageTag: z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
|
|
978
978
|
languageSource: z.ZodNullable<z.ZodEnum<{
|
|
979
|
-
shopify: "shopify";
|
|
980
979
|
"customer-explicit": "customer-explicit";
|
|
981
980
|
detected: "detected";
|
|
981
|
+
shopify: "shopify";
|
|
982
982
|
"merchant-default": "merchant-default";
|
|
983
983
|
"platform-default": "platform-default";
|
|
984
984
|
}>>;
|
|
@@ -1020,7 +1020,7 @@ declare function safeParseShopifyRecoveryEvent(input: unknown): z.ZodSafeParseRe
|
|
|
1020
1020
|
};
|
|
1021
1021
|
internationalContext?: {
|
|
1022
1022
|
languageTag: string | null;
|
|
1023
|
-
languageSource: "
|
|
1023
|
+
languageSource: "customer-explicit" | "detected" | "shopify" | "merchant-default" | "platform-default" | null;
|
|
1024
1024
|
countryCode: string | null;
|
|
1025
1025
|
currencyCode: string | null;
|
|
1026
1026
|
timeZone: string | null;
|
|
@@ -1047,7 +1047,7 @@ declare function safeParseShopifyRecoveryEvent(input: unknown): z.ZodSafeParseRe
|
|
|
1047
1047
|
};
|
|
1048
1048
|
internationalContext?: {
|
|
1049
1049
|
languageTag: string | null;
|
|
1050
|
-
languageSource: "
|
|
1050
|
+
languageSource: "customer-explicit" | "detected" | "shopify" | "merchant-default" | "platform-default" | null;
|
|
1051
1051
|
countryCode: string | null;
|
|
1052
1052
|
currencyCode: string | null;
|
|
1053
1053
|
timeZone: string | null;
|
|
@@ -1073,7 +1073,7 @@ declare function safeParseShopifyRecoveryEvent(input: unknown): z.ZodSafeParseRe
|
|
|
1073
1073
|
};
|
|
1074
1074
|
internationalContext?: {
|
|
1075
1075
|
languageTag: string | null;
|
|
1076
|
-
languageSource: "
|
|
1076
|
+
languageSource: "customer-explicit" | "detected" | "shopify" | "merchant-default" | "platform-default" | null;
|
|
1077
1077
|
countryCode: string | null;
|
|
1078
1078
|
currencyCode: string | null;
|
|
1079
1079
|
timeZone: string | null;
|
|
@@ -1102,7 +1102,7 @@ declare function safeParseShopifyRecoveryEvent(input: unknown): z.ZodSafeParseRe
|
|
|
1102
1102
|
};
|
|
1103
1103
|
internationalContext?: {
|
|
1104
1104
|
languageTag: string | null;
|
|
1105
|
-
languageSource: "
|
|
1105
|
+
languageSource: "customer-explicit" | "detected" | "shopify" | "merchant-default" | "platform-default" | null;
|
|
1106
1106
|
countryCode: string | null;
|
|
1107
1107
|
currencyCode: string | null;
|
|
1108
1108
|
timeZone: string | null;
|
|
@@ -1131,7 +1131,7 @@ declare function safeParseShopifyRecoveryEvent(input: unknown): z.ZodSafeParseRe
|
|
|
1131
1131
|
};
|
|
1132
1132
|
internationalContext?: {
|
|
1133
1133
|
languageTag: string | null;
|
|
1134
|
-
languageSource: "
|
|
1134
|
+
languageSource: "customer-explicit" | "detected" | "shopify" | "merchant-default" | "platform-default" | null;
|
|
1135
1135
|
countryCode: string | null;
|
|
1136
1136
|
currencyCode: string | null;
|
|
1137
1137
|
timeZone: string | null;
|
package/dist/shopify/node.d.ts
CHANGED
|
@@ -3,6 +3,16 @@ import { C as CredentialKeyring } from '../keyring-BLXjNChq.js';
|
|
|
3
3
|
import 'zod';
|
|
4
4
|
|
|
5
5
|
type ShopifyOfflineTokenErrorCode = "SESSION_MISSING" | "SESSION_IDENTITY_CONFLICT" | "INVALID_SESSION" | "REFRESH_TOKEN_EXPIRED" | "OAUTH_CONFIG_UNAVAILABLE" | "LOCK_TIMEOUT" | "CANCELLED" | "DEADLINE" | "REFRESH_REJECTED" | "REFRESH_RESPONSE_INVALID" | "REFRESH_OUTCOME_UNKNOWN" | "PERSISTENCE_UNAVAILABLE";
|
|
6
|
+
/** Bounded refresh lifecycle metadata. Never includes provider credentials or errors. */
|
|
7
|
+
type ShopifyOfflineRefreshEvent = Readonly<{
|
|
8
|
+
event: "shopify.offline_refresh.started" | "shopify.offline_refresh.committed" | "shopify.offline_refresh.failed";
|
|
9
|
+
operationId: string;
|
|
10
|
+
shopId: string | null;
|
|
11
|
+
source: "SHARED" | "SDK";
|
|
12
|
+
durationMs: number;
|
|
13
|
+
outcome: "STARTED" | "COMMITTED" | "REJECTED" | "UNKNOWN" | "CANCELLED" | "UNAVAILABLE";
|
|
14
|
+
reasonCode: ShopifyOfflineTokenErrorCode | null;
|
|
15
|
+
}>;
|
|
6
16
|
declare class ShopifyOfflineTokenError extends Error {
|
|
7
17
|
readonly code: ShopifyOfflineTokenErrorCode;
|
|
8
18
|
readonly retryable: boolean;
|
|
@@ -243,6 +253,7 @@ declare function createShopifyOfflineTokenProvider(input: Readonly<{
|
|
|
243
253
|
}>>;
|
|
244
254
|
fetch: typeof fetch;
|
|
245
255
|
now?: () => number;
|
|
256
|
+
onEvent?: (event: ShopifyOfflineRefreshEvent) => void;
|
|
246
257
|
}>): ShopifyOfflineTokenProvider;
|
|
247
258
|
|
|
248
259
|
declare const CONFIGURATION_KEY: "shopify.oauth";
|
|
@@ -311,4 +322,4 @@ declare function createShopifyDiscountSyncJobId(event: {
|
|
|
311
322
|
*/
|
|
312
323
|
declare function createShopifyWhatsAppConsentSyncJobId(input: ShopifyWhatsAppConsentSyncJobV1): string;
|
|
313
324
|
|
|
314
|
-
export { type LockedSessionContext, type OfflineCredentialSnapshot, type SdkInstallationSessionContext, ShopifyOAuthConfigurationError, type ShopifyOAuthConfigurationErrorCode, type ShopifyOAuthConfigurationPrisma, type ShopifyOAuthConfigurationRow, type ShopifyOAuthCredentials, type ShopifyOfflineBigIntFilter, type ShopifyOfflineBooleanFilter, type ShopifyOfflineDatabase, type ShopifyOfflineDateFilter, type ShopifyOfflineNullableBooleanFilter, type ShopifyOfflineNullableStringFilter, type ShopifyOfflineSessionCreateData, type ShopifyOfflineSessionData, type ShopifyOfflineSessionDelegate, type ShopifyOfflineSessionRecord, type ShopifyOfflineSessionScalarWhere, type ShopifyOfflineSessionSelect, type ShopifyOfflineSessionUniqueWhere, type ShopifyOfflineSessionWhere, type ShopifyOfflineShopRecord, type ShopifyOfflineStringFilter, ShopifyOfflineTokenError, type ShopifyOfflineTokenErrorCode, type ShopifyOfflineTokenProvider, type ShopifyOfflineTransaction, createPendingRecoveryCandidateJobId, createShopifyCheckoutJobId, createShopifyDiscountSyncJobId, createShopifyOfflineTokenProvider, createShopifyOrderJobId, createShopifyWebhookJobId, createShopifyWhatsAppConsentSyncJobId, readShopifyOAuthConfiguration };
|
|
325
|
+
export { type LockedSessionContext, type OfflineCredentialSnapshot, type SdkInstallationSessionContext, ShopifyOAuthConfigurationError, type ShopifyOAuthConfigurationErrorCode, type ShopifyOAuthConfigurationPrisma, type ShopifyOAuthConfigurationRow, type ShopifyOAuthCredentials, type ShopifyOfflineBigIntFilter, type ShopifyOfflineBooleanFilter, type ShopifyOfflineDatabase, type ShopifyOfflineDateFilter, type ShopifyOfflineNullableBooleanFilter, type ShopifyOfflineNullableStringFilter, type ShopifyOfflineRefreshEvent, type ShopifyOfflineSessionCreateData, type ShopifyOfflineSessionData, type ShopifyOfflineSessionDelegate, type ShopifyOfflineSessionRecord, type ShopifyOfflineSessionScalarWhere, type ShopifyOfflineSessionSelect, type ShopifyOfflineSessionUniqueWhere, type ShopifyOfflineSessionWhere, type ShopifyOfflineShopRecord, type ShopifyOfflineStringFilter, ShopifyOfflineTokenError, type ShopifyOfflineTokenErrorCode, type ShopifyOfflineTokenProvider, type ShopifyOfflineTransaction, createPendingRecoveryCandidateJobId, createShopifyCheckoutJobId, createShopifyDiscountSyncJobId, createShopifyOfflineTokenProvider, createShopifyOrderJobId, createShopifyWebhookJobId, createShopifyWhatsAppConsentSyncJobId, readShopifyOAuthConfiguration };
|
package/dist/shopify/node.js
CHANGED
|
@@ -13,6 +13,8 @@ import { createHash } from "crypto";
|
|
|
13
13
|
|
|
14
14
|
// src/shopify/offline-token-provider.ts
|
|
15
15
|
import { Buffer } from "buffer";
|
|
16
|
+
import { randomUUID } from "crypto";
|
|
17
|
+
import { performance } from "perf_hooks";
|
|
16
18
|
var ERROR_MESSAGES = {
|
|
17
19
|
SESSION_MISSING: "Shopify offline session is unavailable.",
|
|
18
20
|
SESSION_IDENTITY_CONFLICT: "Shopify offline session identity is inconsistent.",
|
|
@@ -141,6 +143,12 @@ function snapshot(row, shopId, shop) {
|
|
|
141
143
|
}
|
|
142
144
|
function createShopifyOfflineTokenProvider(input) {
|
|
143
145
|
const now = input.now ?? Date.now;
|
|
146
|
+
function notify(event) {
|
|
147
|
+
try {
|
|
148
|
+
void Promise.resolve(input.onEvent?.(Object.freeze(event))).catch(() => void 0);
|
|
149
|
+
} catch {
|
|
150
|
+
}
|
|
151
|
+
}
|
|
144
152
|
async function resolveShop(shopId, deadline) {
|
|
145
153
|
deadline.check();
|
|
146
154
|
if (typeof shopId !== "string" || !shopId.trim()) fail("SESSION_MISSING");
|
|
@@ -201,12 +209,25 @@ function createShopifyOfflineTokenProvider(input) {
|
|
|
201
209
|
}
|
|
202
210
|
async function getSession(shopId, options) {
|
|
203
211
|
const deadline = createDeadline(options?.signal);
|
|
212
|
+
let attempt;
|
|
213
|
+
const outcome = { remoteSucceeded: false };
|
|
214
|
+
function emit(event, result, reasonCode) {
|
|
215
|
+
if (!attempt) return;
|
|
216
|
+
notify({
|
|
217
|
+
event,
|
|
218
|
+
operationId: attempt.operationId,
|
|
219
|
+
shopId: attempt.shopId,
|
|
220
|
+
source: "SHARED",
|
|
221
|
+
durationMs: Math.min(6e4, Math.max(0, Math.round(performance.now() - attempt.startedAt))),
|
|
222
|
+
outcome: result,
|
|
223
|
+
reasonCode
|
|
224
|
+
});
|
|
225
|
+
}
|
|
204
226
|
try {
|
|
205
227
|
deadline.check();
|
|
206
228
|
const shop = await resolveShop(shopId, deadline);
|
|
207
229
|
deadline.check();
|
|
208
|
-
const
|
|
209
|
-
return await runLocked(shop, shopId, deadline, async (context) => {
|
|
230
|
+
const result = await runLocked(shop, shopId, deadline, async (context) => {
|
|
210
231
|
let row = await context.transaction.session.findUnique({ where: { id: context.sessionId }, select: SESSION_SELECT });
|
|
211
232
|
if (!row) fail("SESSION_IDENTITY_CONFLICT");
|
|
212
233
|
const currentTime = now();
|
|
@@ -235,6 +256,8 @@ function createShopifyOfflineTokenProvider(input) {
|
|
|
235
256
|
let response;
|
|
236
257
|
try {
|
|
237
258
|
const form = new URLSearchParams({ client_id: credentials.apiKey, client_secret: credentials.apiSecret, grant_type: "refresh_token", refresh_token: row.refreshToken });
|
|
259
|
+
attempt = { operationId: randomUUID(), shopId: context.shopId, startedAt: performance.now() };
|
|
260
|
+
emit("shopify.offline_refresh.started", "STARTED", null);
|
|
238
261
|
response = await input.fetch(`https://${context.shop}/admin/oauth/access_token`, {
|
|
239
262
|
method: "POST",
|
|
240
263
|
redirect: "error",
|
|
@@ -294,9 +317,20 @@ function createShopifyOfflineTokenProvider(input) {
|
|
|
294
317
|
outcome.remoteSucceeded = true;
|
|
295
318
|
return snapshot(row, shopId, context.shop);
|
|
296
319
|
}, outcome);
|
|
320
|
+
emit("shopify.offline_refresh.committed", "COMMITTED", null);
|
|
321
|
+
return result;
|
|
297
322
|
} catch (error) {
|
|
298
|
-
|
|
299
|
-
|
|
323
|
+
let failure = error;
|
|
324
|
+
try {
|
|
325
|
+
deadline.check();
|
|
326
|
+
} catch (deadlineError) {
|
|
327
|
+
failure = deadlineError;
|
|
328
|
+
}
|
|
329
|
+
const code = failure instanceof ShopifyOfflineTokenError ? failure.code : "PERSISTENCE_UNAVAILABLE";
|
|
330
|
+
const ambiguous = outcome.remoteSucceeded && code !== "REFRESH_REJECTED" && code !== "CANCELLED";
|
|
331
|
+
const reason = ambiguous ? "REFRESH_OUTCOME_UNKNOWN" : code;
|
|
332
|
+
emit("shopify.offline_refresh.failed", reason === "REFRESH_REJECTED" ? "REJECTED" : reason === "CANCELLED" ? "CANCELLED" : reason === "REFRESH_OUTCOME_UNKNOWN" ? "UNKNOWN" : "UNAVAILABLE", reason);
|
|
333
|
+
throw failure;
|
|
300
334
|
} finally {
|
|
301
335
|
deadline.dispose();
|
|
302
336
|
}
|
package/dist/shopify/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/shopify/node.ts","../../src/shopify/offline-token-provider.ts","../../src/shopify/oauth-configuration.ts"],"sourcesContent":["import { ShopifyWhatsAppConsentSyncJobV1Schema, type ShopifyWhatsAppConsentSyncJobV1 } from \"./whatsapp-consent-sync.schema.js\";\nimport { createHash } from \"node:crypto\";\n\nexport {\n ShopifyOfflineTokenError,\n createShopifyOfflineTokenProvider,\n type ShopifyOfflineTokenErrorCode,\n type ShopifyOfflineDatabase,\n type ShopifyOfflineTransaction,\n type ShopifyOfflineSessionDelegate,\n type ShopifyOfflineSessionRecord,\n type ShopifyOfflineSessionWhere,\n type ShopifyOfflineSessionScalarWhere,\n type ShopifyOfflineSessionUniqueWhere,\n type ShopifyOfflineSessionSelect,\n type ShopifyOfflineSessionData,\n type ShopifyOfflineSessionCreateData,\n type ShopifyOfflineStringFilter,\n type ShopifyOfflineBooleanFilter,\n type ShopifyOfflineNullableStringFilter,\n type ShopifyOfflineNullableBooleanFilter,\n type ShopifyOfflineDateFilter,\n type ShopifyOfflineBigIntFilter,\n type ShopifyOfflineShopRecord,\n type OfflineCredentialSnapshot,\n type LockedSessionContext,\n type SdkInstallationSessionContext,\n type ShopifyOfflineTokenProvider,\n} from \"./offline-token-provider.js\";\nexport {\n ShopifyOAuthConfigurationError,\n readShopifyOAuthConfiguration,\n type ShopifyOAuthConfigurationErrorCode,\n type ShopifyOAuthConfigurationPrisma,\n type ShopifyOAuthConfigurationRow,\n type ShopifyOAuthCredentials,\n} from \"./oauth-configuration.js\";\n\nfunction createShopifyWebhookJobDigest(prefix: string, first: string, second: string): string {\n if (typeof first !== \"string\" || first.length === 0) {\n throw new Error(`${prefix}: first input must be a non-empty string`);\n }\n\n if (typeof second !== \"string\" || second.length === 0) {\n throw new Error(`${prefix}: second input must be a non-empty string`);\n }\n\n const digest = createHash(\"sha256\").update(`${first}:${second}`).digest(\"hex\");\n return `${prefix}-${digest}`;\n}\n\n/**\n * Legacy webhook delivery job id used by earlier receipt/outbox flows.\n * Prefer the resource-scoped helpers below for current queue publication.\n */\nexport function createShopifyWebhookJobId(appKey: string, deliveryId: string): string {\n return createShopifyWebhookJobDigest(\"shopify\", appKey, deliveryId);\n}\n\nexport function createShopifyCheckoutJobId(shopId: string, checkoutToken: string): string {\n return createShopifyWebhookJobDigest(\"checkout\", shopId, checkoutToken);\n}\n\nexport function createShopifyOrderJobId(shopId: string, orderGid: string): string {\n return createShopifyWebhookJobDigest(\"order-created\", shopId, orderGid);\n}\n\nexport function createPendingRecoveryCandidateJobId(\n shopId: string,\n checkoutToken: string,\n): string {\n return createShopifyWebhookJobDigest(\"pending-recovery\", shopId, checkoutToken);\n}\n\nexport function createShopifyDiscountSyncJobId(event: {\n shopId: string;\n reason: \"SUBSCRIPTION_ACTIVATED\" | \"REINSTALL_RECONCILED\" | \"SCOPES_UPDATED\" | \"ADMIN_REQUESTED\" | \"DISCOUNT_WEBHOOK\";\n requestedAt: string;\n deliveryId?: string | null;\n}): string {\n if (typeof event.shopId !== \"string\" || event.shopId.trim().length === 0) {\n throw new Error(\"createShopifyDiscountSyncJobId: shopId must be a non-empty string\");\n }\n\n if (event.reason === \"DISCOUNT_WEBHOOK\") {\n if (typeof event.deliveryId !== \"string\" || event.deliveryId.trim().length === 0) {\n throw new Error(\"createShopifyDiscountSyncJobId: deliveryId is required for DISCOUNT_WEBHOOK\");\n }\n return createShopifyWebhookJobDigest(\"discount-sync\", event.shopId, event.deliveryId);\n }\n\n if (typeof event.requestedAt !== \"string\" || event.requestedAt.trim().length === 0) {\n throw new Error(\"createShopifyDiscountSyncJobId: requestedAt must be a non-empty ISO datetime string\");\n }\n\n return createShopifyWebhookJobDigest(\"discount-sync\", `${event.shopId}:${event.reason}`, event.requestedAt);\n}\n\n/**\n * One deduplication identity per authenticated shop + webhook delivery.\n * Length-safe JSON tuple serialization avoids `a:b` vs `a`/`b:c` collisions;\n * the job ID never reveals the customer ID, delivery ID or phone.\n */\nexport function createShopifyWhatsAppConsentSyncJobId(\n input: ShopifyWhatsAppConsentSyncJobV1,\n): string {\n const job = ShopifyWhatsAppConsentSyncJobV1Schema.parse(input);\n const digest = createHash(\"sha256\")\n .update(JSON.stringify([job.shopId, job.deliveryId]))\n .digest(\"hex\");\n return `shopify-whatsapp-consent-sync-${digest}`;\n}\n","import { Buffer } from \"node:buffer\";\n\nexport type ShopifyOfflineTokenErrorCode =\n | \"SESSION_MISSING\" | \"SESSION_IDENTITY_CONFLICT\" | \"INVALID_SESSION\"\n | \"REFRESH_TOKEN_EXPIRED\" | \"OAUTH_CONFIG_UNAVAILABLE\" | \"LOCK_TIMEOUT\"\n | \"CANCELLED\" | \"DEADLINE\" | \"REFRESH_REJECTED\"\n | \"REFRESH_RESPONSE_INVALID\" | \"REFRESH_OUTCOME_UNKNOWN\" | \"PERSISTENCE_UNAVAILABLE\";\n\nconst ERROR_MESSAGES: Record<ShopifyOfflineTokenErrorCode, string> = {\n SESSION_MISSING: \"Shopify offline session is unavailable.\",\n SESSION_IDENTITY_CONFLICT: \"Shopify offline session identity is inconsistent.\",\n INVALID_SESSION: \"Shopify offline session is invalid.\",\n REFRESH_TOKEN_EXPIRED: \"Shopify offline refresh token has expired.\",\n OAUTH_CONFIG_UNAVAILABLE: \"Shopify OAuth configuration is unavailable.\",\n LOCK_TIMEOUT: \"Shopify offline session is busy; retry the request.\",\n CANCELLED: \"Shopify offline session request was cancelled.\",\n DEADLINE: \"Shopify offline session operation exceeded its time limit.\",\n REFRESH_REJECTED: \"Shopify rejected the offline refresh request.\",\n REFRESH_RESPONSE_INVALID: \"Shopify returned an invalid offline refresh response.\",\n REFRESH_OUTCOME_UNKNOWN: \"Shopify refresh outcome is unknown; retry in a later request.\",\n PERSISTENCE_UNAVAILABLE: \"Shopify offline session could not be persisted.\",\n};\n\nconst RETRYABLE = new Set<ShopifyOfflineTokenErrorCode>([\n \"LOCK_TIMEOUT\", \"DEADLINE\", \"PERSISTENCE_UNAVAILABLE\", \"REFRESH_OUTCOME_UNKNOWN\",\n]);\n\nexport class ShopifyOfflineTokenError extends Error {\n readonly code: ShopifyOfflineTokenErrorCode;\n readonly retryable: boolean;\n\n constructor(code: ShopifyOfflineTokenErrorCode) {\n super(ERROR_MESSAGES[code]);\n this.name = \"ShopifyOfflineTokenError\";\n this.code = code;\n this.retryable = RETRYABLE.has(code);\n }\n}\n\nclass CallbackFailure extends Error {\n constructor(readonly value: unknown) { super(\"Shopify offline callback failed.\"); }\n}\n\nexport type ShopifyOfflineSessionRecord = Readonly<{\n id: string; shop: string; isOnline: boolean; accessToken: string | null; refreshToken: string | null;\n scope: string | null; expires: Date | null; refreshTokenExpires: Date | null;\n}>;\nexport type ShopifyOfflineShopRecord = Readonly<{\n id: string; domain: string; platform: string; status: string;\n}>;\n\nexport type ShopifyOfflineStringFilter = string | Readonly<{\n equals?: string; in?: string[]; notIn?: string[]; lt?: string; lte?: string; gt?: string; gte?: string;\n contains?: string; startsWith?: string; endsWith?: string; mode?: \"default\" | \"insensitive\";\n not?: string | ShopifyOfflineStringFilter;\n}>;\nexport type ShopifyOfflineBooleanFilter = boolean | Readonly<{ equals?: boolean; not?: boolean | ShopifyOfflineBooleanFilter }>;\nexport type ShopifyOfflineNullableStringFilter = string | null | Readonly<{\n equals?: string | null; in?: string[] | null; notIn?: string[] | null; lt?: string; lte?: string; gt?: string; gte?: string;\n contains?: string; startsWith?: string; endsWith?: string; mode?: \"default\" | \"insensitive\";\n not?: string | null | ShopifyOfflineNullableStringFilter;\n}>;\nexport type ShopifyOfflineNullableBooleanFilter = boolean | null | Readonly<{\n equals?: boolean | null; not?: boolean | null | ShopifyOfflineNullableBooleanFilter;\n}>;\nexport type ShopifyOfflineDateFilter = Date | string | null | Readonly<{\n equals?: Date | string | null; in?: Date[] | string[] | null; notIn?: Date[] | string[] | null;\n lt?: Date | string; lte?: Date | string; gt?: Date | string; gte?: Date | string;\n not?: Date | string | null | ShopifyOfflineDateFilter;\n}>;\nexport type ShopifyOfflineBigIntFilter = bigint | number | null | Readonly<{\n equals?: bigint | number | null; in?: bigint[] | number[] | null; notIn?: bigint[] | number[] | null;\n lt?: bigint | number; lte?: bigint | number; gt?: bigint | number; gte?: bigint | number;\n not?: bigint | number | null | ShopifyOfflineBigIntFilter;\n}>;\nexport type ShopifyOfflineSessionScalarWhere = {\n id?: ShopifyOfflineStringFilter;\n shop?: ShopifyOfflineStringFilter;\n state?: ShopifyOfflineStringFilter;\n isOnline?: ShopifyOfflineBooleanFilter;\n scope?: ShopifyOfflineNullableStringFilter;\n expires?: ShopifyOfflineDateFilter;\n accessToken?: ShopifyOfflineStringFilter;\n userId?: ShopifyOfflineBigIntFilter;\n firstName?: ShopifyOfflineNullableStringFilter;\n lastName?: ShopifyOfflineNullableStringFilter;\n email?: ShopifyOfflineNullableStringFilter;\n accountOwner?: ShopifyOfflineBooleanFilter;\n locale?: ShopifyOfflineNullableStringFilter;\n collaborator?: ShopifyOfflineNullableBooleanFilter;\n emailVerified?: ShopifyOfflineNullableBooleanFilter;\n refreshToken?: ShopifyOfflineNullableStringFilter;\n refreshTokenExpires?: ShopifyOfflineDateFilter;\n};\nexport type ShopifyOfflineSessionWhere = ShopifyOfflineSessionScalarWhere & {\n AND?: ShopifyOfflineSessionScalarWhere | ShopifyOfflineSessionScalarWhere[];\n OR?: ShopifyOfflineSessionScalarWhere[];\n NOT?: ShopifyOfflineSessionScalarWhere | ShopifyOfflineSessionScalarWhere[];\n};\nexport type ShopifyOfflineSessionUniqueWhere = Readonly<{ id: string }>;\nexport type ShopifyOfflineSessionSelect = Readonly<Partial<Record<\n \"id\" | \"shop\" | \"state\" | \"isOnline\" | \"scope\" | \"expires\" | \"accessToken\" | \"userId\"\n | \"firstName\" | \"lastName\" | \"email\" | \"accountOwner\" | \"locale\" | \"collaborator\"\n | \"emailVerified\" | \"refreshToken\" | \"refreshTokenExpires\",\n true\n>>>;\nexport type ShopifyOfflineSessionData = Readonly<{\n id?: string;\n shop?: string;\n state?: string;\n isOnline?: boolean;\n scope?: string | null;\n expires?: Date | null;\n accessToken?: string;\n userId?: bigint | null;\n firstName?: string | null;\n lastName?: string | null;\n email?: string | null;\n accountOwner?: boolean;\n locale?: string | null;\n collaborator?: boolean | null;\n emailVerified?: boolean | null;\n refreshToken?: string | null;\n refreshTokenExpires?: Date | null;\n}>;\nexport type ShopifyOfflineSessionCreateData = ShopifyOfflineSessionData & Readonly<{\n id: string;\n shop: string;\n state: string;\n accessToken: string;\n}>;\nexport type ShopifyOfflineSessionDelegate = Readonly<{\n findUnique(args: Readonly<{ where: ShopifyOfflineSessionUniqueWhere; select?: ShopifyOfflineSessionSelect }>): Promise<ShopifyOfflineSessionRecord | null>;\n findMany(args: Readonly<{ where: ShopifyOfflineSessionWhere; select?: ShopifyOfflineSessionSelect; take?: number }>): Promise<ShopifyOfflineSessionRecord[]>;\n create(args: Readonly<{ data: ShopifyOfflineSessionCreateData; select?: ShopifyOfflineSessionSelect }>): Promise<ShopifyOfflineSessionRecord>;\n update(args: Readonly<{ where: ShopifyOfflineSessionUniqueWhere; data: ShopifyOfflineSessionData; select?: ShopifyOfflineSessionSelect }>): Promise<ShopifyOfflineSessionRecord>;\n upsert(args: Readonly<{ where: ShopifyOfflineSessionUniqueWhere; create: ShopifyOfflineSessionCreateData; update: ShopifyOfflineSessionData; select?: ShopifyOfflineSessionSelect }>): Promise<ShopifyOfflineSessionRecord>;\n delete(args: Readonly<{ where: ShopifyOfflineSessionUniqueWhere; select?: ShopifyOfflineSessionSelect }>): Promise<ShopifyOfflineSessionRecord>;\n deleteMany(args: Readonly<{ where?: ShopifyOfflineSessionWhere }>): Promise<{ count: number }>;\n updateMany(args: Readonly<{ where?: ShopifyOfflineSessionWhere; data: ShopifyOfflineSessionData }>): Promise<{ count: number }>;\n}>;\n\nexport type ShopifyOfflineTransaction = Readonly<{\n $queryRawUnsafe<T = unknown>(sql: string, ...values: unknown[]): Promise<T>;\n $executeRawUnsafe(sql: string, ...values: unknown[]): Promise<number>;\n session: ShopifyOfflineSessionDelegate;\n shop: Readonly<{\n findUnique(args: Readonly<{ where: Readonly<{ id: string }>; select: Readonly<{ id: true; domain: true; platform: true; status: true }> }>): Promise<ShopifyOfflineShopRecord | null>;\n }>;\n}>;\n\nexport type ShopifyOfflineDatabase = Readonly<{\n $transaction<T>(\n work: (transaction: ShopifyOfflineTransaction) => Promise<T>,\n options: Readonly<{ maxWait: 5000; timeout: 20000; isolationLevel: \"ReadCommitted\" }>,\n ): Promise<T>;\n shop: ShopifyOfflineTransaction[\"shop\"];\n}>;\n\nexport type OfflineCredentialSnapshot = Readonly<{\n id: string; shopId: string; shop: string; accessToken: string; scope: string | null;\n expires: Date | null; refreshTokenExpires: Date | null;\n}>;\nexport type LockedSessionContext = Readonly<{\n transaction: ShopifyOfflineTransaction; shopId: string; shop: string; sessionId: string; signal: AbortSignal;\n}>;\nexport type SdkInstallationSessionContext = Readonly<{\n transaction: ShopifyOfflineTransaction; shopId: null; shop: string; sessionId: string | null; signal: AbortSignal;\n}>;\nexport type ShopifyOfflineTokenProvider = Readonly<{\n withSdkInstallationSessionLock<T>(integrationDomain: string, work: (context: SdkInstallationSessionContext) => Promise<T>): Promise<T>;\n getAccessToken(shopId: string, options?: Readonly<{ signal?: AbortSignal }>): Promise<string>;\n getSession(shopId: string, options?: Readonly<{ signal?: AbortSignal }>): Promise<OfflineCredentialSnapshot>;\n withSessionLock<T>(shopId: string, work: (context: LockedSessionContext) => Promise<T>, options?: Readonly<{ signal?: AbortSignal }>): Promise<T>;\n}>;\n\ntype PersistedShop = ShopifyOfflineShopRecord;\nconst TX_OPTIONS = { maxWait: 5000, timeout: 20000, isolationLevel: \"ReadCommitted\" } as const;\nconst ACCESS_REFRESH_SKEW_MS = 320_000;\nconst REFRESH_NETWORK_BUDGET_MS = 8_000;\nconst OPERATION_BUDGET_MS = 15_000;\nconst RESPONSE_LIMIT = 16_384;\nconst CONTROL = /[\\u0000-\\u001f\\u007f]/;\nconst SESSION_SELECT = { id: true, shop: true, isOnline: true, accessToken: true, refreshToken: true, scope: true, expires: true, refreshTokenExpires: true } as const;\n\nfunction fail(code: ShopifyOfflineTokenErrorCode): never { throw new ShopifyOfflineTokenError(code); }\nfunction isRecord(value: unknown): value is Record<string, unknown> { return typeof value === \"object\" && value !== null && !Array.isArray(value); }\nfunction validToken(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0 && value.length <= 4096 && value.trim() === value && !/[\\r\\n\\u0000]/.test(value);\n}\nfunction validScope(value: unknown): value is string { return typeof value === \"string\" && value.length <= 4096 && !CONTROL.test(value); }\nfunction validDate(value: unknown): value is Date | null { return value === null || (value instanceof Date && Number.isFinite(value.getTime())); }\nfunction mapDatabaseError(error: unknown): ShopifyOfflineTokenError {\n const code = isRecord(error) && typeof error.code === \"string\" ? error.code : \"\";\n const message = error instanceof Error ? error.message : \"\";\n if (code === \"55P03\" || /lock timeout/i.test(message)) return new ShopifyOfflineTokenError(\"LOCK_TIMEOUT\");\n if (code === \"57014\" || /statement timeout|statement timed out/i.test(message)) return new ShopifyOfflineTokenError(\"DEADLINE\");\n return new ShopifyOfflineTokenError(\"PERSISTENCE_UNAVAILABLE\");\n}\n\nfunction createDeadline(signal?: AbortSignal): Readonly<{ signal: AbortSignal; dispose(): void; check(): void; wait<T>(work: Promise<T>): Promise<T> }> {\n const controller = new AbortController();\n let expired = false;\n const timer = setTimeout(() => { expired = true; controller.abort(); }, OPERATION_BUDGET_MS);\n const onAbort = () => controller.abort(signal?.reason);\n if (signal?.aborted) onAbort();\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n return {\n signal: controller.signal,\n dispose() { clearTimeout(timer); signal?.removeEventListener(\"abort\", onAbort); },\n wait<T>(work: Promise<T>): Promise<T> {\n if (controller.signal.aborted) this.check();\n let onDeadline: (() => void) | undefined;\n const aborted = new Promise<never>((_resolve, reject) => {\n onDeadline = () => reject(new Error(\"operation aborted\"));\n controller.signal.addEventListener(\"abort\", onDeadline, { once: true });\n });\n return Promise.race([work, aborted]).finally(() => {\n if (onDeadline) controller.signal.removeEventListener(\"abort\", onDeadline);\n });\n },\n check() {\n if (signal?.aborted) fail(\"CANCELLED\");\n if (expired) fail(\"DEADLINE\");\n if (controller.signal.aborted) fail(\"DEADLINE\");\n },\n };\n}\n\nasync function readBoundedBody(response: Response, signal: AbortSignal): Promise<string> {\n if (!response.body) return \"\";\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let size = 0;\n try {\n while (true) {\n if (signal.aborted) throw new Error(\"refresh stream aborted\");\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > RESPONSE_LIMIT) {\n await reader.cancel().catch(() => undefined);\n fail(\"REFRESH_OUTCOME_UNKNOWN\");\n }\n chunks.push(value);\n }\n } finally { reader.releaseLock(); }\n return Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))).toString(\"utf8\");\n}\n\nfunction snapshot(row: ShopifyOfflineSessionRecord, shopId: string, shop: string): OfflineCredentialSnapshot {\n if (!validToken(row.accessToken) || !validScope(row.scope) && row.scope !== null\n || !validDate(row.expires) || !validDate(row.refreshTokenExpires)) fail(\"INVALID_SESSION\");\n return Object.freeze({ id: row.id, shopId, shop, accessToken: row.accessToken, scope: row.scope, expires: row.expires, refreshTokenExpires: row.refreshTokenExpires });\n}\n\nexport function createShopifyOfflineTokenProvider(input: Readonly<{\n prisma: ShopifyOfflineDatabase;\n readOAuth: () => Promise<Readonly<{ apiKey: string; apiSecret: string }>>;\n fetch: typeof fetch;\n now?: () => number;\n}>): ShopifyOfflineTokenProvider {\n const now = input.now ?? Date.now;\n\n async function resolveShop(shopId: string, deadline: ReturnType<typeof createDeadline>): Promise<PersistedShop> {\n deadline.check();\n if (typeof shopId !== \"string\" || !shopId.trim()) fail(\"SESSION_MISSING\");\n let shop: PersistedShop | null;\n try {\n shop = await deadline.wait(input.prisma.shop.findUnique({ where: { id: shopId }, select: { id: true, domain: true, platform: true, status: true } }));\n } catch (error) {\n deadline.check();\n throw mapDatabaseError(error);\n }\n deadline.check();\n if (!shop) fail(\"SESSION_MISSING\");\n if (shop.platform !== \"SHOPIFY\" || shop.status !== \"ACTIVE\") fail(\"INVALID_SESSION\");\n if (!shop.domain) fail(\"SESSION_IDENTITY_CONFLICT\");\n return shop;\n }\n\n async function runLocked<T>(shop: PersistedShop, shopId: string, deadline: ReturnType<typeof createDeadline>, work: (context: LockedSessionContext) => Promise<T>, outcome: { remoteSucceeded: boolean } = { remoteSucceeded: false }): Promise<T> {\n try {\n deadline.check();\n const result = await deadline.wait(input.prisma.$transaction(async (tx) => {\n await tx.$executeRawUnsafe(\"SET LOCAL lock_timeout = '5s'\");\n await tx.$executeRawUnsafe(\"SET LOCAL statement_timeout = '18s'\");\n await tx.$queryRawUnsafe(\"SELECT pg_advisory_xact_lock(hashtextextended($1, 0)) IS NULL\", `moda:shopify-offline:v1:${shop.domain}`);\n deadline.check();\n\n const currentShop = await tx.shop.findUnique({ where: { id: shopId }, select: { id: true, domain: true, platform: true, status: true } });\n if (!currentShop) fail(\"SESSION_MISSING\");\n if (currentShop.platform !== \"SHOPIFY\" || currentShop.status !== \"ACTIVE\") fail(\"INVALID_SESSION\");\n if (currentShop.domain !== shop.domain) fail(\"SESSION_IDENTITY_CONFLICT\");\n\n const sessions = await tx.session.findMany({ where: { shop: currentShop.domain, isOnline: false }, select: SESSION_SELECT, take: 2 });\n if (sessions.length === 0) fail(\"SESSION_MISSING\");\n if (sessions.length !== 1) fail(\"SESSION_IDENTITY_CONFLICT\");\n const row = sessions[0]!;\n if (!row.id || row.shop !== currentShop.domain || row.isOnline !== false) fail(\"SESSION_IDENTITY_CONFLICT\");\n await tx.$queryRawUnsafe('SELECT \"id\" FROM \"shopify\".\"Session\" WHERE \"id\" = $1 FOR UPDATE', row.id);\n const reread = await tx.session.findUnique({ where: { id: row.id }, select: SESSION_SELECT });\n if (!reread || reread.id !== row.id || reread.shop !== currentShop.domain || reread.isOnline !== false) fail(\"SESSION_IDENTITY_CONFLICT\");\n\n const context: LockedSessionContext = Object.freeze({ transaction: tx, shopId, shop: currentShop.domain, sessionId: reread.id, signal: deadline.signal });\n deadline.check();\n let value: T;\n try { value = await deadline.wait(work(context)); }\n catch (error) { deadline.check(); throw new CallbackFailure(error); }\n deadline.check();\n return value;\n }, TX_OPTIONS));\n return result;\n } catch (error) {\n if (error instanceof CallbackFailure) throw error.value;\n if (deadline.signal.aborted) deadline.check();\n if (outcome.remoteSucceeded && (error instanceof ShopifyOfflineTokenError\n ? error.code === \"LOCK_TIMEOUT\" || error.code === \"DEADLINE\" || error.code === \"PERSISTENCE_UNAVAILABLE\"\n : true)) fail(\"REFRESH_OUTCOME_UNKNOWN\");\n if (error instanceof ShopifyOfflineTokenError) throw error;\n deadline.check();\n throw mapDatabaseError(error);\n }\n }\n\n async function getSession(shopId: string, options?: Readonly<{ signal?: AbortSignal }>): Promise<OfflineCredentialSnapshot> {\n const deadline = createDeadline(options?.signal);\n try {\n deadline.check();\n const shop = await resolveShop(shopId, deadline);\n deadline.check();\n const outcome = { remoteSucceeded: false };\n return await runLocked(shop, shopId, deadline, async (context) => {\n let row = await context.transaction.session.findUnique({ where: { id: context.sessionId }, select: SESSION_SELECT });\n if (!row) fail(\"SESSION_IDENTITY_CONFLICT\");\n const currentTime = now();\n if (!Number.isFinite(currentTime)) fail(\"INVALID_SESSION\");\n if (row.expires === null && row.refreshToken === null) return snapshot(row, shopId, context.shop);\n if (row.expires === null) fail(\"INVALID_SESSION\");\n const expiresAt = row.expires?.getTime() ?? 0;\n if (expiresAt - currentTime > ACCESS_REFRESH_SKEW_MS) return snapshot(row, shopId, context.shop);\n if (!validToken(row.refreshToken)) fail(\"INVALID_SESSION\");\n if (!validDate(row.refreshTokenExpires) || row.refreshTokenExpires === null) fail(\"INVALID_SESSION\");\n if (row.refreshTokenExpires.getTime() <= currentTime) fail(\"REFRESH_TOKEN_EXPIRED\");\n\n let credentials: Readonly<{ apiKey: string; apiSecret: string }>;\n try { credentials = await input.readOAuth(); }\n catch { fail(\"OAUTH_CONFIG_UNAVAILABLE\"); }\n if (options?.signal?.aborted) fail(\"CANCELLED\");\n if (context.signal.aborted) fail(\"DEADLINE\");\n if (!validToken(credentials.apiKey) || !validToken(credentials.apiSecret)) fail(\"OAUTH_CONFIG_UNAVAILABLE\");\n const requestStartedAt = now();\n const refreshController = new AbortController();\n const refreshTimeout = setTimeout(() => refreshController.abort(), REFRESH_NETWORK_BUDGET_MS);\n const onAbort = () => refreshController.abort();\n context.signal.addEventListener(\"abort\", onAbort, { once: true });\n let response: Response;\n try {\n const form = new URLSearchParams({ client_id: credentials.apiKey, client_secret: credentials.apiSecret, grant_type: \"refresh_token\", refresh_token: row.refreshToken });\n response = await input.fetch(`https://${context.shop}/admin/oauth/access_token`, {\n method: \"POST\", redirect: \"error\", headers: { \"content-type\": \"application/x-www-form-urlencoded\" }, body: form, signal: refreshController.signal,\n });\n } catch {\n clearTimeout(refreshTimeout);\n context.signal.removeEventListener(\"abort\", onAbort);\n if (options?.signal?.aborted) fail(\"CANCELLED\");\n if (context.signal.aborted) fail(\"REFRESH_OUTCOME_UNKNOWN\");\n fail(\"REFRESH_OUTCOME_UNKNOWN\");\n }\n if (response.status >= 400 && response.status < 500) fail(\"REFRESH_REJECTED\");\n if (!response.ok) { outcome.remoteSucceeded = true; fail(\"REFRESH_OUTCOME_UNKNOWN\"); }\n outcome.remoteSucceeded = true;\n let raw: string;\n try { raw = await readBoundedBody(response, refreshController.signal); }\n catch (error) {\n clearTimeout(refreshTimeout);\n context.signal.removeEventListener(\"abort\", onAbort);\n if (options?.signal?.aborted) fail(\"CANCELLED\");\n if (context.signal.aborted) fail(\"REFRESH_OUTCOME_UNKNOWN\");\n fail(\"REFRESH_OUTCOME_UNKNOWN\");\n } finally {\n clearTimeout(refreshTimeout);\n context.signal.removeEventListener(\"abort\", onAbort);\n }\n let payload: unknown;\n try { payload = JSON.parse(raw) as unknown; } catch { fail(\"REFRESH_OUTCOME_UNKNOWN\"); }\n if (!isRecord(payload) || !validToken(payload.access_token) || !validToken(payload.refresh_token)\n || !Number.isSafeInteger(payload.expires_in) || (payload.expires_in as number) <= 0 || (payload.expires_in as number) > 86_400\n || !Number.isSafeInteger(payload.refresh_token_expires_in) || (payload.refresh_token_expires_in as number) <= 0 || (payload.refresh_token_expires_in as number) > 7_776_000\n || (payload.expires_in as number) <= 320\n || (payload.scope !== undefined && !validScope(payload.scope))) fail(\"REFRESH_OUTCOME_UNKNOWN\");\n const expires = requestStartedAt + (payload.expires_in as number) * 1000;\n const refreshTokenExpires = requestStartedAt + (payload.refresh_token_expires_in as number) * 1000;\n if (!Number.isFinite(expires) || !Number.isFinite(refreshTokenExpires) || Number.isNaN(new Date(expires).getTime()) || Number.isNaN(new Date(refreshTokenExpires).getTime())) fail(\"REFRESH_OUTCOME_UNKNOWN\");\n const scope = payload.scope === undefined ? row.scope : payload.scope as string;\n try {\n row = await context.transaction.session.update({ where: { id: row.id }, data: {\n accessToken: payload.access_token, expires: new Date(expires), refreshToken: payload.refresh_token,\n refreshTokenExpires: new Date(refreshTokenExpires), scope,\n }, select: SESSION_SELECT });\n } catch { outcome.remoteSucceeded = true; throw new ShopifyOfflineTokenError(\"REFRESH_OUTCOME_UNKNOWN\"); }\n outcome.remoteSucceeded = true;\n return snapshot(row, shopId, context.shop);\n }, outcome);\n } catch (error) {\n deadline.check();\n throw error;\n } finally { deadline.dispose(); }\n }\n\n async function withSessionLock<T>(shopId: string, work: (context: LockedSessionContext) => Promise<T>, options?: Readonly<{ signal?: AbortSignal }>): Promise<T> {\n const deadline = createDeadline(options?.signal);\n try {\n deadline.check();\n const shop = await resolveShop(shopId, deadline);\n deadline.check();\n return await runLocked(shop, shopId, deadline, work);\n } catch (error) {\n deadline.check();\n throw error;\n } finally { deadline.dispose(); }\n }\n\n async function withSdkInstallationSessionLock<T>(integrationDomain: string, work: (context: SdkInstallationSessionContext) => Promise<T>): Promise<T> {\n if (typeof integrationDomain !== \"string\" || !integrationDomain.trim()) fail(\"INVALID_SESSION\");\n const deadline = createDeadline();\n try {\n return await input.prisma.$transaction(async (tx) => {\n await tx.$executeRawUnsafe(\"SET LOCAL lock_timeout = '5s'\");\n await tx.$executeRawUnsafe(\"SET LOCAL statement_timeout = '18s'\");\n await tx.$queryRawUnsafe(\"SELECT pg_advisory_xact_lock(hashtextextended($1, 0)) IS NULL\", `moda:shopify-offline:v1:${integrationDomain}`);\n let value: T;\n try { value = await deadline.wait(work(Object.freeze({ transaction: tx, shopId: null, shop: integrationDomain, sessionId: null, signal: deadline.signal }))); }\n catch (error) { deadline.check(); throw new CallbackFailure(error); }\n deadline.check();\n return value;\n }, TX_OPTIONS);\n } catch (error) {\n if (error instanceof CallbackFailure) throw error.value;\n if (error instanceof ShopifyOfflineTokenError) throw error;\n if (deadline.signal.aborted) deadline.check();\n throw mapDatabaseError(error);\n } finally { deadline.dispose(); }\n }\n\n return Object.freeze({\n withSdkInstallationSessionLock,\n getAccessToken: async (shopId: string, options?: Readonly<{ signal?: AbortSignal }>) => (await getSession(shopId, options)).accessToken,\n getSession,\n withSessionLock,\n });\n}\n","import { Buffer } from \"node:buffer\";\nimport {\n decryptCredential,\n type CredentialEnvelope,\n type CredentialKeyring,\n} from \"../security/credentials/node.js\";\n\nconst CONFIGURATION_KEY = \"shopify.oauth\" as const;\nconst CONFIGURATION_ENVIRONMENTS = new Set([\"local\", \"test\", \"development\", \"staging\", \"production\"]);\nconst ENVELOPE_KEYS = [\"kind\", \"schemaVersion\", \"algorithm\", \"wrappingKeyId\", \"nonce\", \"ciphertext\", \"authTag\"] as const;\nconst RESERVED_KEY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst KEY_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;\nconst BASE64_PATTERN = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;\nconst CONTROL_CHARACTERS = /[\\u0000-\\u001f\\u007f]/;\n\nexport type ShopifyOAuthConfigurationErrorCode =\n | \"INVALID_ENVIRONMENT\"\n | \"CONFIGURATION_UNAVAILABLE\"\n | \"CONFIGURATION_INVALID\";\n\nconst ERROR_MESSAGES: Record<ShopifyOAuthConfigurationErrorCode, string> = {\n INVALID_ENVIRONMENT: \"Shopify OAuth configuration is unavailable.\",\n CONFIGURATION_UNAVAILABLE: \"Shopify OAuth configuration is unavailable.\",\n CONFIGURATION_INVALID: \"Shopify OAuth configuration is invalid.\",\n};\n\n/** Safe configuration boundary error; never contains a row, key, or decrypt cause. */\nexport class ShopifyOAuthConfigurationError extends Error {\n readonly code: ShopifyOAuthConfigurationErrorCode;\n\n constructor(code: ShopifyOAuthConfigurationErrorCode) {\n super(ERROR_MESSAGES[code]);\n this.name = \"ShopifyOAuthConfigurationError\";\n this.code = code;\n }\n}\n\nexport type ShopifyOAuthConfigurationRow = Readonly<{\n environment: string;\n key: string;\n version: number;\n value: unknown;\n}>;\n\nexport type ShopifyOAuthConfigurationPrisma = Readonly<{\n platformConfiguration: Readonly<{\n findUnique(args: Readonly<{\n where: Readonly<{ environment_key: Readonly<{ environment: string; key: typeof CONFIGURATION_KEY }> }>;\n select: Readonly<{ environment: true; key: true; version: true; value: true }>;\n }>): Promise<ShopifyOAuthConfigurationRow | null>;\n }>;\n}>;\n\nexport type ShopifyOAuthCredentials = Readonly<{\n apiKey: string;\n apiSecret: string;\n}>;\n\nfunction configurationFailure(code: ShopifyOAuthConfigurationErrorCode): never {\n throw new ShopifyOAuthConfigurationError(code);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasExactKeys(value: Record<string, unknown>, expected: readonly string[]): boolean {\n const actual = Object.keys(value);\n return actual.length === expected.length && actual.every((key) => expected.includes(key));\n}\n\nfunction canonicalBase64(value: unknown, exactLength: number | null): Uint8Array | null {\n if (typeof value !== \"string\" || value.length === 0 || !BASE64_PATTERN.test(value)) return null;\n const decoded = Buffer.from(value, \"base64\");\n if (decoded.length < 1 || decoded.length > 8192 || decoded.toString(\"base64\") !== value) return null;\n if (exactLength !== null && decoded.length !== exactLength) return null;\n return Uint8Array.from(decoded);\n}\n\nfunction parseSealedEnvelope(value: unknown): CredentialEnvelope {\n if (!isRecord(value) || !hasExactKeys(value, ENVELOPE_KEYS)\n || value.kind !== \"sealed\"\n || value.schemaVersion !== 1\n || value.algorithm !== \"AES-256-GCM\"\n || typeof value.wrappingKeyId !== \"string\"\n || !KEY_ID_PATTERN.test(value.wrappingKeyId)\n || RESERVED_KEY_IDS.has(value.wrappingKeyId)) {\n return configurationFailure(\"CONFIGURATION_INVALID\");\n }\n\n const nonce = canonicalBase64(value.nonce, 12);\n const ciphertext = canonicalBase64(value.ciphertext, null);\n const authTag = canonicalBase64(value.authTag, 16);\n if (!nonce || !ciphertext || !authTag) return configurationFailure(\"CONFIGURATION_INVALID\");\n return { keyId: value.wrappingKeyId, nonce, ciphertext, authTag };\n}\n\nfunction validCredential(value: unknown): value is string {\n return typeof value === \"string\" && value.length >= 1 && value.length <= 4096\n && value.trim() === value && !CONTROL_CHARACTERS.test(value);\n}\n\nfunction parseCredentials(value: unknown): ShopifyOAuthCredentials {\n if (!isRecord(value) || !hasExactKeys(value, [\"apiKey\", \"apiSecret\"])\n || !validCredential(value.apiKey) || !validCredential(value.apiSecret)) {\n return configurationFailure(\"CONFIGURATION_INVALID\");\n }\n return Object.freeze({ apiKey: value.apiKey, apiSecret: value.apiSecret });\n}\n\n/**\n * Read and unseal the existing platform `shopify.oauth` row. Environment identity\n * is deployment configuration supplied by the caller, never request data.\n */\nexport async function readShopifyOAuthConfiguration(input: Readonly<{\n prisma: ShopifyOAuthConfigurationPrisma;\n environment: string;\n unsealKeyring: CredentialKeyring;\n}>): Promise<ShopifyOAuthCredentials> {\n if (!input || typeof input !== \"object\" || Array.isArray(input)\n || typeof input.environment !== \"string\" || !CONFIGURATION_ENVIRONMENTS.has(input.environment)) {\n return configurationFailure(\"INVALID_ENVIRONMENT\");\n }\n\n let row: ShopifyOAuthConfigurationRow | null;\n try {\n row = await input.prisma.platformConfiguration.findUnique({\n where: { environment_key: { environment: input.environment, key: CONFIGURATION_KEY } },\n select: { environment: true, key: true, version: true, value: true },\n });\n } catch {\n return configurationFailure(\"CONFIGURATION_UNAVAILABLE\");\n }\n\n if (!row) return configurationFailure(\"CONFIGURATION_UNAVAILABLE\");\n if (row.environment !== input.environment || row.key !== CONFIGURATION_KEY\n || !Number.isSafeInteger(row.version) || row.version < 1 || row.version > 2_147_483_647) {\n return configurationFailure(\"CONFIGURATION_INVALID\");\n }\n if (isRecord(row.value) && hasExactKeys(row.value, [\"kind\", \"schemaVersion\"])\n && row.value.kind === \"disabled\" && row.value.schemaVersion === 1) {\n return configurationFailure(\"CONFIGURATION_UNAVAILABLE\");\n }\n\n let plaintext: string;\n try {\n const envelope = parseSealedEnvelope(row.value);\n const aad = JSON.stringify([\"moda-platform-config-v1\", input.environment, CONFIGURATION_KEY, row.version, 1]);\n plaintext = decryptCredential({ keyring: input.unsealKeyring, envelope, aad });\n } catch (error) {\n if (error instanceof ShopifyOAuthConfigurationError) throw error;\n return configurationFailure(\"CONFIGURATION_INVALID\");\n }\n\n try {\n return parseCredentials(JSON.parse(plaintext) as unknown);\n } catch (error) {\n if (error instanceof ShopifyOAuthConfigurationError) throw error;\n return configurationFailure(\"CONFIGURATION_INVALID\");\n }\n}\n"],"mappings":"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","names":["Buffer","ERROR_MESSAGES","isRecord","Buffer"]}
|
|
1
|
+
{"version":3,"sources":["../../src/shopify/node.ts","../../src/shopify/offline-token-provider.ts","../../src/shopify/oauth-configuration.ts"],"sourcesContent":["import { ShopifyWhatsAppConsentSyncJobV1Schema, type ShopifyWhatsAppConsentSyncJobV1 } from \"./whatsapp-consent-sync.schema.js\";\nimport { createHash } from \"node:crypto\";\n\nexport {\n ShopifyOfflineTokenError,\n createShopifyOfflineTokenProvider,\n type ShopifyOfflineTokenErrorCode,\n type ShopifyOfflineRefreshEvent,\n type ShopifyOfflineDatabase,\n type ShopifyOfflineTransaction,\n type ShopifyOfflineSessionDelegate,\n type ShopifyOfflineSessionRecord,\n type ShopifyOfflineSessionWhere,\n type ShopifyOfflineSessionScalarWhere,\n type ShopifyOfflineSessionUniqueWhere,\n type ShopifyOfflineSessionSelect,\n type ShopifyOfflineSessionData,\n type ShopifyOfflineSessionCreateData,\n type ShopifyOfflineStringFilter,\n type ShopifyOfflineBooleanFilter,\n type ShopifyOfflineNullableStringFilter,\n type ShopifyOfflineNullableBooleanFilter,\n type ShopifyOfflineDateFilter,\n type ShopifyOfflineBigIntFilter,\n type ShopifyOfflineShopRecord,\n type OfflineCredentialSnapshot,\n type LockedSessionContext,\n type SdkInstallationSessionContext,\n type ShopifyOfflineTokenProvider,\n} from \"./offline-token-provider.js\";\nexport {\n ShopifyOAuthConfigurationError,\n readShopifyOAuthConfiguration,\n type ShopifyOAuthConfigurationErrorCode,\n type ShopifyOAuthConfigurationPrisma,\n type ShopifyOAuthConfigurationRow,\n type ShopifyOAuthCredentials,\n} from \"./oauth-configuration.js\";\n\nfunction createShopifyWebhookJobDigest(prefix: string, first: string, second: string): string {\n if (typeof first !== \"string\" || first.length === 0) {\n throw new Error(`${prefix}: first input must be a non-empty string`);\n }\n\n if (typeof second !== \"string\" || second.length === 0) {\n throw new Error(`${prefix}: second input must be a non-empty string`);\n }\n\n const digest = createHash(\"sha256\").update(`${first}:${second}`).digest(\"hex\");\n return `${prefix}-${digest}`;\n}\n\n/**\n * Legacy webhook delivery job id used by earlier receipt/outbox flows.\n * Prefer the resource-scoped helpers below for current queue publication.\n */\nexport function createShopifyWebhookJobId(appKey: string, deliveryId: string): string {\n return createShopifyWebhookJobDigest(\"shopify\", appKey, deliveryId);\n}\n\nexport function createShopifyCheckoutJobId(shopId: string, checkoutToken: string): string {\n return createShopifyWebhookJobDigest(\"checkout\", shopId, checkoutToken);\n}\n\nexport function createShopifyOrderJobId(shopId: string, orderGid: string): string {\n return createShopifyWebhookJobDigest(\"order-created\", shopId, orderGid);\n}\n\nexport function createPendingRecoveryCandidateJobId(\n shopId: string,\n checkoutToken: string,\n): string {\n return createShopifyWebhookJobDigest(\"pending-recovery\", shopId, checkoutToken);\n}\n\nexport function createShopifyDiscountSyncJobId(event: {\n shopId: string;\n reason: \"SUBSCRIPTION_ACTIVATED\" | \"REINSTALL_RECONCILED\" | \"SCOPES_UPDATED\" | \"ADMIN_REQUESTED\" | \"DISCOUNT_WEBHOOK\";\n requestedAt: string;\n deliveryId?: string | null;\n}): string {\n if (typeof event.shopId !== \"string\" || event.shopId.trim().length === 0) {\n throw new Error(\"createShopifyDiscountSyncJobId: shopId must be a non-empty string\");\n }\n\n if (event.reason === \"DISCOUNT_WEBHOOK\") {\n if (typeof event.deliveryId !== \"string\" || event.deliveryId.trim().length === 0) {\n throw new Error(\"createShopifyDiscountSyncJobId: deliveryId is required for DISCOUNT_WEBHOOK\");\n }\n return createShopifyWebhookJobDigest(\"discount-sync\", event.shopId, event.deliveryId);\n }\n\n if (typeof event.requestedAt !== \"string\" || event.requestedAt.trim().length === 0) {\n throw new Error(\"createShopifyDiscountSyncJobId: requestedAt must be a non-empty ISO datetime string\");\n }\n\n return createShopifyWebhookJobDigest(\"discount-sync\", `${event.shopId}:${event.reason}`, event.requestedAt);\n}\n\n/**\n * One deduplication identity per authenticated shop + webhook delivery.\n * Length-safe JSON tuple serialization avoids `a:b` vs `a`/`b:c` collisions;\n * the job ID never reveals the customer ID, delivery ID or phone.\n */\nexport function createShopifyWhatsAppConsentSyncJobId(\n input: ShopifyWhatsAppConsentSyncJobV1,\n): string {\n const job = ShopifyWhatsAppConsentSyncJobV1Schema.parse(input);\n const digest = createHash(\"sha256\")\n .update(JSON.stringify([job.shopId, job.deliveryId]))\n .digest(\"hex\");\n return `shopify-whatsapp-consent-sync-${digest}`;\n}\n","import { Buffer } from \"node:buffer\";\nimport { randomUUID } from \"node:crypto\";\nimport { performance } from \"node:perf_hooks\";\n\nexport type ShopifyOfflineTokenErrorCode =\n | \"SESSION_MISSING\" | \"SESSION_IDENTITY_CONFLICT\" | \"INVALID_SESSION\"\n | \"REFRESH_TOKEN_EXPIRED\" | \"OAUTH_CONFIG_UNAVAILABLE\" | \"LOCK_TIMEOUT\"\n | \"CANCELLED\" | \"DEADLINE\" | \"REFRESH_REJECTED\"\n | \"REFRESH_RESPONSE_INVALID\" | \"REFRESH_OUTCOME_UNKNOWN\" | \"PERSISTENCE_UNAVAILABLE\";\n\n/** Bounded refresh lifecycle metadata. Never includes provider credentials or errors. */\nexport type ShopifyOfflineRefreshEvent = Readonly<{\n event: \"shopify.offline_refresh.started\" | \"shopify.offline_refresh.committed\" | \"shopify.offline_refresh.failed\";\n operationId: string;\n shopId: string | null;\n source: \"SHARED\" | \"SDK\";\n durationMs: number;\n outcome: \"STARTED\" | \"COMMITTED\" | \"REJECTED\" | \"UNKNOWN\" | \"CANCELLED\" | \"UNAVAILABLE\";\n reasonCode: ShopifyOfflineTokenErrorCode | null;\n}>;\n\nconst ERROR_MESSAGES: Record<ShopifyOfflineTokenErrorCode, string> = {\n SESSION_MISSING: \"Shopify offline session is unavailable.\",\n SESSION_IDENTITY_CONFLICT: \"Shopify offline session identity is inconsistent.\",\n INVALID_SESSION: \"Shopify offline session is invalid.\",\n REFRESH_TOKEN_EXPIRED: \"Shopify offline refresh token has expired.\",\n OAUTH_CONFIG_UNAVAILABLE: \"Shopify OAuth configuration is unavailable.\",\n LOCK_TIMEOUT: \"Shopify offline session is busy; retry the request.\",\n CANCELLED: \"Shopify offline session request was cancelled.\",\n DEADLINE: \"Shopify offline session operation exceeded its time limit.\",\n REFRESH_REJECTED: \"Shopify rejected the offline refresh request.\",\n REFRESH_RESPONSE_INVALID: \"Shopify returned an invalid offline refresh response.\",\n REFRESH_OUTCOME_UNKNOWN: \"Shopify refresh outcome is unknown; retry in a later request.\",\n PERSISTENCE_UNAVAILABLE: \"Shopify offline session could not be persisted.\",\n};\n\nconst RETRYABLE = new Set<ShopifyOfflineTokenErrorCode>([\n \"LOCK_TIMEOUT\", \"DEADLINE\", \"PERSISTENCE_UNAVAILABLE\", \"REFRESH_OUTCOME_UNKNOWN\",\n]);\n\nexport class ShopifyOfflineTokenError extends Error {\n readonly code: ShopifyOfflineTokenErrorCode;\n readonly retryable: boolean;\n\n constructor(code: ShopifyOfflineTokenErrorCode) {\n super(ERROR_MESSAGES[code]);\n this.name = \"ShopifyOfflineTokenError\";\n this.code = code;\n this.retryable = RETRYABLE.has(code);\n }\n}\n\nclass CallbackFailure extends Error {\n constructor(readonly value: unknown) { super(\"Shopify offline callback failed.\"); }\n}\n\nexport type ShopifyOfflineSessionRecord = Readonly<{\n id: string; shop: string; isOnline: boolean; accessToken: string | null; refreshToken: string | null;\n scope: string | null; expires: Date | null; refreshTokenExpires: Date | null;\n}>;\nexport type ShopifyOfflineShopRecord = Readonly<{\n id: string; domain: string; platform: string; status: string;\n}>;\n\nexport type ShopifyOfflineStringFilter = string | Readonly<{\n equals?: string; in?: string[]; notIn?: string[]; lt?: string; lte?: string; gt?: string; gte?: string;\n contains?: string; startsWith?: string; endsWith?: string; mode?: \"default\" | \"insensitive\";\n not?: string | ShopifyOfflineStringFilter;\n}>;\nexport type ShopifyOfflineBooleanFilter = boolean | Readonly<{ equals?: boolean; not?: boolean | ShopifyOfflineBooleanFilter }>;\nexport type ShopifyOfflineNullableStringFilter = string | null | Readonly<{\n equals?: string | null; in?: string[] | null; notIn?: string[] | null; lt?: string; lte?: string; gt?: string; gte?: string;\n contains?: string; startsWith?: string; endsWith?: string; mode?: \"default\" | \"insensitive\";\n not?: string | null | ShopifyOfflineNullableStringFilter;\n}>;\nexport type ShopifyOfflineNullableBooleanFilter = boolean | null | Readonly<{\n equals?: boolean | null; not?: boolean | null | ShopifyOfflineNullableBooleanFilter;\n}>;\nexport type ShopifyOfflineDateFilter = Date | string | null | Readonly<{\n equals?: Date | string | null; in?: Date[] | string[] | null; notIn?: Date[] | string[] | null;\n lt?: Date | string; lte?: Date | string; gt?: Date | string; gte?: Date | string;\n not?: Date | string | null | ShopifyOfflineDateFilter;\n}>;\nexport type ShopifyOfflineBigIntFilter = bigint | number | null | Readonly<{\n equals?: bigint | number | null; in?: bigint[] | number[] | null; notIn?: bigint[] | number[] | null;\n lt?: bigint | number; lte?: bigint | number; gt?: bigint | number; gte?: bigint | number;\n not?: bigint | number | null | ShopifyOfflineBigIntFilter;\n}>;\nexport type ShopifyOfflineSessionScalarWhere = {\n id?: ShopifyOfflineStringFilter;\n shop?: ShopifyOfflineStringFilter;\n state?: ShopifyOfflineStringFilter;\n isOnline?: ShopifyOfflineBooleanFilter;\n scope?: ShopifyOfflineNullableStringFilter;\n expires?: ShopifyOfflineDateFilter;\n accessToken?: ShopifyOfflineStringFilter;\n userId?: ShopifyOfflineBigIntFilter;\n firstName?: ShopifyOfflineNullableStringFilter;\n lastName?: ShopifyOfflineNullableStringFilter;\n email?: ShopifyOfflineNullableStringFilter;\n accountOwner?: ShopifyOfflineBooleanFilter;\n locale?: ShopifyOfflineNullableStringFilter;\n collaborator?: ShopifyOfflineNullableBooleanFilter;\n emailVerified?: ShopifyOfflineNullableBooleanFilter;\n refreshToken?: ShopifyOfflineNullableStringFilter;\n refreshTokenExpires?: ShopifyOfflineDateFilter;\n};\nexport type ShopifyOfflineSessionWhere = ShopifyOfflineSessionScalarWhere & {\n AND?: ShopifyOfflineSessionScalarWhere | ShopifyOfflineSessionScalarWhere[];\n OR?: ShopifyOfflineSessionScalarWhere[];\n NOT?: ShopifyOfflineSessionScalarWhere | ShopifyOfflineSessionScalarWhere[];\n};\nexport type ShopifyOfflineSessionUniqueWhere = Readonly<{ id: string }>;\nexport type ShopifyOfflineSessionSelect = Readonly<Partial<Record<\n \"id\" | \"shop\" | \"state\" | \"isOnline\" | \"scope\" | \"expires\" | \"accessToken\" | \"userId\"\n | \"firstName\" | \"lastName\" | \"email\" | \"accountOwner\" | \"locale\" | \"collaborator\"\n | \"emailVerified\" | \"refreshToken\" | \"refreshTokenExpires\",\n true\n>>>;\nexport type ShopifyOfflineSessionData = Readonly<{\n id?: string;\n shop?: string;\n state?: string;\n isOnline?: boolean;\n scope?: string | null;\n expires?: Date | null;\n accessToken?: string;\n userId?: bigint | null;\n firstName?: string | null;\n lastName?: string | null;\n email?: string | null;\n accountOwner?: boolean;\n locale?: string | null;\n collaborator?: boolean | null;\n emailVerified?: boolean | null;\n refreshToken?: string | null;\n refreshTokenExpires?: Date | null;\n}>;\nexport type ShopifyOfflineSessionCreateData = ShopifyOfflineSessionData & Readonly<{\n id: string;\n shop: string;\n state: string;\n accessToken: string;\n}>;\nexport type ShopifyOfflineSessionDelegate = Readonly<{\n findUnique(args: Readonly<{ where: ShopifyOfflineSessionUniqueWhere; select?: ShopifyOfflineSessionSelect }>): Promise<ShopifyOfflineSessionRecord | null>;\n findMany(args: Readonly<{ where: ShopifyOfflineSessionWhere; select?: ShopifyOfflineSessionSelect; take?: number }>): Promise<ShopifyOfflineSessionRecord[]>;\n create(args: Readonly<{ data: ShopifyOfflineSessionCreateData; select?: ShopifyOfflineSessionSelect }>): Promise<ShopifyOfflineSessionRecord>;\n update(args: Readonly<{ where: ShopifyOfflineSessionUniqueWhere; data: ShopifyOfflineSessionData; select?: ShopifyOfflineSessionSelect }>): Promise<ShopifyOfflineSessionRecord>;\n upsert(args: Readonly<{ where: ShopifyOfflineSessionUniqueWhere; create: ShopifyOfflineSessionCreateData; update: ShopifyOfflineSessionData; select?: ShopifyOfflineSessionSelect }>): Promise<ShopifyOfflineSessionRecord>;\n delete(args: Readonly<{ where: ShopifyOfflineSessionUniqueWhere; select?: ShopifyOfflineSessionSelect }>): Promise<ShopifyOfflineSessionRecord>;\n deleteMany(args: Readonly<{ where?: ShopifyOfflineSessionWhere }>): Promise<{ count: number }>;\n updateMany(args: Readonly<{ where?: ShopifyOfflineSessionWhere; data: ShopifyOfflineSessionData }>): Promise<{ count: number }>;\n}>;\n\nexport type ShopifyOfflineTransaction = Readonly<{\n $queryRawUnsafe<T = unknown>(sql: string, ...values: unknown[]): Promise<T>;\n $executeRawUnsafe(sql: string, ...values: unknown[]): Promise<number>;\n session: ShopifyOfflineSessionDelegate;\n shop: Readonly<{\n findUnique(args: Readonly<{ where: Readonly<{ id: string }>; select: Readonly<{ id: true; domain: true; platform: true; status: true }> }>): Promise<ShopifyOfflineShopRecord | null>;\n }>;\n}>;\n\nexport type ShopifyOfflineDatabase = Readonly<{\n $transaction<T>(\n work: (transaction: ShopifyOfflineTransaction) => Promise<T>,\n options: Readonly<{ maxWait: 5000; timeout: 20000; isolationLevel: \"ReadCommitted\" }>,\n ): Promise<T>;\n shop: ShopifyOfflineTransaction[\"shop\"];\n}>;\n\nexport type OfflineCredentialSnapshot = Readonly<{\n id: string; shopId: string; shop: string; accessToken: string; scope: string | null;\n expires: Date | null; refreshTokenExpires: Date | null;\n}>;\nexport type LockedSessionContext = Readonly<{\n transaction: ShopifyOfflineTransaction; shopId: string; shop: string; sessionId: string; signal: AbortSignal;\n}>;\nexport type SdkInstallationSessionContext = Readonly<{\n transaction: ShopifyOfflineTransaction; shopId: null; shop: string; sessionId: string | null; signal: AbortSignal;\n}>;\nexport type ShopifyOfflineTokenProvider = Readonly<{\n withSdkInstallationSessionLock<T>(integrationDomain: string, work: (context: SdkInstallationSessionContext) => Promise<T>): Promise<T>;\n getAccessToken(shopId: string, options?: Readonly<{ signal?: AbortSignal }>): Promise<string>;\n getSession(shopId: string, options?: Readonly<{ signal?: AbortSignal }>): Promise<OfflineCredentialSnapshot>;\n withSessionLock<T>(shopId: string, work: (context: LockedSessionContext) => Promise<T>, options?: Readonly<{ signal?: AbortSignal }>): Promise<T>;\n}>;\n\ntype PersistedShop = ShopifyOfflineShopRecord;\nconst TX_OPTIONS = { maxWait: 5000, timeout: 20000, isolationLevel: \"ReadCommitted\" } as const;\nconst ACCESS_REFRESH_SKEW_MS = 320_000;\nconst REFRESH_NETWORK_BUDGET_MS = 8_000;\nconst OPERATION_BUDGET_MS = 15_000;\nconst RESPONSE_LIMIT = 16_384;\nconst CONTROL = /[\\u0000-\\u001f\\u007f]/;\nconst SESSION_SELECT = { id: true, shop: true, isOnline: true, accessToken: true, refreshToken: true, scope: true, expires: true, refreshTokenExpires: true } as const;\n\nfunction fail(code: ShopifyOfflineTokenErrorCode): never { throw new ShopifyOfflineTokenError(code); }\nfunction isRecord(value: unknown): value is Record<string, unknown> { return typeof value === \"object\" && value !== null && !Array.isArray(value); }\nfunction validToken(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0 && value.length <= 4096 && value.trim() === value && !/[\\r\\n\\u0000]/.test(value);\n}\nfunction validScope(value: unknown): value is string { return typeof value === \"string\" && value.length <= 4096 && !CONTROL.test(value); }\nfunction validDate(value: unknown): value is Date | null { return value === null || (value instanceof Date && Number.isFinite(value.getTime())); }\nfunction mapDatabaseError(error: unknown): ShopifyOfflineTokenError {\n const code = isRecord(error) && typeof error.code === \"string\" ? error.code : \"\";\n const message = error instanceof Error ? error.message : \"\";\n if (code === \"55P03\" || /lock timeout/i.test(message)) return new ShopifyOfflineTokenError(\"LOCK_TIMEOUT\");\n if (code === \"57014\" || /statement timeout|statement timed out/i.test(message)) return new ShopifyOfflineTokenError(\"DEADLINE\");\n return new ShopifyOfflineTokenError(\"PERSISTENCE_UNAVAILABLE\");\n}\n\nfunction createDeadline(signal?: AbortSignal): Readonly<{ signal: AbortSignal; dispose(): void; check(): void; wait<T>(work: Promise<T>): Promise<T> }> {\n const controller = new AbortController();\n let expired = false;\n const timer = setTimeout(() => { expired = true; controller.abort(); }, OPERATION_BUDGET_MS);\n const onAbort = () => controller.abort(signal?.reason);\n if (signal?.aborted) onAbort();\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n return {\n signal: controller.signal,\n dispose() { clearTimeout(timer); signal?.removeEventListener(\"abort\", onAbort); },\n wait<T>(work: Promise<T>): Promise<T> {\n if (controller.signal.aborted) this.check();\n let onDeadline: (() => void) | undefined;\n const aborted = new Promise<never>((_resolve, reject) => {\n onDeadline = () => reject(new Error(\"operation aborted\"));\n controller.signal.addEventListener(\"abort\", onDeadline, { once: true });\n });\n return Promise.race([work, aborted]).finally(() => {\n if (onDeadline) controller.signal.removeEventListener(\"abort\", onDeadline);\n });\n },\n check() {\n if (signal?.aborted) fail(\"CANCELLED\");\n if (expired) fail(\"DEADLINE\");\n if (controller.signal.aborted) fail(\"DEADLINE\");\n },\n };\n}\n\nasync function readBoundedBody(response: Response, signal: AbortSignal): Promise<string> {\n if (!response.body) return \"\";\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let size = 0;\n try {\n while (true) {\n if (signal.aborted) throw new Error(\"refresh stream aborted\");\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > RESPONSE_LIMIT) {\n await reader.cancel().catch(() => undefined);\n fail(\"REFRESH_OUTCOME_UNKNOWN\");\n }\n chunks.push(value);\n }\n } finally { reader.releaseLock(); }\n return Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))).toString(\"utf8\");\n}\n\nfunction snapshot(row: ShopifyOfflineSessionRecord, shopId: string, shop: string): OfflineCredentialSnapshot {\n if (!validToken(row.accessToken) || !validScope(row.scope) && row.scope !== null\n || !validDate(row.expires) || !validDate(row.refreshTokenExpires)) fail(\"INVALID_SESSION\");\n return Object.freeze({ id: row.id, shopId, shop, accessToken: row.accessToken, scope: row.scope, expires: row.expires, refreshTokenExpires: row.refreshTokenExpires });\n}\n\nexport function createShopifyOfflineTokenProvider(input: Readonly<{\n prisma: ShopifyOfflineDatabase;\n readOAuth: () => Promise<Readonly<{ apiKey: string; apiSecret: string }>>;\n fetch: typeof fetch;\n now?: () => number;\n onEvent?: (event: ShopifyOfflineRefreshEvent) => void;\n}>): ShopifyOfflineTokenProvider {\n const now = input.now ?? Date.now;\n function notify(event: ShopifyOfflineRefreshEvent): void {\n try {\n // Promise resolution also isolates rejected promises/thenables from adapters.\n void Promise.resolve(input.onEvent?.(Object.freeze(event))).catch(() => undefined);\n } catch { /* Observers never affect credential or transaction outcomes. */ }\n }\n\n async function resolveShop(shopId: string, deadline: ReturnType<typeof createDeadline>): Promise<PersistedShop> {\n deadline.check();\n if (typeof shopId !== \"string\" || !shopId.trim()) fail(\"SESSION_MISSING\");\n let shop: PersistedShop | null;\n try {\n shop = await deadline.wait(input.prisma.shop.findUnique({ where: { id: shopId }, select: { id: true, domain: true, platform: true, status: true } }));\n } catch (error) {\n deadline.check();\n throw mapDatabaseError(error);\n }\n deadline.check();\n if (!shop) fail(\"SESSION_MISSING\");\n if (shop.platform !== \"SHOPIFY\" || shop.status !== \"ACTIVE\") fail(\"INVALID_SESSION\");\n if (!shop.domain) fail(\"SESSION_IDENTITY_CONFLICT\");\n return shop;\n }\n\n async function runLocked<T>(shop: PersistedShop, shopId: string, deadline: ReturnType<typeof createDeadline>, work: (context: LockedSessionContext) => Promise<T>, outcome: { remoteSucceeded: boolean } = { remoteSucceeded: false }): Promise<T> {\n try {\n deadline.check();\n const result = await deadline.wait(input.prisma.$transaction(async (tx) => {\n await tx.$executeRawUnsafe(\"SET LOCAL lock_timeout = '5s'\");\n await tx.$executeRawUnsafe(\"SET LOCAL statement_timeout = '18s'\");\n await tx.$queryRawUnsafe(\"SELECT pg_advisory_xact_lock(hashtextextended($1, 0)) IS NULL\", `moda:shopify-offline:v1:${shop.domain}`);\n deadline.check();\n\n const currentShop = await tx.shop.findUnique({ where: { id: shopId }, select: { id: true, domain: true, platform: true, status: true } });\n if (!currentShop) fail(\"SESSION_MISSING\");\n if (currentShop.platform !== \"SHOPIFY\" || currentShop.status !== \"ACTIVE\") fail(\"INVALID_SESSION\");\n if (currentShop.domain !== shop.domain) fail(\"SESSION_IDENTITY_CONFLICT\");\n\n const sessions = await tx.session.findMany({ where: { shop: currentShop.domain, isOnline: false }, select: SESSION_SELECT, take: 2 });\n if (sessions.length === 0) fail(\"SESSION_MISSING\");\n if (sessions.length !== 1) fail(\"SESSION_IDENTITY_CONFLICT\");\n const row = sessions[0]!;\n if (!row.id || row.shop !== currentShop.domain || row.isOnline !== false) fail(\"SESSION_IDENTITY_CONFLICT\");\n await tx.$queryRawUnsafe('SELECT \"id\" FROM \"shopify\".\"Session\" WHERE \"id\" = $1 FOR UPDATE', row.id);\n const reread = await tx.session.findUnique({ where: { id: row.id }, select: SESSION_SELECT });\n if (!reread || reread.id !== row.id || reread.shop !== currentShop.domain || reread.isOnline !== false) fail(\"SESSION_IDENTITY_CONFLICT\");\n\n const context: LockedSessionContext = Object.freeze({ transaction: tx, shopId, shop: currentShop.domain, sessionId: reread.id, signal: deadline.signal });\n deadline.check();\n let value: T;\n try { value = await deadline.wait(work(context)); }\n catch (error) { deadline.check(); throw new CallbackFailure(error); }\n deadline.check();\n return value;\n }, TX_OPTIONS));\n return result;\n } catch (error) {\n if (error instanceof CallbackFailure) throw error.value;\n if (deadline.signal.aborted) deadline.check();\n if (outcome.remoteSucceeded && (error instanceof ShopifyOfflineTokenError\n ? error.code === \"LOCK_TIMEOUT\" || error.code === \"DEADLINE\" || error.code === \"PERSISTENCE_UNAVAILABLE\"\n : true)) fail(\"REFRESH_OUTCOME_UNKNOWN\");\n if (error instanceof ShopifyOfflineTokenError) throw error;\n deadline.check();\n throw mapDatabaseError(error);\n }\n }\n\n async function getSession(shopId: string, options?: Readonly<{ signal?: AbortSignal }>): Promise<OfflineCredentialSnapshot> {\n const deadline = createDeadline(options?.signal);\n let attempt: { operationId: string; shopId: string; startedAt: number } | undefined;\n const outcome = { remoteSucceeded: false };\n function emit(event: ShopifyOfflineRefreshEvent[\"event\"], result: ShopifyOfflineRefreshEvent[\"outcome\"], reasonCode: ShopifyOfflineTokenErrorCode | null): void {\n if (!attempt) return;\n notify({ event, operationId: attempt.operationId, shopId: attempt.shopId, source: \"SHARED\",\n durationMs: Math.min(60_000, Math.max(0, Math.round(performance.now() - attempt.startedAt))), outcome: result, reasonCode });\n }\n try {\n deadline.check();\n const shop = await resolveShop(shopId, deadline);\n deadline.check();\n const result = await runLocked(shop, shopId, deadline, async (context) => {\n let row = await context.transaction.session.findUnique({ where: { id: context.sessionId }, select: SESSION_SELECT });\n if (!row) fail(\"SESSION_IDENTITY_CONFLICT\");\n const currentTime = now();\n if (!Number.isFinite(currentTime)) fail(\"INVALID_SESSION\");\n if (row.expires === null && row.refreshToken === null) return snapshot(row, shopId, context.shop);\n if (row.expires === null) fail(\"INVALID_SESSION\");\n const expiresAt = row.expires?.getTime() ?? 0;\n if (expiresAt - currentTime > ACCESS_REFRESH_SKEW_MS) return snapshot(row, shopId, context.shop);\n if (!validToken(row.refreshToken)) fail(\"INVALID_SESSION\");\n if (!validDate(row.refreshTokenExpires) || row.refreshTokenExpires === null) fail(\"INVALID_SESSION\");\n if (row.refreshTokenExpires.getTime() <= currentTime) fail(\"REFRESH_TOKEN_EXPIRED\");\n\n let credentials: Readonly<{ apiKey: string; apiSecret: string }>;\n try { credentials = await input.readOAuth(); }\n catch { fail(\"OAUTH_CONFIG_UNAVAILABLE\"); }\n if (options?.signal?.aborted) fail(\"CANCELLED\");\n if (context.signal.aborted) fail(\"DEADLINE\");\n if (!validToken(credentials.apiKey) || !validToken(credentials.apiSecret)) fail(\"OAUTH_CONFIG_UNAVAILABLE\");\n const requestStartedAt = now();\n const refreshController = new AbortController();\n const refreshTimeout = setTimeout(() => refreshController.abort(), REFRESH_NETWORK_BUDGET_MS);\n const onAbort = () => refreshController.abort();\n context.signal.addEventListener(\"abort\", onAbort, { once: true });\n let response: Response;\n try {\n const form = new URLSearchParams({ client_id: credentials.apiKey, client_secret: credentials.apiSecret, grant_type: \"refresh_token\", refresh_token: row.refreshToken });\n attempt = { operationId: randomUUID(), shopId: context.shopId, startedAt: performance.now() };\n emit(\"shopify.offline_refresh.started\", \"STARTED\", null);\n response = await input.fetch(`https://${context.shop}/admin/oauth/access_token`, {\n method: \"POST\", redirect: \"error\", headers: { \"content-type\": \"application/x-www-form-urlencoded\" }, body: form, signal: refreshController.signal,\n });\n } catch {\n clearTimeout(refreshTimeout);\n context.signal.removeEventListener(\"abort\", onAbort);\n if (options?.signal?.aborted) fail(\"CANCELLED\");\n if (context.signal.aborted) fail(\"REFRESH_OUTCOME_UNKNOWN\");\n fail(\"REFRESH_OUTCOME_UNKNOWN\");\n }\n if (response.status >= 400 && response.status < 500) fail(\"REFRESH_REJECTED\");\n if (!response.ok) { outcome.remoteSucceeded = true; fail(\"REFRESH_OUTCOME_UNKNOWN\"); }\n outcome.remoteSucceeded = true;\n let raw: string;\n try { raw = await readBoundedBody(response, refreshController.signal); }\n catch (error) {\n clearTimeout(refreshTimeout);\n context.signal.removeEventListener(\"abort\", onAbort);\n if (options?.signal?.aborted) fail(\"CANCELLED\");\n if (context.signal.aborted) fail(\"REFRESH_OUTCOME_UNKNOWN\");\n fail(\"REFRESH_OUTCOME_UNKNOWN\");\n } finally {\n clearTimeout(refreshTimeout);\n context.signal.removeEventListener(\"abort\", onAbort);\n }\n let payload: unknown;\n try { payload = JSON.parse(raw) as unknown; } catch { fail(\"REFRESH_OUTCOME_UNKNOWN\"); }\n if (!isRecord(payload) || !validToken(payload.access_token) || !validToken(payload.refresh_token)\n || !Number.isSafeInteger(payload.expires_in) || (payload.expires_in as number) <= 0 || (payload.expires_in as number) > 86_400\n || !Number.isSafeInteger(payload.refresh_token_expires_in) || (payload.refresh_token_expires_in as number) <= 0 || (payload.refresh_token_expires_in as number) > 7_776_000\n || (payload.expires_in as number) <= 320\n || (payload.scope !== undefined && !validScope(payload.scope))) fail(\"REFRESH_OUTCOME_UNKNOWN\");\n const expires = requestStartedAt + (payload.expires_in as number) * 1000;\n const refreshTokenExpires = requestStartedAt + (payload.refresh_token_expires_in as number) * 1000;\n if (!Number.isFinite(expires) || !Number.isFinite(refreshTokenExpires) || Number.isNaN(new Date(expires).getTime()) || Number.isNaN(new Date(refreshTokenExpires).getTime())) fail(\"REFRESH_OUTCOME_UNKNOWN\");\n const scope = payload.scope === undefined ? row.scope : payload.scope as string;\n try {\n row = await context.transaction.session.update({ where: { id: row.id }, data: {\n accessToken: payload.access_token, expires: new Date(expires), refreshToken: payload.refresh_token,\n refreshTokenExpires: new Date(refreshTokenExpires), scope,\n }, select: SESSION_SELECT });\n } catch { outcome.remoteSucceeded = true; throw new ShopifyOfflineTokenError(\"REFRESH_OUTCOME_UNKNOWN\"); }\n outcome.remoteSucceeded = true;\n return snapshot(row, shopId, context.shop);\n }, outcome);\n emit(\"shopify.offline_refresh.committed\", \"COMMITTED\", null);\n return result;\n } catch (error) {\n let failure = error;\n try { deadline.check(); } catch (deadlineError) { failure = deadlineError; }\n const code = failure instanceof ShopifyOfflineTokenError ? failure.code : \"PERSISTENCE_UNAVAILABLE\";\n const ambiguous = outcome.remoteSucceeded && code !== \"REFRESH_REJECTED\" && code !== \"CANCELLED\";\n const reason = ambiguous ? \"REFRESH_OUTCOME_UNKNOWN\" : code;\n emit(\"shopify.offline_refresh.failed\", reason === \"REFRESH_REJECTED\" ? \"REJECTED\"\n : reason === \"CANCELLED\" ? \"CANCELLED\" : reason === \"REFRESH_OUTCOME_UNKNOWN\" ? \"UNKNOWN\" : \"UNAVAILABLE\", reason);\n throw failure;\n } finally { deadline.dispose(); }\n }\n\n async function withSessionLock<T>(shopId: string, work: (context: LockedSessionContext) => Promise<T>, options?: Readonly<{ signal?: AbortSignal }>): Promise<T> {\n const deadline = createDeadline(options?.signal);\n try {\n deadline.check();\n const shop = await resolveShop(shopId, deadline);\n deadline.check();\n return await runLocked(shop, shopId, deadline, work);\n } catch (error) {\n deadline.check();\n throw error;\n } finally { deadline.dispose(); }\n }\n\n async function withSdkInstallationSessionLock<T>(integrationDomain: string, work: (context: SdkInstallationSessionContext) => Promise<T>): Promise<T> {\n if (typeof integrationDomain !== \"string\" || !integrationDomain.trim()) fail(\"INVALID_SESSION\");\n const deadline = createDeadline();\n try {\n return await input.prisma.$transaction(async (tx) => {\n await tx.$executeRawUnsafe(\"SET LOCAL lock_timeout = '5s'\");\n await tx.$executeRawUnsafe(\"SET LOCAL statement_timeout = '18s'\");\n await tx.$queryRawUnsafe(\"SELECT pg_advisory_xact_lock(hashtextextended($1, 0)) IS NULL\", `moda:shopify-offline:v1:${integrationDomain}`);\n let value: T;\n try { value = await deadline.wait(work(Object.freeze({ transaction: tx, shopId: null, shop: integrationDomain, sessionId: null, signal: deadline.signal }))); }\n catch (error) { deadline.check(); throw new CallbackFailure(error); }\n deadline.check();\n return value;\n }, TX_OPTIONS);\n } catch (error) {\n if (error instanceof CallbackFailure) throw error.value;\n if (error instanceof ShopifyOfflineTokenError) throw error;\n if (deadline.signal.aborted) deadline.check();\n throw mapDatabaseError(error);\n } finally { deadline.dispose(); }\n }\n\n return Object.freeze({\n withSdkInstallationSessionLock,\n getAccessToken: async (shopId: string, options?: Readonly<{ signal?: AbortSignal }>) => (await getSession(shopId, options)).accessToken,\n getSession,\n withSessionLock,\n });\n}\n","import { Buffer } from \"node:buffer\";\nimport {\n decryptCredential,\n type CredentialEnvelope,\n type CredentialKeyring,\n} from \"../security/credentials/node.js\";\n\nconst CONFIGURATION_KEY = \"shopify.oauth\" as const;\nconst CONFIGURATION_ENVIRONMENTS = new Set([\"local\", \"test\", \"development\", \"staging\", \"production\"]);\nconst ENVELOPE_KEYS = [\"kind\", \"schemaVersion\", \"algorithm\", \"wrappingKeyId\", \"nonce\", \"ciphertext\", \"authTag\"] as const;\nconst RESERVED_KEY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst KEY_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;\nconst BASE64_PATTERN = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;\nconst CONTROL_CHARACTERS = /[\\u0000-\\u001f\\u007f]/;\n\nexport type ShopifyOAuthConfigurationErrorCode =\n | \"INVALID_ENVIRONMENT\"\n | \"CONFIGURATION_UNAVAILABLE\"\n | \"CONFIGURATION_INVALID\";\n\nconst ERROR_MESSAGES: Record<ShopifyOAuthConfigurationErrorCode, string> = {\n INVALID_ENVIRONMENT: \"Shopify OAuth configuration is unavailable.\",\n CONFIGURATION_UNAVAILABLE: \"Shopify OAuth configuration is unavailable.\",\n CONFIGURATION_INVALID: \"Shopify OAuth configuration is invalid.\",\n};\n\n/** Safe configuration boundary error; never contains a row, key, or decrypt cause. */\nexport class ShopifyOAuthConfigurationError extends Error {\n readonly code: ShopifyOAuthConfigurationErrorCode;\n\n constructor(code: ShopifyOAuthConfigurationErrorCode) {\n super(ERROR_MESSAGES[code]);\n this.name = \"ShopifyOAuthConfigurationError\";\n this.code = code;\n }\n}\n\nexport type ShopifyOAuthConfigurationRow = Readonly<{\n environment: string;\n key: string;\n version: number;\n value: unknown;\n}>;\n\nexport type ShopifyOAuthConfigurationPrisma = Readonly<{\n platformConfiguration: Readonly<{\n findUnique(args: Readonly<{\n where: Readonly<{ environment_key: Readonly<{ environment: string; key: typeof CONFIGURATION_KEY }> }>;\n select: Readonly<{ environment: true; key: true; version: true; value: true }>;\n }>): Promise<ShopifyOAuthConfigurationRow | null>;\n }>;\n}>;\n\nexport type ShopifyOAuthCredentials = Readonly<{\n apiKey: string;\n apiSecret: string;\n}>;\n\nfunction configurationFailure(code: ShopifyOAuthConfigurationErrorCode): never {\n throw new ShopifyOAuthConfigurationError(code);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction hasExactKeys(value: Record<string, unknown>, expected: readonly string[]): boolean {\n const actual = Object.keys(value);\n return actual.length === expected.length && actual.every((key) => expected.includes(key));\n}\n\nfunction canonicalBase64(value: unknown, exactLength: number | null): Uint8Array | null {\n if (typeof value !== \"string\" || value.length === 0 || !BASE64_PATTERN.test(value)) return null;\n const decoded = Buffer.from(value, \"base64\");\n if (decoded.length < 1 || decoded.length > 8192 || decoded.toString(\"base64\") !== value) return null;\n if (exactLength !== null && decoded.length !== exactLength) return null;\n return Uint8Array.from(decoded);\n}\n\nfunction parseSealedEnvelope(value: unknown): CredentialEnvelope {\n if (!isRecord(value) || !hasExactKeys(value, ENVELOPE_KEYS)\n || value.kind !== \"sealed\"\n || value.schemaVersion !== 1\n || value.algorithm !== \"AES-256-GCM\"\n || typeof value.wrappingKeyId !== \"string\"\n || !KEY_ID_PATTERN.test(value.wrappingKeyId)\n || RESERVED_KEY_IDS.has(value.wrappingKeyId)) {\n return configurationFailure(\"CONFIGURATION_INVALID\");\n }\n\n const nonce = canonicalBase64(value.nonce, 12);\n const ciphertext = canonicalBase64(value.ciphertext, null);\n const authTag = canonicalBase64(value.authTag, 16);\n if (!nonce || !ciphertext || !authTag) return configurationFailure(\"CONFIGURATION_INVALID\");\n return { keyId: value.wrappingKeyId, nonce, ciphertext, authTag };\n}\n\nfunction validCredential(value: unknown): value is string {\n return typeof value === \"string\" && value.length >= 1 && value.length <= 4096\n && value.trim() === value && !CONTROL_CHARACTERS.test(value);\n}\n\nfunction parseCredentials(value: unknown): ShopifyOAuthCredentials {\n if (!isRecord(value) || !hasExactKeys(value, [\"apiKey\", \"apiSecret\"])\n || !validCredential(value.apiKey) || !validCredential(value.apiSecret)) {\n return configurationFailure(\"CONFIGURATION_INVALID\");\n }\n return Object.freeze({ apiKey: value.apiKey, apiSecret: value.apiSecret });\n}\n\n/**\n * Read and unseal the existing platform `shopify.oauth` row. Environment identity\n * is deployment configuration supplied by the caller, never request data.\n */\nexport async function readShopifyOAuthConfiguration(input: Readonly<{\n prisma: ShopifyOAuthConfigurationPrisma;\n environment: string;\n unsealKeyring: CredentialKeyring;\n}>): Promise<ShopifyOAuthCredentials> {\n if (!input || typeof input !== \"object\" || Array.isArray(input)\n || typeof input.environment !== \"string\" || !CONFIGURATION_ENVIRONMENTS.has(input.environment)) {\n return configurationFailure(\"INVALID_ENVIRONMENT\");\n }\n\n let row: ShopifyOAuthConfigurationRow | null;\n try {\n row = await input.prisma.platformConfiguration.findUnique({\n where: { environment_key: { environment: input.environment, key: CONFIGURATION_KEY } },\n select: { environment: true, key: true, version: true, value: true },\n });\n } catch {\n return configurationFailure(\"CONFIGURATION_UNAVAILABLE\");\n }\n\n if (!row) return configurationFailure(\"CONFIGURATION_UNAVAILABLE\");\n if (row.environment !== input.environment || row.key !== CONFIGURATION_KEY\n || !Number.isSafeInteger(row.version) || row.version < 1 || row.version > 2_147_483_647) {\n return configurationFailure(\"CONFIGURATION_INVALID\");\n }\n if (isRecord(row.value) && hasExactKeys(row.value, [\"kind\", \"schemaVersion\"])\n && row.value.kind === \"disabled\" && row.value.schemaVersion === 1) {\n return configurationFailure(\"CONFIGURATION_UNAVAILABLE\");\n }\n\n let plaintext: string;\n try {\n const envelope = parseSealedEnvelope(row.value);\n const aad = JSON.stringify([\"moda-platform-config-v1\", input.environment, CONFIGURATION_KEY, row.version, 1]);\n plaintext = decryptCredential({ keyring: input.unsealKeyring, envelope, aad });\n } catch (error) {\n if (error instanceof ShopifyOAuthConfigurationError) throw error;\n return configurationFailure(\"CONFIGURATION_INVALID\");\n }\n\n try {\n return parseCredentials(JSON.parse(plaintext) as unknown);\n } catch (error) {\n if (error instanceof ShopifyOAuthConfigurationError) throw error;\n return configurationFailure(\"CONFIGURATION_INVALID\");\n }\n}\n"],"mappings":";;;;;;;;;;;AACA,SAAS,kBAAkB;;;ACD3B,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAmB5B,IAAM,iBAA+D;AAAA,EACnE,iBAAiB;AAAA,EACjB,2BAA2B;AAAA,EAC3B,iBAAiB;AAAA,EACjB,uBAAuB;AAAA,EACvB,0BAA0B;AAAA,EAC1B,cAAc;AAAA,EACd,WAAW;AAAA,EACX,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,0BAA0B;AAAA,EAC1B,yBAAyB;AAAA,EACzB,yBAAyB;AAC3B;AAEA,IAAM,YAAY,oBAAI,IAAkC;AAAA,EACtD;AAAA,EAAgB;AAAA,EAAY;AAAA,EAA2B;AACzD,CAAC;AAEM,IAAM,2BAAN,cAAuC,MAAM;AAAA,EACzC;AAAA,EACA;AAAA,EAET,YAAY,MAAoC;AAC9C,UAAM,eAAe,IAAI,CAAC;AAC1B,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,YAAY,UAAU,IAAI,IAAI;AAAA,EACrC;AACF;AAEA,IAAM,kBAAN,cAA8B,MAAM;AAAA,EAClC,YAAqB,OAAgB;AAAE,UAAM,kCAAkC;AAA1D;AAAA,EAA6D;AAAA,EAA7D;AACvB;AAwIA,IAAM,aAAa,EAAE,SAAS,KAAM,SAAS,KAAO,gBAAgB,gBAAgB;AACpF,IAAM,yBAAyB;AAC/B,IAAM,4BAA4B;AAClC,IAAM,sBAAsB;AAC5B,IAAM,iBAAiB;AACvB,IAAM,UAAU;AAChB,IAAM,iBAAiB,EAAE,IAAI,MAAM,MAAM,MAAM,UAAU,MAAM,aAAa,MAAM,cAAc,MAAM,OAAO,MAAM,SAAS,MAAM,qBAAqB,KAAK;AAE5J,SAAS,KAAK,MAA2C;AAAE,QAAM,IAAI,yBAAyB,IAAI;AAAG;AACrG,SAAS,SAAS,OAAkD;AAAE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAAG;AACnJ,SAAS,WAAW,OAAiC;AACnD,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,KAAK,MAAM,UAAU,QAAQ,MAAM,KAAK,MAAM,SAAS,CAAC,eAAe,KAAK,KAAK;AACtI;AACA,SAAS,WAAW,OAAiC;AAAE,SAAO,OAAO,UAAU,YAAY,MAAM,UAAU,QAAQ,CAAC,QAAQ,KAAK,KAAK;AAAG;AACzI,SAAS,UAAU,OAAsC;AAAE,SAAO,UAAU,QAAS,iBAAiB,QAAQ,OAAO,SAAS,MAAM,QAAQ,CAAC;AAAI;AACjJ,SAAS,iBAAiB,OAA0C;AAClE,QAAM,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;AAC9E,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,MAAI,SAAS,WAAW,gBAAgB,KAAK,OAAO,EAAG,QAAO,IAAI,yBAAyB,cAAc;AACzG,MAAI,SAAS,WAAW,yCAAyC,KAAK,OAAO,EAAG,QAAO,IAAI,yBAAyB,UAAU;AAC9H,SAAO,IAAI,yBAAyB,yBAAyB;AAC/D;AAEA,SAAS,eAAe,QAAgI;AACtJ,QAAM,aAAa,IAAI,gBAAgB;AACvC,MAAI,UAAU;AACd,QAAM,QAAQ,WAAW,MAAM;AAAE,cAAU;AAAM,eAAW,MAAM;AAAA,EAAG,GAAG,mBAAmB;AAC3F,QAAM,UAAU,MAAM,WAAW,MAAM,QAAQ,MAAM;AACrD,MAAI,QAAQ,QAAS,SAAQ;AAC7B,UAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AACzD,SAAO;AAAA,IACL,QAAQ,WAAW;AAAA,IACnB,UAAU;AAAE,mBAAa,KAAK;AAAG,cAAQ,oBAAoB,SAAS,OAAO;AAAA,IAAG;AAAA,IAChF,KAAQ,MAA8B;AACpC,UAAI,WAAW,OAAO,QAAS,MAAK,MAAM;AAC1C,UAAI;AACJ,YAAM,UAAU,IAAI,QAAe,CAAC,UAAU,WAAW;AACvD,qBAAa,MAAM,OAAO,IAAI,MAAM,mBAAmB,CAAC;AACxD,mBAAW,OAAO,iBAAiB,SAAS,YAAY,EAAE,MAAM,KAAK,CAAC;AAAA,MACxE,CAAC;AACD,aAAO,QAAQ,KAAK,CAAC,MAAM,OAAO,CAAC,EAAE,QAAQ,MAAM;AACjD,YAAI,WAAY,YAAW,OAAO,oBAAoB,SAAS,UAAU;AAAA,MAC3E,CAAC;AAAA,IACH;AAAA,IACA,QAAQ;AACN,UAAI,QAAQ,QAAS,MAAK,WAAW;AACrC,UAAI,QAAS,MAAK,UAAU;AAC5B,UAAI,WAAW,OAAO,QAAS,MAAK,UAAU;AAAA,IAChD;AAAA,EACF;AACF;AAEA,eAAe,gBAAgB,UAAoB,QAAsC;AACvF,MAAI,CAAC,SAAS,KAAM,QAAO;AAC3B,QAAM,SAAS,SAAS,KAAK,UAAU;AACvC,QAAM,SAAuB,CAAC;AAC9B,MAAI,OAAO;AACX,MAAI;AACF,WAAO,MAAM;AACX,UAAI,OAAO,QAAS,OAAM,IAAI,MAAM,wBAAwB;AAC5D,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AACV,cAAQ,MAAM;AACd,UAAI,OAAO,gBAAgB;AACzB,cAAM,OAAO,OAAO,EAAE,MAAM,MAAM,MAAS;AAC3C,aAAK,yBAAyB;AAAA,MAChC;AACA,aAAO,KAAK,KAAK;AAAA,IACnB;AAAA,EACF,UAAE;AAAU,WAAO,YAAY;AAAA,EAAG;AAClC,SAAO,OAAO,OAAO,OAAO,IAAI,CAAC,UAAU,OAAO,KAAK,KAAK,CAAC,CAAC,EAAE,SAAS,MAAM;AACjF;AAEA,SAAS,SAAS,KAAkC,QAAgB,MAAyC;AAC3G,MAAI,CAAC,WAAW,IAAI,WAAW,KAAK,CAAC,WAAW,IAAI,KAAK,KAAK,IAAI,UAAU,QACvE,CAAC,UAAU,IAAI,OAAO,KAAK,CAAC,UAAU,IAAI,mBAAmB,EAAG,MAAK,iBAAiB;AAC3F,SAAO,OAAO,OAAO,EAAE,IAAI,IAAI,IAAI,QAAQ,MAAM,aAAa,IAAI,aAAa,OAAO,IAAI,OAAO,SAAS,IAAI,SAAS,qBAAqB,IAAI,oBAAoB,CAAC;AACvK;AAEO,SAAS,kCAAkC,OAMjB;AAC/B,QAAM,MAAM,MAAM,OAAO,KAAK;AAC9B,WAAS,OAAO,OAAyC;AACvD,QAAI;AAEF,WAAK,QAAQ,QAAQ,MAAM,UAAU,OAAO,OAAO,KAAK,CAAC,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,IACnF,QAAQ;AAAA,IAAmE;AAAA,EAC7E;AAEA,iBAAe,YAAY,QAAgB,UAAqE;AAC9G,aAAS,MAAM;AACf,QAAI,OAAO,WAAW,YAAY,CAAC,OAAO,KAAK,EAAG,MAAK,iBAAiB;AACxE,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,SAAS,KAAK,MAAM,OAAO,KAAK,WAAW,EAAE,OAAO,EAAE,IAAI,OAAO,GAAG,QAAQ,EAAE,IAAI,MAAM,QAAQ,MAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,CAAC,CAAC;AAAA,IACtJ,SAAS,OAAO;AACd,eAAS,MAAM;AACf,YAAM,iBAAiB,KAAK;AAAA,IAC9B;AACA,aAAS,MAAM;AACf,QAAI,CAAC,KAAM,MAAK,iBAAiB;AACjC,QAAI,KAAK,aAAa,aAAa,KAAK,WAAW,SAAU,MAAK,iBAAiB;AACnF,QAAI,CAAC,KAAK,OAAQ,MAAK,2BAA2B;AAClD,WAAO;AAAA,EACT;AAEA,iBAAe,UAAa,MAAqB,QAAgB,UAA6C,MAAqD,UAAwC,EAAE,iBAAiB,MAAM,GAAe;AACjP,QAAI;AACF,eAAS,MAAM;AACf,YAAM,SAAS,MAAM,SAAS,KAAK,MAAM,OAAO,aAAa,OAAO,OAAO;AACzE,cAAM,GAAG,kBAAkB,+BAA+B;AAC1D,cAAM,GAAG,kBAAkB,qCAAqC;AAChE,cAAM,GAAG,gBAAgB,iEAAiE,2BAA2B,KAAK,MAAM,EAAE;AAClI,iBAAS,MAAM;AAEf,cAAM,cAAc,MAAM,GAAG,KAAK,WAAW,EAAE,OAAO,EAAE,IAAI,OAAO,GAAG,QAAQ,EAAE,IAAI,MAAM,QAAQ,MAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,CAAC;AACxI,YAAI,CAAC,YAAa,MAAK,iBAAiB;AACxC,YAAI,YAAY,aAAa,aAAa,YAAY,WAAW,SAAU,MAAK,iBAAiB;AACjG,YAAI,YAAY,WAAW,KAAK,OAAQ,MAAK,2BAA2B;AAExE,cAAM,WAAW,MAAM,GAAG,QAAQ,SAAS,EAAE,OAAO,EAAE,MAAM,YAAY,QAAQ,UAAU,MAAM,GAAG,QAAQ,gBAAgB,MAAM,EAAE,CAAC;AACpI,YAAI,SAAS,WAAW,EAAG,MAAK,iBAAiB;AACjD,YAAI,SAAS,WAAW,EAAG,MAAK,2BAA2B;AAC3D,cAAM,MAAM,SAAS,CAAC;AACtB,YAAI,CAAC,IAAI,MAAM,IAAI,SAAS,YAAY,UAAU,IAAI,aAAa,MAAO,MAAK,2BAA2B;AAC1G,cAAM,GAAG,gBAAgB,mEAAmE,IAAI,EAAE;AAClG,cAAM,SAAS,MAAM,GAAG,QAAQ,WAAW,EAAE,OAAO,EAAE,IAAI,IAAI,GAAG,GAAG,QAAQ,eAAe,CAAC;AAC5F,YAAI,CAAC,UAAU,OAAO,OAAO,IAAI,MAAM,OAAO,SAAS,YAAY,UAAU,OAAO,aAAa,MAAO,MAAK,2BAA2B;AAExI,cAAM,UAAgC,OAAO,OAAO,EAAE,aAAa,IAAI,QAAQ,MAAM,YAAY,QAAQ,WAAW,OAAO,IAAI,QAAQ,SAAS,OAAO,CAAC;AACxJ,iBAAS,MAAM;AACf,YAAI;AACJ,YAAI;AAAE,kBAAQ,MAAM,SAAS,KAAK,KAAK,OAAO,CAAC;AAAA,QAAG,SAC3C,OAAO;AAAE,mBAAS,MAAM;AAAG,gBAAM,IAAI,gBAAgB,KAAK;AAAA,QAAG;AACpE,iBAAS,MAAM;AACf,eAAO;AAAA,MACT,GAAG,UAAU,CAAC;AACd,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,iBAAiB,gBAAiB,OAAM,MAAM;AAClD,UAAI,SAAS,OAAO,QAAS,UAAS,MAAM;AAC5C,UAAI,QAAQ,oBAAoB,iBAAiB,2BAC7C,MAAM,SAAS,kBAAkB,MAAM,SAAS,cAAc,MAAM,SAAS,4BAC7E,MAAO,MAAK,yBAAyB;AACzC,UAAI,iBAAiB,yBAA0B,OAAM;AACrD,eAAS,MAAM;AACf,YAAM,iBAAiB,KAAK;AAAA,IAC9B;AAAA,EACF;AAEA,iBAAe,WAAW,QAAgB,SAAkF;AAC1H,UAAM,WAAW,eAAe,SAAS,MAAM;AAC/C,QAAI;AACJ,UAAM,UAAU,EAAE,iBAAiB,MAAM;AACzC,aAAS,KAAK,OAA4C,QAA+C,YAAuD;AAC9J,UAAI,CAAC,QAAS;AACd,aAAO;AAAA,QAAE;AAAA,QAAO,aAAa,QAAQ;AAAA,QAAa,QAAQ,QAAQ;AAAA,QAAQ,QAAQ;AAAA,QAChF,YAAY,KAAK,IAAI,KAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,YAAY,IAAI,IAAI,QAAQ,SAAS,CAAC,CAAC;AAAA,QAAG,SAAS;AAAA,QAAQ;AAAA,MAAW,CAAC;AAAA,IAC/H;AACA,QAAI;AACF,eAAS,MAAM;AACf,YAAM,OAAO,MAAM,YAAY,QAAQ,QAAQ;AAC/C,eAAS,MAAM;AACf,YAAM,SAAS,MAAM,UAAU,MAAM,QAAQ,UAAU,OAAO,YAAY;AAC1E,YAAI,MAAM,MAAM,QAAQ,YAAY,QAAQ,WAAW,EAAE,OAAO,EAAE,IAAI,QAAQ,UAAU,GAAG,QAAQ,eAAe,CAAC;AACnH,YAAI,CAAC,IAAK,MAAK,2BAA2B;AAC1C,cAAM,cAAc,IAAI;AACxB,YAAI,CAAC,OAAO,SAAS,WAAW,EAAG,MAAK,iBAAiB;AACzD,YAAI,IAAI,YAAY,QAAQ,IAAI,iBAAiB,KAAM,QAAO,SAAS,KAAK,QAAQ,QAAQ,IAAI;AAChG,YAAI,IAAI,YAAY,KAAM,MAAK,iBAAiB;AAChD,cAAM,YAAY,IAAI,SAAS,QAAQ,KAAK;AAC5C,YAAI,YAAY,cAAc,uBAAwB,QAAO,SAAS,KAAK,QAAQ,QAAQ,IAAI;AAC/F,YAAI,CAAC,WAAW,IAAI,YAAY,EAAG,MAAK,iBAAiB;AACzD,YAAI,CAAC,UAAU,IAAI,mBAAmB,KAAK,IAAI,wBAAwB,KAAM,MAAK,iBAAiB;AACnG,YAAI,IAAI,oBAAoB,QAAQ,KAAK,YAAa,MAAK,uBAAuB;AAElF,YAAI;AACJ,YAAI;AAAE,wBAAc,MAAM,MAAM,UAAU;AAAA,QAAG,QACvC;AAAE,eAAK,0BAA0B;AAAA,QAAG;AAC1C,YAAI,SAAS,QAAQ,QAAS,MAAK,WAAW;AAC9C,YAAI,QAAQ,OAAO,QAAS,MAAK,UAAU;AAC3C,YAAI,CAAC,WAAW,YAAY,MAAM,KAAK,CAAC,WAAW,YAAY,SAAS,EAAG,MAAK,0BAA0B;AAC1G,cAAM,mBAAmB,IAAI;AAC7B,cAAM,oBAAoB,IAAI,gBAAgB;AAC9C,cAAM,iBAAiB,WAAW,MAAM,kBAAkB,MAAM,GAAG,yBAAyB;AAC5F,cAAM,UAAU,MAAM,kBAAkB,MAAM;AAC9C,gBAAQ,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAChE,YAAI;AACJ,YAAI;AACF,gBAAM,OAAO,IAAI,gBAAgB,EAAE,WAAW,YAAY,QAAQ,eAAe,YAAY,WAAW,YAAY,iBAAiB,eAAe,IAAI,aAAa,CAAC;AACtK,oBAAU,EAAE,aAAa,WAAW,GAAG,QAAQ,QAAQ,QAAQ,WAAW,YAAY,IAAI,EAAE;AAC5F,eAAK,mCAAmC,WAAW,IAAI;AACvD,qBAAW,MAAM,MAAM,MAAM,WAAW,QAAQ,IAAI,6BAA6B;AAAA,YAC/E,QAAQ;AAAA,YAAQ,UAAU;AAAA,YAAS,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,YAAG,MAAM;AAAA,YAAM,QAAQ,kBAAkB;AAAA,UAC7I,CAAC;AAAA,QACH,QAAQ;AACN,uBAAa,cAAc;AAC3B,kBAAQ,OAAO,oBAAoB,SAAS,OAAO;AACnD,cAAI,SAAS,QAAQ,QAAS,MAAK,WAAW;AAC9C,cAAI,QAAQ,OAAO,QAAS,MAAK,yBAAyB;AAC1D,eAAK,yBAAyB;AAAA,QAChC;AACA,YAAI,SAAS,UAAU,OAAO,SAAS,SAAS,IAAK,MAAK,kBAAkB;AAC5E,YAAI,CAAC,SAAS,IAAI;AAAE,kBAAQ,kBAAkB;AAAM,eAAK,yBAAyB;AAAA,QAAG;AACrF,gBAAQ,kBAAkB;AAC1B,YAAI;AACJ,YAAI;AAAE,gBAAM,MAAM,gBAAgB,UAAU,kBAAkB,MAAM;AAAA,QAAG,SAChE,OAAO;AACZ,uBAAa,cAAc;AAC3B,kBAAQ,OAAO,oBAAoB,SAAS,OAAO;AACnD,cAAI,SAAS,QAAQ,QAAS,MAAK,WAAW;AAC9C,cAAI,QAAQ,OAAO,QAAS,MAAK,yBAAyB;AAC1D,eAAK,yBAAyB;AAAA,QAChC,UAAE;AACA,uBAAa,cAAc;AAC3B,kBAAQ,OAAO,oBAAoB,SAAS,OAAO;AAAA,QACrD;AACA,YAAI;AACJ,YAAI;AAAE,oBAAU,KAAK,MAAM,GAAG;AAAA,QAAc,QAAQ;AAAE,eAAK,yBAAyB;AAAA,QAAG;AACvF,YAAI,CAAC,SAAS,OAAO,KAAK,CAAC,WAAW,QAAQ,YAAY,KAAK,CAAC,WAAW,QAAQ,aAAa,KAC3F,CAAC,OAAO,cAAc,QAAQ,UAAU,KAAM,QAAQ,cAAyB,KAAM,QAAQ,aAAwB,SACrH,CAAC,OAAO,cAAc,QAAQ,wBAAwB,KAAM,QAAQ,4BAAuC,KAAM,QAAQ,2BAAsC,UAC9J,QAAQ,cAAyB,OACjC,QAAQ,UAAU,UAAa,CAAC,WAAW,QAAQ,KAAK,EAAI,MAAK,yBAAyB;AAChG,cAAM,UAAU,mBAAoB,QAAQ,aAAwB;AACpE,cAAM,sBAAsB,mBAAoB,QAAQ,2BAAsC;AAC9F,YAAI,CAAC,OAAO,SAAS,OAAO,KAAK,CAAC,OAAO,SAAS,mBAAmB,KAAK,OAAO,MAAM,IAAI,KAAK,OAAO,EAAE,QAAQ,CAAC,KAAK,OAAO,MAAM,IAAI,KAAK,mBAAmB,EAAE,QAAQ,CAAC,EAAG,MAAK,yBAAyB;AAC5M,cAAM,QAAQ,QAAQ,UAAU,SAAY,IAAI,QAAQ,QAAQ;AAChE,YAAI;AACF,gBAAM,MAAM,QAAQ,YAAY,QAAQ,OAAO,EAAE,OAAO,EAAE,IAAI,IAAI,GAAG,GAAG,MAAM;AAAA,YAC5E,aAAa,QAAQ;AAAA,YAAc,SAAS,IAAI,KAAK,OAAO;AAAA,YAAG,cAAc,QAAQ;AAAA,YACrF,qBAAqB,IAAI,KAAK,mBAAmB;AAAA,YAAG;AAAA,UACtD,GAAG,QAAQ,eAAe,CAAC;AAAA,QAC7B,QAAQ;AAAE,kBAAQ,kBAAkB;AAAM,gBAAM,IAAI,yBAAyB,yBAAyB;AAAA,QAAG;AACzG,gBAAQ,kBAAkB;AAC1B,eAAO,SAAS,KAAK,QAAQ,QAAQ,IAAI;AAAA,MACzC,GAAG,OAAO;AACV,WAAK,qCAAqC,aAAa,IAAI;AAC3D,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,UAAU;AACd,UAAI;AAAE,iBAAS,MAAM;AAAA,MAAG,SAAS,eAAe;AAAE,kBAAU;AAAA,MAAe;AAC3E,YAAM,OAAO,mBAAmB,2BAA2B,QAAQ,OAAO;AAC1E,YAAM,YAAY,QAAQ,mBAAmB,SAAS,sBAAsB,SAAS;AACrF,YAAM,SAAS,YAAY,4BAA4B;AACvD,WAAK,kCAAkC,WAAW,qBAAqB,aACnE,WAAW,cAAc,cAAc,WAAW,4BAA4B,YAAY,eAAe,MAAM;AACnH,YAAM;AAAA,IACR,UAAE;AAAU,eAAS,QAAQ;AAAA,IAAG;AAAA,EAClC;AAEA,iBAAe,gBAAmB,QAAgB,MAAqD,SAA0D;AAC/J,UAAM,WAAW,eAAe,SAAS,MAAM;AAC/C,QAAI;AACF,eAAS,MAAM;AACf,YAAM,OAAO,MAAM,YAAY,QAAQ,QAAQ;AAC/C,eAAS,MAAM;AACf,aAAO,MAAM,UAAU,MAAM,QAAQ,UAAU,IAAI;AAAA,IACrD,SAAS,OAAO;AACd,eAAS,MAAM;AACf,YAAM;AAAA,IACR,UAAE;AAAU,eAAS,QAAQ;AAAA,IAAG;AAAA,EAClC;AAEA,iBAAe,+BAAkC,mBAA2B,MAA0E;AACpJ,QAAI,OAAO,sBAAsB,YAAY,CAAC,kBAAkB,KAAK,EAAG,MAAK,iBAAiB;AAC9F,UAAM,WAAW,eAAe;AAChC,QAAI;AACF,aAAO,MAAM,MAAM,OAAO,aAAa,OAAO,OAAO;AACnD,cAAM,GAAG,kBAAkB,+BAA+B;AAC1D,cAAM,GAAG,kBAAkB,qCAAqC;AAChE,cAAM,GAAG,gBAAgB,iEAAiE,2BAA2B,iBAAiB,EAAE;AACxI,YAAI;AACJ,YAAI;AAAE,kBAAQ,MAAM,SAAS,KAAK,KAAK,OAAO,OAAO,EAAE,aAAa,IAAI,QAAQ,MAAM,MAAM,mBAAmB,WAAW,MAAM,QAAQ,SAAS,OAAO,CAAC,CAAC,CAAC;AAAA,QAAG,SACvJ,OAAO;AAAE,mBAAS,MAAM;AAAG,gBAAM,IAAI,gBAAgB,KAAK;AAAA,QAAG;AACpE,iBAAS,MAAM;AACf,eAAO;AAAA,MACT,GAAG,UAAU;AAAA,IACf,SAAS,OAAO;AACd,UAAI,iBAAiB,gBAAiB,OAAM,MAAM;AAClD,UAAI,iBAAiB,yBAA0B,OAAM;AACrD,UAAI,SAAS,OAAO,QAAS,UAAS,MAAM;AAC5C,YAAM,iBAAiB,KAAK;AAAA,IAC9B,UAAE;AAAU,eAAS,QAAQ;AAAA,IAAG;AAAA,EAClC;AAEA,SAAO,OAAO,OAAO;AAAA,IACnB;AAAA,IACA,gBAAgB,OAAO,QAAgB,aAAkD,MAAM,WAAW,QAAQ,OAAO,GAAG;AAAA,IAC5H;AAAA,IACA;AAAA,EACF,CAAC;AACH;;;ACveA,SAAS,UAAAA,eAAc;AAOvB,IAAM,oBAAoB;AAC1B,IAAM,6BAA6B,oBAAI,IAAI,CAAC,SAAS,QAAQ,eAAe,WAAW,YAAY,CAAC;AACpG,IAAM,gBAAgB,CAAC,QAAQ,iBAAiB,aAAa,iBAAiB,SAAS,cAAc,SAAS;AAC9G,IAAM,mBAAmB,oBAAI,IAAI,CAAC,aAAa,aAAa,aAAa,CAAC;AAC1E,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AACvB,IAAM,qBAAqB;AAO3B,IAAMC,kBAAqE;AAAA,EACzE,qBAAqB;AAAA,EACrB,2BAA2B;AAAA,EAC3B,uBAAuB;AACzB;AAGO,IAAM,iCAAN,cAA6C,MAAM;AAAA,EAC/C;AAAA,EAET,YAAY,MAA0C;AACpD,UAAMA,gBAAe,IAAI,CAAC;AAC1B,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AAuBA,SAAS,qBAAqB,MAAiD;AAC7E,QAAM,IAAI,+BAA+B,IAAI;AAC/C;AAEA,SAASC,UAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,aAAa,OAAgC,UAAsC;AAC1F,QAAM,SAAS,OAAO,KAAK,KAAK;AAChC,SAAO,OAAO,WAAW,SAAS,UAAU,OAAO,MAAM,CAAC,QAAQ,SAAS,SAAS,GAAG,CAAC;AAC1F;AAEA,SAAS,gBAAgB,OAAgB,aAA+C;AACtF,MAAI,OAAO,UAAU,YAAY,MAAM,WAAW,KAAK,CAAC,eAAe,KAAK,KAAK,EAAG,QAAO;AAC3F,QAAM,UAAUC,QAAO,KAAK,OAAO,QAAQ;AAC3C,MAAI,QAAQ,SAAS,KAAK,QAAQ,SAAS,QAAQ,QAAQ,SAAS,QAAQ,MAAM,MAAO,QAAO;AAChG,MAAI,gBAAgB,QAAQ,QAAQ,WAAW,YAAa,QAAO;AACnE,SAAO,WAAW,KAAK,OAAO;AAChC;AAEA,SAAS,oBAAoB,OAAoC;AAC/D,MAAI,CAACD,UAAS,KAAK,KAAK,CAAC,aAAa,OAAO,aAAa,KACrD,MAAM,SAAS,YACf,MAAM,kBAAkB,KACxB,MAAM,cAAc,iBACpB,OAAO,MAAM,kBAAkB,YAC/B,CAAC,eAAe,KAAK,MAAM,aAAa,KACxC,iBAAiB,IAAI,MAAM,aAAa,GAAG;AAC9C,WAAO,qBAAqB,uBAAuB;AAAA,EACrD;AAEA,QAAM,QAAQ,gBAAgB,MAAM,OAAO,EAAE;AAC7C,QAAM,aAAa,gBAAgB,MAAM,YAAY,IAAI;AACzD,QAAM,UAAU,gBAAgB,MAAM,SAAS,EAAE;AACjD,MAAI,CAAC,SAAS,CAAC,cAAc,CAAC,QAAS,QAAO,qBAAqB,uBAAuB;AAC1F,SAAO,EAAE,OAAO,MAAM,eAAe,OAAO,YAAY,QAAQ;AAClE;AAEA,SAAS,gBAAgB,OAAiC;AACxD,SAAO,OAAO,UAAU,YAAY,MAAM,UAAU,KAAK,MAAM,UAAU,QACpE,MAAM,KAAK,MAAM,SAAS,CAAC,mBAAmB,KAAK,KAAK;AAC/D;AAEA,SAAS,iBAAiB,OAAyC;AACjE,MAAI,CAACA,UAAS,KAAK,KAAK,CAAC,aAAa,OAAO,CAAC,UAAU,WAAW,CAAC,KAC/D,CAAC,gBAAgB,MAAM,MAAM,KAAK,CAAC,gBAAgB,MAAM,SAAS,GAAG;AACxE,WAAO,qBAAqB,uBAAuB;AAAA,EACrD;AACA,SAAO,OAAO,OAAO,EAAE,QAAQ,MAAM,QAAQ,WAAW,MAAM,UAAU,CAAC;AAC3E;AAMA,eAAsB,8BAA8B,OAId;AACpC,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,KACzD,OAAO,MAAM,gBAAgB,YAAY,CAAC,2BAA2B,IAAI,MAAM,WAAW,GAAG;AAChG,WAAO,qBAAqB,qBAAqB;AAAA,EACnD;AAEA,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,sBAAsB,WAAW;AAAA,MACxD,OAAO,EAAE,iBAAiB,EAAE,aAAa,MAAM,aAAa,KAAK,kBAAkB,EAAE;AAAA,MACrF,QAAQ,EAAE,aAAa,MAAM,KAAK,MAAM,SAAS,MAAM,OAAO,KAAK;AAAA,IACrE,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,qBAAqB,2BAA2B;AAAA,EACzD;AAEA,MAAI,CAAC,IAAK,QAAO,qBAAqB,2BAA2B;AACjE,MAAI,IAAI,gBAAgB,MAAM,eAAe,IAAI,QAAQ,qBACpD,CAAC,OAAO,cAAc,IAAI,OAAO,KAAK,IAAI,UAAU,KAAK,IAAI,UAAU,YAAe;AACzF,WAAO,qBAAqB,uBAAuB;AAAA,EACrD;AACA,MAAIA,UAAS,IAAI,KAAK,KAAK,aAAa,IAAI,OAAO,CAAC,QAAQ,eAAe,CAAC,KACvE,IAAI,MAAM,SAAS,cAAc,IAAI,MAAM,kBAAkB,GAAG;AACnE,WAAO,qBAAqB,2BAA2B;AAAA,EACzD;AAEA,MAAI;AACJ,MAAI;AACF,UAAM,WAAW,oBAAoB,IAAI,KAAK;AAC9C,UAAM,MAAM,KAAK,UAAU,CAAC,2BAA2B,MAAM,aAAa,mBAAmB,IAAI,SAAS,CAAC,CAAC;AAC5G,gBAAY,kBAAkB,EAAE,SAAS,MAAM,eAAe,UAAU,IAAI,CAAC;AAAA,EAC/E,SAAS,OAAO;AACd,QAAI,iBAAiB,+BAAgC,OAAM;AAC3D,WAAO,qBAAqB,uBAAuB;AAAA,EACrD;AAEA,MAAI;AACF,WAAO,iBAAiB,KAAK,MAAM,SAAS,CAAY;AAAA,EAC1D,SAAS,OAAO;AACd,QAAI,iBAAiB,+BAAgC,OAAM;AAC3D,WAAO,qBAAqB,uBAAuB;AAAA,EACrD;AACF;;;AFzHA,SAAS,8BAA8B,QAAgB,OAAe,QAAwB;AAC5F,MAAI,OAAO,UAAU,YAAY,MAAM,WAAW,GAAG;AACnD,UAAM,IAAI,MAAM,GAAG,MAAM,0CAA0C;AAAA,EACrE;AAEA,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,GAAG;AACrD,UAAM,IAAI,MAAM,GAAG,MAAM,2CAA2C;AAAA,EACtE;AAEA,QAAM,SAAS,WAAW,QAAQ,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,EAAE,EAAE,OAAO,KAAK;AAC7E,SAAO,GAAG,MAAM,IAAI,MAAM;AAC5B;AAMO,SAAS,0BAA0B,QAAgB,YAA4B;AACpF,SAAO,8BAA8B,WAAW,QAAQ,UAAU;AACpE;AAEO,SAAS,2BAA2B,QAAgB,eAA+B;AACxF,SAAO,8BAA8B,YAAY,QAAQ,aAAa;AACxE;AAEO,SAAS,wBAAwB,QAAgB,UAA0B;AAChF,SAAO,8BAA8B,iBAAiB,QAAQ,QAAQ;AACxE;AAEO,SAAS,oCACd,QACA,eACQ;AACR,SAAO,8BAA8B,oBAAoB,QAAQ,aAAa;AAChF;AAEO,SAAS,+BAA+B,OAKpC;AACT,MAAI,OAAO,MAAM,WAAW,YAAY,MAAM,OAAO,KAAK,EAAE,WAAW,GAAG;AACxE,UAAM,IAAI,MAAM,mEAAmE;AAAA,EACrF;AAEA,MAAI,MAAM,WAAW,oBAAoB;AACvC,QAAI,OAAO,MAAM,eAAe,YAAY,MAAM,WAAW,KAAK,EAAE,WAAW,GAAG;AAChF,YAAM,IAAI,MAAM,6EAA6E;AAAA,IAC/F;AACA,WAAO,8BAA8B,iBAAiB,MAAM,QAAQ,MAAM,UAAU;AAAA,EACtF;AAEA,MAAI,OAAO,MAAM,gBAAgB,YAAY,MAAM,YAAY,KAAK,EAAE,WAAW,GAAG;AAClF,UAAM,IAAI,MAAM,qFAAqF;AAAA,EACvG;AAEA,SAAO,8BAA8B,iBAAiB,GAAG,MAAM,MAAM,IAAI,MAAM,MAAM,IAAI,MAAM,WAAW;AAC5G;AAOO,SAAS,sCACd,OACQ;AACR,QAAM,MAAM,sCAAsC,MAAM,KAAK;AAC7D,QAAM,SAAS,WAAW,QAAQ,EAC/B,OAAO,KAAK,UAAU,CAAC,IAAI,QAAQ,IAAI,UAAU,CAAC,CAAC,EACnD,OAAO,KAAK;AACf,SAAO,iCAAiC,MAAM;AAChD;","names":["Buffer","ERROR_MESSAGES","isRecord","Buffer"]}
|