@gelabs/ovr 0.4.2 → 0.4.3

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.
@@ -1,16 +1,25 @@
1
1
  /**
2
2
  * Fixed-window rate limiting backed by Redis. Used to throttle admin login
3
3
  * attempts (per username/IP) before the expensive argon2 verify runs.
4
+ *
5
+ * Toggle: set `EOVR_RATE_LIMIT_DISABLED` to a truthy value (`1`/`true`/`yes`/`on`)
6
+ * to bypass throttling entirely — every call is allowed and Redis is never
7
+ * touched. Intended for staging/QA where repeated login attempts must not lock
8
+ * you out. Leave it unset (the default) to keep throttling on in production.
4
9
  */
5
10
 
6
11
  interface RateLimitResult {
7
12
  allowed: boolean;
8
13
  remaining: number;
9
14
  }
15
+ /** Whether rate limiting is switched off via `EOVR_RATE_LIMIT_DISABLED`. */
16
+ declare function isRateLimitDisabled(): boolean;
10
17
  /**
11
18
  * Increment a counter for `key`; the first hit in a window sets its TTL. Returns
12
- * `allowed: false` once more than `max` hits occur within `windowSeconds`.
19
+ * `allowed: false` once more than `max` hits occur within `windowSeconds`. When
20
+ * `EOVR_RATE_LIMIT_DISABLED` is truthy this short-circuits to always-allowed and
21
+ * never touches Redis.
13
22
  */
14
23
  declare function rateLimit(key: string, max: number, windowSeconds: number): Promise<RateLimitResult>;
15
24
 
16
- export { type RateLimitResult, rateLimit };
25
+ export { type RateLimitResult, isRateLimitDisabled, rateLimit };
@@ -1,2 +1,2 @@
1
- export { rateLimit } from './chunk-77ULDXQX.js';
1
+ export { isRateLimitDisabled, rateLimit } from './chunk-6ZJSEM4Y.js';
2
2
  import './chunk-ASFB24ZY.js';
package/dist/auth.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { getRedis } from './auth-redis.js';
2
2
  export { SESSION_COOKIE, SessionData, cookieSecure, createSession, destroySession, getSession } from './auth-session.js';
3
- export { RateLimitResult, rateLimit } from './auth-rate-limit.js';
3
+ export { RateLimitResult, isRateLimitDisabled, rateLimit } from './auth-rate-limit.js';
4
4
  export { ADMIN_COOKIE, Auth, AuthDeps, createAuth } from './auth-auth.js';
5
5
  import 'ioredis';
6
6
  import './schema-CdsFQxIg.js';
package/dist/auth.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { ADMIN_COOKIE, createAuth } from './chunk-AJ2RZTVX.js';
2
- export { rateLimit } from './chunk-77ULDXQX.js';
2
+ export { isRateLimitDisabled, rateLimit } from './chunk-6ZJSEM4Y.js';
3
3
  export { SESSION_COOKIE, cookieSecure, createSession, destroySession, getSession } from './chunk-KIKDXRM5.js';
4
4
  export { getRedis } from './chunk-ASFB24ZY.js';
@@ -1,7 +1,12 @@
1
1
  import { getRedis } from './chunk-ASFB24ZY.js';
2
2
  import 'server-only';
3
3
 
