0

I'm relatively new to node.js and am attempting to utilize a javascript library without any success.

The library itself is psn-api.

To set up for usage I have:

  1. Installed node.js locally
  2. Created my project folder
  3. Ran npm init and successfully created package.json
  4. Ran npm install i -s psn-api which has successfully installed psn-api to my project folder in node-modules and updated the dependencies in package.json.
  5. I've copied the sample code from the psn-api github (see below) and saved as index.ts file in my project folder.
  6. I run npx tsc --init which generates my tsconfig.json file
  7. I run npx tsc index.ts which compiles into index.js
  8. I run node index.js

Sample code (index.ts):

import * as fs from "fs";

import type { Trophy } from "psn-api";
import {
  exchangeCodeForAccessToken,
  exchangeNpssoForCode,
  getTitleTrophies,
  getUserTitles,
  getUserTrophiesEarnedForTitle,
  makeUniversalSearch,
  TrophyRarity
} from "psn-api";

async function main() {
  // 1. Authenticate and become authorized with PSN.
  // See the Authenticating Manually docs for how to get your NPSSO.
  const npsso = "xxxxxxxx";
  const accessCode = await exchangeNpssoForCode(npsso);
  const authorization = await exchangeCodeForAccessToken(accessCode);

  // 2. Get the user's `accountId` from the username.
  const allAccountsSearchResults = await makeUniversalSearch(
    authorization,
    "xelnia",
    "SocialAllAccounts"
  );

  const targetAccountId =
    allAccountsSearchResults.domainResponses[0].results[0].socialMetadata
      .accountId;

  // 3. Get the user's list of titles (games).
  const { trophyTitles } = await getUserTitles(authorization, targetAccountId);

  const games: any[] = [];
  for (const title of trophyTitles) {
    // 4. Get the list of trophies for each of the user's titles.
    const { trophies: titleTrophies } = await getTitleTrophies(
      authorization,
      title.npCommunicationId,
      "all",
      {
        npServiceName:
          title.trophyTitlePlatform !== "PS5" ? "trophy" : undefined
      }
    );

    // 5. Get the list of _earned_ trophies for each of the user's titles.
    const { trophies: earnedTrophies } = await getUserTrophiesEarnedForTitle(
      authorization,
      targetAccountId,
      title.npCommunicationId,
      "all",
      {
        npServiceName:
          title.trophyTitlePlatform !== "PS5" ? "trophy" : undefined
      }
    );

    // 6. Merge the two trophy lists.
    const mergedTrophies = mergeTrophyLists(titleTrophies, earnedTrophies);

    games.push({
      gameName: title.trophyTitleName,
      platform: title.trophyTitlePlatform,
      trophyTypeCounts: title.definedTrophies,
      earnedCounts: title.earnedTrophies,
      trophyList: mergedTrophies
    });
  }

  // 7. Write to a JSON file.
  fs.writeFileSync("./games.json", JSON.stringify(games));
}

const mergeTrophyLists = (
  titleTrophies: Trophy[],
  earnedTrophies: Trophy[]
) => {
  const mergedTrophies: any[] = [];

  for (const earnedTrophy of earnedTrophies) {
    const foundTitleTrophy = titleTrophies.find(
      (t) => t.trophyId === earnedTrophy.trophyId
    );

    mergedTrophies.push(
      normalizeTrophy({ ...earnedTrophy, ...foundTitleTrophy })
    );
  }

  return mergedTrophies;
};

const normalizeTrophy = (trophy: Trophy) => {
  return {
    isEarned: trophy.earned ?? false,
    earnedOn: trophy.earned ? trophy.earnedDateTime : "unearned",
    type: trophy.trophyType,
    rarity: rarityMap[trophy.trophyRare ?? 0],
    earnedRate: Number(trophy.trophyEarnedRate),
    trophyName: trophy.trophyName,
    groupId: trophy.trophyGroupId
  };
};

const rarityMap: Record<TrophyRarity, string> = {
  [TrophyRarity.VeryRare]: "Very Rare",
  [TrophyRarity.UltraRare]: "Ultra Rare",
  [TrophyRarity.Rare]: "Rare",
  [TrophyRarity.Common]: "Common"
};

