Skip to content

Desktop bundle

import {
Access,
Billing,
Credits,
Licensing,
Offer,
Purchase,
checkAccess,
createCheckout,
getCreditBalance,
issueLicenseCredential,
processPaymentNotification,
registerOffers,
} from "@byfungsi/sapa";
const desktopAccess =
yield *
Access.entitlements({
entitlements: ["desktop.use"],
duration: "perpetual",
});
const updateAccess =
yield *
Access.entitlements({
entitlements: ["desktop.updates"],
duration: {
type: "fixed",
months: 12,
anchor: "settlement",
calendar: "utc_clamped",
},
});
const desktopLicense =
yield *
Licensing.eligibility({
entitlement: "desktop.use",
activationLimit: 3,
});
const processingCredits =
yield * Credits.pack({ unit: "desktop.processing", quantity: 100n });
const bundlePurchase =
yield *
Purchase.parse({
key: "desktop.bundle.benefits",
revision: 1,
provides: [desktopAccess, updateAccess, desktopLicense, processingCredits],
});
const bundleBilling =
yield *
Billing.oneTime({
price: { currency: "IDR", amount: 1_999_000n },
});
const bundle =
yield *
Offer.parse({
key: "desktop.bundle",
revision: 1,
purchase: bundlePurchase,
billing: bundleBilling,
});
yield * registerOffers([bundle]);
yield *
createCheckout({
type: "offer",
offerKey: bundle.key,
offerRevision: bundle.revision,
quantity: null,
provider: "midtrans",
customer,
successUrl,
cancelUrl,
clientIp: null,
idempotencyKey: "desktop-bundle-42",
});
yield *
processPaymentNotification({
provider: "midtrans",
payload: rawProviderPayload,
});
// Run fulfillment before explicit license issuance.
const license =
yield *
issueLicenseCredential({
idempotencyKey: "desktop-bundle-license-42",
externalCustomerId: "customer-42",
entitlement: "desktop.use",
});
const canUseApp =
yield *
checkAccess({
externalCustomerId: "customer-42",
entitlement: "desktop.use",
});
const getsUpdates =
yield *
checkAccess({
externalCustomerId: "customer-42",
entitlement: "desktop.updates",
});
const credits =
yield *
getCreditBalance({ customerId: "customer-42", unit: "desktop.processing" });

Each benefit keeps its own historical duration and unit. Twelve months after settlement, desktop.updates becomes inactive while desktop.use, the license eligibility it supports, and unused non-expiring credits remain. Do not collapse the bundle into one shared expiry timestamp.