4
+ function isRateLimitDisabled() {
5
+ const v = process.env.EOVR_RATE_LIMIT_DISABLED?.trim().toLowerCase();
6
+ return v === "1" || v === "true" || v === "yes" || v === "on";
7
+ }
4
8
  async function rateLimit(key, max, windowSeconds) {
9
+ if (isRateLimitDisabled()) return { allowed: true, remaining: max };
5
10
  const redis = getRedis();
6
11
  const k = `eovr:rl:${key}`;
7
12
  const count = await redis.incr(k);
@@ -9,4 +14,4 @@ async function rateLimit(key, max, windowSeconds) {
9
14
  return { allowed: count <= max, remaining: Math.max(0, max - count) };
10
15
  }
11
16
 
12
- export { rateLimit };
17
+ export { isRateLimitDisabled, rateLimit };
@@ -242,7 +242,7 @@ const config = {
242
242
  "value": "prisma-client-js"
243
243
  },
244
244
  "output": {
245
- "value": "/Volumes/satechi/Mac-Documents/GELABS/gelabs-ovr/packages/ovr-data/src/generated/client",
245
+ "value": "/private/tmp/claude-501/-Volumes-satechi-Mac-Documents-GELABS/e90bff27-fc99-4707-8f39-f7ce029d695f/scratchpad/gelabs-ovr-pub/packages/ovr-data/src/generated/client",
246
246
  "fromEnvVar": null
247
247
  },
248
248
  "config": {
@@ -260,7 +260,7 @@ const config = {
260
260
  }
261
261
  ],
262
262
  "previewFeatures": [],
263
- "sourceFilePath": "/Volumes/satechi/Mac-Documents/GELABS/gelabs-ovr/packages/ovr-data/prisma/schema.prisma",
263
+ "sourceFilePath": "/private/tmp/claude-501/-Volumes-satechi-Mac-Documents-GELABS/e90bff27-fc99-4707-8f39-f7ce029d695f/scratchpad/gelabs-ovr-pub/packages/ovr-data/prisma/schema.prisma",
264
264
  "isCustomOutput": true
265
265
  },
266
266
  "relativeEnvPaths": {
@@ -243,7 +243,7 @@ const config = {
243
243
  "value": "prisma-client-js"
244
244
  },
245
245
  "output": {
246
- "value": "/Volumes/satechi/Mac-Documents/GELABS/gelabs-ovr/packages/ovr-data/src/generated/client",
246
+ "value": "/private/tmp/claude-501/-Volumes-satechi-Mac-Documents-GELABS/e90bff27-fc99-4707-8f39-f7ce029d695f/scratchpad/gelabs-ovr-pub/packages/ovr-data/src/generated/client",
247
247
  "fromEnvVar": null
248
248
  },
249
249
  "config": {
@@ -261,7 +261,7 @@ const config = {
261
261
  }
262
262
  ],
263
263
  "previewFeatures": [],
264
- "sourceFilePath": "/Volumes/satechi/Mac-Documents/GELABS/gelabs-ovr/packages/ovr-data/prisma/schema.prisma",
264
+ "sourceFilePath": "/private/tmp/claude-501/-Volumes-satechi-Mac-Documents-GELABS/e90bff27-fc99-4707-8f39-f7ce029d695f/scratchpad/gelabs-ovr-pub/packages/ovr-data/prisma/schema.prisma",
265
265
  "isCustomOutput": true
266
266
  },
267
267
  "relativeEnvPaths": {
@@ -242,7 +242,7 @@ const config = {
242
242
  "value": "prisma-client-js"
243
243
  },
244
244
  "output": {
245
- "value": "/Volumes/satechi/Mac-Documents/GELABS/gelabs-ovr/packages/ovr-data/src/generated/client",
245
+ "value": "/private/tmp/claude-501/-Volumes-satechi-Mac-Documents-GELABS/e90bff27-fc99-4707-8f39-f7ce029d695f/scratchpad/gelabs-ovr-pub/packages/ovr-data/src/generated/client",
246
246
  "fromEnvVar": null
247
247
  },
248
248
  "config": {
@@ -260,7 +260,7 @@ const config = {
260
260
  }
261
261
  ],
262
262
  "previewFeatures": [],
263
- "sourceFilePath": "/Volumes/satechi/Mac-Documents/GELABS/gelabs-ovr/packages/ovr-data/prisma/schema.prisma",
263
+ "sourceFilePath": "/private/tmp/claude-501/-Volumes-satechi-Mac-Documents-GELABS/e90bff27-fc99-4707-8f39-f7ce029d695f/scratchpad/gelabs-ovr-pub/packages/ovr-data/prisma/schema.prisma",
264
264
  "isCustomOutput": true
265
265
  },