I've run around in circles with possible fixes such as adding "type":"module" to the package.json, trying to import or otherwise define psn-api in my js file but I keep hitting error after error. I'm sure there's some fundamental misunderstanding I have. I'd really appreciate if someone could outline the direct steps I need to take to get the sample script running in the cmd line.

My package.json as it stands:

    {
  "name": "psnapitest",
  "version": "1.0.0",
  "description": "",
  "main": "index3.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@types/node": "^18.6.2",
    "psn-api": "^2.7.0"
  },
  "type": "module",
  "devDependencies": {
    "@tsconfig/node16": "^1.0.3",
    "typescript": "^4.7.4"
  }
}

My tsconfig.json as it stands (after advice in comments):

{
  "compilerOptions": {
    "target": "es2016",
    "module": "es6",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true
  }
}

Current error when running compiled js:

Now compiles with no issues.

I run node index.js and get the following error

    exports.__esModule = true;
^

ReferenceError: exports is not defined in ES module scope
Nealbo
  • 529
  • 4
  • 20
  • 1
    Adding `"type": "module"` inside `package.json` should fix the issue. What error do you get then? – Konrad Jul 29 '22 at 21:28
  • Does this answer your question? [Using import fs from 'fs'](https://stackoverflow.com/questions/43622337/using-import-fs-from-fs) – Konrad Jul 29 '22 at 21:29
  • I get a step further but then the error: import type { Trophy } from "psn-api"; SyntaxError: Unexpected token '{' – Nealbo Jul 29 '22 at 21:32
  • No `type` after `import`; just `import { Trophy } from "psn-api";`. – Heretic Monkey Jul 29 '22 at 21:34
  • you have to specify "target":"es6" in your package.json Furthermore if you use Node.js 16 or more es6 modules are supported otherwise you have to install the esm package and use --require esm as execution flag – Nick Jul 29 '22 at 21:34
  • @HereticMonkey `import type {}` is a valid syntax. Seems like op has an old TypeScript version or IDE extension. – Konrad Jul 29 '22 at 21:36
  • 1
    @KonradLinkowski His version of TypeScript is apparently as old as how up-to-date I am with TS syntax ;). – Heretic Monkey Jul 29 '22 at 21:38
  • @Nick Added "target":"es6" to my package.json but still the unexpected token error. Node was freshly installed today so everything up to date. I see discussion around Typescript too - the steps I've taken are outlined above and do not include typescript compilation. Is this a step that I'm missing? As above, I've literally taken the sample code from the git repo and dropped into a js file in my project folder. – Nealbo Jul 29 '22 at 21:42
  • try to give `node --version` why if you had a previous node version installed it can create conflicts – Nick Jul 29 '22 at 21:45
  • have you installed `@types/node` already? – khierl Jul 29 '22 at 21:47
  • Version shown is: v16.16.0 only/ @khierl, no not currently installed to my local project folder. Is this required? – Nealbo Jul 29 '22 at 21:49
  • if you are using typescript yes – khierl Jul 29 '22 at 21:50
  • @khierl I believe this may be the crux of my issue. As above I've simply installed psn-api, created my project with package.json, taken the sample code as shown above and run node myjsfile.js. Any pointers to how I progress past this point/error - or if typescript is a requirement to get this pushed through would be appreciated – Nealbo Jul 29 '22 at 21:52
  • the example code you provided is written in trypescript so you need to setup your environment to work with typescript – khierl Jul 29 '22 at 21:53
  • @khierl Thanks, I was totally unaware of that. OK so have installed typescript, and generated tsdconfig.json. Renamed my .js file to .ts, then I've run "npx tsc myfile.ts". Then I get the error that "Module fs has no default export". – Nealbo Jul 29 '22 at 22:02
  • https://stackoverflow.com/questions/39907142/what-is-definitelytyped You are using typescript and a javascript library. Then you can use the definitely types project. Try to give `npm install --save-dev @types/psn-api – Nick Jul 29 '22 at 22:02
  • @Nick running that gives a Not found: '@types/psn-api@*' is not in this registry. – Nealbo Jul 29 '22 at 22:06
  • @Nick, I've updated my post above with my package.json, tsconfig.json and the note that attempting to compile to ts into js results in the error Module '"fs"' has no default export. 1 import fs from "fs"; Any assistance to get this compiled would be greatly appreciated as I'm at a loss as to what I'm doing wrong here. – Nealbo Jul 29 '22 at 22:13
  • @Nick the psn-api library is written in typescript so the types are included – khierl Jul 29 '22 at 22:16
  • @Nealbo make sure you installed the @types/node – khierl Jul 29 '22 at 22:19
  • Yes. Try this https://stackoverflow.com/questions/50661510/why-doesnt-fs-work-when-imported-as-an-es6-module – Nick Jul 29 '22 at 22:20
  • @types/node is installed (added package.json contents in original post above). And index3.ts updated to use import * as fs from "fs";. then recompiled but now I'm getting "ReferenceError: exports is not defined in ES module scope" – Nealbo Jul 29 '22 at 22:24
  • In tsconfig.json try "module": "es6" – Nick Jul 29 '22 at 22:25
  • you need to configure your tsconfig.json "allowSyntheticDefaultImports": true, "module": "es6" – khierl Jul 29 '22 at 22:27
  • Added "module": "es6", recompiled, then ran and the error. Then added "target": "es6" to tsconfig.json and recompiled with the same error still. – Nealbo Jul 29 '22 at 22:27
  • when enabling "allowSyntheticDefaultImports": true, you can now use import x from "x" – khierl Jul 29 '22 at 22:28
  • @khierl I made the update, recompiled and then "node index3.js" -> still gives the same reference error: exports is not defined in ES scope. tsconfig.json, the script itself and the package.json all updated in my original post to reflect the current situation. – Nealbo Jul 29 '22 at 22:36
  • @Nealbo I did in my local and works fine, I posted a new answer with the `package.json` and `tsconfig.json` – khierl Jul 29 '22 at 22:51
  • Please update your post to show how you're actually running the TS conversion because your package.json has `"type": "module"` so that's good, but you have no npm scripts that do the ts to js covnersion, or anything else that might explain how you're converting your ts code to js code and how you're then running that js. Also, please fix your code blocks and remove all the things that don't actually contribute to the problem (in your post. By all means keep it in your own files of course, but then made sure that what you posted still has the same problem) – Mike 'Pomax' Kamermans Jul 29 '22 at 22:55
  • @Mike'Pomax'Kamermans Updated/cleaned the original post with these details and indicated the current issue. – Nealbo Jul 29 '22 at 23:13
  • You almost certainly want to use the new `node16` or `nodenext` as your `moduleResolution` (see https://www.typescriptlang.org/docs/handbook/esm-node.html) – Mike 'Pomax' Kamermans Jul 30 '22 at 00:47

2 Answers2

1

Try instead of using import, use require:

const fs = require('fs')
const psn = require('psn-api')
type { Trophy } = psn
const { exchangeCodeForAccessToken } = psn
const { exchangeNpssoForCode } = psn
const { getTitleTrophies } = psn
const { getUserTitles } = psn
const { getUserTrophiesEarnedForTitle } = psn
const { makeUniversalSearch } = psn
const { TrophyRarity } = psn

Also, instead of compiling it to node.js, try using this library: https://www.npmjs.com/package/ts-node

Its basicly node.js but for typescript

lolBOT V9.17
  • 141
  • 10
0

I tried this locally and no error

when using node library you need to set "moduleResolution": "node" on your tsconfig.json

index.ts

import fs from 'fs'

package.json

{
  "name": "psn-api-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "tsc index.ts",
    "start": "node index.js"
  },
  "type": "module",
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "psn-api": "^2.7.0"
  },
  "devDependencies": {
    "@types/node": "^18.6.2",
    "typescript": "^4.7.4"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "target": "es2016",
    "module": "es6",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true
  }
}
khierl
  • 605
  • 1
  • 6
  • 16
  • I tried this but still got the error if using "import fs from 'fs'". Reverting it back allows me to compile to js at least, but then running the js with "node index.js" leads back to ReferenceError: exports is not defined in ES module scope – Nealbo Jul 29 '22 at 23:14