@insignia-education/api-sdk-js 0.9.13 → 0.9.18

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 (57) hide show
  1. package/.github/hooks/pre-commit +10 -1
  2. package/.github/workflows/npm-publish-github-packages.yml +6 -5
  3. package/eslint.config.mjs +19 -0
  4. package/index.js +2 -3
  5. package/jest.config.mjs +22 -197
  6. package/package.json +5 -2
  7. package/src/Client.js +18 -22
  8. package/src/api/index.js +6 -18
  9. package/src/api/v1/index.js +35 -42
  10. package/src/index.js +4 -17
  11. package/tests/client.test.js +6 -45
  12. package/tests/integration/api.v1..test.js +92 -0
  13. package/tests/integration/auth.test.js +40 -0
  14. package/tests/integration/cookieJar.js +48 -0
  15. package/tests/integration/loadEnv.js +16 -0
  16. package/coverage/clover.xml +0 -703
  17. package/coverage/coverage-final.json +0 -30
  18. package/coverage/lcov-report/base.css +0 -224
  19. package/coverage/lcov-report/block-navigation.js +0 -87
  20. package/coverage/lcov-report/favicon.png +0 -0
  21. package/coverage/lcov-report/index.html +0 -131
  22. package/coverage/lcov-report/prettify.css +0 -1
  23. package/coverage/lcov-report/prettify.js +0 -2
  24. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  25. package/coverage/lcov-report/sorter.js +0 -210
  26. package/coverage/lcov-report/src/Client.js.html +0 -202
  27. package/coverage/lcov-report/src/api/v1/Accounts.js.html +0 -151
  28. package/coverage/lcov-report/src/api/v1/Auth.js.html +0 -130
  29. package/coverage/lcov-report/src/api/v1/Categories.js.html +0 -121
  30. package/coverage/lcov-report/src/api/v1/Changelogs.js.html +0 -118
  31. package/coverage/lcov-report/src/api/v1/Configs.js.html +0 -121
  32. package/coverage/lcov-report/src/api/v1/ContactForms.js.html +0 -121
  33. package/coverage/lcov-report/src/api/v1/ConversationalTopics.js.html +0 -121
  34. package/coverage/lcov-report/src/api/v1/Countries.js.html +0 -112
  35. package/coverage/lcov-report/src/api/v1/Coupons.js.html +0 -121
  36. package/coverage/lcov-report/src/api/v1/Courses.js.html +0 -328
  37. package/coverage/lcov-report/src/api/v1/Currencies.js.html +0 -115
  38. package/coverage/lcov-report/src/api/v1/Files.js.html +0 -115
  39. package/coverage/lcov-report/src/api/v1/Forums.js.html +0 -157
  40. package/coverage/lcov-report/src/api/v1/Hashes.js.html +0 -118
  41. package/coverage/lcov-report/src/api/v1/Insignias.js.html +0 -121
  42. package/coverage/lcov-report/src/api/v1/Languages.js.html +0 -121
  43. package/coverage/lcov-report/src/api/v1/MailBlacklist.js.html +0 -118
  44. package/coverage/lcov-report/src/api/v1/Organizations.js.html +0 -118
  45. package/coverage/lcov-report/src/api/v1/Quizzes.js.html +0 -181
  46. package/coverage/lcov-report/src/api/v1/ShortLinks.js.html +0 -121
  47. package/coverage/lcov-report/src/api/v1/Surveys.js.html +0 -181
  48. package/coverage/lcov-report/src/api/v1/Tags.js.html +0 -121
  49. package/coverage/lcov-report/src/api/v1/Taxes.js.html +0 -121
  50. package/coverage/lcov-report/src/api/v1/Teacher.js.html +0 -196
  51. package/coverage/lcov-report/src/api/v1/Translations.js.html +0 -121
  52. package/coverage/lcov-report/src/api/v1/UserTypes.js.html +0 -121
  53. package/coverage/lcov-report/src/api/v1/Users.js.html +0 -331
  54. package/coverage/lcov-report/src/api/v1/Zoom.js.html +0 -154
  55. package/coverage/lcov-report/src/api/v1/index.html +0 -521
  56. package/coverage/lcov-report/src/index.html +0 -116
  57. package/coverage/lcov.info +0 -1822
