Bill Bot 1
This commit is contained in:
BIN
backend/.DS_Store
vendored
Normal file
BIN
backend/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
backend/src/.DS_Store
vendored
Normal file
BIN
backend/src/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
backend/src/main/.DS_Store
vendored
Normal file
BIN
backend/src/main/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -51,8 +51,13 @@ public class SecurityConfig {
|
|||||||
|
|
||||||
// ── PUBLIC: Terminal hardware order lookup (auth via X-API-KEY header, not JWT) ──
|
// ── PUBLIC: Terminal hardware order lookup (auth via X-API-KEY header, not JWT) ──
|
||||||
.requestMatchers(HttpMethod.GET, "/api/terminals/orders/**").permitAll()
|
.requestMatchers(HttpMethod.GET, "/api/terminals/orders/**").permitAll()
|
||||||
|
.requestMatchers(HttpMethod.GET, "/api/terminals/validate").permitAll()
|
||||||
|
.requestMatchers(HttpMethod.POST, "/api/terminals/pair").permitAll()
|
||||||
.requestMatchers(HttpMethod.POST, "/api/terminals/*/verify-pin").permitAll()
|
.requestMatchers(HttpMethod.POST, "/api/terminals/*/verify-pin").permitAll()
|
||||||
|
|
||||||
|
// ── PUBLIC: Device log ingestion (ESP32 Bill-Bot devices, no JWT) ──
|
||||||
|
.requestMatchers(HttpMethod.POST, "/api/device-logs").permitAll()
|
||||||
|
|
||||||
// ── PUBLIC: Notifications read (admin frontend polls this before login guard kicks in) ──
|
// ── PUBLIC: Notifications read (admin frontend polls this before login guard kicks in) ──
|
||||||
.requestMatchers(HttpMethod.GET, "/api/notifications/**").permitAll()
|
.requestMatchers(HttpMethod.GET, "/api/notifications/**").permitAll()
|
||||||
|
|
||||||
@@ -66,10 +71,14 @@ public class SecurityConfig {
|
|||||||
.requestMatchers(HttpMethod.GET, "/api/orders/user/**").authenticated()
|
.requestMatchers(HttpMethod.GET, "/api/orders/user/**").authenticated()
|
||||||
.requestMatchers(HttpMethod.GET, "/api/wallet/balance/**").authenticated()
|
.requestMatchers(HttpMethod.GET, "/api/wallet/balance/**").authenticated()
|
||||||
.requestMatchers(HttpMethod.GET, "/api/wallet/transactions/**").authenticated()
|
.requestMatchers(HttpMethod.GET, "/api/wallet/transactions/**").authenticated()
|
||||||
|
.requestMatchers(HttpMethod.POST, "/api/wallet/topup").authenticated()
|
||||||
.requestMatchers(HttpMethod.POST, "/api/coupons/redeem").authenticated()
|
.requestMatchers(HttpMethod.POST, "/api/coupons/redeem").authenticated()
|
||||||
.requestMatchers(HttpMethod.POST, "/api/feedback/**").authenticated()
|
.requestMatchers(HttpMethod.POST, "/api/feedback/**").authenticated()
|
||||||
.requestMatchers(HttpMethod.GET, "/api/feedback/**").authenticated()
|
.requestMatchers(HttpMethod.GET, "/api/feedback/**").authenticated()
|
||||||
.requestMatchers(HttpMethod.GET, "/api/auth/user/**").authenticated()
|
.requestMatchers(HttpMethod.GET, "/api/auth/user/**").authenticated()
|
||||||
|
.requestMatchers(HttpMethod.POST, "/api/auth/change-pin").authenticated()
|
||||||
|
.requestMatchers(HttpMethod.PUT, "/api/auth/users/*").authenticated()
|
||||||
|
.requestMatchers(HttpMethod.PUT, "/api/orders/*").authenticated()
|
||||||
|
|
||||||
// ── STAFF/MANAGER/MASTER: All other management APIs ──
|
// ── STAFF/MANAGER/MASTER: All other management APIs ──
|
||||||
.requestMatchers("/api/**").hasAnyRole("MASTER", "MANAGER", "STAFF", "OPERATOR")
|
.requestMatchers("/api/**").hasAnyRole("MASTER", "MANAGER", "STAFF", "OPERATOR")
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package com.rit.canteen.sales.controller;
|
||||||
|
|
||||||
|
import com.rit.canteen.sales.model.DeviceLog;
|
||||||
|
import com.rit.canteen.sales.service.DeviceLogService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/device-logs")
|
||||||
|
public class DeviceLogController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DeviceLogService deviceLogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /api/device-logs
|
||||||
|
* Accepts JSON: { "device_id": "...", "message": "..." }
|
||||||
|
* Called by ESP32 Bill-Bot devices to log events.
|
||||||
|
*/
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity<Void> createLog(@RequestBody Map<String, String> body) {
|
||||||
|
String deviceId = body.get("device_id");
|
||||||
|
String message = body.get("message");
|
||||||
|
|
||||||
|
if (deviceId == null || message == null) {
|
||||||
|
return ResponseEntity.badRequest().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceLogService.saveLog(deviceId, message);
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /api/device-logs
|
||||||
|
* Returns all device logs (newest first) for admin dashboard.
|
||||||
|
*/
|
||||||
|
@GetMapping
|
||||||
|
public List<DeviceLog> getAllLogs() {
|
||||||
|
return deviceLogService.getAllLogs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /api/device-logs/{deviceId}
|
||||||
|
* Returns logs for a specific device.
|
||||||
|
*/
|
||||||
|
@GetMapping("/{deviceId}")
|
||||||
|
public List<DeviceLog> getLogsByDevice(@PathVariable String deviceId) {
|
||||||
|
return deviceLogService.getLogsByDeviceId(deviceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -256,6 +256,11 @@ public class OrderController {
|
|||||||
public ResponseEntity<?> updateOrder(@PathVariable Long id, @RequestBody Order updatedOrder) {
|
public ResponseEntity<?> updateOrder(@PathVariable Long id, @RequestBody Order updatedOrder) {
|
||||||
try {
|
try {
|
||||||
return orderRepository.findById(id).map(existingOrder -> {
|
return orderRepository.findById(id).map(existingOrder -> {
|
||||||
|
// ── SECURITY: Verify ownership of order ──
|
||||||
|
Long tokenUserId = getTokenUserId();
|
||||||
|
if (tokenUserId != null && !tokenUserId.equals(existingOrder.getUserId()) && !isStaff()) {
|
||||||
|
return ResponseEntity.status(403).body(Map.of("error", "Access denied"));
|
||||||
|
}
|
||||||
BigDecimal oldAmount = existingOrder.getTotalAmount();
|
BigDecimal oldAmount = existingOrder.getTotalAmount();
|
||||||
BigDecimal newAmount = updatedOrder.getTotalAmount();
|
BigDecimal newAmount = updatedOrder.getTotalAmount();
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.rit.canteen.sales.controller;
|
|||||||
import com.rit.canteen.sales.model.Order;
|
import com.rit.canteen.sales.model.Order;
|
||||||
import com.rit.canteen.sales.model.Terminal;
|
import com.rit.canteen.sales.model.Terminal;
|
||||||
import com.rit.canteen.sales.model.TerminalDTO;
|
import com.rit.canteen.sales.model.TerminalDTO;
|
||||||
|
import com.rit.canteen.sales.service.DevicePairingService;
|
||||||
import com.rit.canteen.sales.service.TerminalService;
|
import com.rit.canteen.sales.service.TerminalService;
|
||||||
import com.rit.canteen.sales.repository.TerminalRepository;
|
import com.rit.canteen.sales.repository.TerminalRepository;
|
||||||
import com.rit.canteen.sales.repository.OrderRepository;
|
import com.rit.canteen.sales.repository.OrderRepository;
|
||||||
@@ -22,6 +23,9 @@ public class TerminalController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TerminalService terminalService;
|
private TerminalService terminalService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DevicePairingService devicePairingService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TerminalRepository terminalRepository;
|
private TerminalRepository terminalRepository;
|
||||||
|
|
||||||
@@ -36,7 +40,10 @@ public class TerminalController {
|
|||||||
t.getName(),
|
t.getName(),
|
||||||
t.getLocation(),
|
t.getLocation(),
|
||||||
"********",
|
"********",
|
||||||
"****"
|
"****",
|
||||||
|
t.isPaired(),
|
||||||
|
t.getDeviceId() != null ? maskDeviceId(t.getDeviceId()) : null,
|
||||||
|
t.getPairedAt()
|
||||||
))
|
))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
@@ -64,6 +71,10 @@ public class TerminalController {
|
|||||||
return ResponseEntity.noContent().build();
|
return ResponseEntity.noContent().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ──────────────────────────────────────────────────────────────
|
||||||
|
// Order Lookup (ESP32 uses X-API-KEY)
|
||||||
|
// ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@GetMapping("/orders/{orderNumber}")
|
@GetMapping("/orders/{orderNumber}")
|
||||||
public ResponseEntity<?> getOrderForTerminal(
|
public ResponseEntity<?> getOrderForTerminal(
|
||||||
@PathVariable String orderNumber,
|
@PathVariable String orderNumber,
|
||||||
@@ -97,4 +108,112 @@ public class TerminalController {
|
|||||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of("message", "Order not found"));
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(Map.of("message", "Order not found"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/validate")
|
||||||
|
public ResponseEntity<?> validateApiKey(@RequestHeader("X-API-KEY") String apiKey) {
|
||||||
|
Optional<Terminal> terminal = terminalRepository.findByApiKey(apiKey);
|
||||||
|
if (terminal.isEmpty()) {
|
||||||
|
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Map.of("status", "INVALID", "message", "Invalid API Key"));
|
||||||
|
}
|
||||||
|
Terminal t = terminal.get();
|
||||||
|
System.out.println(">>> Terminal Connected & Validated: " + t.getName() + " [ID: " + t.getId() + ", Location: " + t.getLocation() + "]");
|
||||||
|
return ResponseEntity.ok(Map.of(
|
||||||
|
"status", "VALID",
|
||||||
|
"terminalId", t.getId(),
|
||||||
|
"name", t.getName(),
|
||||||
|
"location", t.getLocation()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ──────────────────────────────────────────────────────────────
|
||||||
|
// OTP-Based Device Pairing
|
||||||
|
// ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /api/terminals/pair
|
||||||
|
* Called by ESP32 during setup. The device sends its OTP and chipId.
|
||||||
|
* If pairing is already completed (admin linked it), returns the apiKey.
|
||||||
|
* Otherwise returns status "WAITING".
|
||||||
|
*
|
||||||
|
* No auth required — the device has no credentials yet.
|
||||||
|
*/
|
||||||
|
@PostMapping("/pair")
|
||||||
|
public ResponseEntity<?> registerDeviceOtp(@RequestBody Map<String, String> body) {
|
||||||
|
String otp = body.get("otp");
|
||||||
|
String deviceId = body.get("deviceId");
|
||||||
|
|
||||||
|
if (otp == null || otp.isBlank() || deviceId == null || deviceId.isBlank()) {
|
||||||
|
return ResponseEntity.badRequest().body(Map.of("message", "Both 'otp' and 'deviceId' are required"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> result = devicePairingService.registerOtp(otp, deviceId);
|
||||||
|
return ResponseEntity.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /api/terminals/{id}/link-device
|
||||||
|
* Called by admin dashboard. Admin enters the OTP shown on the ESP32 screen.
|
||||||
|
* Links the device to this terminal record.
|
||||||
|
*
|
||||||
|
* Requires JWT auth (admin role).
|
||||||
|
*/
|
||||||
|
@PostMapping("/{id}/link-device")
|
||||||
|
public ResponseEntity<?> linkDevice(@PathVariable Long id, @RequestBody Map<String, String> body) {
|
||||||
|
String otp = body.get("otp");
|
||||||
|
|
||||||
|
if (otp == null || otp.isBlank()) {
|
||||||
|
return ResponseEntity.badRequest().body(Map.of("message", "OTP is required"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Terminal> result = devicePairingService.linkDevice(id, otp);
|
||||||
|
if (result.isPresent()) {
|
||||||
|
Terminal t = result.get();
|
||||||
|
return ResponseEntity.ok(Map.of(
|
||||||
|
"message", "Device linked successfully",
|
||||||
|
"terminalId", t.getId(),
|
||||||
|
"name", t.getName(),
|
||||||
|
"deviceId", t.getDeviceId()
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
|
||||||
|
.body(Map.of("message", "Invalid or expired OTP. Please check the code on the device screen and try again."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /api/terminals/{id}/unpair
|
||||||
|
* Called by admin dashboard to disconnect a device from a terminal.
|
||||||
|
* The device will need to re-pair on next boot.
|
||||||
|
*/
|
||||||
|
@PostMapping("/{id}/unpair")
|
||||||
|
public ResponseEntity<?> unpairDevice(@PathVariable Long id) {
|
||||||
|
Optional<Terminal> result = devicePairingService.unpairDevice(id);
|
||||||
|
if (result.isPresent()) {
|
||||||
|
return ResponseEntity.ok(Map.of("message", "Device unpaired successfully"));
|
||||||
|
} else {
|
||||||
|
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||||
|
.body(Map.of("message", "Terminal not found"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ──────────────────────────────────────────────────────────────
|
||||||
|
// Helpers
|
||||||
|
// ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Masks a device ID for display: "Esp 32 - AABBCCDDEEFF" → "Esp 32 - AA••••••EEFF"
|
||||||
|
*/
|
||||||
|
private String maskDeviceId(String deviceId) {
|
||||||
|
if (deviceId == null || deviceId.length() < 8) return deviceId;
|
||||||
|
// Find the last part (MAC portion) of the device ID
|
||||||
|
int dashIndex = deviceId.lastIndexOf('-');
|
||||||
|
if (dashIndex >= 0 && dashIndex + 5 < deviceId.length()) {
|
||||||
|
String prefix = deviceId.substring(0, dashIndex + 1).trim();
|
||||||
|
String mac = deviceId.substring(dashIndex + 1).trim();
|
||||||
|
if (mac.length() >= 6) {
|
||||||
|
return prefix + " " + mac.substring(0, 2) + "••••" + mac.substring(mac.length() - 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceId.substring(0, 4) + "••••" + deviceId.substring(deviceId.length() - 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,6 +128,11 @@ public class UserController {
|
|||||||
public ResponseEntity<LoginResponse.UserDto> updateUser(
|
public ResponseEntity<LoginResponse.UserDto> updateUser(
|
||||||
@PathVariable Long id,
|
@PathVariable Long id,
|
||||||
@Valid @RequestBody UserUpdateRequest request) {
|
@Valid @RequestBody UserUpdateRequest request) {
|
||||||
|
// Extra ownership check: customers can only update their own profile; staff can update any
|
||||||
|
Long tokenUserId = getTokenUserId();
|
||||||
|
if (tokenUserId != null && !tokenUserId.equals(id) && !isStaff()) {
|
||||||
|
return ResponseEntity.status(403).build();
|
||||||
|
}
|
||||||
LoginResponse.UserDto updated = userService.updateUser(id, request.getName(),
|
LoginResponse.UserDto updated = userService.updateUser(id, request.getName(),
|
||||||
request.getMobileNumber(), request.getPin());
|
request.getMobileNumber(), request.getPin());
|
||||||
return updated != null ? ResponseEntity.ok(updated) : ResponseEntity.notFound().build();
|
return updated != null ? ResponseEntity.ok(updated) : ResponseEntity.notFound().build();
|
||||||
@@ -147,6 +152,17 @@ public class UserController {
|
|||||||
|
|
||||||
// ── Helpers ──────────────────────────────────────────────────────────────
|
// ── Helpers ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
private Long getTokenUserId() {
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (auth != null && auth.getDetails() instanceof Claims claims) {
|
||||||
|
Object uid = claims.get("userId");
|
||||||
|
if (uid != null) {
|
||||||
|
return uid instanceof Integer ? ((Integer) uid).longValue() : (Long) uid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private String getAuthenticatedMobile() {
|
private String getAuthenticatedMobile() {
|
||||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
if (auth != null && auth.getDetails() instanceof Claims claims) {
|
if (auth != null && auth.getDetails() instanceof Claims claims) {
|
||||||
|
|||||||
@@ -74,6 +74,9 @@ public class WalletController {
|
|||||||
public ResponseEntity<?> topUp(@RequestBody Map<String, Object> request) {
|
public ResponseEntity<?> topUp(@RequestBody Map<String, Object> request) {
|
||||||
try {
|
try {
|
||||||
Long userId = Long.valueOf(request.get("userId").toString());
|
Long userId = Long.valueOf(request.get("userId").toString());
|
||||||
|
if (!canAccessUser(userId)) {
|
||||||
|
return ResponseEntity.status(403).body(Map.of("error", "Access denied"));
|
||||||
|
}
|
||||||
BigDecimal amount = new BigDecimal(request.get("amount").toString());
|
BigDecimal amount = new BigDecimal(request.get("amount").toString());
|
||||||
|
|
||||||
// ── FIX: validate amount BEFORE touching the database ──
|
// ── FIX: validate amount BEFORE touching the database ──
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.rit.canteen.sales.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "device_logs")
|
||||||
|
public class DeviceLog {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "device_id", nullable = false)
|
||||||
|
private String deviceId;
|
||||||
|
|
||||||
|
@Column(nullable = false, length = 2000)
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
@Column(name = "created_at", nullable = false)
|
||||||
|
private LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@PrePersist
|
||||||
|
protected void onCreate() {
|
||||||
|
this.createdAt = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceLog() {}
|
||||||
|
|
||||||
|
public DeviceLog(String deviceId, String message) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public Long getId() { return id; }
|
||||||
|
public void setId(Long id) { this.id = id; }
|
||||||
|
|
||||||
|
public String getDeviceId() { return deviceId; }
|
||||||
|
public void setDeviceId(String deviceId) { this.deviceId = deviceId; }
|
||||||
|
|
||||||
|
public String getMessage() { return message; }
|
||||||
|
public void setMessage(String message) { this.message = message; }
|
||||||
|
|
||||||
|
public LocalDateTime getCreatedAt() { return createdAt; }
|
||||||
|
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.rit.canteen.sales.model;
|
|||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "terminals")
|
@Table(name = "terminals")
|
||||||
@@ -23,6 +24,15 @@ public class Terminal {
|
|||||||
@Column(unique = true)
|
@Column(unique = true)
|
||||||
private String apiKey;
|
private String apiKey;
|
||||||
|
|
||||||
|
@Column(name = "device_id")
|
||||||
|
private String deviceId;
|
||||||
|
|
||||||
|
@Column(nullable = false, columnDefinition = "boolean default false")
|
||||||
|
private boolean paired = false;
|
||||||
|
|
||||||
|
@Column(name = "paired_at")
|
||||||
|
private LocalDateTime pairedAt;
|
||||||
|
|
||||||
public Terminal() {}
|
public Terminal() {}
|
||||||
|
|
||||||
public Terminal(String name, String location, String pin, String apiKey) {
|
public Terminal(String name, String location, String pin, String apiKey) {
|
||||||
@@ -47,4 +57,13 @@ public class Terminal {
|
|||||||
|
|
||||||
public String getApiKey() { return apiKey; }
|
public String getApiKey() { return apiKey; }
|
||||||
public void setApiKey(String apiKey) { this.apiKey = apiKey; }
|
public void setApiKey(String apiKey) { this.apiKey = apiKey; }
|
||||||
|
|
||||||
|
public String getDeviceId() { return deviceId; }
|
||||||
|
public void setDeviceId(String deviceId) { this.deviceId = deviceId; }
|
||||||
|
|
||||||
|
public boolean isPaired() { return paired; }
|
||||||
|
public void setPaired(boolean paired) { this.paired = paired; }
|
||||||
|
|
||||||
|
public LocalDateTime getPairedAt() { return pairedAt; }
|
||||||
|
public void setPairedAt(LocalDateTime pairedAt) { this.pairedAt = pairedAt; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,29 @@
|
|||||||
package com.rit.canteen.sales.model;
|
package com.rit.canteen.sales.model;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
public class TerminalDTO {
|
public class TerminalDTO {
|
||||||
private Long id;
|
private Long id;
|
||||||
private String name;
|
private String name;
|
||||||
private String location;
|
private String location;
|
||||||
private String apiKey;
|
private String apiKey;
|
||||||
private String pin;
|
private String pin;
|
||||||
|
private boolean paired;
|
||||||
|
private String deviceId;
|
||||||
|
private LocalDateTime pairedAt;
|
||||||
|
|
||||||
public TerminalDTO() {}
|
public TerminalDTO() {}
|
||||||
|
|
||||||
public TerminalDTO(Long id, String name, String location, String apiKey, String pin) {
|
public TerminalDTO(Long id, String name, String location, String apiKey, String pin,
|
||||||
|
boolean paired, String deviceId, LocalDateTime pairedAt) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.location = location;
|
this.location = location;
|
||||||
this.apiKey = apiKey;
|
this.apiKey = apiKey;
|
||||||
this.pin = pin;
|
this.pin = pin;
|
||||||
|
this.paired = paired;
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.pairedAt = pairedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters and Setters
|
// Getters and Setters
|
||||||
@@ -32,4 +41,13 @@ public class TerminalDTO {
|
|||||||
|
|
||||||
public String getPin() { return pin; }
|
public String getPin() { return pin; }
|
||||||
public void setPin(String pin) { this.pin = pin; }
|
public void setPin(String pin) { this.pin = pin; }
|
||||||
|
|
||||||
|
public boolean isPaired() { return paired; }
|
||||||
|
public void setPaired(boolean paired) { this.paired = paired; }
|
||||||
|
|
||||||
|
public String getDeviceId() { return deviceId; }
|
||||||
|
public void setDeviceId(String deviceId) { this.deviceId = deviceId; }
|
||||||
|
|
||||||
|
public LocalDateTime getPairedAt() { return pairedAt; }
|
||||||
|
public void setPairedAt(LocalDateTime pairedAt) { this.pairedAt = pairedAt; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.rit.canteen.sales.repository;
|
||||||
|
|
||||||
|
import com.rit.canteen.sales.model.DeviceLog;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface DeviceLogRepository extends JpaRepository<DeviceLog, Long> {
|
||||||
|
List<DeviceLog> findAllByOrderByCreatedAtDesc();
|
||||||
|
List<DeviceLog> findByDeviceIdOrderByCreatedAtDesc(String deviceId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.rit.canteen.sales.service;
|
||||||
|
|
||||||
|
import com.rit.canteen.sales.model.DeviceLog;
|
||||||
|
import com.rit.canteen.sales.repository.DeviceLogRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class DeviceLogService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DeviceLogRepository deviceLogRepository;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public DeviceLog saveLog(String deviceId, String message) {
|
||||||
|
DeviceLog log = new DeviceLog(deviceId, message);
|
||||||
|
return deviceLogRepository.save(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DeviceLog> getAllLogs() {
|
||||||
|
return deviceLogRepository.findAllByOrderByCreatedAtDesc();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DeviceLog> getLogsByDeviceId(String deviceId) {
|
||||||
|
return deviceLogRepository.findByDeviceIdOrderByCreatedAtDesc(deviceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
package com.rit.canteen.sales.service;
|
||||||
|
|
||||||
|
import com.rit.canteen.sales.model.Terminal;
|
||||||
|
import com.rit.canteen.sales.repository.TerminalRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages the in-memory OTP pairing lifecycle for ESP32 terminal devices.
|
||||||
|
*
|
||||||
|
* Flow:
|
||||||
|
* 1. Device boots, generates a 6-digit OTP, displays it on screen
|
||||||
|
* 2. Device calls registerOtp() — stores OTP + deviceId in memory (5-min TTL)
|
||||||
|
* 3. Admin sees OTP on device screen, enters it in dashboard against a terminal
|
||||||
|
* 4. Admin calls linkDevice() — matches OTP, binds device to terminal, returns apiKey
|
||||||
|
* 5. Device polls checkPairingStatus() — gets back apiKey once admin completes step 4
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class DevicePairingService {
|
||||||
|
|
||||||
|
private static final long OTP_TTL_MS = 5 * 60 * 1000L; // 5 minutes
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TerminalRepository terminalRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a pending pairing request from a device.
|
||||||
|
*/
|
||||||
|
private static class PairingRequest {
|
||||||
|
final String otp;
|
||||||
|
final String deviceId;
|
||||||
|
final Instant createdAt;
|
||||||
|
// Set once admin links the device
|
||||||
|
volatile String apiKey;
|
||||||
|
volatile Long terminalId;
|
||||||
|
volatile boolean completed;
|
||||||
|
|
||||||
|
PairingRequest(String otp, String deviceId) {
|
||||||
|
this.otp = otp;
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.createdAt = Instant.now();
|
||||||
|
this.completed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isExpired() {
|
||||||
|
return Instant.now().toEpochMilli() - createdAt.toEpochMilli() > OTP_TTL_MS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OTP → PairingRequest
|
||||||
|
private final ConcurrentHashMap<String, PairingRequest> pendingPairings = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the ESP32 device. Registers (or refreshes) the device's OTP in memory.
|
||||||
|
* If the OTP was already matched by an admin, returns the assigned apiKey.
|
||||||
|
*
|
||||||
|
* @return Map with status ("WAITING" or "PAIRED") and optionally "apiKey"
|
||||||
|
*/
|
||||||
|
public Map<String, Object> registerOtp(String otp, String deviceId) {
|
||||||
|
PairingRequest existing = pendingPairings.get(otp);
|
||||||
|
|
||||||
|
// If this OTP was already linked by admin, return the apiKey
|
||||||
|
if (existing != null && existing.completed && existing.deviceId.equals(deviceId)) {
|
||||||
|
// Clean up after delivering the key
|
||||||
|
pendingPairings.remove(otp);
|
||||||
|
return Map.of(
|
||||||
|
"status", "PAIRED",
|
||||||
|
"apiKey", existing.apiKey,
|
||||||
|
"terminalId", existing.terminalId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register or refresh the OTP
|
||||||
|
pendingPairings.put(otp, new PairingRequest(otp, deviceId));
|
||||||
|
|
||||||
|
return Map.of("status", "WAITING");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the admin dashboard. Links a device's OTP to a specific terminal.
|
||||||
|
*
|
||||||
|
* @return Optional.empty() if OTP not found/expired, or the updated Terminal
|
||||||
|
*/
|
||||||
|
public Optional<Terminal> linkDevice(Long terminalId, String otp) {
|
||||||
|
PairingRequest request = pendingPairings.get(otp);
|
||||||
|
|
||||||
|
if (request == null || request.isExpired()) {
|
||||||
|
pendingPairings.remove(otp); // Clean up expired
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Terminal> terminalOpt = terminalRepository.findById(terminalId);
|
||||||
|
if (terminalOpt.isEmpty()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Terminal terminal = terminalOpt.get();
|
||||||
|
|
||||||
|
// Bind the device to the terminal
|
||||||
|
terminal.setDeviceId(request.deviceId);
|
||||||
|
terminal.setPaired(true);
|
||||||
|
terminal.setPairedAt(LocalDateTime.now());
|
||||||
|
terminalRepository.save(terminal);
|
||||||
|
|
||||||
|
// Mark the pairing as completed so the device can pick up the apiKey
|
||||||
|
request.apiKey = terminal.getApiKey();
|
||||||
|
request.terminalId = terminal.getId();
|
||||||
|
request.completed = true;
|
||||||
|
|
||||||
|
System.out.println(">>> Device paired: " + request.deviceId +
|
||||||
|
" → Terminal: " + terminal.getName() + " [ID: " + terminal.getId() + "]");
|
||||||
|
|
||||||
|
return Optional.of(terminal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpairs a device from a terminal, clearing its deviceId and paired status.
|
||||||
|
*/
|
||||||
|
public Optional<Terminal> unpairDevice(Long terminalId) {
|
||||||
|
Optional<Terminal> terminalOpt = terminalRepository.findById(terminalId);
|
||||||
|
if (terminalOpt.isEmpty()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Terminal terminal = terminalOpt.get();
|
||||||
|
terminal.setDeviceId(null);
|
||||||
|
terminal.setPaired(false);
|
||||||
|
terminal.setPairedAt(null);
|
||||||
|
terminalRepository.save(terminal);
|
||||||
|
|
||||||
|
System.out.println(">>> Device unpaired from Terminal: " + terminal.getName() +
|
||||||
|
" [ID: " + terminal.getId() + "]");
|
||||||
|
|
||||||
|
return Optional.of(terminal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Periodic cleanup of expired OTP entries (runs every 60 seconds).
|
||||||
|
*/
|
||||||
|
@Scheduled(fixedRate = 60000)
|
||||||
|
public void cleanupExpiredOtps() {
|
||||||
|
pendingPairings.entrySet().removeIf(entry -> entry.getValue().isExpired());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
spring.application.name=backend
|
spring.application.name=backend
|
||||||
server.address=0.0.0.0
|
server.address=0.0.0.0
|
||||||
|
server.port=8080
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# DATABASE — REQUIRED environment variables
|
# DATABASE — REQUIRED environment variables
|
||||||
# Set these in your environment or a .env file
|
# Set these in your environment or a .env file
|
||||||
# ============================================================
|
# ============================================================
|
||||||
spring.datasource.url=${DB_URL:jdbc:postgresql://localhost:5432/positeasy}
|
spring.datasource.url=${DB_URL:jdbc:postgresql://localhost:5432/positeasy}
|
||||||
spring.datasource.username=${DB_USER:postgres}
|
spring.datasource.username=postgres
|
||||||
spring.datasource.password=${DB_PASSWORD:}
|
spring.datasource.password=sidharth
|
||||||
spring.datasource.driver-class-name=org.postgresql.Driver
|
spring.datasource.driver-class-name=org.postgresql.Driver
|
||||||
|
|
||||||
spring.jpa.hibernate.ddl-auto=update
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
|
|||||||
327
backend/terminal_api_spec.md
Normal file
327
backend/terminal_api_spec.md
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
# Terminal Integration & ESP32 Firmware API Specification
|
||||||
|
|
||||||
|
This document provides the API specifications of the Spring Boot backend for integrating terminal hardware (ESP32 controllers that scan QR codes and print bills).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Authentication
|
||||||
|
|
||||||
|
### For Paired Devices
|
||||||
|
Once a device is paired, all terminal-specific APIs use **API Key authentication**.
|
||||||
|
- **Header Key**: `X-API-KEY`
|
||||||
|
- **Value**: `POS-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` (Auto-generated when a terminal is created).
|
||||||
|
|
||||||
|
### For Unpaired Devices (During Pairing)
|
||||||
|
The pairing endpoint requires no authentication — the device has no credentials yet.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Device Onboarding (OTP-Based Pairing)
|
||||||
|
|
||||||
|
### Flow Overview
|
||||||
|
|
||||||
|
1. **Admin** creates a terminal in the dashboard (name, location, PIN)
|
||||||
|
2. **ESP32** boots with no stored API key → enters pairing mode
|
||||||
|
3. **ESP32** generates a 6-digit OTP and displays it on screen
|
||||||
|
4. **ESP32** POSTs the OTP + its chipId to `POST /api/terminals/pair`
|
||||||
|
5. **Admin** enters the OTP in the dashboard against the specific terminal
|
||||||
|
6. **Backend** matches the OTP, binds the device to the terminal
|
||||||
|
7. **ESP32** polls `POST /api/terminals/pair` again → receives `"PAIRED"` + API key
|
||||||
|
8. **ESP32** saves the API key to NVS flash and restarts
|
||||||
|
9. All subsequent communication uses `X-API-KEY` header — no further pairing needed
|
||||||
|
|
||||||
|
### A. Register Device OTP (ESP32 → Backend)
|
||||||
|
|
||||||
|
Used by the ESP32 to register its OTP and poll for pairing completion.
|
||||||
|
|
||||||
|
* **URL**: `/api/terminals/pair`
|
||||||
|
* **Method**: `POST`
|
||||||
|
* **Auth**: None (public endpoint)
|
||||||
|
* **Headers**:
|
||||||
|
* `Content-Type`: `application/json`
|
||||||
|
* **Request Body**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"otp": "482916",
|
||||||
|
"deviceId": "Esp 32 - AABBCCDDEEFF"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Response — Waiting (Admin hasn't linked yet):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "WAITING"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Response — Paired (Admin completed linking):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "PAIRED",
|
||||||
|
"apiKey": "POS-EF9832B743CA90B2381F0A1B2C3D4E5F",
|
||||||
|
"terminalId": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* **Response Codes**:
|
||||||
|
* `200 OK`: Always — check `status` field for state.
|
||||||
|
* `400 BAD_REQUEST`: Missing `otp` or `deviceId`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### B. Link Device (Admin Dashboard → Backend)
|
||||||
|
|
||||||
|
Used by the admin to match a device's OTP to a terminal.
|
||||||
|
|
||||||
|
* **URL**: `/api/terminals/{id}/link-device`
|
||||||
|
* **Method**: `POST`
|
||||||
|
* **Auth**: JWT (admin role)
|
||||||
|
* **Headers**:
|
||||||
|
* `Content-Type`: `application/json`
|
||||||
|
* `Authorization`: `Bearer <jwt>`
|
||||||
|
* **Path Parameters**:
|
||||||
|
* `id` (Long): The terminal ID to link the device to.
|
||||||
|
* **Request Body**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"otp": "482916"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Response (`200 OK`):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "Device linked successfully",
|
||||||
|
"terminalId": 1,
|
||||||
|
"name": "Counter 1 Printer",
|
||||||
|
"deviceId": "Esp 32 - AABBCCDDEEFF"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* **Response Codes**:
|
||||||
|
* `200 OK`: Device linked successfully.
|
||||||
|
* `400 BAD_REQUEST`: Invalid or expired OTP.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### C. Unpair Device (Admin Dashboard → Backend)
|
||||||
|
|
||||||
|
Used by the admin to disconnect a device from a terminal.
|
||||||
|
|
||||||
|
* **URL**: `/api/terminals/{id}/unpair`
|
||||||
|
* **Method**: `POST`
|
||||||
|
* **Auth**: JWT (admin role)
|
||||||
|
|
||||||
|
#### Response (`200 OK`):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "Device unpaired successfully"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Operational Endpoints
|
||||||
|
|
||||||
|
### D. Get Order Details
|
||||||
|
|
||||||
|
Used by the ESP32 to fetch the order details after scanning a QR code.
|
||||||
|
|
||||||
|
* **URL**: `/api/terminals/orders/{orderNumber}`
|
||||||
|
* **Method**: `GET`
|
||||||
|
* **Headers**:
|
||||||
|
* `X-API-KEY`: `<YOUR_TERMINAL_API_KEY>`
|
||||||
|
* **Path Parameters**:
|
||||||
|
* `orderNumber` (String): The order ID scanned from the QR code (e.g., `ORD-87A3B2D9`).
|
||||||
|
|
||||||
|
#### Response Codes:
|
||||||
|
* `200 OK`: Order found and is eligible for processing.
|
||||||
|
* `401 UNAUTHORIZED`: Invalid or missing `X-API-KEY`.
|
||||||
|
* `404 NOT_FOUND`: Order number does not exist.
|
||||||
|
* `400 BAD_REQUEST`: Order has already been fulfilled (`status` is `COMPLETED`).
|
||||||
|
* `410 GONE`: Order has expired/archived.
|
||||||
|
|
||||||
|
#### Response Body (`200 OK` JSON Schema):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 12,
|
||||||
|
"orderNumber": "ORD-68EF73C9",
|
||||||
|
"displayOrderId": "045",
|
||||||
|
"userId": 5,
|
||||||
|
"totalAmount": 250.00,
|
||||||
|
"status": "PAID",
|
||||||
|
"paymentMethod": "RITZ_TOKEN",
|
||||||
|
"createdAt": "2026-06-17T13:30:00",
|
||||||
|
"orderType": "STORE_ORDER",
|
||||||
|
"archived": false,
|
||||||
|
"hasFeedback": false,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": 24,
|
||||||
|
"productId": 3,
|
||||||
|
"productName": "Masala Dosa",
|
||||||
|
"price": 60.00,
|
||||||
|
"quantity": 2,
|
||||||
|
"stallId": 1,
|
||||||
|
"stallName": "RIT Canteen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 25,
|
||||||
|
"productId": 7,
|
||||||
|
"productName": "Cold Coffee",
|
||||||
|
"price": 40.00,
|
||||||
|
"quantity": 1,
|
||||||
|
"stallId": 2,
|
||||||
|
"stallName": "Juice Bar"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### E. Validate API Key
|
||||||
|
|
||||||
|
Used by the ESP32 to verify its API key is still valid (optional health check).
|
||||||
|
|
||||||
|
* **URL**: `/api/terminals/validate`
|
||||||
|
* **Method**: `GET`
|
||||||
|
* **Headers**:
|
||||||
|
* `X-API-KEY`: `<YOUR_TERMINAL_API_KEY>`
|
||||||
|
|
||||||
|
#### Response (`200 OK`):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "VALID",
|
||||||
|
"terminalId": 1,
|
||||||
|
"name": "Counter 1 Printer",
|
||||||
|
"location": "Main Hall"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### F. Device Logging
|
||||||
|
|
||||||
|
Used by the ESP32 to submit runtime system logs to the backend.
|
||||||
|
|
||||||
|
* **URL**: `/api/device-logs`
|
||||||
|
* **Method**: `POST`
|
||||||
|
* **Headers**:
|
||||||
|
* `Content-Type`: `application/json`
|
||||||
|
* **Request Body**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"device_id": "Esp 32 - AABBCCDDEEFF",
|
||||||
|
"message": "Firmware Version: 1.2.6"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
* **Response Codes**:
|
||||||
|
* `201 CREATED`: Log successfully recorded.
|
||||||
|
* `400 BAD_REQUEST`: Missing `device_id` or `message`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### G. Verify Terminal PIN (Admin Tool)
|
||||||
|
|
||||||
|
Used during admin operations to reveal the terminal's API Key.
|
||||||
|
|
||||||
|
* **URL**: `/api/terminals/{id}/verify-pin`
|
||||||
|
* **Method**: `POST`
|
||||||
|
* **Headers**:
|
||||||
|
* `Content-Type`: `application/json`
|
||||||
|
* **Path Parameters**:
|
||||||
|
* `id` (Long): The database ID of the terminal registration.
|
||||||
|
* **Request Body**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"pin": "1234"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
* **Response Body (`200 OK`):**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "Counter 1 Printer",
|
||||||
|
"location": "Main Hall",
|
||||||
|
"pin": "1234",
|
||||||
|
"apiKey": "POS-EF9832B743CA90B2381F",
|
||||||
|
"deviceId": "Esp 32 - AABBCCDDEEFF",
|
||||||
|
"paired": true,
|
||||||
|
"pairedAt": "2026-06-17T14:00:00"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. ESP32 Firmware Integration Guide
|
||||||
|
|
||||||
|
### Pairing Flow (`database.cpp`)
|
||||||
|
|
||||||
|
The ESP32 now uses OTP-based pairing instead of JWT token polling:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void setupPairing()
|
||||||
|
{
|
||||||
|
// 1. Generate 6-digit OTP
|
||||||
|
currentOtp = generateUniqueOTP(oldOtp);
|
||||||
|
displayStatus("OTP: " + currentOtp + "\nEnter on Admin Panel", 300);
|
||||||
|
|
||||||
|
// 2. POST OTP + deviceId to /api/terminals/pair
|
||||||
|
JsonDocument requestDoc;
|
||||||
|
requestDoc["otp"] = currentOtp;
|
||||||
|
requestDoc["deviceId"] = getDeviceId();
|
||||||
|
|
||||||
|
// 3. Poll every 3 seconds — check if status == "PAIRED"
|
||||||
|
// 4. On success, extract apiKey and save to NVS
|
||||||
|
apiKey = doc["apiKey"].as<String>();
|
||||||
|
saveApiKey(apiKey);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Data Fetching (`database.cpp`)
|
||||||
|
|
||||||
|
All requests use `X-API-KEY` instead of `Authorization: Bearer`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
String getData(String orderNumber)
|
||||||
|
{
|
||||||
|
httpClient.addHeader("X-API-KEY", apiKey); // Not Bearer token
|
||||||
|
// ... GET /api/terminals/orders/{orderNumber}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Order JSON Parsing (`bill_bot_system.cpp`)
|
||||||
|
|
||||||
|
The new backend returns order details at the **root level** (no `"data"` wrapper):
|
||||||
|
|
||||||
|
| Old Path | New Path |
|
||||||
|
|---|---|
|
||||||
|
| `doc["data"]["orderId"]` | `doc["displayOrderId"]` or `doc["orderNumber"]` |
|
||||||
|
| `doc["data"]["status"]` | `doc["status"]` (`"PAID"` = ready, `"COMPLETED"` = already done) |
|
||||||
|
| `doc["data"]["dateTz"]` | `doc["createdAt"]` |
|
||||||
|
| `doc["data"]["order"]` (items) | `doc["items"]` |
|
||||||
|
| `item["productInfo"]["name"]` | `item["productName"]` |
|
||||||
|
| `item["counterId"]` | `item["stallId"]` / `item["stallName"]` |
|
||||||
|
| `item["price"]` (in paise) | `item["price"]` (in rupees, no /100 needed) |
|
||||||
|
|
||||||
|
### Device Logging (`database.cpp`)
|
||||||
|
|
||||||
|
Logs now go to the Spring Boot backend directly (no Supabase):
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void sendLog(String message)
|
||||||
|
{
|
||||||
|
httpClient.begin(logUrl); // /api/device-logs
|
||||||
|
httpClient.addHeader("Content-Type", "application/json");
|
||||||
|
// No supabaseApiKey header needed
|
||||||
|
httpClient.POST(body);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### QR Code Format
|
||||||
|
|
||||||
|
The QR code payload is now the **order number directly**:
|
||||||
|
- Old: `prefix$PAYMENT_ID$suffix` → parsed with `$` delimiters
|
||||||
|
- New: `ORD-87A3B2D9` → passed directly to `getData()`
|
||||||
468
frontend/package-lock.json
generated
468
frontend/package-lock.json
generated
@@ -56,13 +56,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
|
||||||
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
|
"integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": "^7.28.5",
|
"@babel/helper-validator-identifier": "^7.29.7",
|
||||||
"js-tokens": "^4.0.0",
|
"js-tokens": "^4.0.0",
|
||||||
"picocolors": "^1.1.1"
|
"picocolors": "^1.1.1"
|
||||||
},
|
},
|
||||||
@@ -71,9 +71,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/compat-data": {
|
"node_modules/@babel/compat-data": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
|
||||||
"integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
|
"integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -81,21 +81,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/core": {
|
"node_modules/@babel/core": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
|
||||||
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.7",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.7",
|
||||||
"@babel/helper-compilation-targets": "^7.28.6",
|
"@babel/helper-compilation-targets": "^7.29.7",
|
||||||
"@babel/helper-module-transforms": "^7.28.6",
|
"@babel/helper-module-transforms": "^7.29.7",
|
||||||
"@babel/helpers": "^7.28.6",
|
"@babel/helpers": "^7.29.7",
|
||||||
"@babel/parser": "^7.29.0",
|
"@babel/parser": "^7.29.7",
|
||||||
"@babel/template": "^7.28.6",
|
"@babel/template": "^7.29.7",
|
||||||
"@babel/traverse": "^7.29.0",
|
"@babel/traverse": "^7.29.7",
|
||||||
"@babel/types": "^7.29.0",
|
"@babel/types": "^7.29.7",
|
||||||
"@jridgewell/remapping": "^2.3.5",
|
"@jridgewell/remapping": "^2.3.5",
|
||||||
"convert-source-map": "^2.0.0",
|
"convert-source-map": "^2.0.0",
|
||||||
"debug": "^4.1.0",
|
"debug": "^4.1.0",
|
||||||
@@ -112,14 +112,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/generator": {
|
"node_modules/@babel/generator": {
|
||||||
"version": "7.29.1",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz",
|
||||||
"integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
|
"integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.29.0",
|
"@babel/parser": "^7.29.7",
|
||||||
"@babel/types": "^7.29.0",
|
"@babel/types": "^7.29.7",
|
||||||
"@jridgewell/gen-mapping": "^0.3.12",
|
"@jridgewell/gen-mapping": "^0.3.12",
|
||||||
"@jridgewell/trace-mapping": "^0.3.28",
|
"@jridgewell/trace-mapping": "^0.3.28",
|
||||||
"jsesc": "^3.0.2"
|
"jsesc": "^3.0.2"
|
||||||
@@ -129,14 +129,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-compilation-targets": {
|
"node_modules/@babel/helper-compilation-targets": {
|
||||||
"version": "7.28.6",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
|
||||||
"integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
|
"integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/compat-data": "^7.28.6",
|
"@babel/compat-data": "^7.29.7",
|
||||||
"@babel/helper-validator-option": "^7.27.1",
|
"@babel/helper-validator-option": "^7.29.7",
|
||||||
"browserslist": "^4.24.0",
|
"browserslist": "^4.24.0",
|
||||||
"lru-cache": "^5.1.1",
|
"lru-cache": "^5.1.1",
|
||||||
"semver": "^6.3.1"
|
"semver": "^6.3.1"
|
||||||
@@ -146,9 +146,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-globals": {
|
"node_modules/@babel/helper-globals": {
|
||||||
"version": "7.28.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
|
||||||
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
|
"integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -156,29 +156,29 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-module-imports": {
|
"node_modules/@babel/helper-module-imports": {
|
||||||
"version": "7.28.6",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
|
||||||
"integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
|
"integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/traverse": "^7.28.6",
|
"@babel/traverse": "^7.29.7",
|
||||||
"@babel/types": "^7.28.6"
|
"@babel/types": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-module-transforms": {
|
"node_modules/@babel/helper-module-transforms": {
|
||||||
"version": "7.28.6",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
|
||||||
"integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
|
"integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-module-imports": "^7.28.6",
|
"@babel/helper-module-imports": "^7.29.7",
|
||||||
"@babel/helper-validator-identifier": "^7.28.5",
|
"@babel/helper-validator-identifier": "^7.29.7",
|
||||||
"@babel/traverse": "^7.28.6"
|
"@babel/traverse": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -188,9 +188,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-string-parser": {
|
"node_modules/@babel/helper-string-parser": {
|
||||||
"version": "7.27.1",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
|
||||||
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
|
"integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -198,9 +198,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-identifier": {
|
"node_modules/@babel/helper-validator-identifier": {
|
||||||
"version": "7.28.5",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
|
||||||
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
|
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -208,9 +208,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-option": {
|
"node_modules/@babel/helper-validator-option": {
|
||||||
"version": "7.27.1",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
|
||||||
"integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
|
"integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -218,27 +218,27 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helpers": {
|
"node_modules/@babel/helpers": {
|
||||||
"version": "7.29.2",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
|
||||||
"integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==",
|
"integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/template": "^7.28.6",
|
"@babel/template": "^7.29.7",
|
||||||
"@babel/types": "^7.29.0"
|
"@babel/types": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.29.2",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz",
|
||||||
"integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==",
|
"integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.29.0"
|
"@babel/types": "^7.29.7"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
@@ -257,33 +257,33 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/template": {
|
"node_modules/@babel/template": {
|
||||||
"version": "7.28.6",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
|
||||||
"integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
|
"integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.28.6",
|
"@babel/code-frame": "^7.29.7",
|
||||||
"@babel/parser": "^7.28.6",
|
"@babel/parser": "^7.29.7",
|
||||||
"@babel/types": "^7.28.6"
|
"@babel/types": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/traverse": {
|
"node_modules/@babel/traverse": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz",
|
||||||
"integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
|
"integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.7",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.7",
|
||||||
"@babel/helper-globals": "^7.28.0",
|
"@babel/helper-globals": "^7.29.7",
|
||||||
"@babel/parser": "^7.29.0",
|
"@babel/parser": "^7.29.7",
|
||||||
"@babel/template": "^7.28.6",
|
"@babel/template": "^7.29.7",
|
||||||
"@babel/types": "^7.29.0",
|
"@babel/types": "^7.29.7",
|
||||||
"debug": "^4.3.1"
|
"debug": "^4.3.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -291,23 +291,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz",
|
||||||
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
|
"integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-string-parser": "^7.27.1",
|
"@babel/helper-string-parser": "^7.29.7",
|
||||||
"@babel/helper-validator-identifier": "^7.28.5"
|
"@babel/helper-validator-identifier": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/core": {
|
"node_modules/@emnapi/core": {
|
||||||
"version": "1.9.2",
|
"version": "1.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
||||||
"integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==",
|
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@@ -317,9 +317,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/runtime": {
|
"node_modules/@emnapi/runtime": {
|
||||||
"version": "1.9.2",
|
"version": "1.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
||||||
"integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==",
|
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@@ -598,14 +598,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@napi-rs/wasm-runtime": {
|
"node_modules/@napi-rs/wasm-runtime": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz",
|
||||||
"integrity": "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==",
|
"integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tybys/wasm-util": "^0.10.1"
|
"@tybys/wasm-util": "^0.10.2"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -617,9 +617,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@oxc-project/types": {
|
"node_modules/@oxc-project/types": {
|
||||||
"version": "0.123.0",
|
"version": "0.133.0",
|
||||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.123.0.tgz",
|
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz",
|
||||||
"integrity": "sha512-YtECP/y8Mj1lSHiUWGSRzy/C6teUKlS87dEfuVKT09LgQbUsBW1rNg+MiJ4buGu3yuADV60gbIvo9/HplA56Ew==",
|
"integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
@@ -663,9 +663,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-android-arm64": {
|
"node_modules/@rolldown/binding-android-arm64": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz",
|
||||||
"integrity": "sha512-5ZiiecKH2DXAVJTNN13gNMUcCDg4Jy8ZjbXEsPnqa248wgOVeYRX0iqXXD5Jz4bI9BFHgKsI2qmyJynstbmr+g==",
|
"integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -680,9 +680,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz",
|
||||||
"integrity": "sha512-tz/v/8G77seu8zAB3A5sK3UFoOl06zcshEzhUO62sAEtrEuW/H1CcyoupOrD+NbQJytYgA4CppXPzlrmp4JZKA==",
|
"integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -697,9 +697,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-darwin-x64": {
|
"node_modules/@rolldown/binding-darwin-x64": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz",
|
||||||
"integrity": "sha512-8DakphqOz8JrMYWTJmWA+vDJxut6LijZ8Xcdc4flOlAhU7PNVwo2MaWBF9iXjJAPo5rC/IxEFZDhJ3GC7NHvug==",
|
"integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -714,9 +714,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz",
|
||||||
"integrity": "sha512-4wBQFfjDuXYN/SVI8inBF3Aa+isq40rc6VMFbk5jcpolUBTe5cYnMsHZ51nFWsx3PVyyNN3vgoESki0Hmr/4BA==",
|
"integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -731,9 +731,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz",
|
||||||
"integrity": "sha512-JW/e4yPIXLms+jmnbwwy5LA/LxVwZUWLN8xug+V200wzaVi5TEGIWQlh8o91gWYFxW609euI98OCCemmWGuPrw==",
|
"integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -748,13 +748,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz",
|
||||||
"integrity": "sha512-ZfKWpXiUymDnavepCaM6KG/uGydJ4l2nBmMxg60Ci4CbeefpqjPWpfaZM7PThOhk2dssqBAcwLc6rAyr0uTdXg==",
|
"integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -765,13 +768,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz",
|
||||||
"integrity": "sha512-bmRg3O6Z0gq9yodKKWCIpnlH051sEfdVwt+6m5UDffAQMUUqU0xjnQqqAUm+Gu7ofAAly9DqiQDtKu2nPDEABA==",
|
"integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -782,13 +788,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz",
|
||||||
"integrity": "sha512-8Wtnbw4k7pMYN9B/mOEAsQ8HOiq7AZ31Ig4M9BKn2So4xRaFEhtCSa4ZJaOutOWq50zpgR4N5+L/opnlaCx8wQ==",
|
"integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -799,13 +808,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz",
|
||||||
"integrity": "sha512-D/0Nlo8mQuxSMohNJUF2lDXWRsFDsHldfRRgD9bRgktj+EndGPj4DOV37LqDKPYS+osdyhZEH7fTakTAEcW7qg==",
|
"integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -816,13 +828,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz",
|
||||||
"integrity": "sha512-eRrPvat2YaVQcwwKi/JzOP6MKf1WRnOCr+VaI3cTWz3ZoLcP/654z90lVCJ4dAuMEpPdke0n+qyAqXDZdIC4rA==",
|
"integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -833,13 +848,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz",
|
||||||
"integrity": "sha512-PsdONiFRp8hR8KgVjTWjZ9s7uA3uueWL0t74/cKHfM4dR5zXYv4AjB8BvA+QDToqxAFg4ZkcVEqeu5F7inoz5w==",
|
"integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -850,9 +868,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz",
|
||||||
"integrity": "sha512-hCNXgC5dI3TVOLrPT++PKFNZ+1EtS0mLQwfXXXSUD/+rGlB65gZDwN/IDuxLpQP4x8RYYHqGomlUXzpO8aVI2w==",
|
"integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -867,9 +885,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-wasm32-wasi": {
|
"node_modules/@rolldown/binding-wasm32-wasi": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz",
|
||||||
"integrity": "sha512-viLS5C5et8NFtLWw9Sw3M/w4vvnVkbWkO7wSNh3C+7G1+uCkGpr6PcjNDSFcNtmXY/4trjPBqUfcOL+P3sWy/g==",
|
"integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"wasm32"
|
"wasm32"
|
||||||
],
|
],
|
||||||
@@ -877,52 +895,18 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/core": "1.9.1",
|
"@emnapi/core": "1.10.0",
|
||||||
"@emnapi/runtime": "1.9.1",
|
"@emnapi/runtime": "1.10.0",
|
||||||
"@napi-rs/wasm-runtime": "^1.1.2"
|
"@napi-rs/wasm-runtime": "^1.1.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": {
|
|
||||||
"version": "1.9.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz",
|
|
||||||
"integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"@emnapi/wasi-threads": "1.2.0",
|
|
||||||
"tslib": "^2.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": {
|
|
||||||
"version": "1.9.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz",
|
|
||||||
"integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"tslib": "^2.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
|
|
||||||
"version": "1.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz",
|
|
||||||
"integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"tslib": "^2.4.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz",
|
||||||
"integrity": "sha512-Fqa3Tlt1xL4wzmAYxGNFV36Hb+VfPc9PYU+E25DAnswXv3ODDu/yyWjQDbXMo5AGWkQVjLgQExuVu8I/UaZhPQ==",
|
"integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -937,9 +921,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz",
|
||||||
"integrity": "sha512-/pLI5kPkGEi44TDlnbio3St/5gUFeN51YWNAk/Gnv6mEQBOahRBh52qVFVBpmrnU01n2yysvBML9Ynu7K4kGAQ==",
|
"integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -1259,9 +1243,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tybys/wasm-util": {
|
"node_modules/@tybys/wasm-util": {
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
|
||||||
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
|
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@@ -1607,9 +1591,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||||
"version": "5.0.5",
|
"version": "5.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
|
||||||
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2245,9 +2229,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dompurify": {
|
"node_modules/dompurify": {
|
||||||
"version": "3.4.0",
|
"version": "3.4.10",
|
||||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.10.tgz",
|
||||||
"integrity": "sha512-nolgK9JcaUXMSmW+j1yaSvaEaoXYHwWyGJlkoCTghc97KgGDDSnpoU/PlEnw63Ah+TGKFOyY+X5LnxaWbCSfXg==",
|
"integrity": "sha512-0xzNv0e7oYC6yyuOGZIABPM4qtg3QxLFniDNPP4ZP90wR8Yq3zgwpRbrNiT4N3IKqDbbYFEJLV+JWEs19aZ//w==",
|
||||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
@@ -2855,10 +2839,20 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
"version": "4.1.1",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz",
|
||||||
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
"integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/puzrin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/nodeca"
|
||||||
|
}
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
@@ -3313,9 +3307,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.11",
|
"version": "3.3.12",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
||||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3462,9 +3456,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.8",
|
"version": "8.5.15",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
|
||||||
"integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
|
"integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -3482,7 +3476,7 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.11",
|
"nanoid": "^3.3.12",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"source-map-js": "^1.2.1"
|
"source-map-js": "^1.2.1"
|
||||||
},
|
},
|
||||||
@@ -3588,9 +3582,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router": {
|
"node_modules/react-router": {
|
||||||
"version": "7.14.0",
|
"version": "7.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.0.tgz",
|
||||||
"integrity": "sha512-m/xR9N4LQLmAS0ZhkY2nkPA1N7gQ5TUVa5n8TgANuDTARbn1gt+zLPXEm7W0XDTbrQ2AJSJKhoa6yx1D8BcpxQ==",
|
"integrity": "sha512-pTTGt8J+ji1NOmYnjzT+bAJy/1zD+Jp4ziO6cL7T3ZLvXKtusO7BpFqlRXitqpcPVqllsIXFHRMt+2/k3Xn6HQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cookie": "^1.0.1",
|
"cookie": "^1.0.1",
|
||||||
@@ -3610,12 +3604,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router-dom": {
|
"node_modules/react-router-dom": {
|
||||||
"version": "7.14.0",
|
"version": "7.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.0.tgz",
|
||||||
"integrity": "sha512-2G3ajSVSZMEtmTjIklRWlNvo8wICEpLihfD/0YMDxbWK2UyP5EGfnoIn9AIQGnF3G/FX0MRbHXdFcD+rL1ZreQ==",
|
"integrity": "sha512-Fi0yY6kgtKae/Th2xibdWK0KSdYZ4B53Gyf6wRtomOKWgpNm7H7+DyfDhncdz9FKbpS+1jmDhg3F4WoGJ+yFOA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-router": "7.14.0"
|
"react-router": "7.18.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.0.0"
|
"node": ">=20.0.0"
|
||||||
@@ -3704,14 +3698,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rolldown": {
|
"node_modules/rolldown": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
|
||||||
"integrity": "sha512-bvVj8YJmf0rq4pSFmH7laLa6pYrhghv3PRzrCdRAr23g66zOKVJ4wkvFtgohtPLWmthgg8/rkaqRHrpUEh0Zbw==",
|
"integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oxc-project/types": "=0.123.0",
|
"@oxc-project/types": "=0.133.0",
|
||||||
"@rolldown/pluginutils": "1.0.0-rc.13"
|
"@rolldown/pluginutils": "^1.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"rolldown": "bin/cli.mjs"
|
"rolldown": "bin/cli.mjs"
|
||||||
@@ -3720,27 +3714,27 @@
|
|||||||
"node": "^20.19.0 || >=22.12.0"
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rolldown/binding-android-arm64": "1.0.0-rc.13",
|
"@rolldown/binding-android-arm64": "1.0.3",
|
||||||
"@rolldown/binding-darwin-arm64": "1.0.0-rc.13",
|
"@rolldown/binding-darwin-arm64": "1.0.3",
|
||||||
"@rolldown/binding-darwin-x64": "1.0.0-rc.13",
|
"@rolldown/binding-darwin-x64": "1.0.3",
|
||||||
"@rolldown/binding-freebsd-x64": "1.0.0-rc.13",
|
"@rolldown/binding-freebsd-x64": "1.0.3",
|
||||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.13",
|
"@rolldown/binding-linux-arm-gnueabihf": "1.0.3",
|
||||||
"@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.13",
|
"@rolldown/binding-linux-arm64-gnu": "1.0.3",
|
||||||
"@rolldown/binding-linux-arm64-musl": "1.0.0-rc.13",
|
"@rolldown/binding-linux-arm64-musl": "1.0.3",
|
||||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.13",
|
"@rolldown/binding-linux-ppc64-gnu": "1.0.3",
|
||||||
"@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.13",
|
"@rolldown/binding-linux-s390x-gnu": "1.0.3",
|
||||||
"@rolldown/binding-linux-x64-gnu": "1.0.0-rc.13",
|
"@rolldown/binding-linux-x64-gnu": "1.0.3",
|
||||||
"@rolldown/binding-linux-x64-musl": "1.0.0-rc.13",
|
"@rolldown/binding-linux-x64-musl": "1.0.3",
|
||||||
"@rolldown/binding-openharmony-arm64": "1.0.0-rc.13",
|
"@rolldown/binding-openharmony-arm64": "1.0.3",
|
||||||
"@rolldown/binding-wasm32-wasi": "1.0.0-rc.13",
|
"@rolldown/binding-wasm32-wasi": "1.0.3",
|
||||||
"@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.13",
|
"@rolldown/binding-win32-arm64-msvc": "1.0.3",
|
||||||
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.13"
|
"@rolldown/binding-win32-x64-msvc": "1.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rolldown/node_modules/@rolldown/pluginutils": {
|
"node_modules/rolldown/node_modules/@rolldown/pluginutils": {
|
||||||
"version": "1.0.0-rc.13",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.13.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
|
||||||
"integrity": "sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==",
|
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@@ -3893,14 +3887,14 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/tinyglobby": {
|
"node_modules/tinyglobby": {
|
||||||
"version": "0.2.15",
|
"version": "0.2.17",
|
||||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
|
||||||
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
"picomatch": "^4.0.3"
|
"picomatch": "^4.0.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.0.0"
|
"node": ">=12.0.0"
|
||||||
@@ -4069,17 +4063,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "8.0.7",
|
"version": "8.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
|
||||||
"integrity": "sha512-P1PbweD+2/udplnThz3btF4cf6AgPky7kk23RtHUkJIU5BIxwPprhRGmOAHs6FTI7UiGbTNrgNP6jSYD6JaRnw==",
|
"integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lightningcss": "^1.32.0",
|
"lightningcss": "^1.32.0",
|
||||||
"picomatch": "^4.0.4",
|
"picomatch": "^4.0.4",
|
||||||
"postcss": "^8.5.8",
|
"postcss": "^8.5.15",
|
||||||
"rolldown": "1.0.0-rc.13",
|
"rolldown": "1.0.3",
|
||||||
"tinyglobby": "^0.2.15"
|
"tinyglobby": "^0.2.17"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"vite": "bin/vite.js"
|
"vite": "bin/vite.js"
|
||||||
@@ -4095,7 +4089,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/node": "^20.19.0 || >=22.12.0",
|
"@types/node": "^20.19.0 || >=22.12.0",
|
||||||
"@vitejs/devtools": "^0.1.0",
|
"@vitejs/devtools": "^0.1.18",
|
||||||
"esbuild": "^0.27.0 || ^0.28.0",
|
"esbuild": "^0.27.0 || ^0.28.0",
|
||||||
"jiti": ">=1.21.0",
|
"jiti": ">=1.21.0",
|
||||||
"less": "^4.0.0",
|
"less": "^4.0.0",
|
||||||
|
|||||||
195
frontend/src/components/LinkDeviceModal.tsx
Normal file
195
frontend/src/components/LinkDeviceModal.tsx
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
import { apiFetch } from '../api';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
|
import { X, Wifi, CheckCircle2, AlertCircle, Smartphone } from 'lucide-react';
|
||||||
|
import Numpad from './Numpad.tsx';
|
||||||
|
|
||||||
|
interface LinkDeviceModalProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
onSuccess: () => void;
|
||||||
|
terminalId: number | null;
|
||||||
|
terminalName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LinkDeviceModal: React.FC<LinkDeviceModalProps> = ({
|
||||||
|
isOpen,
|
||||||
|
onClose,
|
||||||
|
onSuccess,
|
||||||
|
terminalId,
|
||||||
|
terminalName
|
||||||
|
}) => {
|
||||||
|
const [otp, setOtp] = useState('');
|
||||||
|
const [success, setSuccess] = useState(false);
|
||||||
|
const [linkedDeviceId, setLinkedDeviceId] = useState<string | null>(null);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const handleLink = async (freshOtp?: string) => {
|
||||||
|
if (!terminalId) return;
|
||||||
|
const otpToSubmit = freshOtp || otp;
|
||||||
|
if (!otpToSubmit || otpToSubmit.length < 6) return;
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
try {
|
||||||
|
const response = await apiFetch(`/api/terminals/${terminalId}/link-device`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ otp: otpToSubmit }),
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
setSuccess(true);
|
||||||
|
setLinkedDeviceId(data.deviceId || null);
|
||||||
|
onSuccess();
|
||||||
|
} else {
|
||||||
|
setError(data.message || 'Failed to link device');
|
||||||
|
setOtp('');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setError('Connection error. Please try again.');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setOtp('');
|
||||||
|
setSuccess(false);
|
||||||
|
setLinkedDeviceId(null);
|
||||||
|
setError(null);
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!isOpen) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 z-[60] flex items-center justify-center p-4 bg-black/40 backdrop-blur-sm">
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, scale: 0.95, y: 20 }}
|
||||||
|
animate={{ opacity: 1, scale: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, scale: 0.95, y: 20 }}
|
||||||
|
className="bg-white rounded-3xl shadow-2xl w-full max-w-md overflow-hidden relative"
|
||||||
|
>
|
||||||
|
<div className="p-6 border-b border-gray-100 flex items-center justify-between">
|
||||||
|
<h3 className="text-xl font-bold text-[#231651]">Link Physical Device</h3>
|
||||||
|
<button onClick={handleClose} className="p-2 hover:bg-gray-100 rounded-full transition-colors">
|
||||||
|
<X size={20} className="text-gray-400" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-8">
|
||||||
|
<AnimatePresence mode="wait">
|
||||||
|
{!success ? (
|
||||||
|
<motion.div
|
||||||
|
key="otp-entry"
|
||||||
|
initial={{ opacity: 0, scale: 0.95 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
exit={{ opacity: 0, scale: 1.05 }}
|
||||||
|
className="space-y-6 text-center"
|
||||||
|
>
|
||||||
|
<div className="inline-flex p-4 bg-indigo-50 text-indigo-600 rounded-2xl mb-2">
|
||||||
|
<Wifi size={32} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4 className="text-lg font-bold text-gray-900">{terminalName}</h4>
|
||||||
|
<p className="text-sm text-gray-500 mt-1">
|
||||||
|
Enter the 6-digit OTP shown on the device screen
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Step-by-step instructions */}
|
||||||
|
<div className="p-4 bg-gray-50 rounded-2xl text-left space-y-2">
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<span className="flex-shrink-0 w-5 h-5 rounded-full bg-[#231651] text-white text-[10px] font-bold flex items-center justify-center mt-0.5">1</span>
|
||||||
|
<p className="text-xs text-gray-600 leading-relaxed">Power on the ESP32 device and connect it to Wi-Fi</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<span className="flex-shrink-0 w-5 h-5 rounded-full bg-[#231651] text-white text-[10px] font-bold flex items-center justify-center mt-0.5">2</span>
|
||||||
|
<p className="text-xs text-gray-600 leading-relaxed">A 6-digit OTP will appear on the device display</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-start gap-3">
|
||||||
|
<span className="flex-shrink-0 w-5 h-5 rounded-full bg-[#231651] text-white text-[10px] font-bold flex items-center justify-center mt-0.5">3</span>
|
||||||
|
<p className="text-xs text-gray-600 leading-relaxed">Enter that OTP below to link the device</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0, y: -10 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
className="p-3 bg-red-50 text-red-600 rounded-xl text-sm font-medium flex items-center justify-center gap-2"
|
||||||
|
>
|
||||||
|
<AlertCircle size={16} />
|
||||||
|
{error}
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Numpad value={otp} onChange={(v) => {
|
||||||
|
setOtp(v);
|
||||||
|
if (v.length === 6) {
|
||||||
|
setTimeout(() => handleLink(v), 100);
|
||||||
|
}
|
||||||
|
}} maxLength={6} />
|
||||||
|
|
||||||
|
<button
|
||||||
|
disabled={otp.length < 6 || loading}
|
||||||
|
onClick={() => handleLink()}
|
||||||
|
className="w-full h-14 bg-[#231651] text-white rounded-2xl font-bold shadow-lg shadow-[#231651]/20 hover:scale-[1.02] active:scale-[0.98] transition-all disabled:opacity-50 disabled:scale-100"
|
||||||
|
>
|
||||||
|
{loading ? 'Linking Device...' : 'Link Device'}
|
||||||
|
</button>
|
||||||
|
</motion.div>
|
||||||
|
) : (
|
||||||
|
<motion.div
|
||||||
|
key="success"
|
||||||
|
initial={{ opacity: 0, scale: 1.1 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
className="space-y-8 text-center"
|
||||||
|
>
|
||||||
|
<div className="inline-flex p-4 bg-green-50 text-green-600 rounded-full mb-2">
|
||||||
|
<CheckCircle2 size={40} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h4 className="text-xl font-bold text-gray-900">Device Linked Successfully!</h4>
|
||||||
|
<p className="text-sm text-gray-500 mt-1">
|
||||||
|
The physical device is now paired with <span className="font-semibold">{terminalName}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{linkedDeviceId && (
|
||||||
|
<div className="p-4 bg-gray-50 border border-gray-200 rounded-2xl">
|
||||||
|
<div className="flex items-center justify-center gap-2 text-sm text-gray-600">
|
||||||
|
<Smartphone size={16} />
|
||||||
|
<span className="font-mono font-medium">{linkedDeviceId}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="p-4 bg-green-50/50 rounded-2xl flex gap-3 text-left">
|
||||||
|
<CheckCircle2 size={20} className="text-green-600 shrink-0 mt-0.5" />
|
||||||
|
<p className="text-[12px] text-green-700 leading-relaxed font-medium">
|
||||||
|
The device will automatically receive its API key and restart. It's now ready to scan QR codes and print bills.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={handleClose}
|
||||||
|
className="w-full h-14 bg-[#231651] text-white rounded-2xl font-bold shadow-lg shadow-[#231651]/20 hover:scale-[1.02] active:scale-[0.98] transition-all"
|
||||||
|
>
|
||||||
|
Done
|
||||||
|
</button>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LinkDeviceModal;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { apiFetch } from '../api';
|
import { apiFetch } from '../api';
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import {
|
import {
|
||||||
@@ -10,16 +10,25 @@ import {
|
|||||||
Search,
|
Search,
|
||||||
ExternalLink,
|
ExternalLink,
|
||||||
Info,
|
Info,
|
||||||
Key
|
Key,
|
||||||
|
Wifi,
|
||||||
|
WifiOff,
|
||||||
|
LinkIcon,
|
||||||
|
Unlink,
|
||||||
|
Smartphone
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import AddTerminalModal from '../components/AddTerminalModal.tsx';
|
import AddTerminalModal from '../components/AddTerminalModal.tsx';
|
||||||
import PinVerificationModal from '../components/PinVerificationModal.tsx';
|
import PinVerificationModal from '../components/PinVerificationModal.tsx';
|
||||||
|
import LinkDeviceModal from '../components/LinkDeviceModal.tsx';
|
||||||
|
|
||||||
interface Terminal {
|
interface Terminal {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
location: string;
|
location: string;
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
|
paired: boolean;
|
||||||
|
deviceId: string | null;
|
||||||
|
pairedAt: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Terminals = () => {
|
const Terminals = () => {
|
||||||
@@ -28,6 +37,7 @@ const Terminals = () => {
|
|||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
const [isAddModalOpen, setIsAddModalOpen] = useState(false);
|
const [isAddModalOpen, setIsAddModalOpen] = useState(false);
|
||||||
const [isPinModalOpen, setIsPinModalOpen] = useState(false);
|
const [isPinModalOpen, setIsPinModalOpen] = useState(false);
|
||||||
|
const [isLinkModalOpen, setIsLinkModalOpen] = useState(false);
|
||||||
const [selectedTerminal, setSelectedTerminal] = useState<Terminal | null>(null);
|
const [selectedTerminal, setSelectedTerminal] = useState<Terminal | null>(null);
|
||||||
|
|
||||||
const fetchTerminals = async () => {
|
const fetchTerminals = async () => {
|
||||||
@@ -61,11 +71,26 @@ const Terminals = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleUnpair = async (id: number, e: React.MouseEvent) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (window.confirm('Unpair this device? It will need to be re-paired on next boot.')) {
|
||||||
|
try {
|
||||||
|
const response = await apiFetch(`/api/terminals/${id}/unpair`, { method: 'POST' });
|
||||||
|
if (response.ok) fetchTerminals();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to unpair device:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const pairedCount = terminals.filter(t => t.paired).length;
|
||||||
|
|
||||||
const filteredTerminals = terminals.filter(t => {
|
const filteredTerminals = terminals.filter(t => {
|
||||||
const query = (searchQuery || '').toLowerCase();
|
const query = (searchQuery || '').toLowerCase();
|
||||||
return (t.name || '').toLowerCase().includes(query) ||
|
return (t.name || '').toLowerCase().includes(query) ||
|
||||||
(t.location || '').toLowerCase().includes(query);
|
(t.location || '').toLowerCase().includes(query);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-8 max-w-7xl mx-auto space-y-8 font-inter">
|
<div className="p-8 max-w-7xl mx-auto space-y-8 font-inter">
|
||||||
{/* Header Section */}
|
{/* Header Section */}
|
||||||
@@ -94,26 +119,28 @@ const Terminals = () => {
|
|||||||
<Monitor size={24} />
|
<Monitor size={24} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-sm font-medium">Active Devices</p>
|
<p className="text-white/60 text-sm font-medium">Registered Devices</p>
|
||||||
<p className="text-2xl font-bold">{terminals.length}</p>
|
<p className="text-2xl font-bold">{terminals.length}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-white p-6 rounded-3xl border border-gray-100 shadow-sm flex items-center gap-4">
|
<div className="bg-white p-6 rounded-3xl border border-gray-100 shadow-sm flex items-center gap-4">
|
||||||
<div className="p-3 bg-green-50 text-green-600 rounded-2xl">
|
<div className={`p-3 rounded-2xl ${pairedCount > 0 ? 'bg-green-50 text-green-600' : 'bg-gray-50 text-gray-400'}`}>
|
||||||
<ShieldCheck size={24} />
|
<Wifi size={24} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-gray-500 text-sm font-medium">System Status</p>
|
<p className="text-gray-500 text-sm font-medium">Paired Devices</p>
|
||||||
<p className="text-xl font-bold text-gray-900 border-b-2 border-green-500 inline-block leading-tight">Secure & Online</p>
|
<p className="text-xl font-bold text-gray-900">
|
||||||
|
{pairedCount} <span className="text-sm font-medium text-gray-400">/ {terminals.length}</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="bg-blue-50 p-6 rounded-3xl flex items-center gap-4 border border-blue-100">
|
<div className="bg-blue-50 p-6 rounded-3xl flex items-center gap-4 border border-blue-100">
|
||||||
<Info size={24} className="text-blue-600 shrink-0" />
|
<Info size={24} className="text-blue-600 shrink-0" />
|
||||||
<p className="text-sm text-blue-700 font-medium leading-relaxed">
|
<p className="text-sm text-blue-700 font-medium leading-relaxed">
|
||||||
Terminals are used at physical counters to scan order QRs and print bills.
|
Power on a device and enter its 6-digit OTP here to pair it with a terminal.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -159,15 +186,30 @@ const Terminals = () => {
|
|||||||
|
|
||||||
<div className="relative z-10 space-y-4">
|
<div className="relative z-10 space-y-4">
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-start justify-between">
|
||||||
<div className="p-4 bg-gray-50 text-[#231651] rounded-2xl border border-gray-200 group-hover:bg-[#231651] group-hover:text-white transition-colors duration-300">
|
<div className={`p-4 rounded-2xl border transition-colors duration-300 ${
|
||||||
|
terminal.paired
|
||||||
|
? 'bg-green-50 text-green-600 border-green-200 group-hover:bg-green-600 group-hover:text-white'
|
||||||
|
: 'bg-gray-50 text-[#231651] border-gray-200 group-hover:bg-[#231651] group-hover:text-white'
|
||||||
|
}`}>
|
||||||
<Monitor size={28} />
|
<Monitor size={28} />
|
||||||
</div>
|
</div>
|
||||||
<button
|
<div className="flex items-center gap-1">
|
||||||
onClick={(e) => handleDelete(terminal.id, e)}
|
{terminal.paired && (
|
||||||
className="p-2 text-gray-400 hover:text-red-500 hover:bg-red-50 rounded-xl transition-all"
|
<button
|
||||||
>
|
onClick={(e) => handleUnpair(terminal.id, e)}
|
||||||
<Trash2 size={18} />
|
title="Unpair device"
|
||||||
</button>
|
className="p-2 text-gray-400 hover:text-orange-500 hover:bg-orange-50 rounded-xl transition-all"
|
||||||
|
>
|
||||||
|
<Unlink size={16} />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
onClick={(e) => handleDelete(terminal.id, e)}
|
||||||
|
className="p-2 text-gray-400 hover:text-red-500 hover:bg-red-50 rounded-xl transition-all"
|
||||||
|
>
|
||||||
|
<Trash2 size={18} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -178,16 +220,48 @@ const Terminals = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Device ID for paired terminals */}
|
||||||
|
{terminal.paired && terminal.deviceId && (
|
||||||
|
<div className="flex items-center gap-2 text-xs text-gray-400 font-mono bg-gray-50 px-3 py-1.5 rounded-lg w-fit">
|
||||||
|
<Smartphone size={12} />
|
||||||
|
<span>{terminal.deviceId}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="pt-4 flex items-center justify-between border-t border-gray-50">
|
<div className="pt-4 flex items-center justify-between border-t border-gray-50">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="w-2 h-2 rounded-full bg-green-500 animate-pulse" />
|
{terminal.paired ? (
|
||||||
<span className="text-[12px] font-bold text-gray-500 uppercase tracking-wider">Device Ready</span>
|
<>
|
||||||
</div>
|
<div className="w-2 h-2 rounded-full bg-green-500 animate-pulse" />
|
||||||
<div className="flex items-center gap-2 text-[#231651] font-bold text-sm">
|
<span className="text-[12px] font-bold text-green-600 uppercase tracking-wider">Paired</span>
|
||||||
<Key size={16} />
|
</>
|
||||||
<span>View API Key</span>
|
) : (
|
||||||
<ExternalLink size={14} />
|
<>
|
||||||
|
<div className="w-2 h-2 rounded-full bg-gray-300" />
|
||||||
|
<span className="text-[12px] font-bold text-gray-400 uppercase tracking-wider">Unpaired</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{terminal.paired ? (
|
||||||
|
<div className="flex items-center gap-2 text-[#231651] font-bold text-sm">
|
||||||
|
<Key size={16} />
|
||||||
|
<span>View API Key</span>
|
||||||
|
<ExternalLink size={14} />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
setSelectedTerminal(terminal);
|
||||||
|
setIsLinkModalOpen(true);
|
||||||
|
}}
|
||||||
|
className="flex items-center gap-2 text-indigo-600 font-bold text-sm hover:text-indigo-700 transition-colors bg-indigo-50 px-3 py-1.5 rounded-xl hover:bg-indigo-100"
|
||||||
|
>
|
||||||
|
<LinkIcon size={14} />
|
||||||
|
<span>Link Device</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
@@ -226,6 +300,17 @@ const Terminals = () => {
|
|||||||
terminalName={selectedTerminal?.name || ''}
|
terminalName={selectedTerminal?.name || ''}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<LinkDeviceModal
|
||||||
|
isOpen={isLinkModalOpen}
|
||||||
|
onClose={() => {
|
||||||
|
setIsLinkModalOpen(false);
|
||||||
|
setSelectedTerminal(null);
|
||||||
|
}}
|
||||||
|
onSuccess={fetchTerminals}
|
||||||
|
terminalId={selectedTerminal?.id || null}
|
||||||
|
terminalName={selectedTerminal?.name || ''}
|
||||||
|
/>
|
||||||
|
|
||||||
<style dangerouslySetInnerHTML={{ __html: `
|
<style dangerouslySetInnerHTML={{ __html: `
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
|
||||||
.font-inter { font-family: 'Inter', sans-serif; }
|
.font-inter { font-family: 'Inter', sans-serif; }
|
||||||
|
|||||||
440
ordering_site/package-lock.json
generated
440
ordering_site/package-lock.json
generated
@@ -31,13 +31,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
|
||||||
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
|
"integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": "^7.28.5",
|
"@babel/helper-validator-identifier": "^7.29.7",
|
||||||
"js-tokens": "^4.0.0",
|
"js-tokens": "^4.0.0",
|
||||||
"picocolors": "^1.1.1"
|
"picocolors": "^1.1.1"
|
||||||
},
|
},
|
||||||
@@ -46,9 +46,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/compat-data": {
|
"node_modules/@babel/compat-data": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
|
||||||
"integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
|
"integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -56,21 +56,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/core": {
|
"node_modules/@babel/core": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
|
||||||
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.7",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.7",
|
||||||
"@babel/helper-compilation-targets": "^7.28.6",
|
"@babel/helper-compilation-targets": "^7.29.7",
|
||||||
"@babel/helper-module-transforms": "^7.28.6",
|
"@babel/helper-module-transforms": "^7.29.7",
|
||||||
"@babel/helpers": "^7.28.6",
|
"@babel/helpers": "^7.29.7",
|
||||||
"@babel/parser": "^7.29.0",
|
"@babel/parser": "^7.29.7",
|
||||||
"@babel/template": "^7.28.6",
|
"@babel/template": "^7.29.7",
|
||||||
"@babel/traverse": "^7.29.0",
|
"@babel/traverse": "^7.29.7",
|
||||||
"@babel/types": "^7.29.0",
|
"@babel/types": "^7.29.7",
|
||||||
"@jridgewell/remapping": "^2.3.5",
|
"@jridgewell/remapping": "^2.3.5",
|
||||||
"convert-source-map": "^2.0.0",
|
"convert-source-map": "^2.0.0",
|
||||||
"debug": "^4.1.0",
|
"debug": "^4.1.0",
|
||||||
@@ -87,14 +87,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/generator": {
|
"node_modules/@babel/generator": {
|
||||||
"version": "7.29.1",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz",
|
||||||
"integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
|
"integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "^7.29.0",
|
"@babel/parser": "^7.29.7",
|
||||||
"@babel/types": "^7.29.0",
|
"@babel/types": "^7.29.7",
|
||||||
"@jridgewell/gen-mapping": "^0.3.12",
|
"@jridgewell/gen-mapping": "^0.3.12",
|
||||||
"@jridgewell/trace-mapping": "^0.3.28",
|
"@jridgewell/trace-mapping": "^0.3.28",
|
||||||
"jsesc": "^3.0.2"
|
"jsesc": "^3.0.2"
|
||||||
@@ -104,14 +104,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-compilation-targets": {
|
"node_modules/@babel/helper-compilation-targets": {
|
||||||
"version": "7.28.6",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
|
||||||
"integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
|
"integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/compat-data": "^7.28.6",
|
"@babel/compat-data": "^7.29.7",
|
||||||
"@babel/helper-validator-option": "^7.27.1",
|
"@babel/helper-validator-option": "^7.29.7",
|
||||||
"browserslist": "^4.24.0",
|
"browserslist": "^4.24.0",
|
||||||
"lru-cache": "^5.1.1",
|
"lru-cache": "^5.1.1",
|
||||||
"semver": "^6.3.1"
|
"semver": "^6.3.1"
|
||||||
@@ -121,9 +121,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-globals": {
|
"node_modules/@babel/helper-globals": {
|
||||||
"version": "7.28.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
|
||||||
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
|
"integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -131,29 +131,29 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-module-imports": {
|
"node_modules/@babel/helper-module-imports": {
|
||||||
"version": "7.28.6",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
|
||||||
"integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
|
"integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/traverse": "^7.28.6",
|
"@babel/traverse": "^7.29.7",
|
||||||
"@babel/types": "^7.28.6"
|
"@babel/types": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-module-transforms": {
|
"node_modules/@babel/helper-module-transforms": {
|
||||||
"version": "7.28.6",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
|
||||||
"integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
|
"integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-module-imports": "^7.28.6",
|
"@babel/helper-module-imports": "^7.29.7",
|
||||||
"@babel/helper-validator-identifier": "^7.28.5",
|
"@babel/helper-validator-identifier": "^7.29.7",
|
||||||
"@babel/traverse": "^7.28.6"
|
"@babel/traverse": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -163,9 +163,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-string-parser": {
|
"node_modules/@babel/helper-string-parser": {
|
||||||
"version": "7.27.1",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
|
||||||
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
|
"integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -173,9 +173,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-identifier": {
|
"node_modules/@babel/helper-validator-identifier": {
|
||||||
"version": "7.28.5",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
|
||||||
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
|
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -183,9 +183,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-option": {
|
"node_modules/@babel/helper-validator-option": {
|
||||||
"version": "7.27.1",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
|
||||||
"integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
|
"integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -193,27 +193,27 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helpers": {
|
"node_modules/@babel/helpers": {
|
||||||
"version": "7.29.2",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
|
||||||
"integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==",
|
"integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/template": "^7.28.6",
|
"@babel/template": "^7.29.7",
|
||||||
"@babel/types": "^7.29.0"
|
"@babel/types": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.29.2",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz",
|
||||||
"integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==",
|
"integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.29.0"
|
"@babel/types": "^7.29.7"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
@@ -223,33 +223,33 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/template": {
|
"node_modules/@babel/template": {
|
||||||
"version": "7.28.6",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
|
||||||
"integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
|
"integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.28.6",
|
"@babel/code-frame": "^7.29.7",
|
||||||
"@babel/parser": "^7.28.6",
|
"@babel/parser": "^7.29.7",
|
||||||
"@babel/types": "^7.28.6"
|
"@babel/types": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/traverse": {
|
"node_modules/@babel/traverse": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz",
|
||||||
"integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
|
"integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.7",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.7",
|
||||||
"@babel/helper-globals": "^7.28.0",
|
"@babel/helper-globals": "^7.29.7",
|
||||||
"@babel/parser": "^7.29.0",
|
"@babel/parser": "^7.29.7",
|
||||||
"@babel/template": "^7.28.6",
|
"@babel/template": "^7.29.7",
|
||||||
"@babel/types": "^7.29.0",
|
"@babel/types": "^7.29.7",
|
||||||
"debug": "^4.3.1"
|
"debug": "^4.3.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -257,40 +257,38 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.29.0",
|
"version": "7.29.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz",
|
||||||
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
|
"integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-string-parser": "^7.27.1",
|
"@babel/helper-string-parser": "^7.29.7",
|
||||||
"@babel/helper-validator-identifier": "^7.28.5"
|
"@babel/helper-validator-identifier": "^7.29.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/core": {
|
"node_modules/@emnapi/core": {
|
||||||
"version": "1.9.2",
|
"version": "1.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
||||||
"integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==",
|
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emnapi/wasi-threads": "1.2.1",
|
"@emnapi/wasi-threads": "1.2.1",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@emnapi/runtime": {
|
"node_modules/@emnapi/runtime": {
|
||||||
"version": "1.9.2",
|
"version": "1.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
||||||
"integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==",
|
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
@@ -302,7 +300,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
@@ -567,14 +564,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@napi-rs/wasm-runtime": {
|
"node_modules/@napi-rs/wasm-runtime": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz",
|
||||||
"integrity": "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==",
|
"integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tybys/wasm-util": "^0.10.1"
|
"@tybys/wasm-util": "^0.10.2"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -586,9 +583,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@oxc-project/types": {
|
"node_modules/@oxc-project/types": {
|
||||||
"version": "0.122.0",
|
"version": "0.133.0",
|
||||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.122.0.tgz",
|
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz",
|
||||||
"integrity": "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==",
|
"integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
@@ -596,9 +593,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-android-arm64": {
|
"node_modules/@rolldown/binding-android-arm64": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz",
|
||||||
"integrity": "sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==",
|
"integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -613,9 +610,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz",
|
||||||
"integrity": "sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==",
|
"integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -630,9 +627,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-darwin-x64": {
|
"node_modules/@rolldown/binding-darwin-x64": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz",
|
||||||
"integrity": "sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==",
|
"integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -647,9 +644,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz",
|
||||||
"integrity": "sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==",
|
"integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -664,9 +661,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz",
|
||||||
"integrity": "sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==",
|
"integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@@ -681,9 +678,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz",
|
||||||
"integrity": "sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==",
|
"integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -701,9 +698,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz",
|
||||||
"integrity": "sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==",
|
"integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -721,9 +718,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz",
|
||||||
"integrity": "sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==",
|
"integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
@@ -741,9 +738,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz",
|
||||||
"integrity": "sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==",
|
"integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
@@ -761,9 +758,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz",
|
||||||
"integrity": "sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==",
|
"integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -781,9 +778,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz",
|
||||||
"integrity": "sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==",
|
"integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -801,9 +798,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz",
|
||||||
"integrity": "sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==",
|
"integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -818,9 +815,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-wasm32-wasi": {
|
"node_modules/@rolldown/binding-wasm32-wasi": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz",
|
||||||
"integrity": "sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==",
|
"integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"wasm32"
|
"wasm32"
|
||||||
],
|
],
|
||||||
@@ -828,16 +825,18 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@napi-rs/wasm-runtime": "^1.1.1"
|
"@emnapi/core": "1.10.0",
|
||||||
|
"@emnapi/runtime": "1.10.0",
|
||||||
|
"@napi-rs/wasm-runtime": "^1.1.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz",
|
||||||
"integrity": "sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==",
|
"integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -852,9 +851,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz",
|
||||||
"integrity": "sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==",
|
"integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -876,9 +875,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@tybys/wasm-util": {
|
"node_modules/@tybys/wasm-util": {
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
|
||||||
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
|
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
@@ -1129,9 +1128,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||||
"version": "5.0.5",
|
"version": "5.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
|
||||||
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1322,9 +1321,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/baseline-browser-mapping": {
|
"node_modules/baseline-browser-mapping": {
|
||||||
"version": "2.10.16",
|
"version": "2.10.37",
|
||||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.16.tgz",
|
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.37.tgz",
|
||||||
"integrity": "sha512-Lyf3aK28zpsD1yQMiiHD4RvVb6UdMoo8xzG2XzFIfR9luPzOpcBlAsT/qfB1XWS1bxWT+UtE4WmQgsp297FYOA==",
|
"integrity": "sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -1390,9 +1389,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001786",
|
"version": "1.0.30001799",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001786.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz",
|
||||||
"integrity": "sha512-4oxTZEvqmLLrERwxO76yfKM7acZo310U+v4kqexI2TL1DkkUEMT8UijrxxcnVdxR3qkVf5awGRX+4Z6aPHVKrA==",
|
"integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -1532,9 +1531,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.332",
|
"version": "1.5.375",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.332.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.375.tgz",
|
||||||
"integrity": "sha512-7OOtytmh/rINMLwaFTbcMVvYXO3AUm029X0LcyfYk0B557RlPkdpTpnH9+htMlfu5dKwOmT0+Zs2Aw+lnn6TeQ==",
|
"integrity": "sha512-ZWP5eB4BVPW/ZYo9252hQZHZ5XavtsTgpbhcmMmRwymavC5AsLWQWBPaKMeNd2LW0KGby5HPXvj7+sr4ta5j/Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
@@ -2015,10 +2014,20 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
"version": "4.1.1",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz",
|
||||||
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
|
"integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/puzrin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/nodeca"
|
||||||
|
}
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
@@ -2449,9 +2458,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.11",
|
"version": "3.3.12",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
||||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2475,11 +2484,14 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.37",
|
"version": "2.0.47",
|
||||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz",
|
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz",
|
||||||
"integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==",
|
"integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/optionator": {
|
"node_modules/optionator": {
|
||||||
"version": "0.9.4",
|
"version": "0.9.4",
|
||||||
@@ -2585,9 +2597,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.5.8",
|
"version": "8.5.15",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
|
||||||
"integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
|
"integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -2605,7 +2617,7 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.11",
|
"nanoid": "^3.3.12",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"source-map-js": "^1.2.1"
|
"source-map-js": "^1.2.1"
|
||||||
},
|
},
|
||||||
@@ -2664,9 +2676,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router": {
|
"node_modules/react-router": {
|
||||||
"version": "7.14.0",
|
"version": "7.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.0.tgz",
|
||||||
"integrity": "sha512-m/xR9N4LQLmAS0ZhkY2nkPA1N7gQ5TUVa5n8TgANuDTARbn1gt+zLPXEm7W0XDTbrQ2AJSJKhoa6yx1D8BcpxQ==",
|
"integrity": "sha512-pTTGt8J+ji1NOmYnjzT+bAJy/1zD+Jp4ziO6cL7T3ZLvXKtusO7BpFqlRXitqpcPVqllsIXFHRMt+2/k3Xn6HQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cookie": "^1.0.1",
|
"cookie": "^1.0.1",
|
||||||
@@ -2686,12 +2698,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router-dom": {
|
"node_modules/react-router-dom": {
|
||||||
"version": "7.14.0",
|
"version": "7.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.0.tgz",
|
||||||
"integrity": "sha512-2G3ajSVSZMEtmTjIklRWlNvo8wICEpLihfD/0YMDxbWK2UyP5EGfnoIn9AIQGnF3G/FX0MRbHXdFcD+rL1ZreQ==",
|
"integrity": "sha512-Fi0yY6kgtKae/Th2xibdWK0KSdYZ4B53Gyf6wRtomOKWgpNm7H7+DyfDhncdz9FKbpS+1jmDhg3F4WoGJ+yFOA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-router": "7.14.0"
|
"react-router": "7.18.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.0.0"
|
"node": ">=20.0.0"
|
||||||
@@ -2712,14 +2724,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rolldown": {
|
"node_modules/rolldown": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz",
|
||||||
"integrity": "sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==",
|
"integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oxc-project/types": "=0.122.0",
|
"@oxc-project/types": "=0.133.0",
|
||||||
"@rolldown/pluginutils": "1.0.0-rc.12"
|
"@rolldown/pluginutils": "^1.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"rolldown": "bin/cli.mjs"
|
"rolldown": "bin/cli.mjs"
|
||||||
@@ -2728,27 +2740,27 @@
|
|||||||
"node": "^20.19.0 || >=22.12.0"
|
"node": "^20.19.0 || >=22.12.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rolldown/binding-android-arm64": "1.0.0-rc.12",
|
"@rolldown/binding-android-arm64": "1.0.3",
|
||||||
"@rolldown/binding-darwin-arm64": "1.0.0-rc.12",
|
"@rolldown/binding-darwin-arm64": "1.0.3",
|
||||||
"@rolldown/binding-darwin-x64": "1.0.0-rc.12",
|
"@rolldown/binding-darwin-x64": "1.0.3",
|
||||||
"@rolldown/binding-freebsd-x64": "1.0.0-rc.12",
|
"@rolldown/binding-freebsd-x64": "1.0.3",
|
||||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.12",
|
"@rolldown/binding-linux-arm-gnueabihf": "1.0.3",
|
||||||
"@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.12",
|
"@rolldown/binding-linux-arm64-gnu": "1.0.3",
|
||||||
"@rolldown/binding-linux-arm64-musl": "1.0.0-rc.12",
|
"@rolldown/binding-linux-arm64-musl": "1.0.3",
|
||||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.12",
|
"@rolldown/binding-linux-ppc64-gnu": "1.0.3",
|
||||||
"@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.12",
|
"@rolldown/binding-linux-s390x-gnu": "1.0.3",
|
||||||
"@rolldown/binding-linux-x64-gnu": "1.0.0-rc.12",
|
"@rolldown/binding-linux-x64-gnu": "1.0.3",
|
||||||
"@rolldown/binding-linux-x64-musl": "1.0.0-rc.12",
|
"@rolldown/binding-linux-x64-musl": "1.0.3",
|
||||||
"@rolldown/binding-openharmony-arm64": "1.0.0-rc.12",
|
"@rolldown/binding-openharmony-arm64": "1.0.3",
|
||||||
"@rolldown/binding-wasm32-wasi": "1.0.0-rc.12",
|
"@rolldown/binding-wasm32-wasi": "1.0.3",
|
||||||
"@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.12",
|
"@rolldown/binding-win32-arm64-msvc": "1.0.3",
|
||||||
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.12"
|
"@rolldown/binding-win32-x64-msvc": "1.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rolldown/node_modules/@rolldown/pluginutils": {
|
"node_modules/rolldown/node_modules/@rolldown/pluginutils": {
|
||||||
"version": "1.0.0-rc.12",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.12.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
|
||||||
"integrity": "sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==",
|
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@@ -2834,14 +2846,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tinyglobby": {
|
"node_modules/tinyglobby": {
|
||||||
"version": "0.2.15",
|
"version": "0.2.17",
|
||||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
|
||||||
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
"integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
"picomatch": "^4.0.3"
|
"picomatch": "^4.0.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.0.0"
|
"node": ">=12.0.0"
|
||||||
@@ -2969,17 +2981,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "8.0.5",
|
"version": "8.0.16",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
|
||||||
"integrity": "sha512-nmu43Qvq9UopTRfMx2jOYW5l16pb3iDC1JH6yMuPkpVbzK0k+L7dfsEDH4jRgYFmsg0sTAqkojoZgzLMlwHsCQ==",
|
"integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lightningcss": "^1.32.0",
|
"lightningcss": "^1.32.0",
|
||||||
"picomatch": "^4.0.4",
|
"picomatch": "^4.0.4",
|
||||||
"postcss": "^8.5.8",
|
"postcss": "^8.5.15",
|
||||||
"rolldown": "1.0.0-rc.12",
|
"rolldown": "1.0.3",
|
||||||
"tinyglobby": "^0.2.15"
|
"tinyglobby": "^0.2.17"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"vite": "bin/vite.js"
|
"vite": "bin/vite.js"
|
||||||
@@ -2995,7 +3007,7 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/node": "^20.19.0 || >=22.12.0",
|
"@types/node": "^20.19.0 || >=22.12.0",
|
||||||
"@vitejs/devtools": "^0.1.0",
|
"@vitejs/devtools": "^0.1.18",
|
||||||
"esbuild": "^0.27.0 || ^0.28.0",
|
"esbuild": "^0.27.0 || ^0.28.0",
|
||||||
"jiti": ">=1.21.0",
|
"jiti": ">=1.21.0",
|
||||||
"less": "^4.0.0",
|
"less": "^4.0.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Star, Send, X } from 'lucide-react';
|
import { Star } from 'lucide-react';
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import './FeedbackModal.css';
|
import './FeedbackModal.css';
|
||||||
|
|
||||||
interface OrderItem {
|
interface OrderItem {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ interface AuthContextType {
|
|||||||
user: User | null;
|
user: User | null;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
checkUserExists: (mobileNumber: string) => Promise<{ success: boolean; userExists: boolean; message: string }>;
|
checkUserExists: (mobileNumber: string) => Promise<{ success: boolean; userExists: boolean; message: string }>;
|
||||||
login: (mobileNumber: string, pin: string) => Promise<{ success: boolean; message: string }>;
|
login: (mobileNumber: string, pin: string) => Promise<{ success: boolean; message: string; isSuspended?: boolean }>;
|
||||||
register: (mobileNumber: string, name: string, pin: string) => Promise<{ success: boolean; message: string }>;
|
register: (mobileNumber: string, name: string, pin: string) => Promise<{ success: boolean; message: string }>;
|
||||||
logout: () => void;
|
logout: () => void;
|
||||||
changePin: (currentPin: string, newPin: string) => Promise<{ success: boolean; message: string }>;
|
changePin: (currentPin: string, newPin: string) => Promise<{ success: boolean; message: string }>;
|
||||||
@@ -53,9 +53,12 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
|||||||
if (data.success && data.user) {
|
if (data.success && data.user) {
|
||||||
setUser(data.user);
|
setUser(data.user);
|
||||||
localStorage.setItem('user', JSON.stringify(data.user));
|
localStorage.setItem('user', JSON.stringify(data.user));
|
||||||
|
if (data.token) {
|
||||||
|
localStorage.setItem('token', data.token);
|
||||||
|
}
|
||||||
return { success: true, message: data.message };
|
return { success: true, message: data.message };
|
||||||
}
|
}
|
||||||
return { success: false, message: data.message || 'Login failed' };
|
return { success: false, message: data.message || 'Login failed', isSuspended: data.suspended || data.isSuspended };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { success: false, message: 'Network error. Please try again.' };
|
return { success: false, message: 'Network error. Please try again.' };
|
||||||
}
|
}
|
||||||
@@ -72,6 +75,9 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
|||||||
if (data.success && data.user) {
|
if (data.success && data.user) {
|
||||||
setUser(data.user);
|
setUser(data.user);
|
||||||
localStorage.setItem('user', JSON.stringify(data.user));
|
localStorage.setItem('user', JSON.stringify(data.user));
|
||||||
|
if (data.token) {
|
||||||
|
localStorage.setItem('token', data.token);
|
||||||
|
}
|
||||||
return { success: true, message: data.message };
|
return { success: true, message: data.message };
|
||||||
}
|
}
|
||||||
return { success: false, message: data.message || 'Registration failed' };
|
return { success: false, message: data.message || 'Registration failed' };
|
||||||
@@ -82,22 +88,31 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
|||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
if (user) {
|
if (user) {
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
fetch(`${API_BASE_URL}/logout`, { cache: 'no-store',
|
fetch(`${API_BASE_URL}/logout`, { cache: 'no-store',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(token ? { 'Authorization': `Bearer ${token}` } : {})
|
||||||
|
},
|
||||||
body: JSON.stringify({ mobileNumber: user.mobileNumber }),
|
body: JSON.stringify({ mobileNumber: user.mobileNumber }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setUser(null);
|
setUser(null);
|
||||||
localStorage.removeItem('user');
|
localStorage.removeItem('user');
|
||||||
|
localStorage.removeItem('token');
|
||||||
};
|
};
|
||||||
|
|
||||||
const changePin = async (currentPin: string, newPin: string) => {
|
const changePin = async (currentPin: string, newPin: string) => {
|
||||||
if (!user) return { success: false, message: 'Not logged in' };
|
if (!user) return { success: false, message: 'Not logged in' };
|
||||||
try {
|
try {
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
const response = await fetch(`${API_BASE_URL}/change-pin`, { cache: 'no-store',
|
const response = await fetch(`${API_BASE_URL}/change-pin`, { cache: 'no-store',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(token ? { 'Authorization': `Bearer ${token}` } : {})
|
||||||
|
},
|
||||||
body: JSON.stringify({ mobileNumber: user.mobileNumber, currentPin, newPin }),
|
body: JSON.stringify({ mobileNumber: user.mobileNumber, currentPin, newPin }),
|
||||||
});
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
@@ -110,9 +125,13 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
|||||||
const updateProfile = async (name: string, mobileNumber: string) => {
|
const updateProfile = async (name: string, mobileNumber: string) => {
|
||||||
if (!user) return { success: false, message: 'Not logged in' };
|
if (!user) return { success: false, message: 'Not logged in' };
|
||||||
try {
|
try {
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
const response = await fetch(`${API_BASE_URL}/users/${user.id}`, { cache: 'no-store',
|
const response = await fetch(`${API_BASE_URL}/users/${user.id}`, { cache: 'no-store',
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(token ? { 'Authorization': `Bearer ${token}` } : {})
|
||||||
|
},
|
||||||
body: JSON.stringify({ name, mobileNumber }),
|
body: JSON.stringify({ name, mobileNumber }),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -141,7 +160,13 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
|||||||
const refreshUser = async () => {
|
const refreshUser = async () => {
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/user/${user.mobileNumber}`, { cache: 'no-store' });
|
const token = localStorage.getItem('token');
|
||||||
|
const response = await fetch(`${API_BASE_URL}/user/${user.mobileNumber}`, {
|
||||||
|
cache: 'no-store',
|
||||||
|
headers: {
|
||||||
|
...(token ? { 'Authorization': `Bearer ${token}` } : {})
|
||||||
|
}
|
||||||
|
});
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
const updatedUser: User = {
|
const updatedUser: User = {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ interface FoodContextType {
|
|||||||
stalls: Stall[];
|
stalls: Stall[];
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
refreshData: () => Promise<void>;
|
refreshData: (silent?: boolean) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FoodContext = createContext<FoodContextType | undefined>(undefined);
|
const FoodContext = createContext<FoodContextType | undefined>(undefined);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
CircleDollarSign,
|
|
||||||
Wallet,
|
Wallet,
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
AlertCircle,
|
AlertCircle,
|
||||||
@@ -24,7 +23,6 @@ const CheckoutScreen: React.FC = () => {
|
|||||||
const { refreshData } = useFood();
|
const { refreshData } = useFood();
|
||||||
const [isProcessing, setIsProcessing] = useState(false);
|
const [isProcessing, setIsProcessing] = useState(false);
|
||||||
const [currentBalance, setCurrentBalance] = useState<number>(user?.ritzTokenBalance || 0);
|
const [currentBalance, setCurrentBalance] = useState<number>(user?.ritzTokenBalance || 0);
|
||||||
const [isLoadingBalance, setIsLoadingBalance] = useState(true);
|
|
||||||
|
|
||||||
// Conflict state
|
// Conflict state
|
||||||
const [stockConflicts, setStockConflicts] = useState<any[]>([]);
|
const [stockConflicts, setStockConflicts] = useState<any[]>([]);
|
||||||
@@ -37,14 +35,16 @@ const CheckoutScreen: React.FC = () => {
|
|||||||
const fetchBalance = async () => {
|
const fetchBalance = async () => {
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
try {
|
try {
|
||||||
setIsLoadingBalance(true);
|
const token = localStorage.getItem('token');
|
||||||
const response = await fetch(`http://${window.location.hostname}:8080/api/wallet/balance/${user.id}`);
|
const response = await fetch(`http://${window.location.hostname}:8080/api/wallet/balance/${user.id}`, {
|
||||||
|
headers: {
|
||||||
|
...(token ? { 'Authorization': `Bearer ${token}` } : {})
|
||||||
|
}
|
||||||
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setCurrentBalance(data.balance || 0);
|
setCurrentBalance(data.balance || 0);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching balance:', error);
|
console.error('Error fetching balance:', error);
|
||||||
} finally {
|
|
||||||
setIsLoadingBalance(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -76,9 +76,13 @@ const CheckoutScreen: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
const response = await fetch(`http://${window.location.hostname}:8080/api/orders`, {
|
const response = await fetch(`http://${window.location.hostname}:8080/api/orders`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(token ? { 'Authorization': `Bearer ${token}` } : {})
|
||||||
|
},
|
||||||
body: JSON.stringify(orderData),
|
body: JSON.stringify(orderData),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,12 @@ const HomeScreen: React.FC = () => {
|
|||||||
if (sessionStorage.getItem('feedback_dismissed')) return;
|
if (sessionStorage.getItem('feedback_dismissed')) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`http://${window.location.hostname}:8080/api/feedback/latest-unrated/${user?.id}`);
|
const token = localStorage.getItem('token');
|
||||||
|
const response = await fetch(`http://${window.location.hostname}:8080/api/feedback/latest-unrated/${user?.id}`, {
|
||||||
|
headers: {
|
||||||
|
...(token ? { 'Authorization': `Bearer ${token}` } : {})
|
||||||
|
}
|
||||||
|
});
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
const order = await response.json();
|
const order = await response.json();
|
||||||
console.log('Unrated order found:', order);
|
console.log('Unrated order found:', order);
|
||||||
@@ -53,8 +58,12 @@ const HomeScreen: React.FC = () => {
|
|||||||
if (!unratedOrder) return;
|
if (!unratedOrder) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
await fetch(`http://${window.location.hostname}:8080/api/feedback/skip/${unratedOrder.id}`, {
|
await fetch(`http://${window.location.hostname}:8080/api/feedback/skip/${unratedOrder.id}`, {
|
||||||
method: 'POST'
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
...(token ? { 'Authorization': `Bearer ${token}` } : {})
|
||||||
|
}
|
||||||
});
|
});
|
||||||
setShowFeedbackModal(false);
|
setShowFeedbackModal(false);
|
||||||
setShowFeedbackSnackbar(false);
|
setShowFeedbackSnackbar(false);
|
||||||
@@ -70,9 +79,13 @@ const HomeScreen: React.FC = () => {
|
|||||||
|
|
||||||
const handleFeedbackSubmit = async (feedbackData: any) => {
|
const handleFeedbackSubmit = async (feedbackData: any) => {
|
||||||
try {
|
try {
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
const response = await fetch(`http://${window.location.hostname}:8080/api/feedback/submit`, {
|
const response = await fetch(`http://${window.location.hostname}:8080/api/feedback/submit`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(token ? { 'Authorization': `Bearer ${token}` } : {})
|
||||||
|
},
|
||||||
body: JSON.stringify(feedbackData)
|
body: JSON.stringify(feedbackData)
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -112,7 +125,7 @@ const HomeScreen: React.FC = () => {
|
|||||||
<div className="container" style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: 24, textAlign: 'center' }}>
|
<div className="container" style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: 24, textAlign: 'center' }}>
|
||||||
<h2 style={{ marginBottom: 12 }}>Oops! Something went wrong</h2>
|
<h2 style={{ marginBottom: 12 }}>Oops! Something went wrong</h2>
|
||||||
<p style={{ color: 'var(--text-mid)', marginBottom: 24 }}>{error}</p>
|
<p style={{ color: 'var(--text-mid)', marginBottom: 24 }}>{error}</p>
|
||||||
<button className="primary-button" onClick={refreshData} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
<button className="primary-button" onClick={() => refreshData()} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||||
<RefreshCcw size={18} /> Try Again
|
<RefreshCcw size={18} /> Try Again
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import type { FoodItem } from '../types';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { AlertCircle } from 'lucide-react';
|
import { AlertCircle } from 'lucide-react';
|
||||||
import Header from '../components/Header';
|
import Header from '../components/Header';
|
||||||
@@ -56,21 +57,18 @@ const ItemDetailScreen: React.FC = () => {
|
|||||||
fetchItem();
|
fetchItem();
|
||||||
}
|
}
|
||||||
}, [itemId, contextItem]);
|
}, [itemId, contextItem]);
|
||||||
const quantity = item ? getItemQuantity(item.id) : 0;
|
if (isGlobalLoading || isFetching || !item) {
|
||||||
const isLimitReached = item && item.stock !== undefined && quantity >= item.stock && item.stock > 0;
|
if (isGlobalLoading || isFetching) {
|
||||||
|
return (
|
||||||
if ((isGlobalLoading && foodItems.length === 0) || isFetching) {
|
<div className="container item-loading-wrapper">
|
||||||
return (
|
<div className="loading-spinner-wrapper">
|
||||||
<div className="container item-loading-wrapper">
|
<div className="loading-spinner"></div>
|
||||||
<div className="loading-spinner-wrapper">
|
<p>Loading Delights...</p>
|
||||||
<div className="loading-spinner"></div>
|
</div>
|
||||||
<p>Loading Delights...</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!item && !isGlobalLoading && !isFetching) {
|
|
||||||
return (
|
return (
|
||||||
<div className="container item-not-found-wrapper">
|
<div className="container item-not-found-wrapper">
|
||||||
<Header />
|
<Header />
|
||||||
@@ -84,6 +82,9 @@ const ItemDetailScreen: React.FC = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const quantity = getItemQuantity(item.id);
|
||||||
|
const isLimitReached = item.stock !== undefined && quantity >= item.stock && item.stock > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`container item-detail-page ${item.stock === 0 ? 'out-of-stock' : ''}`}>
|
<div className={`container item-detail-page ${item.stock === 0 ? 'out-of-stock' : ''}`}>
|
||||||
<Header title="" />
|
<Header title="" />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { Clock, ShoppingBag as ShoppingBagIcon, ChevronRight as ChevronRightIcon, X, RefreshCcw, AlertCircle, ShoppingCart } from 'lucide-react';
|
import { Clock, ShoppingBag as ShoppingBagIcon, ChevronRight as ChevronRightIcon, X, RefreshCcw, AlertCircle } from 'lucide-react';
|
||||||
import { QRCodeCanvas } from 'qrcode.react';
|
import { QRCodeCanvas } from 'qrcode.react';
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
import Header from '../components/Header';
|
import Header from '../components/Header';
|
||||||
@@ -58,7 +58,7 @@ const MyOrdersScreen: React.FC = () => {
|
|||||||
|
|
||||||
// Polling for live updates (Sync when Dashboard regenerates QR or changes status)
|
// Polling for live updates (Sync when Dashboard regenerates QR or changes status)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let interval: NodeJS.Timeout;
|
let interval: ReturnType<typeof setInterval>;
|
||||||
|
|
||||||
// Only poll if there are active (non-finalized) orders
|
// Only poll if there are active (non-finalized) orders
|
||||||
const hasActiveOrders = orders.some(o =>
|
const hasActiveOrders = orders.some(o =>
|
||||||
@@ -79,7 +79,12 @@ const MyOrdersScreen: React.FC = () => {
|
|||||||
|
|
||||||
const fetchOrders = async () => {
|
const fetchOrders = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`http://${window.location.hostname}:8080/api/orders/user/${user?.id}`);
|
const token = localStorage.getItem('token');
|
||||||
|
const response = await fetch(`http://${window.location.hostname}:8080/api/orders/user/${user?.id}`, {
|
||||||
|
headers: {
|
||||||
|
...(token ? { 'Authorization': `Bearer ${token}` } : {})
|
||||||
|
}
|
||||||
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setOrders(data);
|
setOrders(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -132,10 +137,14 @@ const MyOrdersScreen: React.FC = () => {
|
|||||||
if (!selectedOrder) return;
|
if (!selectedOrder) return;
|
||||||
setIsRegenerating(true);
|
setIsRegenerating(true);
|
||||||
try {
|
try {
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
const newOrderNumber = `ORD-${Math.random().toString(36).substring(2, 10).toUpperCase()}`;
|
const newOrderNumber = `ORD-${Math.random().toString(36).substring(2, 10).toUpperCase()}`;
|
||||||
const response = await fetch(`http://${window.location.hostname}:8080/api/orders/${selectedOrder.id}`, {
|
const response = await fetch(`http://${window.location.hostname}:8080/api/orders/${selectedOrder.id}`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(token ? { 'Authorization': `Bearer ${token}` } : {})
|
||||||
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
...selectedOrder,
|
...selectedOrder,
|
||||||
orderNumber: newOrderNumber
|
orderNumber: newOrderNumber
|
||||||
|
|||||||
@@ -71,9 +71,9 @@ const StallDetailScreen: React.FC = () => {
|
|||||||
if (!prevStall) return prevStall;
|
if (!prevStall) return prevStall;
|
||||||
return {
|
return {
|
||||||
...prevStall,
|
...prevStall,
|
||||||
products: prevStall.products.map(p =>
|
products: prevStall.products ? prevStall.products.map(p =>
|
||||||
p.id === update.productId.toString() ? { ...p, stock: update.stock } : p
|
p.id === update.productId.toString() ? { ...p, stock: update.stock } : p
|
||||||
)
|
) : []
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
Reference in New Issue
Block a user