266
266
  "relativeEnvPaths": {
@@ -3,8 +3,8 @@ import { Card, CardContent } from '../chunk-SETIN6XP.js';
3
3
  import { usePagination, Pagination } from '../chunk-6YFZLXFP.js';
4
4
  import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
5
5
  import { Badge } from '../chunk-55FQP2DO.js';
6
- import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
7
6
  import { Label } from '../chunk-XQTVSNHC.js';
7
+ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
8
8
  import { Input } from '../chunk-K3KIBHJF.js';
9
9
  import { Button } from '../chunk-I4WDVYHX.js';
10
10
  import { useCopy, useOvrConfig } from '../chunk-TJSNVTVB.js';
@@ -150,15 +150,14 @@ function NewAccountDialog({
150
150
  onCreated
151
151
  }) {
152
152
  const t = useCopy().admin.accountsPage;
153
- const assignableRoles = roles.filter((r) => r.name !== "SUPER_ADMIN");
154
- const defaultRole = assignableRoles.find((r) => r.name === "ENFORCER")?.name ?? assignableRoles[0]?.name ?? "";
153
+ const defaultRole = roles.find((r) => r.name === "ENFORCER")?.name ?? roles[0]?.name ?? "";
155
154
  const [open, setOpen] = React.useState(false);
156
155
  const [username, setUsername] = React.useState("");
157
156
  const [password, setPassword] = React.useState("");
158
157
  const [role, setRole] = React.useState(defaultRole);
159
158
  const [officerId, setOfficerId] = React.useState("");
160
159
  const [submitting, setSubmitting] = React.useState(false);
161
- const selectedRole = assignableRoles.find((r) => r.name === role);
160
+ const selectedRole = roles.find((r) => r.name === role);
162
161
  const showOfficer = hasPermission(selectedRole?.permissions, "tickets:create");
163
162
  function reset() {
164
163
  setUsername("");
@@ -238,7 +237,7 @@ function NewAccountDialog({
238
237
  value: role,
239
238
  onChange: (e) => setRole(e.target.value),
240
239
  className: fieldClass,
241
- children: assignableRoles.map((r) => /* @__PURE__ */ jsx("option", { value: r.name, children: r.label }, r.name))
240
+ children: roles.map((r) => /* @__PURE__ */ jsx("option", { value: r.name, children: r.label }, r.name))
242
241
  }
243
242
  )
244
243
  ] }),
@@ -358,8 +357,6 @@ function EditAccountDialog({
358
357
  const [role, setRole] = React.useState(user.role);
359
358
  const [officerId, setOfficerId] = React.useState(user.officerId ?? "");
360
359
  const [submitting, setSubmitting] = React.useState(false);
361
- const isSuperAdmin = user.role === "SUPER_ADMIN";
362
- const assignableRoles = roles.filter((r) => r.name !== "SUPER_ADMIN");
363
360
  const selectedRole = roles.find((r) => r.name === role);
364
361
  const showOfficer = hasPermission(selectedRole?.permissions, "tickets:create");
365
362
  async function submit(e) {
@@ -433,8 +430,7 @@ function EditAccountDialog({
433
430
  value: role,
434
431
  onChange: (e) => setRole(e.target.value),
435
432
  className: fieldClass,
436
- disabled: isSuperAdmin,
437
- children: isSuperAdmin ? /* @__PURE__ */ jsx("option", { value: user.role, children: user.roleLabel ?? user.role }) : assignableRoles.map((r) => /* @__PURE__ */ jsx("option", { value: r.name, children: r.label }, r.name))
433
+ children: roles.map((r) => /* @__PURE__ */ jsx("option", { value: r.name, children: r.label }, r.name))
438
434
  }
439
435
  )
440
436
  ] }),
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from '../chunk-V7VQVDWS.js';
3
2
  import { Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, SheetFooter } from '../chunk-3YKVH4Y7.js';
4
- import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
3
+ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator } from '../chunk-V7VQVDWS.js';
5
4
  import { Label } from '../chunk-XQTVSNHC.js';
5
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
6
6
  import { Input } from '../chunk-K3KIBHJF.js';
7
7
  import { Button } from '../chunk-I4WDVYHX.js';