@@ -0,0 +1,92 @@
1
+ import './cookieJar.js';
2
+ import InsigniaApiV1 from '../../src/api/v1/index.js';
3
+
4
+ const api = new InsigniaApiV1(process.env.INSIGNIA_EDUCATION_API_BASE_URL);
5
+ beforeAll(async () => {
6
+ const email = process.env.TEST_EMAIL;
7
+ const password = process.env.TEST_PASSWORD;
8
+ const login = await api.auth.login({ email, password });
9
+ });
10
+
11
+ afterAll(async () => {
12
+ await api.auth.logout();
13
+ });
14
+
15
+ // ─── Read-only endpoints ──────────────────────────────────────────────────────
16
+ describe('Countries', () => {
17
+ test('get() returns a list', async () => {
18
+ api.countries.get()
19
+ .then(response => {
20
+ expect(response["11"]).toBeDefined();
21
+ expect(response["11"]["id"]).toBeDefined();
22
+ expect(response["11"]["cod"]).toBeDefined();
23
+ expect(response["11"]["domain"]).toBeDefined();
24
+ expect(response["11"]["phone_prefix"]).toBeDefined();
25
+ });
26
+ });
27
+ });
28
+
29
+ describe('Currencies', () => {
30
+ test('get() returns a list', async () => {
31
+ api.currencies.get()
32
+ .then(response => {
33
+ expect(response["1"]).toBeDefined();
34
+ expect(response["1"]["id"]).toBeDefined();
35
+ expect(response["1"]["country_id"]).toBeDefined();
36
+ expect(response["1"]["cod"]).toBeDefined();
37
+ expect(response["1"]["title"]).toBeDefined();
38
+ expect(response["1"]["enabled"]).toBeDefined();
39
+ expect(response["1"]["has_double_expression"]).toBeDefined();
40
+ expect(response["1"]["double_expression_by"]).toBeDefined();
41
+ expect(response["1"]["created_at"]).toBeDefined();
42
+ expect(response["1"]["updated_at"]).toBeDefined();
43
+ expect(response["1"]["deleted_at"]).toBeDefined();
44
+ });
45
+ });
46
+
47
+ test('getValues() returns exchange values', async () => {
48
+ const res = await api.currencies.getValues()
49
+ .then(response => {
50
+ expect(response["USD"]).toBeDefined();
51
+ expect(response["USD"]["id"]).toBeDefined();
52
+ expect(response["USD"]["currency_id"]).toBeDefined();
53
+ expect(response["USD"]["value"]).toBeDefined();
54
+ expect(response["USD"]["created_at"]).toBeDefined();
55
+ expect(response["USD"]["updated_at"]).toBeDefined();
56
+ });
57
+ });
58
+ });
59
+
60
+ describe('Languages', () => {
61
+ test('get() returns a list', async () => {
62
+ const res = await api.languages.get()
63
+ .then(response => {
64
+ expect(response["1"]).toBeDefined();
65
+ expect(response["1"]["id"]).toBeDefined();
66
+ expect(response["1"]["iso"]).toBeDefined();
67
+ expect(response["1"]["flag_emoji"]).toBeDefined();
68
+ expect(response["1"]["enabled"]).toBeDefined();
69
+ expect(response["1"]["default"]).toBeDefined();
70
+ expect(response["1"]["created_at"]).toBeDefined();
71
+ expect(response["1"]["updated_at"]).toBeDefined();
72
+ expect(response["1"]["deleted_at"]).toBeDefined();
73
+ });
74
+ });
75
+ });
76
+
77
+
78
+
79
+ describe('Auth', () => {
80
+ test('get() returns a list', async () => {
81
+ const res = await api.auth.login({
82
+ email: process.env.TEST_EMAIL,
83
+ password: process.env.TEST_PASSWORD
84
+ })
85
+ .then(response => {
86
+
87
+ expect(response["success"]).toBeDefined();
88
+ expect(response["success"]).toBe("ok");
89
+ });
90
+ });
91
+ });
92
+
@@ -0,0 +1,40 @@
1
+ import './cookieJar.js';
2
+ import InsigniaApiV1 from '../../src/api/v1/index.js';
3
+
4
+ const api = new InsigniaApiV1(process.env.INSIGNIA_EDUCATION_API_BASE_URL);
5
+
6
+ describe('Auth (integration)', () => {
7
+ test('login returns token metadata and sets cookie', async () => {
8
+ const res = await api.auth.login({
9
+ email: process.env.TEST_EMAIL,
10
+ password: process.env.TEST_PASSWORD,
11
+ });
12
+ const body = res?.response ?? res;
13
+ expect(body.success).toBe('ok');
14
+ });
15
+
16
+ test('auth/user returns the authenticated user', async () => {
17
+ const res = await api.auth.user();
18
+ const body = res?.response ?? res;
19
+ expect(body.email).toBe(process.env.TEST_EMAIL);
20
+ });
21
+
22
+ test('refresh returns new token metadata', async () => {
23
+ const res = await api.auth.refresh();
24
+ const body = res?.response ?? res;
25
+ expect(body.token_type).toBe('bearer');
26
+ expect(body.expires_in).toBeGreaterThan(0);
27
+ });
28
+
29
+ test('logout clears the session', async () => {
30
+ const res = await api.auth.logout();
31
+ const body = res?.response ?? res;
32
+ expect(body.message).toBe('Successfully logged out');
33
+ });
34
+
35
+ test('auth/user returns 401 after logout', async () => {
36
+ const res = await api.auth.user();
37
+ const body = res?.response ?? res;
38
+ expect(res?.status ?? body?.status).toBe(401);
39
+ });
40
+ });
@@ -0,0 +1,48 @@
1
+ // Wraps globalThis.fetch with a simple cookie jar so HTTP-only cookies
2
+ // set by the server are replayed on subsequent requests — mirrors what
3
+ // browsers do automatically but Node.js does not.
4
+
5
+ const jar = new Map(); // origin → { name: value }
6
+
7
+ const _fetch = globalThis.fetch;
8
+
9
+ globalThis.fetch = async function (url, options = {}) {
10
+ const origin = new URL(url).origin;
11
+
12
+ // Inject stored cookies for this origin
13
+ const stored = jar.get(origin);
14
+ if (stored && Object.keys(stored).length > 0) {
15
+ const cookieStr = Object.entries(stored)
16
+ .map(([k, v]) => `${k}=${v}`)
17
+ .join('; ');
18
+ options = { ...options, headers: { ...options.headers, Cookie: cookieStr } };
19
+ }
20
+
21
+ const response = await _fetch(url, options);
22
+
23
+ // Capture Set-Cookie headers (getSetCookie() returns each header separately,
24
+ // avoiding the comma-in-Expires parsing problem)
25
+ const setCookies = response.headers.getSetCookie?.() ??
26
+ [response.headers.get('set-cookie')].filter(Boolean);
27
+
28
+ for (const raw of setCookies) {
29
+ const nameVal = raw.split(';')[0].trim();
30
+ const eq = nameVal.indexOf('=');
31
+ if (eq < 1) continue;
32
+
33
+ const name = nameVal.slice(0, eq).trim();
34
+ const value = nameVal.slice(eq + 1).trim();
35
+ const attrs = raw.toLowerCase();
36
+ const isDeleted = attrs.includes('max-age=0') ||
37
+ attrs.includes('expires=thu, 01 jan 1970');
38
+
39
+ if (!jar.has(origin)) jar.set(origin, {});
40
+ if (isDeleted) {
41
+ delete jar.get(origin)[name];
42
+ } else {
43
+ jar.get(origin)[name] = value;
44
+ }
45
+ }
46
+
47
+ return response;
48
+ };
@@ -0,0 +1,16 @@
1
+ import { readFileSync } from 'fs';
2
+ import { resolve } from 'path';
3
+
4
+ try {
5
+ const content = readFileSync(resolve(process.cwd(), '.env.test'), 'utf8');
6
+ for (const line of content.split('\n')) {
7
+ const trimmed = line.trim();
8
+ if (!trimmed || trimmed.startsWith('#')) continue;
9
+ const eq = trimmed.indexOf('=');
10
+ if (eq > 0) {
11
+ process.env[trimmed.slice(0, eq).trim()] = trimmed.slice(eq + 1).trim();
12
+ }
13
+ }
14
+ } catch {
15
+ // .env.test not found — tests will use existing process.env
16
+ }