FastAPI backend (Python 3.11, MSSQL ODBC for SambaPOS, Azure DI OCR),
kitchen_db on central PG. React/TS/Vite frontend with navy sidebar layout.
Backend: auth.py (APP_SLUG=kitchen, SimpleNamespace — archive routes use
.kitchen_id/.is_admin without modification), main.py (51 migrations, scheduler,
internal router for KDS bookings feed), api/internal.py, full archive API
(31 routers: invoices, recipes, menus, sambapos, resos, newbook, disputes,
purchase_orders, etc.), models, migrations, OCR pipeline.
kitchen_id pinned to 1 (B1 — single hotel).
Frontend: AuthGate (app=kitchen, token shim for archive compat — B5b pending),
Layout (navy sidebar, 6 sections, Lucide icons, teal --app-primary),
App.tsx (Outlet pattern, UploadApp outside Layout), index.css (full :root block).
strict: false — archive components have type issues; build clean.
Note: 45 archive components call fetch('/api/...') without /kitchen/ prefix
(B5b). Runtime 404s; deferred until after initial testing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
64 lines
2.1 KiB
JavaScript
64 lines
2.1 KiB
JavaScript
import utils from '../utils.js';
|
|
import platform from '../platform/index.js';
|
|
|
|
export default platform.hasStandardBrowserEnv
|
|
? // Standard browser envs support document.cookie
|
|
{
|
|
write(name, value, expires, path, domain, secure, sameSite) {
|
|
if (typeof document === 'undefined') return;
|
|
|
|
const cookie = [`${name}=${encodeURIComponent(value)}`];
|
|
|
|
if (utils.isNumber(expires)) {
|
|
cookie.push(`expires=${new Date(expires).toUTCString()}`);
|
|
}
|
|
if (utils.isString(path)) {
|
|
cookie.push(`path=${path}`);
|
|
}
|
|
if (utils.isString(domain)) {
|
|
cookie.push(`domain=${domain}`);
|
|
}
|
|
if (secure === true) {
|
|
cookie.push('secure');
|
|
}
|
|
if (utils.isString(sameSite)) {
|
|
cookie.push(`SameSite=${sameSite}`);
|
|
}
|
|
|
|
document.cookie = cookie.join('; ');
|
|
},
|
|
|
|
read(name) {
|
|
if (typeof document === 'undefined') return null;
|
|
// Match name=value by splitting on the semicolon separator instead of building a
|
|
// RegExp from `name` — interpolating an unescaped string into a RegExp would let
|
|
// metacharacters (e.g. `.+?` in an attacker-influenced cookie name) cause ReDoS or
|
|
// match the wrong cookie. Browsers may serialize cookie pairs as either ";" or
|
|
// "; ", so ignore optional whitespace before each cookie name.
|
|
const cookies = document.cookie.split(';');
|
|
for (let i = 0; i < cookies.length; i++) {
|
|
const cookie = cookies[i].replace(/^\s+/, '');
|
|
const eq = cookie.indexOf('=');
|
|
if (eq !== -1 && cookie.slice(0, eq) === name) {
|
|
try {
|
|
return decodeURIComponent(cookie.slice(eq + 1));
|
|
} catch (e) {
|
|
return cookie.slice(eq + 1);
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
},
|
|
|
|
remove(name) {
|
|
this.write(name, '', Date.now() - 86400000, '/');
|
|
},
|
|
}
|
|
: // Non-standard browser env (web workers, react-native) lack needed support.
|
|
{
|
|
write() {},
|
|
read() {
|
|
return null;
|
|
},
|
|
remove() {},
|
|
};
|