@feelflow/ffid-sdk 8.1.0 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +1010 -960
  2. package/dist/{FFIDCookieLink-Bwr0FBrV.d.cts → FFIDCookieLink-yt5SUr-W.d.cts} +47 -3
  3. package/dist/{FFIDCookieLink-Bwr0FBrV.d.ts → FFIDCookieLink-yt5SUr-W.d.ts} +47 -3
  4. package/dist/{chunk-CPXTIRB6.cjs → chunk-2LU2F3F2.cjs} +283 -11
  5. package/dist/{chunk-P5A6C5SK.js → chunk-OXW6QSTO.js} +270 -12
  6. package/dist/{chunk-XELXXL2F.cjs → chunk-RZCQ22GH.cjs} +29 -9
  7. package/dist/{chunk-RHBZHSRD.js → chunk-S2AEBJRX.js} +29 -9
  8. package/dist/components/index.cjs +8 -8
  9. package/dist/components/index.d.cts +1 -1
  10. package/dist/components/index.d.ts +1 -1
  11. package/dist/components/index.js +1 -1
  12. package/dist/consent/index.cjs +63 -63
  13. package/dist/consent/index.d.cts +2 -2
  14. package/dist/consent/index.d.ts +2 -2
  15. package/dist/consent/index.js +1 -1
  16. package/dist/{ffid-client-B0cORHac.d.ts → ffid-client-5uxXRgIO.d.ts} +686 -376
  17. package/dist/{ffid-client-6aLs9Fqc.d.cts → ffid-client-CumygXXz.d.cts} +686 -376
  18. package/dist/{index-BG7g99pK.d.ts → index-KjewcNn1.d.cts} +813 -2
  19. package/dist/{index-BG7g99pK.d.cts → index-KjewcNn1.d.ts} +813 -2
  20. package/dist/index.cjs +151 -95
  21. package/dist/index.d.cts +116 -505
  22. package/dist/index.d.ts +116 -505
  23. package/dist/index.js +3 -3
  24. package/dist/server/index.cjs +253 -11
  25. package/dist/server/index.d.cts +2 -2
  26. package/dist/server/index.d.ts +2 -2
  27. package/dist/server/index.js +253 -11
  28. package/dist/server/test/index.d.cts +1 -1
  29. package/dist/server/test/index.d.ts +1 -1
  30. package/dist/webhooks/index.d.cts +112 -7
  31. package/dist/webhooks/index.d.ts +112 -7
  32. package/package.json +131 -131
@@ -222,18 +222,16 @@ function mapUserinfoSubscriptionToSession(userinfo, serviceCode) {
222
222
  ];
223
223
  }
224
224
  var JWKS_ENDPOINT = "/.well-known/jwks.json";
225
- var LEGACY_JWT_ISSUER = "https://id.feelflow.net";
226
225
  var JWT_ALGORITHM = "ES256";
227
226
  var JWT_CLOCK_TOLERANCE_SECONDS = 30;
