@pelygo/janus 0.3.0 → 0.5.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,29 +95,31 @@ 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
- function F(t) {
101
+ function D(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) {
108
- return e ? u(t, F(e)) : t;
108
+ if (!e) return t;
109
+ const r = { pageNumber: 1, ...e };
110
+ return u(t, D(r));
109
111
  }
110
112
  function o(t, e) {
111
113
  if (e.clientId == null)
112
114
  throw new Error("clientId is required for this endpoint");
113
115
  return l(t, e);
114
116
  }
115
- function b(t) {
117
+ function F(t) {
116
118
  return {
117
119
  // ── Core returns ─────────────────────────────────────────────
118
120
  async query(e) {
119
- const r = u("/returns/", e);
120
- return t.get(r);
121
+ const r = e && { page: 1, ...e }, n = u("/returns/", r);
122
+ return t.get(n);
121
123
  },
122
124
  async queryPost(e) {
123
125
  return t.post("/returns/query", e);
@@ -264,30 +266,30 @@ function b(t) {
264
266
  }
265
267
  };
266
268
  }
267
- function x(t) {
269
+ function N(t) {
268
270
  return {
269
271
  async returnsSummary(e) {
270
- const r = u("/reports/returns/summary/", e);
271
- return t.get(r);
272
+ const r = e && { page: 1, ...e }, n = u("/reports/returns/summary/", r);
273
+ return t.get(n);
272
274
  },
273
275
  async returnsSummaryCsv(e) {
274
- const r = { ...e, csv: !0, pageSize: 1e5 }, n = u("/reports/returns/summary/", r);
276
+ const r = { ...e, csv: !0, pageSize: 1e5, page: 1 }, n = u("/reports/returns/summary/", r);
275
277
  return t.get(n);
276
278
  },
277
279
  async returnsReasons(e) {
278
- const r = u("/reports/returns/reasons/", e);
279
- return t.get(r);
280
+ const r = e && { page: 1, ...e }, n = u("/reports/returns/reasons/", r);
281
+ return t.get(n);
280
282
  },
281
283
  async returnsReasonsCsv(e) {
282
- const r = { ...e, csv: !0, pageSize: 1e5 }, n = u("/reports/returns/reasons/", r);
284
+ const r = { ...e, csv: !0, pageSize: 1e5, page: 1 }, n = u("/reports/returns/reasons/", r);
283
285
  return t.get(n);
284
286
  },
285
287
  async returnsOverview(e) {
286
- const r = u("/reports/returns/overview/", e);
287
- return t.get(r);
288
+ const r = e && { page: 1, ...e }, n = u("/reports/returns/overview/", r);
289
+ return t.get(n);
288
290
  },
289
291
  async returnsOverviewCsv(e) {
290
- const r = { ...e, csv: !0, pageSize: 1e5 }, n = u("/reports/returns/overview/", r);
292
+ const r = { ...e, csv: !0, pageSize: 1e5, page: 1 }, n = u("/reports/returns/overview/", r);
291
293
  return t.get(n);
292
294
  },
293
295
  async returnsStats(e) {
@@ -295,7 +297,7 @@ function x(t) {
295
297
  }
296
298
  };
297
299
  }
298
- function N(t) {
300
+ function x(t) {
299
301
  const { baseUrl: e } = t;
300
302
  async function r(n, s) {
301
303
  const c = await fetch(n, {
@@ -333,7 +335,7 @@ function N(t) {
333
335
  }
334
336
  };
335
337
  }
336
- function z(t) {
338
+ function q(t) {
337
339
  return {
338
340
  async getAll() {
339
341
  return t.get("/couriers");
@@ -361,19 +363,19 @@ function z(t) {
361
363
  }
362
364
  };
363
365
  }
364
- function j(t) {
366
+ function J(t) {
365
367
  return {
366
368
  async getAll(e) {
367
- const r = u("/orders", e);
368
- return t.get(r);
369
+ const r = e && { pageNumber: 1, ...e }, n = u("/orders", r);
370
+ return t.get(n);
369
371
  },
370
372
  async getStats(e) {
371
373
  const r = u("/orders/stats", e);
372
374
  return t.get(r);
373
375
  },
374
376
  async getReturns(e) {
375
- const r = u("/orders/returns", e);
376
- return t.get(r);
377
+ const r = e && { pageNumber: 1, ...e }, n = u("/orders/returns", r);
378
+ return t.get(n);
377
379
  },
378
380
  async getByRef(e, r) {
379
381
  const n = u(`/orders/${encodeURIComponent(e)}`, r != null ? { clientId: r } : void 0);
@@ -394,7 +396,7 @@ function j(t) {
394
396
  }
395
397
  };
396
398
  }
397
- function q(t) {
399
+ function j(t) {
398
400
  return {
399
401
  async getAll() {
400
402
  return t.get("/integrations");
@@ -419,7 +421,7 @@ function q(t) {
419
421
  }
420
422
  };
421
423
  }
422
- function J(t) {
424
+ function z(t) {
423
425
  return {
424
426
  async getAll(e) {
425
427
  const r = l("/users", e);
@@ -448,7 +450,7 @@ function J(t) {
448
450
  }
449
451
  };
450
452
  }
451
- function D(t) {
453
+ function W(t) {
452
454
  return {
453
455
  async createActivity(e) {
454
456
  return t.post("/logs/activity", e);
@@ -516,7 +518,7 @@ function V(t) {
516
518
  }
517
519
  };
518
520
  }
519
- function W(t) {
521
+ function G(t) {
520
522
  return {
521
523
  async getCouriers() {
522
524
  return t.get("/legacy-couriers");
@@ -536,7 +538,7 @@ function W(t) {
536
538
  }
537
539
  };
538
540
  }
539
- function G(t) {
541
+ function K(t) {
540
542
  return {
541
543
  async getAll(e) {
542
544
  const r = o("/products", e);
@@ -556,7 +558,7 @@ function G(t) {
556
558
  }
557
559
  };
558
560
  }
559
- function K(t) {
561
+ function M(t) {
560
562
  return {
561
563
  async getAll(e) {
562
564
  const r = o("/product-categories", e);
@@ -576,7 +578,7 @@ function K(t) {
576
578
  }
577
579
  };
578
580
  }
579
- function M(t) {
581
+ function Q(t) {
580
582
  return {
581
583
  async getAll(e) {
582
584
  const r = o("/stocks", e);
@@ -596,7 +598,7 @@ function M(t) {
596
598
  }
597
599
  };
598
600
  }
599
- function Q(t) {
601
+ function Z(t) {
600
602
  return {
601
603
  async getAll(e) {
602
604
  const r = o("/transactions", e);
@@ -616,7 +618,7 @@ function Q(t) {
616
618
  }
617
619
  };
618
620
  }
619
- function Z(t) {
621
+ function X(t) {
620
622
  return {
621
623
  async getAll(e) {
622
624
  const r = o("/allocations", e);
@@ -633,7 +635,7 @@ function Z(t) {
633
635
  }
634
636
  };
635
637
  }
636
- function X(t) {
638
+ function Y(t) {
637
639
  return {
638
640
  async getAll(e) {
639
641
  const r = o("/locations", e);
@@ -653,7 +655,7 @@ function X(t) {
653
655
  }
654
656
  };
655
657
  }
656
- function Y(t) {
658
+ function ee(t) {
657
659
  return {
658
660
  async getAll(e) {
659
661
  const r = o("/audits", e);
@@ -664,7 +666,7 @@ function Y(t) {
664
666
  }
665
667
  };
666
668
  }
667
- function ee(t) {
669
+ function te(t) {
668
670
  return {
669
671
  // ── ASN CRUD ─────────────────────────────────
670
672
  async getAll(e) {
@@ -731,7 +733,7 @@ function ee(t) {
731
733
  }
732
734
  };
733
735
  }
734
- function te(t) {
736
+ function re(t) {
735
737
  return {
736
738
  async getAll(e) {
737
739
  const r = o("/dispatches", e);
@@ -751,7 +753,7 @@ function te(t) {
751
753
  }
752
754
  };
753
755
  }
754
- function re(t) {
756
+ function ne(t) {
755
757
  return {
756
758
  async getByDispatchId(e) {
757
759
  return t.get(`/consignments/${e}`);
@@ -767,7 +769,7 @@ function re(t) {
767
769
  }
768
770
  };
769
771
  }
770
- function ne(t) {
772
+ function se(t) {
771
773
  return {
772
774
  // ── Invoice CRUD ────────────────────────────────────────────
773
775
  async getAll(e) {
@@ -813,39 +815,63 @@ function ne(t) {
813
815
  }
814
816
  };
815
817
  }
816
- const se = "https://api.janus.pelygo.com";
817
- function oe(t = {}) {
818
- const e = t.baseUrl || se, r = {
818
+ const ce = "https://api.janus.pelygo.com", ue = [
819
+ "/auth/",
820
+ "/returns/query",
821
+ "/legacy/products/query",
822
+ "/legacy/"
823
+ ];
824
+ function oe(t) {
825
+ return ue.some((e) => t.includes(e));
826
+ }
827
+ function ae(t) {
828
+ const e = (r, n) => {
829
+ throw new Error(
830
+ `@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:
831
+
832
+ createJanusApi({ baseUrl: '...', allowWrites: true })`
833
+ );
834
+ };
835
+ return {
836
+ ...t,
837
+ post: (r, n, s) => oe(r) ? t.post(r, n, s) : e("POST", r),
838
+ put: (r, n, s) => e("PUT", r),
839
+ patch: (r, n, s) => e("PATCH", r),
840
+ delete: (r, n) => e("DELETE", r)
841
+ };
842
+ }
843
+ function le(t = {}) {
844
+ const e = t.baseUrl || ce, r = {
819
845
  baseUrl: e,
820
846
  authUrl: t.authUrl,
821
847
  onUnauthorized: t.onUnauthorized,
822
848
  onLoginSuccess: t.onLoginSuccess,
823
849
  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);
850
+ }, n = L(r), s = t.allowWrites ? n : ae(n), c = P(s), a = F(s), y = N(s), g = x({ baseUrl: e }), d = q(s), $ = J(s), m = j(s), p = z(s), h = W(s), v = H(s), f = V({ baseUrl: e }), R = G(s), S = K(s), I = M(s), C = Q(s), w = Z(s), A = X(s), U = Y(s), B = ee(s), k = te(s), _ = re(s), E = ne(s), T = se(s);
825
851
  return {
826
- clients: s,
827
- returns: c,
828
- reports: a,
829
- helpers: y,
830
- couriers: g,
831
- orders: d,
832
- integrations: $,
833
- users: m,
834
- logs: f,
852
+ clients: c,
853
+ returns: a,
854
+ reports: y,
855
+ helpers: g,
856
+ couriers: d,
857
+ orders: $,
858
+ integrations: m,
859
+ users: p,
860
+ logs: h,
835
861
  tasks: v,
836
- customer: h,
862
+ customer: f,
837
863
  legacy: R,
838
- products: p,
839
- productCategories: S,
840
- stocks: I,
841
- stockTransactions: C,
864
+ products: S,
865
+ productCategories: I,
866
+ stocks: C,
867
+ stockTransactions: w,
842
868
  stockAllocations: A,
843
- locations: B,
844
- audits: U,
845
- asns: w,
846
- dispatches: k,
847
- consignments: _,
848
- invoices: E,
869
+ locations: U,
870
+ audits: B,
871
+ asns: k,
872
+ dispatches: _,
873
+ consignments: E,
874
+ invoices: T,
849
875
  auth: n
850
876
  };
851
877
  }
@@ -856,44 +882,44 @@ class i extends Error {
856
882
  s.captureStackTrace && s.captureStackTrace(this, i);
857
883
  }
858
884
  }
859
- class ce extends i {
885
+ class ie extends i {
860
886
  constructor(e = "Unauthorized", r) {
861
887
  super(e, 401, r), this.name = "UnauthorizedError";
862
888
  }
863
889
  }
864
- class ae extends i {
890
+ class ge extends i {
865
891
  constructor(e = "Forbidden", r) {
866
892
  super(e, 403, r), this.name = "ForbiddenError";
867
893
  }
868
894
  }
869
- class ie extends i {
895
+ class de extends i {
870
896
  constructor(e = "Not Found", r) {
871
897
  super(e, 404, r), this.name = "NotFoundError";
872
898
  }
873
899
  }
874
- class ye extends i {
900
+ class $e extends i {
875
901
  constructor(e = "Validation Error", r, n) {
876
902
  super(e, 400, n), this.name = "ValidationError", this.errors = r;
877
903
  }
878
904
  }
879
- function le(t) {
905
+ function me(t) {
880
906
  return t instanceof i;
881
907
  }
882
- function ge(t) {
883
- return t instanceof ce;
908
+ function pe(t) {
909
+ return t instanceof ie;
884
910
  }
885
911
  export {
886
- se as DEFAULT_JANUS_URL,
887
- ae as ForbiddenError,
912
+ ce as DEFAULT_JANUS_URL,
913
+ ge as ForbiddenError,
888
914
  i as JanusApiError,
889
- ie as NotFoundError,
890
- ce as UnauthorizedError,
891
- ye as ValidationError,
915
+ de as NotFoundError,
916
+ ie as UnauthorizedError,
917
+ $e as ValidationError,
892
918
  o as buildClientScopedPaginatedUrl,
893
919
  l as buildPaginatedUrl,
894
920
  O as buildQueryString,
895
921
  u as buildUrl,
896
- oe as createJanusApi,
897
- le as isJanusApiError,
898
- ge as isUnauthorizedError
922
+ le as createJanusApi,
923
+ me as isJanusApiError,
924
+ pe as isUnauthorizedError
899
925
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pelygo/janus",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "TypeScript API client for JANUS endpoints with full type safety",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",