@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.
- package/dist/auth-rate-limit.d.ts +11 -2
- package/dist/auth-rate-limit.js +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/auth.js +1 -1
- package/dist/{chunk-77ULDXQX.js → chunk-6ZJSEM4Y.js} +6 -1
- package/dist/generated/client/edge.js +2 -2
- package/dist/generated/client/index.js +2 -2
- package/dist/generated/client/wasm.js +2 -2
- package/dist/ui-components-admin/accounts-manager.js +5 -9
- package/dist/ui-components-admin/admin-nav.js +2 -2
- package/dist/ui-components-admin/issuance-form.js +1 -1
- package/dist/ui-components-admin/officers-manager.js +1 -1
- package/dist/ui-components-admin/roles-manager.js +1 -1
- package/dist/ui-components-admin/violations-manager.js +1 -1
- package/package.json +6 -6
|
@@ -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 };
|
package/dist/auth-rate-limit.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { rateLimit } from './chunk-
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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:
|
|
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
|
-
|
|
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 {
|
|
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.
|
|
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-
|
|
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-
|
|
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",
|