@feelflow/ffid-sdk 5.27.0 → 5.29.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/{chunk-JZB2IM7Y.js → chunk-4QQJMLL7.js} +40 -5
- package/dist/{chunk-R4KUHR4S.cjs → chunk-MESRDT7H.cjs} +41 -4
- package/dist/components/index.cjs +8 -8
- package/dist/components/index.d.cts +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +1 -1
- package/dist/{ffid-client-BqnzUmG7.d.ts → ffid-client-DCS-MoxK.d.ts} +53 -1
- package/dist/{ffid-client-BlVuH6ja.d.cts → ffid-client-hv2PuUr7.d.cts} +53 -1
- package/dist/{index-D3S_Pkkv.d.cts → index-_-MqJCN3.d.cts} +56 -2
- package/dist/{index-D3S_Pkkv.d.ts → index-_-MqJCN3.d.ts} +56 -2
- package/dist/index.cjs +64 -56
- package/dist/index.d.cts +28 -2
- package/dist/index.d.ts +28 -2
- package/dist/index.js +2 -2
- package/dist/server/index.cjs +189 -6
- package/dist/server/index.d.cts +180 -3
- package/dist/server/index.d.ts +180 -3
- package/dist/server/index.js +176 -7
- package/dist/server/test/index.d.cts +1 -1
- package/dist/server/test/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/server/index.cjs
CHANGED
|
@@ -851,6 +851,157 @@ var FFID_CATALOG_PUBLICATION_STATUSES = [
|
|
|
851
851
|
|
|
852
852
|
// src/shared/catalog-hash.ts
|
|
853
853
|
var CATALOG_HASH_PATTERN = /^[0-9a-f]{64}$/;
|
|
854
|
+
var HEX_RADIX = 16;
|
|
855
|
+
var HEX_DIGITS_PER_BYTE = 2;
|
|
856
|
+
var FFIDCatalogHashError = class extends Error {
|
|
857
|
+
constructor(message) {
|
|
858
|
+
super(message);
|
|
859
|
+
this.name = "FFIDCatalogHashError";
|
|
860
|
+
}
|
|
861
|
+
};
|
|
862
|
+
function isPlainObject(value) {
|
|
863
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
864
|
+
return false;
|
|
865
|
+
}
|
|
866
|
+
const proto = Object.getPrototypeOf(value);
|
|
867
|
+
return proto === Object.prototype || proto === null;
|
|
868
|
+
}
|
|
869
|
+
function canonicalize(value, path) {
|
|
870
|
+
if (value === null) return "null";
|
|
871
|
+
switch (typeof value) {
|
|
872
|
+
case "string":
|
|
873
|
+
return JSON.stringify(value);
|
|
874
|
+
case "boolean":
|
|
875
|
+
return value ? "true" : "false";
|
|
876
|
+
case "number":
|
|
877
|
+
if (!Number.isFinite(value)) {
|
|
878
|
+
throw new FFIDCatalogHashError(
|
|
879
|
+
`canonicalize: non-finite number at ${path} \u2014 hashes require finite numbers`
|
|
880
|
+
);
|
|
881
|
+
}
|
|
882
|
+
return JSON.stringify(value);
|
|
883
|
+
case "undefined":
|
|
884
|
+
throw new FFIDCatalogHashError(
|
|
885
|
+
`canonicalize: undefined at ${path} \u2014 omit the key entirely or use null`
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
if (Array.isArray(value)) {
|
|
889
|
+
const items = value.map((item, index) => canonicalize(item, `${path}[${index}]`));
|
|
890
|
+
return `[${items.join(",")}]`;
|
|
891
|
+
}
|
|
892
|
+
if (isPlainObject(value)) {
|
|
893
|
+
const keys = Object.keys(value).sort();
|
|
894
|
+
const entries = [];
|
|
895
|
+
for (const key of keys) {
|
|
896
|
+
const child = value[key];
|
|
897
|
+
if (child === void 0) {
|
|
898
|
+
throw new FFIDCatalogHashError(
|
|
899
|
+
`canonicalize: undefined at ${path}.${key} \u2014 omit the key entirely or use null`
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
entries.push(`${JSON.stringify(key)}:${canonicalize(child, `${path}.${key}`)}`);
|
|
903
|
+
}
|
|
904
|
+
return `{${entries.join(",")}}`;
|
|
905
|
+
}
|
|
906
|
+
throw new FFIDCatalogHashError(
|
|
907
|
+
`canonicalize: unsupported value type (${typeof value}${typeof value === "object" ? `: ${Object.prototype.toString.call(value)}` : ""}) at ${path} \u2014 only JSON-plain values are hashable`
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
function canonicalizeCatalogValue(value) {
|
|
911
|
+
return canonicalize(value, "$");
|
|
912
|
+
}
|
|
913
|
+
async function sha256Hex(text) {
|
|
914
|
+
const subtle = globalThis.crypto?.subtle;
|
|
915
|
+
if (!subtle) {
|
|
916
|
+
throw new FFIDCatalogHashError(
|
|
917
|
+
"sha256Hex: Web Crypto (crypto.subtle) is not available in this runtime"
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
const digest = await subtle.digest("SHA-256", new TextEncoder().encode(text));
|
|
921
|
+
return Array.from(new Uint8Array(digest)).map((byte) => byte.toString(HEX_RADIX).padStart(HEX_DIGITS_PER_BYTE, "0")).join("");
|
|
922
|
+
}
|
|
923
|
+
async function hashCanonicalJson(value) {
|
|
924
|
+
return sha256Hex(canonicalizeCatalogValue(value));
|
|
925
|
+
}
|
|
926
|
+
function assertHashFormat(hash, field) {
|
|
927
|
+
if (!CATALOG_HASH_PATTERN.test(hash)) {
|
|
928
|
+
throw new FFIDCatalogHashError(
|
|
929
|
+
`${field} must be lowercase SHA-256 hex (64 chars), got: ${JSON.stringify(hash)}`
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
function normalizeStringSet(values) {
|
|
934
|
+
return [...new Set(values)].sort();
|
|
935
|
+
}
|
|
936
|
+
function compareByCodeUnits(a, b) {
|
|
937
|
+
if (a.code < b.code) return -1;
|
|
938
|
+
if (a.code > b.code) return 1;
|
|
939
|
+
return 0;
|
|
940
|
+
}
|
|
941
|
+
async function computePraxisCopyHash(presentation) {
|
|
942
|
+
return hashCanonicalJson(presentation);
|
|
943
|
+
}
|
|
944
|
+
async function computeFFIDCheckoutCopyHash(checkoutCopy) {
|
|
945
|
+
return hashCanonicalJson(checkoutCopy);
|
|
946
|
+
}
|
|
947
|
+
async function computeLegalDisclosureHash(canonicalText) {
|
|
948
|
+
return sha256Hex(canonicalText.replace(/\r\n?/g, "\n"));
|
|
949
|
+
}
|
|
950
|
+
async function computeTaxConfigurationHash(config) {
|
|
951
|
+
return hashCanonicalJson({
|
|
952
|
+
allowedCountries: normalizeStringSet(config.allowedCountries),
|
|
953
|
+
stripeTaxRegistrations: normalizeStringSet(config.stripeTaxRegistrations),
|
|
954
|
+
billingAddressRequired: config.billingAddressRequired,
|
|
955
|
+
planTaxCodes: config.planTaxCodes,
|
|
956
|
+
planTaxBehaviors: config.planTaxBehaviors
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
async function computePaymentConfigurationHash(config) {
|
|
960
|
+
return hashCanonicalJson({
|
|
961
|
+
environment: config.environment,
|
|
962
|
+
currency: config.currency,
|
|
963
|
+
paymentMethodTypes: normalizeStringSet(config.paymentMethodTypes),
|
|
964
|
+
dynamicPaymentMethodsEnabled: config.dynamicPaymentMethodsEnabled,
|
|
965
|
+
manualInvoiceAllowed: config.manualInvoiceAllowed,
|
|
966
|
+
customerBalanceAllowed: config.customerBalanceAllowed,
|
|
967
|
+
delayedPaymentMethodsAllowed: config.delayedPaymentMethodsAllowed,
|
|
968
|
+
customerInvoiceBalanceRequired: config.customerInvoiceBalanceRequired
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
async function computeScopeHash(input) {
|
|
972
|
+
assertHashFormat(input.praxisCopyHash, "praxisCopyHash");
|
|
973
|
+
assertHashFormat(input.ffidCheckoutCopyHash, "ffidCheckoutCopyHash");
|
|
974
|
+
assertHashFormat(input.legalDisclosureHash, "legalDisclosureHash");
|
|
975
|
+
assertHashFormat(input.taxConfigurationHash, "taxConfigurationHash");
|
|
976
|
+
assertHashFormat(input.paymentConfigurationHash, "paymentConfigurationHash");
|
|
977
|
+
const seenCodes = /* @__PURE__ */ new Set();
|
|
978
|
+
for (const plan of input.plans) {
|
|
979
|
+
if (seenCodes.has(plan.code)) {
|
|
980
|
+
throw new FFIDCatalogHashError(
|
|
981
|
+
`computeScopeHash: duplicate plan code ${JSON.stringify(plan.code)}`
|
|
982
|
+
);
|
|
983
|
+
}
|
|
984
|
+
seenCodes.add(plan.code);
|
|
985
|
+
}
|
|
986
|
+
const plans = [...input.plans].sort(compareByCodeUnits).map((plan) => ({
|
|
987
|
+
code: plan.code,
|
|
988
|
+
priceMonthly: plan.priceMonthly,
|
|
989
|
+
priceYearly: plan.priceYearly,
|
|
990
|
+
currency: plan.currency,
|
|
991
|
+
// Set semantics — interval order must not flip the digest.
|
|
992
|
+
billingIntervals: normalizeStringSet(plan.billingIntervals),
|
|
993
|
+
taxBehavior: plan.taxBehavior,
|
|
994
|
+
minSeats: plan.minSeats
|
|
995
|
+
}));
|
|
996
|
+
return hashCanonicalJson({
|
|
997
|
+
plans,
|
|
998
|
+
praxisCopyHash: input.praxisCopyHash,
|
|
999
|
+
ffidCheckoutCopyHash: input.ffidCheckoutCopyHash,
|
|
1000
|
+
legalDisclosureHash: input.legalDisclosureHash,
|
|
1001
|
+
taxConfigurationHash: input.taxConfigurationHash,
|
|
1002
|
+
paymentConfigurationHash: input.paymentConfigurationHash
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
854
1005
|
|
|
855
1006
|
// src/client/catalog-methods.ts
|
|
856
1007
|
var EXT_CATALOG_ENDPOINT = "/api/v1/subscriptions/ext/catalog";
|
|
@@ -1133,6 +1284,7 @@ function createMembersMethods(deps) {
|
|
|
1133
1284
|
|
|
1134
1285
|
// src/client/provisioning-methods.ts
|
|
1135
1286
|
var USER_PROVISION_ENDPOINT = "/api/v1/ext/users/provision";
|
|
1287
|
+
var USER_WELCOME_EMAIL_ENDPOINT = "/api/v1/ext/users/welcome-email";
|
|
1136
1288
|
var ORGANIZATION_PROVISION_ENDPOINT = "/api/v1/ext/organizations/provision";
|
|
1137
1289
|
var MAX_PROVISION_MEMBERS = 100;
|
|
1138
1290
|
var ASSIGNABLE_MEMBER_ROLES = {
|
|
@@ -1149,7 +1301,7 @@ function createProvisioningMethods(deps) {
|
|
|
1149
1301
|
if (authMode === "service-key") return null;
|
|
1150
1302
|
return createError(
|
|
1151
1303
|
"VALIDATION_ERROR",
|
|
1152
|
-
"provisionUser / provisionOrganization \u306F service-key \u8A8D\u8A3C\uFF08X-Service-Api-Key\uFF09\u3067\u306E\u307F\u5229\u7528\u3067\u304D\u307E\u3059\u3002Bearer / cookie \u30E2\u30FC\u30C9\u3067\u306F\u547C\u3073\u51FA\u305B\u307E\u305B\u3093"
|
|
1304
|
+
"provisionUser / sendProvisionWelcomeEmail / provisionOrganization \u306F service-key \u8A8D\u8A3C\uFF08X-Service-Api-Key\uFF09\u3067\u306E\u307F\u5229\u7528\u3067\u304D\u307E\u3059\u3002Bearer / cookie \u30E2\u30FC\u30C9\u3067\u306F\u547C\u3073\u51FA\u305B\u307E\u305B\u3093"
|
|
1153
1305
|
);
|
|
1154
1306
|
}
|
|
1155
1307
|
async function provisionUser(params) {
|
|
@@ -1166,6 +1318,17 @@ function createProvisioningMethods(deps) {
|
|
|
1166
1318
|
body: JSON.stringify(body)
|
|
1167
1319
|
});
|
|
1168
1320
|
}
|
|
1321
|
+
async function sendProvisionWelcomeEmail(params) {
|
|
1322
|
+
const modeError = serviceKeyModeError();
|
|
1323
|
+
if (modeError) return { error: modeError };
|
|
1324
|
+
if (!params.email || !params.email.trim()) {
|
|
1325
|
+
return { error: createError("VALIDATION_ERROR", "email \u306F\u5FC5\u9808\u3067\u3059") };
|
|
1326
|
+
}
|
|
1327
|
+
return fetchWithAuth(USER_WELCOME_EMAIL_ENDPOINT, {
|
|
1328
|
+
method: "POST",
|
|
1329
|
+
body: JSON.stringify({ email: params.email.trim() })
|
|
1330
|
+
});
|
|
1331
|
+
}
|
|
1169
1332
|
async function provisionOrganization(params) {
|
|
1170
1333
|
const modeError = serviceKeyModeError();
|
|
1171
1334
|
if (modeError) return { error: modeError };
|
|
@@ -1215,7 +1378,7 @@ function createProvisioningMethods(deps) {
|
|
|
1215
1378
|
body: JSON.stringify(body)
|
|
1216
1379
|
});
|
|
1217
1380
|
}
|
|
1218
|
-
return { provisionUser, provisionOrganization };
|
|
1381
|
+
return { provisionUser, sendProvisionWelcomeEmail, provisionOrganization };
|
|
1219
1382
|
}
|
|
1220
1383
|
|
|
1221
1384
|
// src/client/seat-methods.ts
|
|
@@ -1489,7 +1652,7 @@ function validateTokenResponse(tokenResponse) {
|
|
|
1489
1652
|
}
|
|
1490
1653
|
|
|
1491
1654
|
// src/client/version-check.ts
|
|
1492
|
-
var SDK_VERSION = "5.
|
|
1655
|
+
var SDK_VERSION = "5.29.0";
|
|
1493
1656
|
var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
|
|
1494
1657
|
var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
|
|
1495
1658
|
function sdkHeaders() {
|
|
@@ -2901,6 +3064,11 @@ function createInquiryMethods(deps) {
|
|
|
2901
3064
|
name,
|
|
2902
3065
|
message,
|
|
2903
3066
|
category: params.category,
|
|
3067
|
+
// Normalize null ("survey not collected", e.g. forwarded verbatim
|
|
3068
|
+
// from FFIDInquiryFormSubmitData) to undefined so JSON.stringify
|
|
3069
|
+
// drops the key entirely — older FFID deployments never see it and
|
|
3070
|
+
// current ones treat the omission as NULL.
|
|
3071
|
+
acquisitionSource: params.acquisitionSource ?? void 0,
|
|
2904
3072
|
company: params.company,
|
|
2905
3073
|
phone: params.phone,
|
|
2906
3074
|
locale: params.locale,
|
|
@@ -3360,7 +3528,7 @@ function createFFIDClient(config) {
|
|
|
3360
3528
|
createError,
|
|
3361
3529
|
serviceCode: config.serviceCode
|
|
3362
3530
|
});
|
|
3363
|
-
const { provisionUser, provisionOrganization } = createProvisioningMethods({
|
|
3531
|
+
const { provisionUser, sendProvisionWelcomeEmail, provisionOrganization } = createProvisioningMethods({
|
|
3364
3532
|
fetchWithAuth,
|
|
3365
3533
|
createError,
|
|
3366
3534
|
authMode
|
|
@@ -3461,6 +3629,7 @@ function createFFIDClient(config) {
|
|
|
3461
3629
|
updateMemberRole,
|
|
3462
3630
|
removeMember,
|
|
3463
3631
|
provisionUser,
|
|
3632
|
+
sendProvisionWelcomeEmail,
|
|
3464
3633
|
provisionOrganization,
|
|
3465
3634
|
getProfile,
|
|
3466
3635
|
updateProfile,
|
|
@@ -3662,11 +3831,11 @@ function getFFIDConsentFromCookieHeader(cookieHeader) {
|
|
|
3662
3831
|
|
|
3663
3832
|
// src/server/auth/server-state.ts
|
|
3664
3833
|
var STATE_RANDOM_BYTES2 = 16;
|
|
3665
|
-
var
|
|
3834
|
+
var HEX_RADIX2 = 16;
|
|
3666
3835
|
function generateServerState() {
|
|
3667
3836
|
const bytes = new Uint8Array(STATE_RANDOM_BYTES2);
|
|
3668
3837
|
globalThis.crypto.getRandomValues(bytes);
|
|
3669
|
-
return Array.from(bytes, (b) => b.toString(
|
|
3838
|
+
return Array.from(bytes, (b) => b.toString(HEX_RADIX2).padStart(2, "0")).join("");
|
|
3670
3839
|
}
|
|
3671
3840
|
|
|
3672
3841
|
// src/server/auth/server-oauth-token.ts
|
|
@@ -3925,10 +4094,21 @@ Object.defineProperty(exports, "DEFAULT_OAUTH_SCOPES", {
|
|
|
3925
4094
|
get: function () { return chunkMDHKSVLP_cjs.DEFAULT_OAUTH_SCOPES; }
|
|
3926
4095
|
});
|
|
3927
4096
|
exports.ALL_DENIED_EXCEPT_NECESSARY = ALL_DENIED_EXCEPT_NECESSARY;
|
|
4097
|
+
exports.CATALOG_HASH_PATTERN = CATALOG_HASH_PATTERN;
|
|
3928
4098
|
exports.CONSENT_COOKIE_NAME = CONSENT_COOKIE_NAME;
|
|
3929
4099
|
exports.COOKIE_VERSION = COOKIE_VERSION;
|
|
4100
|
+
exports.FFIDCatalogHashError = FFIDCatalogHashError;
|
|
4101
|
+
exports.FFID_CATALOG_ENVIRONMENTS = FFID_CATALOG_ENVIRONMENTS;
|
|
4102
|
+
exports.FFID_CATALOG_PUBLICATION_STATUSES = FFID_CATALOG_PUBLICATION_STATUSES;
|
|
3930
4103
|
exports.FFID_ERROR_CODES = FFID_ERROR_CODES;
|
|
3931
4104
|
exports.FFID_SESSION_COOKIE_NAME = FFID_SESSION_COOKIE_NAME;
|
|
4105
|
+
exports.canonicalizeCatalogValue = canonicalizeCatalogValue;
|
|
4106
|
+
exports.computeFFIDCheckoutCopyHash = computeFFIDCheckoutCopyHash;
|
|
4107
|
+
exports.computeLegalDisclosureHash = computeLegalDisclosureHash;
|
|
4108
|
+
exports.computePaymentConfigurationHash = computePaymentConfigurationHash;
|
|
4109
|
+
exports.computePraxisCopyHash = computePraxisCopyHash;
|
|
4110
|
+
exports.computeScopeHash = computeScopeHash;
|
|
4111
|
+
exports.computeTaxConfigurationHash = computeTaxConfigurationHash;
|
|
3932
4112
|
exports.createFFIDClient = createFFIDClient;
|
|
3933
4113
|
exports.createKVCacheAdapter = createKVCacheAdapter;
|
|
3934
4114
|
exports.createMemoryCacheAdapter = createMemoryCacheAdapter;
|
|
@@ -3940,4 +4120,7 @@ exports.encodeConsentCookie = encodeConsentCookie;
|
|
|
3940
4120
|
exports.generateServerState = generateServerState;
|
|
3941
4121
|
exports.getFFIDConsentFromCookieHeader = getFFIDConsentFromCookieHeader;
|
|
3942
4122
|
exports.getFFIDConsentFromCookies = getFFIDConsentFromCookies;
|
|
4123
|
+
exports.hashCanonicalJson = hashCanonicalJson;
|
|
3943
4124
|
exports.sessionCookies = sessionCookies;
|
|
4125
|
+
exports.sha256Hex = sha256Hex;
|
|
4126
|
+
exports.validatePublishedCatalog = validatePublishedCatalog;
|
package/dist/server/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as FFIDLogger, a as FFIDError, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo } from '../ffid-client-
|
|
2
|
-
export {
|
|
1
|
+
import { F as FFIDLogger, a as FFIDError, b as FFIDCacheAdapter, c as FFIDVerifyAccessTokenOptions, d as FFIDApiResponse, e as FFIDOAuthUserInfo, f as FFIDCatalogEnvironment, g as FFIDBillingInterval, h as FFIDTaxBehavior, i as FFIDPublishedCatalog } from '../ffid-client-hv2PuUr7.cjs';
|
|
2
|
+
export { j as FFIDAddMemberParams, k as FFIDAddMemberRequest, l as FFIDAddMemberResponse, m as FFIDAssignableMemberRole, n as FFIDCacheConfig, o as FFIDCatalogPublication, p as FFIDCatalogPublicationStatus, q as FFIDClient, r as FFIDConfig, s as FFIDListMembersResponse, t as FFIDMemberRole, u as FFIDOrganization, v as FFIDOrganizationMember, w as FFIDOtpSendResponse, x as FFIDOtpVerifyResponse, y as FFIDPasswordResetConfirmResponse, z as FFIDPasswordResetResponse, A as FFIDPasswordResetVerifyResponse, B as FFIDProfileCallOptions, C as FFIDProvisionMemberPlan, D as FFIDProvisionMemberPlanStatus, E as FFIDProvisionMemberResult, G as FFIDProvisionMemberStatus, H as FFIDProvisionOrganizationDryRun, I as FFIDProvisionOrganizationMemberInput, J as FFIDProvisionOrganizationOutcome, K as FFIDProvisionOrganizationParams, L as FFIDProvisionOrganizationResponse, M as FFIDProvisionUserDryRun, N as FFIDProvisionUserOutcome, O as FFIDProvisionUserParams, P as FFIDProvisionUserProfileInput, Q as FFIDProvisionUserResponse, R as FFIDProvisionedOrganization, S as FFIDProvisionedUser, T as FFIDPublishedPlan, U as FFIDRemoveMemberResponse, V as FFIDResetSessionResponse, W as FFIDSubscription, X as FFIDUpdateMemberRoleResponse, Y as FFIDUpdateUserProfileRequest, Z as FFIDUser, _ as FFIDUserProfile, $ as FFID_CATALOG_ENVIRONMENTS, a0 as FFID_CATALOG_PUBLICATION_STATUSES, a1 as TokenData, a2 as TokenStore, a3 as createFFIDClient, a4 as createTokenStore } from '../ffid-client-hv2PuUr7.cjs';
|
|
3
3
|
export { D as DEFAULT_API_BASE_URL, a as DEFAULT_OAUTH_SCOPES } from '../constants-D61jqRIO.cjs';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import '../types-Cjb9J0rL.cjs';
|
|
@@ -389,4 +389,181 @@ declare const sessionCookies: {
|
|
|
389
389
|
*/
|
|
390
390
|
declare function generateServerState(): string;
|
|
391
391
|
|
|
392
|
-
|
|
392
|
+
/**
|
|
393
|
+
* Catalog approval hash helpers (#4342 / ASDD-PRICING-002 SP4A)
|
|
394
|
+
*
|
|
395
|
+
* Shared canonicalization + SHA-256 helpers that FIX the cross-repo hash
|
|
396
|
+
* contract between FFID (publisher) and consumers (Praxis). Both sides compute
|
|
397
|
+
* hashes with these helpers and refuse new sales on any mismatch, so the
|
|
398
|
+
* canonical form below is a compatibility contract:
|
|
399
|
+
*
|
|
400
|
+
* 1. Objects serialize with keys sorted by UTF-16 code unit order,
|
|
401
|
+
* recursively. Arrays keep their element order.
|
|
402
|
+
* 2. Serialization is `JSON.stringify`-compatible per token (string
|
|
403
|
+
* escaping, number formatting) with NO whitespace.
|
|
404
|
+
* 3. `undefined`, non-finite numbers (NaN/±Infinity), functions, symbols,
|
|
405
|
+
* bigints and non-plain objects (Date, Map, class instances) are
|
|
406
|
+
* REJECTED with FFIDCatalogHashError — never silently dropped, because a
|
|
407
|
+
* dropped key would let two semantically different payloads collide.
|
|
408
|
+
* Only own enumerable string-keyed properties participate; symbol-keyed
|
|
409
|
+
* properties are ignored (same as `JSON.stringify`).
|
|
410
|
+
* 4. The hash is lowercase SHA-256 hex over the UTF-8 bytes of the
|
|
411
|
+
* canonical string (no domain-separation prefix).
|
|
412
|
+
*
|
|
413
|
+
* Changing ANY of these rules is a breaking change to published catalog
|
|
414
|
+
* verification and requires re-publishing catalogs — the fixed test vectors
|
|
415
|
+
* in `__tests__/catalog-hash.test.ts` exist to make such a change loud.
|
|
416
|
+
*/
|
|
417
|
+
|
|
418
|
+
/** Lowercase SHA-256 hex format shared by all catalog approval hashes */
|
|
419
|
+
declare const CATALOG_HASH_PATTERN: RegExp;
|
|
420
|
+
/**
|
|
421
|
+
* Thrown when a value cannot be canonicalized (or an embedded hash is
|
|
422
|
+
* malformed). Always indicates a programming error on the hashing side —
|
|
423
|
+
* never caused by end-user input.
|
|
424
|
+
*/
|
|
425
|
+
declare class FFIDCatalogHashError extends Error {
|
|
426
|
+
constructor(message: string);
|
|
427
|
+
}
|
|
428
|
+
/** JSON value accepted by the canonicalizer */
|
|
429
|
+
type FFIDCanonicalJsonValue = string | number | boolean | null | FFIDCanonicalJsonValue[] | {
|
|
430
|
+
[key: string]: FFIDCanonicalJsonValue;
|
|
431
|
+
};
|
|
432
|
+
/**
|
|
433
|
+
* Serializes a JSON-plain value into its canonical string form (see module
|
|
434
|
+
* doc for the exact rules). Exposed so both sides can debug hash mismatches
|
|
435
|
+
* by diffing canonical strings instead of opaque digests.
|
|
436
|
+
*/
|
|
437
|
+
declare function canonicalizeCatalogValue(value: FFIDCanonicalJsonValue): string;
|
|
438
|
+
/**
|
|
439
|
+
* Lowercase SHA-256 hex of the UTF-8 bytes of `text`.
|
|
440
|
+
*
|
|
441
|
+
* Requires Web Crypto (`globalThis.crypto.subtle`) — available by default in
|
|
442
|
+
* Node.js >= 19 (Node 18 needs `--experimental-global-webcrypto`), browsers,
|
|
443
|
+
* and edge runtimes. Throws instead of falling back to a weaker digest so a
|
|
444
|
+
* missing crypto implementation can never silently change the contract.
|
|
445
|
+
*/
|
|
446
|
+
declare function sha256Hex(text: string): Promise<string>;
|
|
447
|
+
/** Canonicalizes `value` and returns its lowercase SHA-256 hex digest. */
|
|
448
|
+
declare function hashCanonicalJson(value: FFIDCanonicalJsonValue): Promise<string>;
|
|
449
|
+
/**
|
|
450
|
+
* Human-approved tax configuration snapshot hashed into
|
|
451
|
+
* `publication.taxConfigurationHash`. FFID re-computes this from its live
|
|
452
|
+
* Stripe Tax settings at paid-checkout start and refuses the session on
|
|
453
|
+
* mismatch.
|
|
454
|
+
*/
|
|
455
|
+
interface FFIDTaxConfiguration {
|
|
456
|
+
/** ISO 3166-1 alpha-2 country/region codes where paid sales are allowed */
|
|
457
|
+
allowedCountries: string[];
|
|
458
|
+
/** Country/region codes with completed Stripe Tax registrations */
|
|
459
|
+
stripeTaxRegistrations: string[];
|
|
460
|
+
/** Whether full billing address collection is required before paid checkout */
|
|
461
|
+
billingAddressRequired: boolean;
|
|
462
|
+
/** Stripe Product tax code per plan code (e.g. `txcd_10000000`) */
|
|
463
|
+
planTaxCodes: Record<string, string>;
|
|
464
|
+
/** Tax behavior per plan code */
|
|
465
|
+
planTaxBehaviors: Record<string, FFIDTaxBehavior>;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Human-approved payment configuration snapshot hashed into
|
|
469
|
+
* `publication.paymentConfigurationHash`.
|
|
470
|
+
*/
|
|
471
|
+
interface FFIDPaymentConfiguration {
|
|
472
|
+
environment: FFIDCatalogEnvironment;
|
|
473
|
+
/** Lowercase ISO 4217 currency (e.g. `jpy`) */
|
|
474
|
+
currency: string;
|
|
475
|
+
/** Explicit Stripe payment method allow-list (initial sales: `['card']`) */
|
|
476
|
+
paymentMethodTypes: string[];
|
|
477
|
+
/** Stripe Dashboard dynamic payment methods must stay disabled for sales */
|
|
478
|
+
dynamicPaymentMethodsEnabled: boolean;
|
|
479
|
+
manualInvoiceAllowed: boolean;
|
|
480
|
+
customerBalanceAllowed: boolean;
|
|
481
|
+
delayedPaymentMethodsAllowed: boolean;
|
|
482
|
+
/** Required Stripe Customer invoice credit balance before checkout (spec: 0) */
|
|
483
|
+
customerInvoiceBalanceRequired: number;
|
|
484
|
+
}
|
|
485
|
+
/** Sales-scope-relevant snapshot of one published plan (subset of the catalog) */
|
|
486
|
+
interface FFIDScopeHashPlan {
|
|
487
|
+
code: string;
|
|
488
|
+
priceMonthly: number | null;
|
|
489
|
+
priceYearly: number | null;
|
|
490
|
+
currency: string;
|
|
491
|
+
billingIntervals: FFIDBillingInterval[];
|
|
492
|
+
taxBehavior: FFIDTaxBehavior;
|
|
493
|
+
minSeats: number;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Input of `computeScopeHash` — the published plans' sales conditions plus
|
|
497
|
+
* the five content/config hashes. Changing any of them changes `scopeHash`,
|
|
498
|
+
* which invalidates the previous publication approval (fail-closed).
|
|
499
|
+
*/
|
|
500
|
+
interface FFIDScopeHashInput {
|
|
501
|
+
plans: FFIDScopeHashPlan[];
|
|
502
|
+
praxisCopyHash: string;
|
|
503
|
+
ffidCheckoutCopyHash: string;
|
|
504
|
+
legalDisclosureHash: string;
|
|
505
|
+
taxConfigurationHash: string;
|
|
506
|
+
paymentConfigurationHash: string;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* `praxisCopyHash`: hash of the consumer's entire structured sales
|
|
510
|
+
* presentation (`PRAXIS_SALES_PRESENTATION` — locales, plan display names,
|
|
511
|
+
* prices, feature matrix, CTAs, eligibility). The consumer re-hashes what it
|
|
512
|
+
* actually renders and must refuse new sales on mismatch.
|
|
513
|
+
*/
|
|
514
|
+
declare function computePraxisCopyHash(presentation: Record<string, FFIDCanonicalJsonValue>): Promise<string>;
|
|
515
|
+
/** `ffidCheckoutCopyHash`: hash of FFID's structured final-confirmation copy */
|
|
516
|
+
declare function computeFFIDCheckoutCopyHash(checkoutCopy: Record<string, FFIDCanonicalJsonValue>): Promise<string>;
|
|
517
|
+
/**
|
|
518
|
+
* `legalDisclosureHash`: hash of the canonical body text of the reviewed
|
|
519
|
+
* legal disclosure document version. Line endings are normalized to LF before
|
|
520
|
+
* hashing so the digest is independent of platform line-ending conventions;
|
|
521
|
+
* the text is otherwise hashed byte-exact (no trimming, no Unicode
|
|
522
|
+
* normalization).
|
|
523
|
+
*/
|
|
524
|
+
declare function computeLegalDisclosureHash(canonicalText: string): Promise<string>;
|
|
525
|
+
/**
|
|
526
|
+
* `taxConfigurationHash`: hash of the human-approved tax configuration.
|
|
527
|
+
* Country lists are treated as sets (sorted + deduplicated) so representation
|
|
528
|
+
* order cannot flip the digest.
|
|
529
|
+
*/
|
|
530
|
+
declare function computeTaxConfigurationHash(config: FFIDTaxConfiguration): Promise<string>;
|
|
531
|
+
/**
|
|
532
|
+
* `paymentConfigurationHash`: hash of the human-approved payment
|
|
533
|
+
* configuration. `paymentMethodTypes` is treated as a set.
|
|
534
|
+
*/
|
|
535
|
+
declare function computePaymentConfigurationHash(config: FFIDPaymentConfiguration): Promise<string>;
|
|
536
|
+
/**
|
|
537
|
+
* `scopeHash`: hash of the published sales scope — plan codes, amounts,
|
|
538
|
+
* currency, intervals, tax behavior, minimum seats, plus the five embedded
|
|
539
|
+
* content/config hashes. Plans are sorted by `code`; duplicate codes are
|
|
540
|
+
* rejected. Embedded hashes are validated for format so a malformed digest
|
|
541
|
+
* can never be baked into an approval.
|
|
542
|
+
*/
|
|
543
|
+
declare function computeScopeHash(input: FFIDScopeHashInput): Promise<string>;
|
|
544
|
+
|
|
545
|
+
/** Published catalog methods (#4342 / ASDD-PRICING-002 SP4A) */
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Validates the full published-catalog shape the SDK's compile-time types
|
|
549
|
+
* promise to consumers:
|
|
550
|
+
* - `service.code` / `service.name` are non-empty strings
|
|
551
|
+
* - top-level `catalogVersion` equals `publication.catalogVersion`
|
|
552
|
+
* - `publication.status` is one of the four known literals (unknown statuses
|
|
553
|
+
* must fail loud here, NOT be treated as sellable downstream) and
|
|
554
|
+
* `publication.environment` is a known environment
|
|
555
|
+
* - the six approval hashes are lowercase SHA-256 hex; `salesEpoch` is a
|
|
556
|
+
* positive integer; timestamps are present (or explicitly null where the
|
|
557
|
+
* type allows null)
|
|
558
|
+
* - every plan carries the full `FFIDPublishedPlan` field set with
|
|
559
|
+
* cross-field invariants (an offered interval has its price;
|
|
560
|
+
* `minSeats <= maxSeats`), and no plan field NAME mentions Stripe
|
|
561
|
+
* (defense-in-depth heuristic — the authoritative no-Stripe-ID guard is
|
|
562
|
+
* the FFID server's `.strict()` snapshot schema)
|
|
563
|
+
*
|
|
564
|
+
* Throws FFIDSDKError on violation so a server regression surfaces at the
|
|
565
|
+
* SDK boundary instead of silently reaching a consumer's sales gate.
|
|
566
|
+
*/
|
|
567
|
+
declare function validatePublishedCatalog(catalog: unknown): asserts catalog is FFIDPublishedCatalog;
|
|
568
|
+
|
|
569
|
+
export { ALL_DENIED_EXCEPT_NECESSARY, type BuildAuthorizeUrlOptions, type BuildAuthorizeUrlResult, CATALOG_HASH_PATTERN, CONSENT_COOKIE_NAME, COOKIE_VERSION, type CookieOptions, FFIDCacheAdapter, type FFIDCanonicalJsonValue, FFIDCatalogEnvironment, FFIDCatalogHashError, type FFIDConsentCategories, type FFIDConsentCategoryCode, type FFIDCookieStoreLike, type FFIDErrorCode, FFIDOAuthUserInfo, type FFIDPaymentConfiguration, FFIDPublishedCatalog, type FFIDScopeHashInput, type FFIDScopeHashPlan, FFIDTaxBehavior, type FFIDTaxConfiguration, FFIDVerifyAccessTokenOptions, FFID_ERROR_CODES, FFID_SESSION_COOKIE_NAME, type HandleCallbackInput, type KVNamespaceLike, type ServerAuthClient, type ServerAuthConfig, type ServerSessionTokens, type ServerTokenResult, canonicalizeCatalogValue, computeFFIDCheckoutCopyHash, computeLegalDisclosureHash, computePaymentConfigurationHash, computePraxisCopyHash, computeScopeHash, computeTaxConfigurationHash, createKVCacheAdapter, createMemoryCacheAdapter, createServerAuthClient, createVerifyAccessToken, decodeConsentCookie, encodeConsentCookie, generateServerState, getFFIDConsentFromCookieHeader, getFFIDConsentFromCookies, hashCanonicalJson, sessionCookies, sha256Hex, validatePublishedCatalog };
|