228
- function resolveAcceptedIssuers(baseUrl) {
229
- const deployedOrigin = new URL(baseUrl).origin;
230
- return deployedOrigin === LEGACY_JWT_ISSUER ? [LEGACY_JWT_ISSUER] : [deployedOrigin, LEGACY_JWT_ISSUER];
227
+ function resolveAcceptedIssuer(baseUrl) {
228
+ return new URL(baseUrl).origin;
231
229
  }
232
230
  function createJwtVerifier(deps) {
233
231
  const { baseUrl, serviceCode, logger, createError, errorCodes } = deps;
234
232
  const jwksUrl = new URL(JWKS_ENDPOINT, baseUrl);
235
233
  const jwks = createRemoteJWKSet(jwksUrl);
236
- const acceptedIssuers = resolveAcceptedIssuers(baseUrl);
234
+ const acceptedIssuer = resolveAcceptedIssuer(baseUrl);
237
235
  async function verifyJwt(accessToken) {
238
236
  if (!accessToken || !accessToken.trim()) {
239
237
  return {
@@ -246,7 +244,7 @@ function createJwtVerifier(deps) {
246
244
  try {
247
245
  const { payload } = await jwtVerify(accessToken, jwks, {
248
246
  algorithms: [JWT_ALGORITHM],
249
- issuer: acceptedIssuers,
247
+ issuer: acceptedIssuer,
250
248
  audience: serviceCode,
251
249
  clockTolerance: JWT_CLOCK_TOLERANCE_SECONDS
252
250
  });
@@ -1372,7 +1370,7 @@ var FFID_ORGANIZATION_PROFILE_ERROR_CODES = {
1372
1370
  };
1373
1371
 
1374
1372
  // src/client/version-check.ts
1375
- var SDK_VERSION = "8.1.0";
1373
+ var SDK_VERSION = "10.0.0";
1376
1374
  var SDK_USER_AGENT = `FFID-SDK/${SDK_VERSION} (TypeScript)`;
1377
1375
  var SDK_VERSION_HEADER = "X-FFID-SDK-Version";
1378
1376
  function sdkHeaders() {
@@ -1728,8 +1726,11 @@ function createProvisioningMethods(deps) {
1728
1726
  }
1729
1727
 
1730
1728
  // src/client/seat-methods.ts
1729
+ function seatSummaryEndpoint(subscriptionId) {
1730
+ return `/api/v1/subscriptions/ext/${encodeURIComponent(subscriptionId)}/seats`;
1731
+ }
1731
1732
  function seatsEndpoint(subscriptionId) {
1732
- return `/api/v1/subscriptions/ext/${encodeURIComponent(subscriptionId)}/seats/assignments`;
1733
+ return `${seatSummaryEndpoint(subscriptionId)}/assignments`;
1733
1734
  }
1734
1735
  function createSeatMethods(deps) {
1735
1736
  const { fetchWithAuth, createError } = deps;
@@ -1739,6 +1740,12 @@ function createSeatMethods(deps) {
1739
1740
  }
1740
1741
  return fetchWithAuth(seatsEndpoint(params.subscriptionId));
1741
1742
  }
1743
+ async function getSeats(subscriptionId) {
1744
+ if (!subscriptionId || !subscriptionId.trim()) {
1745
+ return { error: createError("VALIDATION_ERROR", "subscriptionId \u306F\u5FC5\u9808\u3067\u3059") };
1746
+ }
1747
+ return fetchWithAuth(seatSummaryEndpoint(subscriptionId));
1748
+ }
1742
1749
  async function assignSeats(params) {
1743
1750
  if (!params.subscriptionId) {
1744
1751
  return { error: createError("VALIDATION_ERROR", "subscriptionId \u306F\u5FC5\u9808\u3067\u3059") };
@@ -1763,7 +1770,7 @@ function createSeatMethods(deps) {
1763
1770
  { method: "DELETE" }
1764
1771
  );
1765
1772
  }
1766
- return { listSeatAssignments, assignSeats, unassignSeat };
1773
+ return { listSeatAssignments, getSeats, assignSeats, unassignSeat };
1767
1774
  }
1768
1775
 
1769
1776
  // src/client/profile-methods.ts
@@ -3490,6 +3497,222 @@ function createInquiryMethods(deps) {
3490
3497
  return { create };
3491
3498
  }
3492
3499
 
3500
+ // src/types/credits.ts
3501
+ var FFID_CREDITS_CONSUME_MIN_AMOUNT = 1;
3502
+ var FFID_CREDITS_CONSUME_MAX_AMOUNT = 1e6;
3503
+ var FFID_CREDITS_METADATA_MAX_BYTES = 4096;
3504
+ var FFID_CREDITS_HISTORY_MIN_LIMIT = 1;
3505
+ var FFID_CREDITS_HISTORY_MAX_LIMIT = 100;
3506
+ var FFID_CREDIT_PACK_MIN_QUANTITY = 1;
3507
+ var FFID_CREDIT_PACK_MAX_QUANTITY = 10;
3508
+ var FFID_CREDITS_IDEMPOTENCY_KEY_PATTERN = /^[A-Za-z0-9._:-]{8,128}$/;
3509
+ var FFID_CREDITS_FEATURE_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/;
3510
+ var FFID_CREDIT_HISTORY_TYPES = ["grant", "consumption", "revocation"];
3511
+
3512
+ // src/client/credits-methods.ts
3513
+ var EXT_SUBSCRIPTIONS_PATH = "/api/v1/subscriptions/ext";
3514
+ var CREDIT_PACKS_ENDPOINT = `${EXT_SUBSCRIPTIONS_PATH}/credits/packs`;
3515
+ var CREDIT_PACK_CHECKOUT_ENDPOINT = `${CREDIT_PACKS_ENDPOINT}/checkout`;
3516
+ var PORTAL_SUBSCRIPTION_PATH = "/subscriptions";
3517
+ var BUY_CREDITS_QUERY = { key: "purchase", value: "credits" };
3518
+ var ORG_QUERY_KEY = "org";
3519
+ var FFID_CONTRACT_ID_PREFIX = "ffid:";
3520
+ var STRIPE_SUBSCRIPTION_ID_PREFIX = "sub_";
3521
+ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
3522
+ var VALIDATION_ERROR = "VALIDATION_ERROR";
3523
+ var FORBIDDEN = "FORBIDDEN";
3524
+ var utf8Encoder = new TextEncoder();
3525
+ function creditsEndpoint(subscriptionId, action) {
3526
+ return `${EXT_SUBSCRIPTIONS_PATH}/${encodeURIComponent(subscriptionId)}/credits/${action}`;
3527
+ }
3528
+ function isPlainObject2(value) {
3529
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3530
+ }
3531
+ function isIntegerInRange(value, min, max) {
3532
+ return typeof value === "number" && Number.isInteger(value) && value >= min && value <= max;
3533
+ }
3534
+ function createCreditsMethods(deps) {
3535
+ const { fetchWithAuth, createError, authMode, baseUrl, serviceCode, logger } = deps;
3536
+ function validationError(field, message) {
3537
+ return { error: { ...createError(VALIDATION_ERROR, message), details: { field } } };
3538
+ }
3539
+ function forbidden(reason, message) {
3540
+ return { error: { ...createError(FORBIDDEN, message), details: { reason } } };
3541
+ }
3542
+ function missingSubscriptionId(subscriptionId) {
3543
+ return subscriptionId && subscriptionId.trim() ? null : validationError("subscriptionId", "subscriptionId \u306F\u5FC5\u9808\u3067\u3059");
3544
+ }
3545
+ async function getBalance(subscriptionId) {
3546
+ const invalid = missingSubscriptionId(subscriptionId);
3547
+ if (invalid) return invalid;
3548
+ return fetchWithAuth(creditsEndpoint(subscriptionId, "balance"));
3549
+ }
3550
+ async function listHistory(subscriptionId, options = {}) {
3551
+ const invalid = missingSubscriptionId(subscriptionId);
3552
+ if (invalid) return invalid;
3553
+ const query = new URLSearchParams();
3554
+ if (options.cursor !== void 0) query.set("cursor", options.cursor);
3555
+ if (options.limit !== void 0) {
3556
+ if (!isIntegerInRange(options.limit, FFID_CREDITS_HISTORY_MIN_LIMIT, FFID_CREDITS_HISTORY_MAX_LIMIT)) {
3557
+ return validationError(
3558
+ "limit",
3559
+ `limit \u306F ${FFID_CREDITS_HISTORY_MIN_LIMIT}\u301C${FFID_CREDITS_HISTORY_MAX_LIMIT} \u306E\u6574\u6570\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044`
3560
+ );
3561
+ }
3562
+ query.set("limit", String(options.limit));
3563
+ }
3564
+ if (options.type !== void 0) {
3565
+ if (!FFID_CREDIT_HISTORY_TYPES.includes(options.type)) {
3566
+ return validationError("type", `type \u306F ${FFID_CREDIT_HISTORY_TYPES.join(" / ")} \u306E\u3044\u305A\u308C\u304B\u3067\u3059`);
3567
+ }
3568
+ query.set("type", options.type);
3569
+ }
3570
+ const qs = query.toString();
3571
+ return fetchWithAuth(
3572
+ `${creditsEndpoint(subscriptionId, "history")}${qs ? `?${qs}` : ""}`
3573
+ );
3574
+ }
3575
+ async function listPacks(packServiceCode) {
3576
+ const resolved = packServiceCode ?? (authMode === "service-key" ? void 0 : serviceCode);
3577
+ if (resolved !== void 0 && !resolved.trim()) {
3578
+ return validationError("serviceCode", "serviceCode \u3092\u6307\u5B9A\u3059\u308B\u5834\u5408\u3001\u7A7A\u6587\u5B57\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093");
3579
+ }
3580
+ const qs = resolved === void 0 ? "" : `?${new URLSearchParams({ serviceCode: resolved }).toString()}`;
3581
+ return fetchWithAuth(`${CREDIT_PACKS_ENDPOINT}${qs}`);
3582
+ }
3583
+ async function createPackCheckout(params) {
3584
+ if (authMode !== "token") {
3585
+ return forbidden(
3586
+ "bearer_required",
3587
+ "createPackCheckout \u306F token \u30E2\u30FC\u30C9\uFF08Bearer\uFF09\u3067\u306E\u307F\u5229\u7528\u3067\u304D\u307E\u3059\u3002\u8CFC\u5165\u8005\u306E\u8A18\u9332\u306B\u5B9F\u30E6\u30FC\u30B6\u30FC\u304C\u5FC5\u8981\u306A\u305F\u3081\u3067\u3059"
3588
+ );
3589
+ }
3590
+ const invalid = missingSubscriptionId(params.subscriptionId);
3591
+ if (invalid) return invalid;
3592
+ for (const field of ["packCode", "successUrl", "cancelUrl"]) {
3593
+ if (!params[field] || !params[field].trim()) {
3594
+ return validationError(field, `${field} \u306F\u5FC5\u9808\u3067\u3059`);
3595
+ }
3596
+ }
3597
+ if (params.quantity !== void 0 && !isIntegerInRange(params.quantity, FFID_CREDIT_PACK_MIN_QUANTITY, FFID_CREDIT_PACK_MAX_QUANTITY)) {
3598
+ return validationError(
3599
+ "quantity",
3600
+ `quantity \u306F ${FFID_CREDIT_PACK_MIN_QUANTITY}\u301C${FFID_CREDIT_PACK_MAX_QUANTITY} \u306E\u6574\u6570\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044`
3601
+ );
3602
+ }
3603
+ const body = {
3604
+ subscriptionId: params.subscriptionId,
3605
+ packCode: params.packCode,
3606
+ successUrl: params.successUrl,
3607
+ cancelUrl: params.cancelUrl
3608
+ };
3609
+ if (params.quantity !== void 0) body.quantity = params.quantity;
3610
+ return fetchWithAuth(CREDIT_PACK_CHECKOUT_ENDPOINT, {
3611
+ method: "POST",
3612
+ body: JSON.stringify(body)
3613
+ });
3614
+ }
3615
+ function validateConsume(params) {
3616
+ const invalid = missingSubscriptionId(params.subscriptionId);
3617
+ if (invalid) return invalid;
3618
+ if (!isIntegerInRange(params.amount, FFID_CREDITS_CONSUME_MIN_AMOUNT, FFID_CREDITS_CONSUME_MAX_AMOUNT)) {
3619
+ return validationError(
3620
+ "amount",
3621
+ `amount \u306F ${FFID_CREDITS_CONSUME_MIN_AMOUNT}\u301C${FFID_CREDITS_CONSUME_MAX_AMOUNT} \u306E\u6574\u6570\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044`
3622
+ );
3623
+ }
3624
+ if (typeof params.idempotencyKey !== "string" || !FFID_CREDITS_IDEMPOTENCY_KEY_PATTERN.test(params.idempotencyKey)) {
3625
+ return validationError(
3626
+ "idempotencyKey",
3627
+ "idempotencyKey \u306E\u5F62\u5F0F\u304C\u4E0D\u6B63\u3067\u3059\uFF08\u82F1\u6570\u5B57\u3068 . _ : - \u306E 8\u301C128 \u6587\u5B57\u3002\u63A8\u5968\u306F feature:requestId\uFF09"
3628
+ );
3629
+ }
3630
+ if (typeof params.feature !== "string" || !FFID_CREDITS_FEATURE_PATTERN.test(params.feature)) {
3631
+ return validationError("feature", "feature \u306E\u5F62\u5F0F\u304C\u4E0D\u6B63\u3067\u3059\uFF08\u5C0F\u6587\u5B57\u82F1\u6570\u5B57\u3067\u59CB\u307E\u308B\u3001\u5C0F\u6587\u5B57\u82F1\u6570\u5B57\u3068 . _ - \u306E 1\u301C64 \u6587\u5B57\uFF09");
3632
+ }
3633
+ if (params.metadata !== void 0) {
3634
+ if (!isPlainObject2(params.metadata)) {
3635
+ return validationError("metadata", "metadata \u306F JSON \u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");
3636
+ }
3637
+ let serialized;
3638
+ try {
3639
+ serialized = JSON.stringify(params.metadata);
3640
+ } catch {
3641
+ return validationError("metadata", "metadata \u306F JSON \u306B\u5909\u63DB\u3067\u304D\u308B\u5024\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08BigInt\u30FB\u5FAA\u74B0\u53C2\u7167\u306F\u4E0D\u53EF\uFF09");
3642
+ }
3643
+ if (utf8Encoder.encode(serialized).byteLength > FFID_CREDITS_METADATA_MAX_BYTES) {
3644
+ return validationError("metadata", `metadata \u306F ${FFID_CREDITS_METADATA_MAX_BYTES} \u30D0\u30A4\u30C8\u4EE5\u4E0B\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059`);
3645
+ }
3646
+ }
3647
+ if (params.userId !== void 0 && !UUID_PATTERN.test(params.userId)) {
3648
+ return validationError("userId", "userId \u306F\u6709\u52B9\u306AUUID\u5F62\u5F0F\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");
3649
+ }
3650
+ return null;
3651
+ }
3652
+ async function consume(params) {
3653
+ if (authMode !== "service-key") {
3654
+ return forbidden(
3655
+ "api_key_required",
3656
+ "credits.consume \u306F service-key \u8A8D\u8A3C\uFF08X-Service-Api-Key\uFF09\u3067\u306E\u307F\u5229\u7528\u3067\u304D\u307E\u3059\u3002\u6D88\u8CBB\u306E\u5831\u544A\u306F\u30B5\u30FC\u30D3\u30B9\u306E\u30D0\u30C3\u30AF\u30A8\u30F3\u30C9\u304B\u3089\u884C\u3063\u3066\u304F\u3060\u3055\u3044"
3657
+ );
3658
+ }
3659
+ const invalid = validateConsume(params);
3660
+ if (invalid) return invalid;
3661
+ const body = {
3662
+ amount: params.amount,
3663
+ idempotencyKey: params.idempotencyKey,
3664
+ feature: params.feature
3665
+ };
3666
+ if (params.metadata !== void 0) body.metadata = params.metadata;
3667
+ if (params.userId !== void 0) body.userId = params.userId;
3668
+ return fetchWithAuth(creditsEndpoint(params.subscriptionId, "consume"), {
3669
+ method: "POST",
3670
+ body: JSON.stringify(body)
3671
+ });
3672
+ }
3673
+ function getBuyCreditsUrl(params) {
3674
+ const raw = params.subscriptionId?.trim() ?? "";
3675
+ if (raw.startsWith(STRIPE_SUBSCRIPTION_ID_PREFIX)) {
3676
+ return validationError(
3677
+ "subscriptionId",
3678
+ "getBuyCreditsUrl \u306B\u306F\u5951\u7D04\u306E UUID\uFF08\u307E\u305F\u306F ffid:<uuid>\uFF09\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002Stripe \u306E sub_... \u306F\u4F7F\u3048\u307E\u305B\u3093"
3679
+ );
3680
+ }
3681
+ const uuid = raw.startsWith(FFID_CONTRACT_ID_PREFIX) ? raw.slice(FFID_CONTRACT_ID_PREFIX.length) : raw;
3682
+ if (!UUID_PATTERN.test(uuid)) {
3683
+ return validationError("subscriptionId", "subscriptionId \u306F\u5951\u7D04\u306E UUID\uFF08\u307E\u305F\u306F ffid:<uuid>\uFF09\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");
3684
+ }
3685
+ const query = new URLSearchParams({ [BUY_CREDITS_QUERY.key]: BUY_CREDITS_QUERY.value });
3686
+ if (params.orgId !== void 0 && params.orgId.trim()) {
3687
+ query.set(ORG_QUERY_KEY, params.orgId);
3688
+ }
3689
+ return { data: `${baseUrl}${PORTAL_SUBSCRIPTION_PATH}/${encodeURIComponent(uuid)}?${query.toString()}` };
3690
+ }
3691
+ function redirectToBuyCredits(params) {
3692
+ const result = getBuyCreditsUrl(params);
3693
+ if (result.error) {
3694
+ logger.warn("redirectToBuyCredits:", result.error.message);
3695
+ return { success: false, error: result.error.message };
3696
+ }
3697
+ if (typeof window === "undefined") {
3698
+ logger.warn("SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093");
3699
+ return { success: false, error: "SSR \u74B0\u5883\u3067\u306F\u30EA\u30C0\u30A4\u30EC\u30AF\u30C8\u3067\u304D\u307E\u305B\u3093" };
3700
+ }
3701
+ logger.debug("Redirecting to buy credits:", result.data);
3702
+ window.location.href = result.data;
3703
+ return { success: true };
3704
+ }
3705
+ return {
3706
+ getBalance,
3707
+ listHistory,
3708
+ listPacks,
3709
+ createPackCheckout,
3710
+ consume,
3711
+ getBuyCreditsUrl,
3712
+ redirectToBuyCredits
3713
+ };
3714
+ }
3715
+
3493
3716
  // src/subscriptions/userinfo-helpers.ts
3494
3717
  var ACCESS_GRANTING_EFFECTIVE_STATUSES = [
3495
3718
  "active",
@@ -3548,7 +3771,12 @@ function toServiceAccessDecision(response, allowGrace) {
3548
3771
  planCode: response.planCode,
3549
3772
  currentPeriodEnd: response.currentPeriodEnd,
3550
3773
  gracePeriodEndsAt: response.gracePeriodEndsAt ?? null,
3551
- reactivatable: response.reactivatable ?? false
3774
+ reactivatable: response.reactivatable ?? false,
3775
+ // Informational pass-through (10.0.0). Deliberately not part of hasAccess /
3776
+ // denialReason: credits and the member limit never gate access (CREDITS_API §1-5).
3777
+ ...response.pricingModel !== void 0 ? { pricingModel: response.pricingModel } : {},
3778
+ ...response.credits !== void 0 ? { credits: response.credits } : {},
3779
+ ...response.memberLimitReached !== void 0 ? { memberLimitReached: response.memberLimitReached } : {}
3552
3780
  };
3553
3781
  }
3554
3782
  function failClosedServiceAccessDecision(params, error) {
@@ -3910,7 +4138,7 @@ function createFFIDClient(config) {
3910
4138
  fetchWithAuth,
3911
4139
  createError
3912
4140
  });
3913
- const { listSeatAssignments, assignSeats, unassignSeat } = createSeatMethods({
4141
+ const { listSeatAssignments, getSeats, assignSeats, unassignSeat } = createSeatMethods({
3914
4142
  fetchWithAuth,
3915
4143
  createError
3916
4144
  });
@@ -4017,6 +4245,14 @@ function createFFIDClient(config) {
4017
4245
  fetchWithAuth,
4018
4246
  createError
4019
4247
  });
4248
+ const credits = createCreditsMethods({
4249
+ fetchWithAuth,
4250
+ createError,
4251
+ authMode,
4252
+ baseUrl,
4253
+ serviceCode: config.serviceCode,
4254
+ logger
4255
+ });
4020
4256
  const verifyAccessToken = createVerifyAccessToken({
4021
4257
  authMode,
4022
4258
  baseUrl,
@@ -4072,6 +4308,7 @@ function createFFIDClient(config) {
4072
4308
  getInvoice,
4073
4309
  retryPayment,
4074
4310
  listSeatAssignments,
4311
+ getSeats,
4075
4312
  assignSeats,
4076
4313
  unassignSeat,
4077
4314
  listPlans,
@@ -4082,13 +4319,16 @@ function createFFIDClient(config) {
4082
4319
  cancelSubscription,
4083
4320
  cancelPendingDowngrade,
4084
4321
  previewPlanChange,
4322
+ /** @deprecated 10.0.0: per_seat (praxis) only; removed in 11.0.0 */
4085
4323
  previewSeatChange,
4086
4324
  verifyAccessToken,
4087
4325
  getSubscribeUrl,
4088
4326
  redirectToSubscribe,
4089
4327
  getChangePlanUrl,
4090
4328
  redirectToChangePlan,
4329
+ /** @deprecated 10.0.0: per_seat (praxis) only; removed in 11.0.0 */
4091
4330
  getChangeSeatsUrl,
4331
+ /** @deprecated 10.0.0: per_seat (praxis) only; removed in 11.0.0 */
4092
4332
  redirectToChangeSeats,
4093
4333
  getRecoverPaymentUrl,
4094
4334
  redirectToRecoverPayment,
@@ -4104,6 +4344,8 @@ function createFFIDClient(config) {
4104
4344
  newsletter,
4105
4345
  /** Inquiry methods (create) */
4106
4346
  inquiry,
4347
+ /** Credits methods for flat plans (consume / balance / history / packs) */
4348
+ credits,
4107
4349
  /** Token store (token mode only) */
4108
4350
  tokenStore,
4109
4351
  /**
@@ -1,4 +1,4 @@
1
- import { r as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-6aLs9Fqc.cjs';
1
+ import { r as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-CumygXXz.cjs';
2
2
  import '../../types-Cjb9J0rL.cjs';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { r as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-B0cORHac.js';
1
+ import { r as FFIDClient, e as FFIDOAuthUserInfo } from '../../ffid-client-5uxXRgIO.js';
2
2
  import '../../types-Cjb9J0rL.js';
3
3
 
4
4
  /**
@@ -39,6 +39,74 @@ declare class FFIDWebhookPayloadError extends FFIDWebhookError {
39
39
  constructor(message?: string);
40
40
  }
41
41
 
42
+ /**
43
+ * `credits.*` webhook payloads (SDK 10.0.0, FFID CREDITS_API §8).
44
+ *
45
+ * Separate file to keep `types.ts` small. Mirrors the FFID server's
46
+ * `src/lib/webhooks/credits-payloads.ts`; the FFID repository type-checks the two
47
+ * against each other (`sdk-credits-payloads.sync.test.ts`).
48
+ */
49
+ /**
50
+ * Fields every `credits.*` payload carries (10.0.0, CREDITS_API §8).
51
+ *
52
+ * `credits.*` events are broadcast to every endpoint subscribed to the event type,
53
+ * so compare `serviceCode` with your own service code before acting. It is absent
54
+ * only when FFID could not resolve it — do not read absence as "not for this service".
55
+ */
56
+ interface FFIDCreditsEventBase {
57
+ subscriptionId: string;
58
+ organizationId: string;
59
+ /** Time the event happened (ISO 8601) */
60
+ occurredAt: string;
61
+ serviceCode?: string;
62
+ }
63
+ /**
64
+ * `credits.granted` — a monthly / manual / pack grant was created. Sent once per
65
+ * grant (`grantId`). A pack purchase also sends `credits.pack_purchased`.
66
+ */
67
+ interface FFIDCreditsGrantedPayload extends FFIDCreditsEventBase {
68
+ grantId: string;
69
+ kind: 'monthly' | 'manual' | 'pack';
70
+ amount: number;
71
+ expiresAt: string;
72
+ /** Only when `kind === 'monthly'` */
73
+ periodStart?: string;
74
+ /** Only when `kind === 'monthly'` */
75
+ periodEnd?: string;
76
+ /** Balance read after the grant — a reference value; the balance API is authoritative */
77
+ balanceAfter: number;
78
+ }
79
+ /** `credits.low` — the balance fell below the low threshold (once per period) */
80
+ interface FFIDCreditsLowPayload extends FFIDCreditsEventBase {
81
+ available: number;
82
+ monthlyCredits: number;
83
+ thresholdPercent: number;
84
+ /** End of the current period; null only when FFID could not read it */
85
+ periodEnd: string | null;
86
+ }
87
+ /** `credits.exhausted` — the balance reached 0 (once per period) */
88
+ interface FFIDCreditsExhaustedPayload extends FFIDCreditsEventBase {
89
+ available: number;
90
+ monthlyCredits: number;
91
+ /** End of the current period; null only when FFID could not read it */
92
+ periodEnd: string | null;
93
+ }
94
+ /** `credits.pack_purchased` — a credit pack purchase completed and its credits were granted */
95
+ interface FFIDCreditsPackPurchasedPayload extends FFIDCreditsEventBase {
96
+ operationId: string;
97
+ grantId: string;
98
+ packCode: string;
99
+ /** Credits granted in total (pack credits × `quantity`) */
100
+ credits: number;
101
+ quantity: number;
102
+ /** Amount paid (tax-inclusive, smallest currency unit) */
103
+ amount: number;
104
+ currency: string;
105
+ expiresAt: string;
106
+ /** User who bought the pack */
107
+ purchasedBy: string;
108
+ }
109
+
42
110
  /**
43
111
  * FFID Webhook SDK Type Definitions
44
112
  *
@@ -47,7 +115,7 @@ declare class FFIDWebhookPayloadError extends FFIDWebhookError {
47
115
  */
48
116
 
49
117
  /** All supported webhook event types */
50
- type FFIDWebhookEventType = 'subscription.created' | 'subscription.reactivated' | 'subscription.updated' | 'subscription.canceled' | 'subscription.downgrade_scheduled' | 'subscription.downgrade_applied' | 'subscription.downgrade_canceled' | 'subscription.trial_ending' | 'subscription.payment_failed' | 'user.created' | 'user.updated' | 'user.deleted' | 'user.deletion_requested' | 'organization.created' | 'organization.updated' | 'organization.member.added' | 'organization.member.removed' | 'organization.member.role_changed' | 'legal.document.updated' | 'legal.agreement.required' | 'system.maintenance.scheduled' | 'system.maintenance.started' | 'system.maintenance.completed' | 'announcement.published' | 'test.ping';
118
+ type FFIDWebhookEventType = 'subscription.created' | 'subscription.reactivated' | 'subscription.updated' | 'subscription.canceled' | 'subscription.downgrade_scheduled' | 'subscription.downgrade_applied' | 'subscription.downgrade_canceled' | 'subscription.trial_ending' | 'subscription.payment_failed' | 'user.created' | 'user.updated' | 'user.deleted' | 'user.deletion_requested' | 'organization.created' | 'organization.updated' | 'organization.member.added' | 'organization.member.removed' | 'organization.member.role_changed' | 'legal.document.updated' | 'legal.agreement.required' | 'system.maintenance.scheduled' | 'system.maintenance.started' | 'system.maintenance.completed' | 'announcement.published' | 'credits.granted' | 'credits.low' | 'credits.exhausted' | 'credits.pack_purchased' | 'test.ping';
51
119
  interface FFIDSubscriptionCreatedPayload {
52
120
  subscriptionId: string;
53
121
  organizationId?: string;
@@ -64,12 +132,27 @@ interface FFIDSubscriptionCreatedPayload {
64
132
  */
65
133
  serviceCode?: string;
66
134
  }
135
+ /**
136
+ * `subscription.updated`.
137
+ *
138
+ * 9.0.0 aligned this type with what FFID sends (#6380): `status` is always present, and
139
+ * `subscriptionId` / `organizationId` are absent when the event comes from a Stripe notice
140
+ * whose subscription FFID could not match to its own record (check before use).
141
+ * `previousPlan` was removed — FFID never sent it.
142
+ */
67
143
  interface FFIDSubscriptionUpdatedPayload {
68
- subscriptionId: string;
144
+ /**
145
+ * Subscription status after the change — the raw status string (FFID's or Stripe's), not a
146
+ * closed enum. Use `effectiveStatus` for access decisions.
147
+ */
148
+ status: string;
149
+ /** FFID subscription UUID. Absent when FFID could not match the Stripe subscription */
150
+ subscriptionId?: string;
151
+ /** Stripe subscription id (`sub_...`). Present on events that come from Stripe notices */
152
+ stripeSubscriptionId?: string;
69
153
  organizationId?: string;
154
+ /** Plan code after the change */
70
155
  plan?: string;
71
- previousPlan?: string;
72
- status?: string;
73
156
  effectiveStatus?: EffectiveSubscriptionStatus;
74
157
  gracePeriodEndsAt?: string | null;
75
158
  /**
@@ -242,9 +325,27 @@ interface FFIDSubscriptionDowngradeCanceledPayload {
242
325
  */
243
326
  serviceCode?: string;
244
327
  }
328
+ /**
329
+ * `subscription.trial_ending` — sent when Stripe announces that a trial is about to end.
330
+ *
331
+ * 9.0.0 aligned this type with what FFID sends (#6380). FFID does not resolve its own
332
+ * subscription UUID for this event; identify the subscription by `stripeSubscriptionId`
333
+ * (and the service by `serviceCode`).
334
+ */
245
335
  interface FFIDSubscriptionTrialEndingPayload {
246
- subscriptionId: string;
247
- organizationId?: string;
336
+ /** Stripe subscription id (`sub_...`) */
337
+ stripeSubscriptionId: string;
338
+ /**
339
+ * Days until the trial ends, rounded **up** at the moment FFID processed Stripe's notice
340
+ * (a trial ending later the same day is `1`). `0` only when the trial had already ended by
341
+ * then. Fixed when the event is created — a redelivered event carries the same value.
342
+ */
343
+ daysRemaining: number;
344
+ /**
345
+ * Trial end date **for display**, in Japanese long form in JST (e.g. `2026年10月3日`) — not
346
+ * an ISO timestamp. `(無効な日時)` when FFID could not read Stripe's timestamp. Use
347
+ * `daysRemaining` for any calculation.
348
+ */
248
349
  trialEndDate: string;
249
350
  /**
250
351
  * Code of the service the subscription belongs to (e.g. `chatbot-v2`), resolved by FFID when
@@ -420,6 +521,10 @@ interface FFIDWebhookEventMap {
420
521
  'system.maintenance.started': FFIDSystemMaintenancePayload;
421
522
  'system.maintenance.completed': FFIDSystemMaintenancePayload;
422
523
  'announcement.published': FFIDAnnouncementPublishedPayload;
524
+ 'credits.granted': FFIDCreditsGrantedPayload;
525
+ 'credits.low': FFIDCreditsLowPayload;
526
+ 'credits.exhausted': FFIDCreditsExhaustedPayload;
527
+ 'credits.pack_purchased': FFIDCreditsPackPurchasedPayload;
423
528
  'test.ping': FFIDTestPingPayload;
424
529
  }
425
530
  /** A webhook event envelope with typed payload */
@@ -545,4 +650,4 @@ declare function createFFIDWebhookHandler(config: FFIDWebhookHandlerConfig): {
545
650
  /** Type of the FFID Webhook handler */
546
651
  type FFIDWebhookHandler = ReturnType<typeof createFFIDWebhookHandler>;
547
652
 
548
- export { DEFAULT_TOLERANCE_SECONDS, type FFIDLegalAgreementRequiredPayload, type FFIDLegalDocumentUpdatedPayload, type FFIDOrganizationCreatedPayload, type FFIDOrganizationMemberAddedPayload, type FFIDOrganizationMemberRemovedPayload, type FFIDOrganizationMemberRoleChangedPayload, type FFIDOrganizationUpdatedPayload, type FFIDSubscriptionCanceledPayload, type FFIDSubscriptionCreatedPayload, type FFIDSubscriptionDowngradeAppliedPayload, type FFIDSubscriptionDowngradeCanceledPayload, type FFIDSubscriptionDowngradeScheduledPayload, type FFIDSubscriptionPaymentFailedPayload, type FFIDSubscriptionReactivatedPayload, type FFIDSubscriptionTrialEndingPayload, type FFIDSubscriptionUpdatedPayload, type FFIDSystemMaintenancePayload, type FFIDTestPingPayload, type FFIDUserCreatedPayload, type FFIDUserDeletedPayload, type FFIDUserDeletionRequestedPayload, type FFIDUserUpdatedPayload, FFIDWebhookError, type FFIDWebhookEvent, type FFIDWebhookEventHandler, type FFIDWebhookEventMap, type FFIDWebhookEventType, type FFIDWebhookHandler, type FFIDWebhookHandlerConfig, type FFIDWebhookLogger, FFIDWebhookPayloadError, FFIDWebhookSignatureError, FFIDWebhookTimestampError, FFID_WEBHOOK_EVENT_ID_HEADER, FFID_WEBHOOK_SIGNATURE_HEADER, FFID_WEBHOOK_SIGNATURE_VERSION, FFID_WEBHOOK_TIMESTAMP_HEADER, computeSignature, createFFIDWebhookHandler, parseSignatureHeader, verifyWebhookSignature };
653
+ export { DEFAULT_TOLERANCE_SECONDS, type FFIDAnnouncementPublishedPayload, type FFIDCreditsExhaustedPayload, type FFIDCreditsGrantedPayload, type FFIDCreditsLowPayload, type FFIDCreditsPackPurchasedPayload, type FFIDLegalAgreementRequiredPayload, type FFIDLegalDocumentUpdatedPayload, type FFIDOrganizationCreatedPayload, type FFIDOrganizationMemberAddedPayload, type FFIDOrganizationMemberRemovedPayload, type FFIDOrganizationMemberRoleChangedPayload, type FFIDOrganizationUpdatedPayload, type FFIDSubscriptionCanceledPayload, type FFIDSubscriptionCreatedPayload, type FFIDSubscriptionDowngradeAppliedPayload, type FFIDSubscriptionDowngradeCanceledPayload, type FFIDSubscriptionDowngradeScheduledPayload, type FFIDSubscriptionPaymentFailedPayload, type FFIDSubscriptionReactivatedPayload, type FFIDSubscriptionTrialEndingPayload, type FFIDSubscriptionUpdatedPayload, type FFIDSystemMaintenancePayload, type FFIDTestPingPayload, type FFIDUserCreatedPayload, type FFIDUserDeletedPayload, type FFIDUserDeletionRequestedPayload, type FFIDUserUpdatedPayload, FFIDWebhookError, type FFIDWebhookEvent, type FFIDWebhookEventHandler, type FFIDWebhookEventMap, type FFIDWebhookEventType, type FFIDWebhookHandler, type FFIDWebhookHandlerConfig, type FFIDWebhookLogger, FFIDWebhookPayloadError, FFIDWebhookSignatureError, FFIDWebhookTimestampError, FFID_WEBHOOK_EVENT_ID_HEADER, FFID_WEBHOOK_SIGNATURE_HEADER, FFID_WEBHOOK_SIGNATURE_VERSION, FFID_WEBHOOK_TIMESTAMP_HEADER, computeSignature, createFFIDWebhookHandler, parseSignatureHeader, verifyWebhookSignature };