Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,8 @@ jobs:
- name: Install dependencies
run: pnpm install

- name: Run tests
- name: Run build
run: pnpm build

- name: Run coverage
run: pnpm coverage
27 changes: 27 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# AGENTS

## Fast facts
- Package manager is `pnpm` (lockfile + CI use `pnpm`); use `pnpm install` and `pnpm <script>`.
- This is a single-package ESM TypeScript library (`"type": "module"`), not a monorepo.
- Public entrypoint is `src/index.ts`, default export target is `src/client.ts` (`NetsuiteApiClient`).

## Verified commands
- Build: `pnpm build` (runs `tsc --build --clean && tsc`, outputs to `dist/`).
- Tests: `pnpm test` (Vitest).
- Coverage (CI command): `pnpm coverage`.
- Single test file: `pnpm test -- test/request.test.ts`.
- Single test case: `pnpm test -- test/request.test.ts -t "should work with base_url"`.

## Test and env gotchas
- Tests are integration-heavy, not unit-only: they call real NetSuite endpoints.
- Required env vars are loaded from `.env` via `dotenv/config`; copy `.env.sample` keys exactly.
- `test/request.test.ts` creates and then deletes a customer record; avoid running against sensitive production data.
- CI injects NetSuite secrets and runs coverage on pull requests (`.github/workflows/node.js.yml`).
- Vitest timeout is `20000` ms (`vitest.config.ts`), so network tests are expected.

## Code behavior that is easy to miss
- URL construction defaults to `https://{realm}.suitetalk.api.netsuite.com/services/rest/{path}`.
- `base_url` overrides realm-host construction and is sanitized to remove trailing slash.
- `path` is sanitized to remove one leading slash; `restletUrl` bypasses normal URL construction entirely.
- `request()` parses JSON response bodies and wraps `got` `HTTPError` as `NetsuiteError` with NetSuite detail text when possible.
- `query()` enforces `limit <= 1000` and strips tabs/newlines before sending SuiteQL.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
"homepage": "https://github.com/julbrs/netsuite-api-client#readme",
"bugs": "https://github.com/julbrs/netsuite-api-client/issues",
"exports": {
".": "./dist/index.js"
".": "./dist/src/index.js"
},
"types": "dist/index.d.ts",
"types": "dist/src/index.d.ts",
"scripts": {
"build": "tsc --build --clean && tsc",
"test": "vitest",
"coverage": "vitest --coverage",
"prepublishOnly": "yarn build"
"prepublishOnly": "pnpm build"
},
"devDependencies": {
"@tsconfig/node20": "^20.1.4",
Expand Down
13 changes: 6 additions & 7 deletions test/request.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "dotenv/config";
import NetsuiteApiClient from "../src/client.js";
import { describe, expect, test, beforeAll, afterAll, it } from "vitest";
import { describe, expect, beforeAll, it } from "vitest";

describe("Test request method", () => {
let client: NetsuiteApiClient;
Expand All @@ -14,7 +14,6 @@ describe("Test request method", () => {
process.env.token_secret == undefined ||
process.env.realm == undefined ||
process.env.base_url == undefined
// || process.env.restlet_url == undefined
) {
throw new Error("Please create a `.env` file based on `.env.sample`");
}
Expand Down Expand Up @@ -142,7 +141,7 @@ describe("Test request method", () => {
await expect(() =>
client.request({
path: "record/v1/bad-path",
})
}),
).rejects.toThrowError("Record type 'bad-path' does not exist");
});

Expand All @@ -151,9 +150,9 @@ describe("Test request method", () => {
await expect(() =>
client.request({
path: "record/v1/customer/-1",
})
}),
).rejects.toThrowError(
"The record instance does not exist. Provide a valid record instance ID."
"The record instance does not exist. Provide a valid record instance ID.",
);
});

Expand All @@ -164,7 +163,7 @@ describe("Test request method", () => {
method: "post",
path: "record/v1/customer",
body: "bad body",
})
}),
).rejects.toThrowError("Invalid content in the request body");
});

Expand All @@ -175,7 +174,7 @@ describe("Test request method", () => {
method: "post",
path: "record/v1/customer",
body: JSON.stringify({}),
})
}),
).rejects.toThrowError("Error while accessing a resource. Please enter value(s) for: ");
});
});
9 changes: 6 additions & 3 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
"extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"declaration": true,
"outDir": "./dist"
},
"include": ["src"]
"rootDir": "./",
"outDir": "./dist",
"paths": {
"@/*": ["./src/*"]
}
}
}
Loading