@pelygo/janus 0.3.0 → 0.4.0

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.
package/README.md CHANGED
@@ -38,6 +38,34 @@ const janus = createJanusApi({
38
38
  });
39
39
  ```
40
40
 
41
+ ### Read-only mode (default)
42
+
43
+ By default the client is **read-only** — any attempt to create, update, or delete data will throw an error. This prevents accidental writes from AI-generated code or dashboard apps that should only display data.
44
+
45
+ ```typescript
46
+ // Read-only (default) — getAll, query, getById work; create, update, delete throw
47
+ const janus = createJanusApi({ baseUrl: '...' });
48
+
49
+ // Full access — all operations allowed
50
+ const janus = createJanusApi({ baseUrl: '...', allowWrites: true });
51
+ ```
52
+
53
+ Read-only mode allows:
54
+ - All `GET` requests (list, getById, stats, reports, filter options)
55
+ - Query-style `POST` requests (`returns.queryPost`, `legacy.queryProducts`)
56
+ - Authentication (`janus.auth.login`, `janus.auth.verify`)
57
+
58
+ Read-only mode blocks:
59
+ - `POST` create operations (e.g. `products.create`, `orders.create`)
60
+ - `PUT` / `PATCH` update operations (e.g. `clients.update`, `returns.update`)
61
+ - `DELETE` operations (e.g. `products.delete`, `users.delete`)
62
+
63
+ When a blocked operation is attempted, it throws:
64
+ ```
65
+ @pelygo/janus: Write operation blocked (POST /products).
66
+ The client is in read-only mode. To enable writes, set allowWrites: true in createJanusApi options.
67
+ ```
68
+
41
69
  ### Authenticate
42
70
 
43
71
  ```typescript
package/USAGE.md CHANGED
@@ -19,9 +19,26 @@ export const janus = createJanusApi({
19
19
  onUnauthorized: () => {
20
20
  setTimeout(() => { window.location.href = '/SignIn'; }, 100);
21
21
  },
22
+ // allowWrites: true, // uncomment to enable create/update/delete operations
22
23
  });