8
8
  import { useCopy } from '../chunk-TJSNVTVB.js';
@@ -12,8 +12,8 @@ import '../chunk-BVI5XDDA.js';
12
12
  import { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../chunk-SETIN6XP.js';
13
13
  import '../chunk-OWCGEEAZ.js';
14
14
  import '../chunk-55FQP2DO.js';
15
- import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
16
15
  import { Label } from '../chunk-XQTVSNHC.js';
16
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
17
17
  import { Input } from '../chunk-K3KIBHJF.js';
18
18
  import { Button } from '../chunk-I4WDVYHX.js';
19
19
  import { useFormatters, useOvrConfig } from '../chunk-TJSNVTVB.js';
@@ -2,8 +2,8 @@
2
2
  import { Card, CardContent } from '../chunk-SETIN6XP.js';
3
3
  import { usePagination, Pagination } from '../chunk-6YFZLXFP.js';
4
4
  import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
5
- import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
6
5
  import { Label } from '../chunk-XQTVSNHC.js';
6
+ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
7
7
  import { Input } from '../chunk-K3KIBHJF.js';
8
8
  import { Button } from '../chunk-I4WDVYHX.js';
9
9
  import { useCopy } from '../chunk-TJSNVTVB.js';
@@ -2,8 +2,8 @@
2
2
  import { Checkbox } from '../chunk-BBQBKQA4.js';
3
3
  import { Card, CardContent } from '../chunk-SETIN6XP.js';
4
4
  import { Badge } from '../chunk-55FQP2DO.js';
5
- import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
6
5
  import { Label } from '../chunk-XQTVSNHC.js';
6
+ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
7
7
  import { Input } from '../chunk-K3KIBHJF.js';
8
8
  import { Button } from '../chunk-I4WDVYHX.js';
9
9
  import { useCopy } from '../chunk-TJSNVTVB.js';
@@ -5,8 +5,8 @@ import { Card, CardContent } from '../chunk-SETIN6XP.js';
5
5
  import { usePagination, Pagination } from '../chunk-6YFZLXFP.js';
6
6
  import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from '../chunk-OWCGEEAZ.js';
7
7
  import { Badge } from '../chunk-55FQP2DO.js';
8
- import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
9
8
  import { Label } from '../chunk-XQTVSNHC.js';
9
+ import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose } from '../chunk-M35R6JLA.js';
10
10
  import { Input } from '../chunk-K3KIBHJF.js';
11
11
  import { Button } from '../chunk-I4WDVYHX.js';
12
12
  import { useCopy } from '../chunk-TJSNVTVB.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gelabs/ovr",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "The @gelabs/ovr SDK — one self-contained package over the OVR (Online Ordinance Violation Receipt) platform. A standalone per-LGU app installs ONLY this package and imports from @gelabs/ovr/{config,core,data,runtime,auth,ui,...}; the seven @gelabs/ovr-* implementation packages are bundled in at build time.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -158,14 +158,14 @@
158
158
  "react-dom": "19.2.4",
159
159
  "tsup": "^8.4.0",
160
160
  "typescript": "^5",
161
- "@gelabs/ovr-auth": "0.0.0",
162
- "@gelabs/ovr-data": "0.0.0",
163
161
  "@gelabs/ovr-types": "0.0.0",
164
- "@gelabs/ovr-offline": "0.0.0",
162
+ "@gelabs/ovr-config": "0.0.0",
163
+ "@gelabs/ovr-data": "0.0.0",
165
164
  "@gelabs/ovr-core": "0.0.0",
165
+ "@gelabs/ovr-runtime": "0.0.0",
166
+ "@gelabs/ovr-auth": "0.0.0",
166
167
  "@gelabs/ovr-ui": "0.0.0",
167
- "@gelabs/ovr-config": "0.0.0",
168
- "@gelabs/ovr-runtime": "0.0.0"
168
+ "@gelabs/ovr-offline": "0.0.0"
169
169
  },
170
170
  "scripts": {
171
171
  "build": "tsup && node scripts/copy-assets.mjs",