Google IAP with validation hook in TS

Here i using the registerAfterValidatePurchaseGoogle hook

export const afterGooglePurchase: nkruntime.AfterHookFunction<nkruntime.ValidatePurchaseResponse, nkruntime.ValidatePurchaseGoogleRequest> = async (ctx, logger, nk, response, request) => {
  const userId = ctx.userId;
  logger.info("--------userId---------" + JSON.stringify(userId));
  logger.info("------------request-----------" + JSON.stringify(request));
  if (!response.validatedPurchases || response.validatedPurchases.length === 0) {
    logger.warn("No validated purchases found in response.");
    return response;
  }

  for (const purchase of response.validatedPurchases) {
    const transactionId = purchase.transactionId;
    logger.info("---------transactionId--------" + JSON.stringify(transactionId));

    // Prevent duplicate reward (idempotency)
    const existing = nk.storageRead([{ collection: "IAP_COLLECTION", key: transactionId, userId }]);
    if (existing.length > 0) {
      logger.warn(`Transaction ${transactionId} already processed.`);
      continue;
    }

    // Reward based on productId
   .......

  return response;
};

Here, when i am log the purchase form the response.validatedPurchase
there is no seenBefore.

And my question are:

  1. firstly should i use the after hook or before hook.
  2. How should i validate that purchase is duplicate purchase (should i use the custom RPC for validate here i got the seenBefore)
  3. And one main question When a Google IAP purchase is made in Unity, but the network is down when validating the receipt with Nakama, here’s what happens and how I should handle it.

Please help me

  1. Either an after hook or a custom RPC should be fine.
  2. You should use the seenBefore to know whether the receipt was already validated and if you should grant your purchase or not, but this depends on your purchase granting logic. I wouldn’t expect the seenBefore to be missing, are you using the latest Nakama + TS definitions?
  3. If the network is down, the request will fail, so Nakama won’t see the receipt, nor handle its validation or your custom purchase granting logic. The client should retry submitting the receipt when the network is available again.

Thanks @sesposito,
Here, the nakama version is
FROM registry.heroiclabs.com/heroiclabs/nakama:3.21.0 AS runner
and i’m using
initializer.registerAfterValidatePurchaseGoogle(afterGooglePurchase);
In this hook there is no seenBefore.

Please upgrade to latest, as well as the TS definitions, if the issue is still there please clarify if it’s missing from the runtime payload or just the TS definitions.

@sesposito Sir here i update the

#Dockerfile
FROM registry.heroiclabs.com/heroiclabs/nakama:3.27.1 AS runner
#pakage.json
 "dependencies": {
    "nakama-runtime": "github:heroiclabs/nakama-common#master"
  },

and

#pakage-lock.json

  "node_modules/nakama-runtime": {
      "version": "1.37.0",
      "resolved": "git+ssh://git@github.com/heroiclabs/nakama-common.git#ba2d0a14678f3cbd8cb915511d5a4ccca6139487",
      "license": "Apache-2.0"
    },

and still there is not seen before on initializer.registerAfterValidatePurchaseGoogle(afterGooglePurchase);
Please check this issue

But I used

const validateToken = nk.purchaseGetByTransactionId(purchaseToken);

get the seenBefore

please clarify if it’s missing from the runtime payload or just the TS definitions

That seenBefore is missing on the runtime payload TS definitions is good.

export const afterGooglePurchase: nkruntime.AfterHookFunction<nkruntime.ValidatePurchaseResponse, nkruntime.ValidatePurchaseGoogleRequest> = async (ctx, logger, nk, response, request) => {
    logger.info("---------response----------" + JSON.stringify(response)); //now seenBefore
}

If you guys fix this, please let me know

@developerdinno the key/value is currently omitted from the json if the bool is false - this has to do with some of the inner workings of Nakama and the bridging between Go and JS.

It’s something that we can improve, but you can currently safely inspect this value by assuming that if the key is missing, the value is false, but if the value is true, the key/value are present in the response payload.

1 Like