23
24
  ```
24
25
 
26
+ ## Read-only mode (default)
27
+
28
+ The client is **read-only by default**. All GET requests and query-style POSTs work. Create, update, and delete operations throw an error unless `allowWrites: true` is set.
29
+
30
+ ```js
31
+ // Read-only (default) — safe for dashboards and analytics
32
+ const janus = createJanusApi({ baseUrl: '...' });
33
+
34
+ // Full access — required for apps that create/update/delete data
35
+ const janus = createJanusApi({ baseUrl: '...', allowWrites: true });
36
+ ```
37
+
38
+ **Always allowed** (even in read-only mode): `getAll`, `getById`, `query`, `queryPost`, `getStats`, `getFilterOptions`, `auth.login`, `auth.verify`, all report methods, all CSV exports.
39
+
40
+ **Blocked in read-only mode**: `create`, `update`, `replace`, `delete`, `addItem`, `addComment`, `addStatus`, and all other write operations.
41
+
25
42
  ## Rules
26
43
 
27
44
  1. **Always pass `clientId`** to every query. Get it from `useClient()`:
package/dist/index.d.ts CHANGED
@@ -1897,6 +1897,29 @@ export declare interface JanusApiOptions {
1897
1897
  onLoginSuccess?: (token: string) => void;
1898
1898
  /** Called on login failure */
1899
1899
  onLoginError?: (error: Error) => void;
1900
+ /**
1901
+ * Allow write operations (POST, PUT, PATCH, DELETE).
1902
+ *
1903
+ * By default the client is **read-only** — any attempt to create, update,
1904
+ * or delete data will throw an error. Set this to `true` to enable write
1905
+ * operations.
1906
+ *
1907
+ * Query-style POST endpoints (e.g. `/returns/query`, `/legacy/products/query`)
1908
+ * and authentication endpoints (e.g. `/auth/login`) are always allowed
1909
+ * regardless of this setting.
1910
+ *
1911
+ * @default false
1912
+ *
1913
+ * @example
1914
+ * ```typescript
1915
+ * // Read-only (default) — getAll, query, getById work; create, update, delete throw
1916
+ * const janus = createJanusApi({ baseUrl: '...' });
1917
+ *
1918
+ * // Full access — all operations allowed
1919
+ * const janus = createJanusApi({ baseUrl: '...', allowWrites: true });
1920
+ * ```
1921
+ */
1922
+ allowWrites?: boolean;
1900
1923
  }
1901
1924
 
1902
1925
  /**
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createAuthApi as L } from "@pelygo/auth/core";
2
- function T(t) {
2
+ function P(t) {
3
3
  return {
4
4
  async getAll() {
5
5
  return t.get("/clients");
@@ -95,13 +95,13 @@ function u(t, e) {
95
95
  const n = t.includes("?") ? "&" : "?";
96
96
  return `${t}${n}${r}`;
97
97
  }
98
- function P(t) {
98
+ function b(t) {
99
99
  return t.replace(/[A-Z]/g, (e) => `_${e.toLowerCase()}`);
100
100
  }
101
101
  function F(t) {
102
102
  const e = {};
103
103
  for (const [r, n] of Object.entries(t))
104
- e[P(r)] = n;
104
+ e[b(r)] = n;
105
105
  return e;
106
106
  }
107
107
  function l(t, e) {
@@ -112,7 +112,7 @@ function o(t, e) {
112
112
  throw new Error("clientId is required for this endpoint");
113
113
  return l(t, e);
114
114
  }
115
- function b(t) {
115
+ function x(t) {
116
116
  return {
117
117
  // ── Core returns ─────────────────────────────────────────────
118
118
  async query(e) {
@@ -264,7 +264,7 @@ function b(t) {
264
264
  }
265
265
  };
266
266
  }
267
- function x(t) {
267
+ function N(t) {
268
268
  return {
269
269
  async returnsSummary(e) {
270
270
  const r = u("/reports/returns/summary/", e);
@@ -295,7 +295,7 @@ function x(t) {
295
295
  }
296
296
  };
297
297
  }
298
- function N(t) {
298
+ function q(t) {
299
299
  const { baseUrl: e } = t;
300
300
  async function r(n, s) {
301
301
  const c = await fetch(n, {
@@ -333,7 +333,7 @@ function N(t) {
333
333
  }
334
334
  };
335
335
  }
336
- function z(t) {
336
+ function J(t) {
337
337
  return {
338
338
  async getAll() {
339
339
  return t.get("/couriers");
@@ -394,7 +394,7 @@ function j(t) {
394
394
  }
395
395
  };
396
396
  }
397
- function q(t) {
397
+ function z(t) {
398
398
  return {
399
399
  async getAll() {
400
400
  return t.get("/integrations");
@@ -419,7 +419,7 @@ function q(t) {
419
419
  }
420
420
  };
421
421
  }
422
- function J(t) {
422
+ function D(t) {
423
423
  return {
424
424
  async getAll(e) {
425
425
  const r = l("/users", e);
@@ -448,7 +448,7 @@ function J(t) {
448
448
  }
449
449
  };
450
450
  }
451
- function D(t) {
451
+ function W(t) {
452
452
  return {
453
453
  async createActivity(e) {
454
454
  return t.post("/logs/activity", e);
@@ -516,7 +516,7 @@ function V(t) {
516
516
  }
517
517
  };
518
518
  }
519
- function W(t) {
519
+ function G(t) {
520
520
  return {
521
521
  async getCouriers() {
522
522
  return t.get("/legacy-couriers");
@@ -536,7 +536,7 @@ function W(t) {
536
536
  }
537
537
  };
538
538
  }
539
- function G(t) {
539
+ function K(t) {
540
540
  return {
541
541
  async getAll(e) {
542
542
  const r = o("/products", e);
@@ -556,7 +556,7 @@ function G(t) {
556
556
  }
557
557
  };
558
558
  }
559
- function K(t) {
559
+ function M(t) {
560
560
  return {
561
561
  async getAll(e) {
562
562
  const r = o("/product-categories", e);
@@ -576,7 +576,7 @@ function K(t) {
576
576
  }
577
577
  };
578
578
  }
579
- function M(t) {
579
+ function Q(t) {
580
580
  return {
581
581
  async getAll(e) {
582
582
  const r = o("/stocks", e);
@@ -596,7 +596,7 @@ function M(t) {
596
596
  }
597
597
  };
598
598
  }
599
- function Q(t) {
599
+ function Z(t) {
600
600
  return {
601
601
  async getAll(e) {
602
602
  const r = o("/transactions", e);
@@ -616,7 +616,7 @@ function Q(t) {
616
616
  }
617
617
  };
618
618
  }
619
- function Z(t) {
619
+ function X(t) {
620
620
  return {
621
621
  async getAll(e) {
622
622
  const r = o("/allocations", e);
@@ -633,7 +633,7 @@ function Z(t) {
633
633
  }
634
634
  };
635
635
  }
636
- function X(t) {
636
+ function Y(t) {
637
637
  return {
638
638
  async getAll(e) {
639
639
  const r = o("/locations", e);
@@ -653,7 +653,7 @@ function X(t) {
653
653
  }
654
654
  };
655
655
  }
656
- function Y(t) {
656
+ function ee(t) {
657
657
  return {
658
658
  async getAll(e) {
659
659
  const r = o("/audits", e);
@@ -664,7 +664,7 @@ function Y(t) {
664
664
  }
665
665
  };
666
666
  }
667
- function ee(t) {
667
+ function te(t) {
668
668
  return {
669
669
  // ── ASN CRUD ─────────────────────────────────
670
670
  async getAll(e) {
@@ -731,7 +731,7 @@ function ee(t) {
731
731
  }
732
732
  };
733
733
  }
734
- function te(t) {
734
+ function re(t) {
735
735
  return {
736
736
  async getAll(e) {
737
737
  const r = o("/dispatches", e);
@@ -751,7 +751,7 @@ function te(t) {
751
751
  }
752
752
  };
753
753
  }
754
- function re(t) {
754
+ function ne(t) {
755
755
  return {
756
756
  async getByDispatchId(e) {
757
757
  return t.get(`/consignments/${e}`);
@@ -767,7 +767,7 @@ function re(t) {
767
767
  }
768
768
  };
769
769
  }
770
- function ne(t) {
770
+ function se(t) {
771
771
  return {
772
772
  // ── Invoice CRUD ────────────────────────────────────────────
773
773
  async getAll(e) {
@@ -813,39 +813,63 @@ function ne(t) {
813
813
  }
814
814
  };
815
815
  }
816
- const se = "https://api.janus.pelygo.com";
817
- function oe(t = {}) {
818
- const e = t.baseUrl || se, r = {
816
+ const ce = "https://api.janus.pelygo.com", ue = [
817
+ "/auth/",
818
+ "/returns/query",
819
+ "/legacy/products/query",
820
+ "/legacy/"
821
+ ];
822
+ function oe(t) {
823
+ return ue.some((e) => t.includes(e));
824
+ }
825
+ function ae(t) {
826
+ const e = (r, n) => {
827
+ throw new Error(
828
+ `@pelygo/janus: Write operation blocked (${r.toUpperCase()}${n ? " " + n : ""}). The client is in read-only mode. To enable writes, set allowWrites: true in createJanusApi options:
829
+
830
+ createJanusApi({ baseUrl: '...', allowWrites: true })`
831
+ );
832
+ };
833
+ return {
834
+ ...t,
835
+ post: (r, n, s) => oe(r) ? t.post(r, n, s) : e("POST", r),
836
+ put: (r, n, s) => e("PUT", r),
837
+ patch: (r, n, s) => e("PATCH", r),
838
+ delete: (r, n) => e("DELETE", r)
839
+ };
840
+ }
841
+ function le(t = {}) {
842
+ const e = t.baseUrl || ce, r = {
819
843
  baseUrl: e,
820
844
  authUrl: t.authUrl,
821
845
  onUnauthorized: t.onUnauthorized,
822
846
  onLoginSuccess: t.onLoginSuccess,
823
847
  onLoginError: t.onLoginError
824
- }, n = L(r), s = T(n), c = b(n), a = x(n), y = N({ baseUrl: e }), g = z(n), d = j(n), $ = q(n), m = J(n), f = D(n), v = H(n), h = V({ baseUrl: e }), R = W(n), p = G(n), S = K(n), I = M(n), C = Q(n), A = Z(n), B = X(n), U = Y(n), w = ee(n), k = te(n), _ = re(n), E = ne(n);
848
+ }, n = L(r), s = t.allowWrites ? n : ae(n), c = P(s), a = x(s), y = N(s), d = q({ baseUrl: e }), g = J(s), $ = j(s), m = z(s), f = D(s), p = W(s), v = H(s), h = V({ baseUrl: e }), R = G(s), S = K(s), I = M(s), C = Q(s), A = Z(s), w = X(s), U = Y(s), B = ee(s), k = te(s), _ = re(s), E = ne(s), T = se(s);
825
849
  return {
826
- clients: s,
827
- returns: c,
828
- reports: a,
829
- helpers: y,
850
+ clients: c,
851
+ returns: a,
852
+ reports: y,
853
+ helpers: d,
830
854
  couriers: g,
831
- orders: d,
832
- integrations: $,
833
- users: m,
834
- logs: f,
855
+ orders: $,
856
+ integrations: m,
857
+ users: f,
858
+ logs: p,
835
859
  tasks: v,
836
860
  customer: h,
837
861
  legacy: R,
838
- products: p,
839
- productCategories: S,
840
- stocks: I,
841
- stockTransactions: C,
842
- stockAllocations: A,
843
- locations: B,
844
- audits: U,
845
- asns: w,
846
- dispatches: k,
847
- consignments: _,
848
- invoices: E,
862
+ products: S,
863
+ productCategories: I,
864
+ stocks: C,
865
+ stockTransactions: A,
866
+ stockAllocations: w,
867
+ locations: U,
868
+ audits: B,
869
+ asns: k,
870
+ dispatches: _,
871
+ consignments: E,
872
+ invoices: T,
849
873
  auth: n
850
874
  };
851
875
  }
@@ -856,44 +880,44 @@ class i extends Error {
856
880
  s.captureStackTrace && s.captureStackTrace(this, i);
857
881
  }
858
882
  }
859
- class ce extends i {
883
+ class ie extends i {
860
884
  constructor(e = "Unauthorized", r) {
861
885
  super(e, 401, r), this.name = "UnauthorizedError";
862
886
  }
863
887
  }
864
- class ae extends i {
888
+ class de extends i {
865
889
  constructor(e = "Forbidden", r) {
866
890
  super(e, 403, r), this.name = "ForbiddenError";
867
891
  }
868
892
  }
869
- class ie extends i {
893
+ class ge extends i {
870
894
  constructor(e = "Not Found", r) {
871
895
  super(e, 404, r), this.name = "NotFoundError";
872
896
  }
873
897
  }
874
- class ye extends i {
898
+ class $e extends i {
875
899
  constructor(e = "Validation Error", r, n) {
876
900
  super(e, 400, n), this.name = "ValidationError", this.errors = r;
877
901
  }
878
902
  }
879
- function le(t) {
903
+ function me(t) {
880
904
  return t instanceof i;
881
905
  }
882
- function ge(t) {
883
- return t instanceof ce;
906
+ function fe(t) {
907
+ return t instanceof ie;
884
908
  }
885
909
  export {
886
- se as DEFAULT_JANUS_URL,
887
- ae as ForbiddenError,
910
+ ce as DEFAULT_JANUS_URL,
911
+ de as ForbiddenError,
888
912
  i as JanusApiError,
889
- ie as NotFoundError,
890
- ce as UnauthorizedError,
891
- ye as ValidationError,
913
+ ge as NotFoundError,
914
+ ie as UnauthorizedError,
915
+ $e as ValidationError,
892
916
  o as buildClientScopedPaginatedUrl,
893
917
  l as buildPaginatedUrl,
894
918
  O as buildQueryString,
895
919
  u as buildUrl,
896
- oe as createJanusApi,
897
- le as isJanusApiError,
898
- ge as isUnauthorizedError
920
+ le as createJanusApi,
921
+ me as isJanusApiError,
922
+ fe as isUnauthorizedError
899
923
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pelygo/janus",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "TypeScript API client for JANUS endpoints with full type safety",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",