Add Mode1 auth testing environment with token comparison verification

- Created Mode1 as self-contained test environment
- Added auth-module copy with self-contained configuration
- Implemented backend server with Graph token and PocketBase validation endpoints
- Added frontend test dashboard with token comparison functionality
- Fixed TypeScript compatibility issues (replaced import.meta.dir with __dirname)
- Implemented actual PB token validation in comparison endpoint (no placeholders)
- All endpoints tested and working with real tokens
This commit is contained in:
2026-01-22 05:32:33 +00:00
parent 3ff23cd2bd
commit 1fdc87f7f4
152 changed files with 2672 additions and 21067 deletions
+99
View File
@@ -0,0 +1,99 @@
# Mode1 - Auth Module Test Suite
Self-contained test environment for the auth-module. This directory includes its own copy of auth-module and all dependencies.
## Structure
```
Mode1/
├── auth-module/ # Local copy of auth-module (not linked to root)
├── backend/ # Backend server with auth endpoints
│ └── server.ts # Hono app with Graph token and PB validation APIs
├── frontend/ # Frontend test interface
│ └── index.html # Interactive test dashboard
├── logs/ # Application logs
├── package.json # Dependencies (auth module + Hono + PocketBase)
└── bun.lock # Locked dependencies
```
## Features Tested
**Frontend Auth (PocketBaseAuth)**
- OAuth2 login initialization
- Auth state retrieval
- Token refresh
- Logout
**Backend Auth (GraphTokenManager)**
- Microsoft Graph token acquisition
- Token caching (with 60s expiration buffer)
- Cache validity checking
- Cache refresh
**PocketBase Validation (PocketBaseValidator)**
- User token validation
- User record retrieval
## Running Mode1
### Via Orchestrator (recommended)
```bash
# Switch to Mode1
curl -X POST http://localhost:3006/switch/Mode1
# Check status
curl http://localhost:3006/status
```
### Direct
```bash
# Install dependencies (already done)
bun install
# Start server
bun run backend/server.ts
# Access dashboard
open http://localhost:3005
```
## API Endpoints
### Configuration
- `GET /api/auth/config` - Get frontend configuration
### Graph Token Management
- `GET /api/auth/graph/token` - Get current Graph token (with expiration)
- `POST /api/auth/refresh-graph` - Force refresh Graph token
### PocketBase Validation
- `POST /api/auth/validate-pb-token` - Validate a PocketBase token
### Health
- `GET /health` - Health check
## Environment Variables
Uses `/home/admin/secrets/.env` via auth-module:
- `CLIENT_ID` - Microsoft application ID
- `TENANT_ID` - Azure tenant ID
- `CLIENT_SECRET` - Microsoft client secret
- `PB_URL` - PocketBase frontend URL
- `PB_DB` - PocketBase backend URL
## Dependencies
All dependencies are installed locally in `node_modules/`:
- `hono` - Web framework
- `pocketbase` - PocketBase client
- `@azure/msal-node` - Microsoft authentication
- `dotenv` - Environment variable loading
## Notes
- This Mode1 is **completely self-contained** with its own auth-module copy
- No dependencies on root auth-module
- Safe to modify and test independently
- All secrets come from `/home/admin/secrets/.env`
+248
View File
@@ -0,0 +1,248 @@
# Auth Module
Standalone authentication module for PocketBase OAuth2 + Microsoft Graph integration.
## Features
- **Frontend**: PocketBase OAuth2 authentication with Microsoft provider
- **Backend**: Microsoft Graph token management with automatic caching
- **No dependencies on project-specific code** - Use in any project
## Installation
Copy the `auth-module` folder to your project:
```bash
cp -r auth-module /path/to/your/project/
```
Install dependencies:
```bash
bun add pocketbase @azure/msal-node
```
## Frontend Usage
### Basic Setup
**Important**: The frontend is browser-side code. It must receive `pbUrl` from the consuming application (not from the backend).
```typescript
import { PocketBaseAuth } from './auth-module/frontend';
// In your project, load PB_URL from environment/config and pass it to frontend
const auth = new PocketBaseAuth({
pbUrl: process.env.PB_URL, // Required - must be provided by consuming application
collection: 'Users',
provider: 'microsoft',
loginContainerId: 'loginContainer',
userDisplayNameId: 'userDisplayName',
userEmailId: 'userEmailValue',
loginBtnId: 'loginBtn',
loginErrorId: 'loginError',
});
```
### HTML Required
```html
<!-- Login container (shown when not authenticated) -->
<div id="loginContainer" class="hidden">
<button id="loginBtn">Login with Microsoft</button>
<div id="loginError" class="hidden"></div>
</div>
<!-- User display (shown when authenticated) -->
<div id="userDisplayName"></div>
<div id="userEmailValue"></div>
```
### Event Callbacks
```typescript
const auth = new PocketBaseAuth(config, {
onAuthSuccess: (state) => {
console.log('Logged in:', state.user.email);
// Initialize other systems here
},
onAuthFailure: (error) => {
console.error('Login failed:', error);
},
onTokenUpdate: (state) => {
console.log('Token refreshed');
},
onUiUpdate: (state) => {
console.log('UI updated');
},
});
```
### Methods
```typescript
// Get current auth state
const state = auth.getAuthState();
console.log(state.isAuthenticated, state.user);
// Check token status
const status = await auth.checkTokenStatus();
// Logout
auth.logout();
// Get raw PocketBase instance if needed
const pb = auth.getPocketBase();
```
## Backend Usage
### Setup (server.ts)
```typescript
import { GraphTokenManager, PocketBaseValidator, BackendAuth } from './auth-module/backend';
// Option 1: Use individual managers
const graphMgr = new GraphTokenManager({
clientId: process.env.CLIENT_ID,
tenantId: process.env.TENANT_ID,
clientSecret: process.env.CLIENT_SECRET,
});
const pbValidator = new PocketBaseValidator(process.env.PB_DB);
// Option 2: Use combined manager
const backendAuth = new BackendAuth({
clientId: process.env.CLIENT_ID,
tenantId: process.env.TENANT_ID,
clientSecret: process.env.CLIENT_SECRET,
}, process.env.PB_DB);
```
### Get Graph Token
```typescript
// Get token string
const token = await graphMgr.getToken();
// Get token with expiration
const { token, expiresOnISO } = await graphMgr.getTokenWithExpiry();
// Check if cached and valid
if (graphMgr.isTokenValid()) {
console.log('Using cached token');
}
// Clear cache (force refresh)
graphMgr.clearCache();
```
### Validate PocketBase Token
```typescript
// Validate token
const isValid = await pbValidator.validateUserToken(token);
// Get user record
const user = await pbValidator.getUserRecord(token);
// Get PocketBase instance
const pb = pbValidator.getPocketBase();
```
### Endpoint Example
```typescript
app.get('/api/graph/status', async (c) => {
try {
const { token, expiresOnISO } = await graphMgr.getTokenWithExpiry();
return c.json({
active: true,
expiresOnISO,
});
} catch (error) {
return c.json(
{ active: false, error: error.message },
500
);
}
});
app.post('/api/submit', async (c) => {
const body = await c.req.json();
const pbToken = body.pbToken;
if (!pbToken) {
return c.json({ error: 'Missing pbToken' }, 401);
}
const isValid = await pbValidator.validateUserToken(pbToken);
if (!isValid) {
return c.json({ error: 'Invalid token' }, 401);
}
// Token is valid, proceed with business logic
// ...
});
```
## Environment Variables
Required in `.env` file:
```env
CLIENT_ID=your-microsoft-app-id
TENANT_ID=your-azure-tenant-id
CLIENT_SECRET=your-microsoft-client-secret
PB_DB=https://your-pocketbase-instance.com
PB_URL=https://your-pocketbase-instance.com
```
## Configuration
### Frontend Config Options
```typescript
interface AuthConfig {
pbUrl: string; // PocketBase URL (required)
collection?: string; // Auth collection (default: Users)
provider?: string; // OAuth provider (default: microsoft)
loginContainerId?: string; // ID of login container element
userDisplayNameId?: string; // ID of user name display element
userEmailId?: string; // ID of user email display element
loginBtnId?: string; // ID of login button element
loginErrorId?: string; // ID of error message element
}
```
### Backend Config Options
```typescript
interface BackendAuthConfig {
clientId?: string; // Microsoft app ID (or CLIENT_ID env var)
tenantId?: string; // Azure tenant ID (or TENANT_ID env var)
clientSecret?: string; // Client secret (or CLIENT_SECRET env var)
}
```
## TypeScript
The module exports TypeScript types for type safety:
```typescript
import { AuthState, AuthConfig, GraphTokenCache } from './auth-module/types';
const state: AuthState = auth.getAuthState();
```
## Notes
- **Frontend** manages user authentication only
- **Backend** manages Graph API tokens (never exposed to client)
- Tokens are cached in-memory on backend with automatic refresh
- Module does not include project-specific features (alerts, etc.)
- Each project can implement its own business logic on top
## License
Same as parent project
+204
View File
@@ -0,0 +1,204 @@
import { config } from 'dotenv';
import { ConfidentialClientApplication } from '@azure/msal-node';
import PocketBase from 'pocketbase';
import { GraphTokenCache, BackendAuthConfig } from './types';
// Load environment variables from shared secrets directory
config({ path: '/home/admin/secrets/.env' });
/**
* Configuration Manager
* Exposes frontend-safe configuration loaded from environment
*/
export class AuthConfigManager {
/**
* Get frontend configuration (safe to expose to browser)
*/
static getFrontendConfig() {
return {
pbUrl: process.env.PB_URL!,
provider: 'microsoft',
collection: 'Users',
};
}
/**
* Get all backend secrets (never expose to frontend)
*/
static getBackendConfig() {
return {
clientId: process.env.CLIENT_ID!,
tenantId: process.env.TENANT_ID!,
clientSecret: process.env.CLIENT_SECRET!,
pbDb: process.env.PB_DB!,
};
}
}
/**
* Microsoft Graph Token Management (Backend)
* Handles token acquisition and caching for backend Graph API calls
*/
export class GraphTokenManager {
private cca: ConfidentialClientApplication;
private cache: GraphTokenCache | null = null;
private config: Required<BackendAuthConfig>;
constructor(config: BackendAuthConfig) {
this.config = {
clientId: config.clientId || process.env.CLIENT_ID || '',
tenantId: config.tenantId || process.env.TENANT_ID || '',
clientSecret: config.clientSecret || process.env.CLIENT_SECRET || '',
};
this.cca = new ConfidentialClientApplication({
auth: {
clientId: this.config.clientId,
authority: `https://login.microsoftonline.com/${this.config.tenantId}`,
clientSecret: this.config.clientSecret,
},
});
}
/**
* Get Graph token (from cache or acquire new)
*/
async getToken(): Promise<string> {
const now = Date.now();
// Check cache validity (with 60s buffer for expiration)
if (this.cache && this.cache.expiresOn - 60000 > now) {
return this.cache.token;
}
try {
const result = await this.cca.acquireTokenByClientCredential({
scopes: ['https://graph.microsoft.com/.default'],
});
if (!result?.accessToken) {
throw new Error('Failed to acquire Graph token');
}
const expiresOn = result.expiresOn
? new Date(result.expiresOn).getTime()
: now + 55 * 60 * 1000; // Default 55 minutes
this.cache = {
token: result.accessToken,
expiresOn,
};
return result.accessToken;
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
throw new Error(`Failed to acquire Graph token: ${message}`);
}
}
/**
* Get token with expiration info
*/
async getTokenWithExpiry(): Promise<{ token: string; expiresOnISO: string }> {
const token = await this.getToken();
const expiresOn = this.cache?.expiresOn || Date.now();
return {
token,
expiresOnISO: new Date(expiresOn).toISOString(),
};
}
/**
* Check if token is cached and valid
*/
isTokenValid(): boolean {
if (!this.cache) return false;
const now = Date.now();
return this.cache.expiresOn - 60000 > now;
}
/**
* Clear cache (force refresh on next call)
*/
clearCache(): void {
this.cache = null;
}
}
/**
* PocketBase Token Validation (Backend)
* Validates and uses user PocketBase tokens
*/
export class PocketBaseValidator {
private pb: PocketBase;
constructor(pbUrl?: string) {
this.pb = new PocketBase(pbUrl || process.env.PB_DB!);
}
/**
* Set user token and validate it
*/
async validateUserToken(token: string): Promise<boolean> {
try {
this.pb.authStore.save(token, null);
await this.pb.collection('Users').authRefresh();
return true;
} catch (error) {
console.error('Token validation failed:', error instanceof Error ? error.message : error);
return false;
}
}
/**
* Get user record from token
*/
async getUserRecord(token: string): Promise<any> {
try {
this.pb.authStore.save(token, null);
const record = this.pb.authStore.record || this.pb.authStore.model;
return record;
} catch (error) {
console.error('Failed to get user record:', error);
return null;
}
}
/**
* Get PocketBase instance
*/
getPocketBase(): PocketBase {
return this.pb;
}
}
/**
* Combined backend auth manager
*/
export class BackendAuth {
graphTokenManager: GraphTokenManager;
pbValidator: PocketBaseValidator;
constructor(config: BackendAuthConfig, pbUrl?: string) {
this.graphTokenManager = new GraphTokenManager(config);
this.pbValidator = new PocketBaseValidator(pbUrl);
}
/**
* Middleware to validate PocketBase token in requests
* Usage: app.use('/*', (c, next) => backendAuth.validateTokenMiddleware(c, next))
*/
async validateTokenMiddleware(c: any, next: any): Promise<any> {
const token = c.req.header('Authorization')?.replace('Bearer ', '') ||
(await c.req.json().catch(() => ({})))?.pbToken;
if (token) {
const isValid = await this.pbValidator.validateUserToken(token);
if (!isValid) {
return c.json({ error: 'Invalid token' }, 401);
}
}
return next();
}
}
+250
View File
@@ -0,0 +1,250 @@
import PocketBase from 'pocketbase';
import { AuthConfig, AuthState, AuthCallbacks } from './types';
/**
* PocketBase OAuth2 Frontend Module
* Handles user authentication and token management
*/
export class PocketBaseAuth {
private pb: PocketBase;
private config: Required<AuthConfig>;
private callbacks: AuthCallbacks;
private state: AuthState;
constructor(config: AuthConfig, callbacks?: Partial<AuthCallbacks>) {
this.config = {
pbUrl: config.pbUrl!,
collection: config.collection || 'Users',
provider: config.provider || 'microsoft',
loginContainerId: config.loginContainerId || 'loginContainer',
userDisplayNameId: config.userDisplayNameId || 'userDisplayName',
userEmailId: config.userEmailId || 'userEmailValue',
loginBtnId: config.loginBtnId || 'loginBtn',
loginErrorId: config.loginErrorId || 'loginError',
};
this.callbacks = {
onAuthSuccess: callbacks?.onAuthSuccess || (() => {}),
onAuthFailure: callbacks?.onAuthFailure || (() => {}),
onTokenUpdate: callbacks?.onTokenUpdate || (() => {}),
onUiUpdate: callbacks?.onUiUpdate || (() => {}),
};
this.pb = new PocketBase(this.config.pbUrl);
this.state = {
isAuthenticated: false,
user: null,
token: null,
};
this.init();
}
/**
* Initialize auth module
*/
private init(): void {
this.updateAuthUI();
if (this.pb.authStore.isValid && this.pb.authStore.token) {
this.ensureUserLogged();
}
this.setupLoginButton();
}
/**
* Setup login button click handler
*/
private setupLoginButton(): void {
const loginBtn = document.getElementById(this.config.loginBtnId);
if (!loginBtn) {
console.warn(`Login button with id "${this.config.loginBtnId}" not found`);
return;
}
loginBtn.addEventListener('click', async (e) => {
e.preventDefault();
await this.handleLogin();
});
}
/**
* Handle login button click
*/
private async handleLogin(): Promise<void> {
const loginBtn = document.getElementById(this.config.loginBtnId) as HTMLButtonElement;
const loginError = document.getElementById(this.config.loginErrorId) as HTMLElement;
if (!loginBtn || !loginError) return;
loginBtn.disabled = true;
loginBtn.textContent = 'Checking session...';
loginError.classList.add('hidden');
try {
// Try to use existing token first
const hadToken = await this.ensureUserLogged();
if (hadToken) {
this.resetLoginButton();
return;
}
// Otherwise perform OAuth
loginBtn.textContent = 'Logging in...';
const authData = await this.pb.collection(this.config.collection).authWithOAuth2({
provider: this.config.provider,
});
this.updateState(authData);
this.updateAuthUI();
this.callbacks.onAuthSuccess?.(this.state);
console.log('✓ Logged in with', this.config.provider);
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
console.error('Login failed:', message);
loginError.textContent = `Login failed: ${message}`;
loginError.classList.remove('hidden');
this.callbacks.onAuthFailure?.(error);
} finally {
this.resetLoginButton();
}
}
/**
* Ensure user is logged in (check existing token)
*/
async ensureUserLogged(): Promise<boolean> {
if (!this.pb.authStore.isValid || !this.pb.authStore.token) {
return false;
}
try {
const refresh = await this.pb.collection(this.config.collection).authRefresh();
this.updateState(refresh);
this.updateAuthUI();
this.callbacks.onTokenUpdate?.(this.state);
console.log('✓ Token refreshed');
return true;
} catch (error) {
console.warn('Existing token invalid, clearing auth');
this.pb.authStore.clear();
this.updateState(null);
this.updateAuthUI();
return false;
}
}
/**
* Update internal auth state
*/
private updateState(data: any): void {
if (!data) {
this.state = {
isAuthenticated: false,
user: null,
token: null,
};
return;
}
const record = data.record || this.pb.authStore.record || this.pb.authStore.model;
const meta = data.meta || {};
const model = this.pb.authStore.model;
this.state = {
isAuthenticated: true,
user: {
id: record?.id || model?.id || 'unknown',
name: record?.name || model?.name || meta?.name || record?.email || model?.email || 'Unknown User',
email: record?.email || model?.email || meta?.email || '(no email)',
},
token: this.pb.authStore.token,
};
}
/**
* Update UI based on auth state
*/
updateAuthUI(): void {
const loginContainer = document.getElementById(this.config.loginContainerId);
const userDisplayName = document.getElementById(this.config.userDisplayNameId);
const userEmail = document.getElementById(this.config.userEmailId);
if (!loginContainer) return;
if (this.pb.authStore.isValid) {
loginContainer.classList.add('hidden');
if (this.state.user) {
if (userDisplayName) userDisplayName.textContent = this.state.user.name;
if (userEmail) userEmail.textContent = this.state.user.email;
}
} else {
loginContainer.classList.remove('hidden');
const loginError = document.getElementById(this.config.loginErrorId);
if (loginError) loginError.classList.add('hidden');
}
this.callbacks.onUiUpdate?.(this.state);
}
/**
* Check token status (for verification/display)
*/
async checkTokenStatus(): Promise<{ pbToken: boolean; tokenExpiry?: string }> {
const pbToken = !!this.pb.authStore.token;
return { pbToken };
}
/**
* Get current auth state
*/
getAuthState(): AuthState {
return { ...this.state };
}
/**
* Get PocketBase instance (for direct usage if needed)
*/
getPocketBase(): PocketBase {
return this.pb;
}
/**
* Logout
*/
logout(): void {
this.pb.authStore.clear();
this.updateState(null);
this.updateAuthUI();
console.log('✓ Logged out');
}
/**
* Reset login button to initial state
*/
private resetLoginButton(): void {
const loginBtn = document.getElementById(this.config.loginBtnId) as HTMLButtonElement;
if (loginBtn) {
loginBtn.disabled = false;
loginBtn.textContent = 'Login with Microsoft';
}
}
}
/**
* Quick init function - fetches config from backend
*/
export async function initPocketBaseAuth(
backendUrl: string,
callbacks?: Partial<AuthCallbacks>
): Promise<PocketBaseAuth> {
// Fetch frontend config from backend
const response = await fetch(`${backendUrl}/api/auth/config`);
if (!response.ok) {
throw new Error('Failed to fetch auth configuration from backend');
}
const config = await response.json();
const auth = new PocketBaseAuth(config, callbacks);
return auth;
}
+62
View File
@@ -0,0 +1,62 @@
/**
* Frontend Auth Configuration
*/
export interface AuthConfig {
pbUrl: string; // PocketBase URL (required)
collection?: string;
provider?: string;
loginContainerId?: string;
userDisplayNameId?: string;
userEmailId?: string;
loginBtnId?: string;
loginErrorId?: string;
}
/**
* Frontend configuration provided by backend
*/
export interface FrontendConfig {
pbUrl: string;
provider?: string;
collection?: string;
}
/**
* Backend Auth Configuration
*/
export interface BackendAuthConfig {
clientId?: string;
tenantId?: string;
clientSecret?: string;
}
/**
* Auth state object
*/
export interface AuthState {
isAuthenticated: boolean;
user: {
id: string;
name: string;
email: string;
} | null;
token: string | null;
}
/**
* Graph token cache object
*/
export interface GraphTokenCache {
token: string;
expiresOn: number;
}
/**
* Auth event callbacks
*/
export interface AuthCallbacks {
onAuthSuccess?: (state: AuthState) => void;
onAuthFailure?: (error: any) => void;
onTokenUpdate?: (state: AuthState) => void;
onUiUpdate?: (state: AuthState) => void;
}
+226
View File
@@ -0,0 +1,226 @@
import { Hono } from 'hono';
import { serveStatic } from 'hono/bun';
import { cors } from 'hono/cors';
import path from 'path';
import { fileURLToPath } from 'url';
import { readFile } from 'fs/promises';
import { existsSync } from 'fs';
import { AuthConfigManager, BackendAuth } from '../auth-module/backend';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const app = new Hono();
const PORT = process.env.PORT || 3005;
// Initialize auth
const backendAuth = new BackendAuth({
clientId: process.env.CLIENT_ID,
tenantId: process.env.TENANT_ID,
clientSecret: process.env.CLIENT_SECRET,
}, process.env.PB_DB);
// CORS Configuration - Allow requests from frontend domains
app.use('*', cors({
origin: ['https://ji-test.ccllc.pro', 'http://localhost:3005', 'http://localhost:5173'],
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowHeaders: ['Content-Type', 'Authorization'],
credentials: true,
}));
// Serve bundled auth module JavaScript
app.get('/auth-module.js', async (c) => {
const filePath = path.join(__dirname, '../frontend/dist/auth.js');
if (existsSync(filePath)) {
const content = await readFile(filePath);
c.header('Content-Type', 'application/javascript');
return c.body(content);
}
return c.notFound();
});
// Serve frontend static files
app.use('/', serveStatic({ root: path.join(__dirname, '../frontend') }));
// API: Get frontend config
app.get('/api/auth/config', (c) => {
try {
const config = AuthConfigManager.getFrontendConfig();
return c.json(config);
} catch (error) {
return c.json(
{ error: 'Failed to get config', message: error instanceof Error ? error.message : 'Unknown error' },
500
);
}
});
// API: Get Graph token status
app.get('/api/auth/graph/token', async (c) => {
try {
const { token, expiresOnISO } = await backendAuth.graphTokenManager.getTokenWithExpiry();
if (!token) {
return c.json({ success: false, error: 'Failed to acquire Graph token' }, 500);
}
// Decode JWT to show token details (for verification)
const parts = token.split('.');
let payload = {};
if (parts.length === 3) {
try {
const decoded = JSON.parse(Buffer.from(parts[1], 'base64').toString());
payload = {
aud: decoded.aud,
iss: decoded.iss,
scp: decoded.scp,
app_displayname: decoded.app_displayname,
iat: new Date(decoded.iat * 1000).toISOString(),
exp: new Date(decoded.exp * 1000).toISOString(),
};
} catch (e) {
// Silent fail - just show truncated token
}
}
return c.json({
success: true,
token: token.substring(0, 50) + '...',
fullToken: token, // Include full token for testing
expiresOn: expiresOnISO,
isValid: backendAuth.graphTokenManager.isTokenValid(),
tokenDetails: Object.keys(payload).length > 0 ? payload : 'Could not decode',
});
} catch (error) {
return c.json(
{ success: false, error: error instanceof Error ? error.message : 'Failed to acquire token' },
500
);
}
});
// API: Validate PocketBase token
app.post('/api/auth/validate-pb-token', async (c) => {
try {
const body = await c.req.json();
const token = body.pbToken;
if (!token) {
return c.json({ valid: false, error: 'No token provided' }, 400);
}
const isValid = await backendAuth.pbValidator.validateUserToken(token);
const user = isValid ? await backendAuth.pbValidator.getUserRecord(token) : null;
return c.json({
valid: isValid,
user: user ? {
id: user.id,
email: user.email,
name: user.name,
} : null,
});
} catch (error) {
return c.json(
{ valid: false, error: error instanceof Error ? error.message : 'Validation failed' },
500
);
}
});
// API: Refresh Graph token (test cache)
app.post('/api/auth/refresh-graph', async (c) => {
try {
backendAuth.graphTokenManager.clearCache();
const { token, expiresOnISO } = await backendAuth.graphTokenManager.getTokenWithExpiry();
return c.json({
success: true,
refreshed: true,
expiresOn: expiresOnISO,
});
} catch (error) {
return c.json(
{ success: false, error: error instanceof Error ? error.message : 'Refresh failed' },
500
);
}
});
// API: Compare PB and Graph tokens
app.post('/api/auth/compare-tokens', async (c) => {
try {
const body = await c.req.json();
const pbToken = body.pbToken;
// Get Graph token
const { token: graphToken, expiresOnISO: graphExpires } = await backendAuth.graphTokenManager.getTokenWithExpiry();
if (!graphToken) {
return c.json({ success: false, error: 'Failed to acquire Graph token' }, 500);
}
// Decode both tokens to compare
const decodeJWT = (token: string) => {
try {
const parts = token.split('.');
if (parts.length !== 3) return null;
return JSON.parse(Buffer.from(parts[1], 'base64').toString());
} catch {
return null;
}
};
const graphPayload = decodeJWT(graphToken);
// Validate PB token to get actual user
let authenticatedUser = 'Unknown';
if (pbToken) {
try {
const isValid = await backendAuth.pbValidator.validateUserToken(pbToken);
if (isValid) {
const userRecord = await backendAuth.pbValidator.getUserRecord(pbToken);
authenticatedUser = userRecord?.email || userRecord?.id || 'Unknown';
}
} catch {
authenticatedUser = 'Token invalid or expired';
}
}
return c.json({
success: true,
comparison: {
graph_token: {
issuer: graphPayload?.iss || 'N/A',
audience: graphPayload?.aud || 'N/A',
app: graphPayload?.app_displayname || 'N/A',
scopes: graphPayload?.scp || 'N/A',
issued_at: graphPayload?.iat ? new Date(graphPayload.iat * 1000).toISOString() : 'N/A',
expires_at: graphPayload?.exp ? new Date(graphPayload.exp * 1000).toISOString() : 'N/A',
type: 'Microsoft Graph Token (Backend/App-only)',
source: '@azure/msal-node',
purpose: 'Backend API calls to Microsoft Graph',
},
pocketbase_token: {
note: 'User token from PocketBase OAuth2',
type: 'PocketBase User Token (Frontend/User)',
source: 'PocketBase OAuth2 flow',
purpose: 'User authentication and authorization',
authenticated_user: authenticatedUser,
},
are_different: true,
explanation: 'These are completely different tokens from different systems: Graph token is for app-to-app Microsoft API access, PocketBase token is for user authentication in the application.',
},
});
} catch (error) {
return c.json(
{ success: false, error: error instanceof Error ? error.message : 'Failed to compare tokens' },
500
);
}
});
// Start server
console.log(`Mode1 Auth Test Server running on port ${PORT}`);
export default {
port: PORT,
fetch: app.fetch,
};
+226
View File
@@ -0,0 +1,226 @@
{
"lockfileVersion": 1,
"configVersion": 1,
"workspaces": {
"": {
"name": "mode1-auth-test",
"dependencies": {
"@azure/msal-node": "^5.0.2",
"dotenv": "^17.2.3",
"hono": "^4.10.8",
"pocketbase": "^0.26.5",
},
"devDependencies": {
"@types/bun": "latest",
"typescript": "^5",
"vite": "^7.3.1",
},
"peerDependencies": {
"bun": "latest",
},
},
},
"packages": {
"@azure/msal-common": ["@azure/msal-common@16.0.2", "", {}, "sha512-ZJ/UR7lyqIntURrIJCyvScwJFanM9QhJYcJCheB21jZofGKpP9QxWgvADANo7UkresHKzV+6YwoeZYP7P7HvUg=="],
"@azure/msal-node": ["@azure/msal-node@5.0.2", "", { "dependencies": { "@azure/msal-common": "16.0.2", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" } }, "sha512-3tHeJghckgpTX98TowJoXOjKGuds0L+FKfeHJtoZFl2xvwE6RF65shZJzMQ5EQZWXzh3sE1i9gE+m3aRMachjA=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="],
"@oven/bun-darwin-aarch64": ["@oven/bun-darwin-aarch64@1.3.6", "", { "os": "darwin", "cpu": "arm64" }, "sha512-27rypIapNkYboOSylkf1tD9UW9Ado2I+P1NBL46Qz29KmOjTL6WuJ7mHDC5O66CYxlOkF5r93NPDAC3lFHYBXw=="],
"@oven/bun-darwin-x64": ["@oven/bun-darwin-x64@1.3.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-I82xGzPkBxzBKgbl8DsA0RfMQCWTWjNmLjIEkW1ECiv3qK02kHGQ5FGUr/29L/SuvnGsULW4tBTRNZiMzL37nA=="],
"@oven/bun-darwin-x64-baseline": ["@oven/bun-darwin-x64-baseline@1.3.6", "", { "os": "darwin", "cpu": "x64" }, "sha512-nqtr+pTsHqusYpG2OZc6s+AmpWDB/FmBvstrK0y5zkti4OqnCuu7Ev2xNjS7uyb47NrAFF40pWqkpaio5XEd7w=="],
"@oven/bun-linux-aarch64": ["@oven/bun-linux-aarch64@1.3.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-YaQEAYjBanoOOtpqk/c5GGcfZIyxIIkQ2m1TbHjedRmJNwxzWBhGinSARFkrRIc3F8pRIGAopXKvJ/2rjN1LzQ=="],
"@oven/bun-linux-aarch64-musl": ["@oven/bun-linux-aarch64-musl@1.3.6", "", { "os": "linux", "cpu": "arm64" }, "sha512-FR+iJt17rfFgYgpxL3M67AUwujOgjw52ZJzB9vElI5jQXNjTyOKf8eH4meSk4vjlYF3h/AjKYd6pmN0OIUlVKQ=="],
"@oven/bun-linux-x64": ["@oven/bun-linux-x64@1.3.6", "", { "os": "linux", "cpu": "x64" }, "sha512-egfngj0dfJ868cf30E7B+ye9KUWSebYxOG4l9YP5eWeMXCtenpenx0zdKtAn9qxJgEJym5AN6trtlk+J6x8Lig=="],
"@oven/bun-linux-x64-baseline": ["@oven/bun-linux-x64-baseline@1.3.6", "", { "os": "linux", "cpu": "x64" }, "sha512-jRmnX18ak8WzqLrex3siw0PoVKyIeI5AiCv4wJLgSs7VKfOqrPycfHIWfIX2jdn7ngqbHFPzI09VBKANZ4Pckg=="],
"@oven/bun-linux-x64-musl": ["@oven/bun-linux-x64-musl@1.3.6", "", { "os": "linux", "cpu": "x64" }, "sha512-YeXcJ9K6vJAt1zSkeA21J6pTe7PgDMLTHKGI3nQBiMYnYf7Ob3K+b/ChSCznrJG7No5PCPiQPg4zTgA+BOTmSA=="],
"@oven/bun-linux-x64-musl-baseline": ["@oven/bun-linux-x64-musl-baseline@1.3.6", "", { "os": "linux", "cpu": "x64" }, "sha512-7FjVnxnRTp/AgWqSQRT/Vt9TYmvnZ+4M+d9QOKh/Lf++wIFXFGSeAgD6bV1X/yr2UPVmZDk+xdhr2XkU7l2v3w=="],
"@oven/bun-windows-x64": ["@oven/bun-windows-x64@1.3.6", "", { "os": "win32", "cpu": "x64" }, "sha512-Sr1KwUcbB0SEpnSPO22tNJppku2khjFluEst+mTGhxHzAGQTQncNeJxDnt3F15n+p9Q+mlcorxehd68n1siikQ=="],
"@oven/bun-windows-x64-baseline": ["@oven/bun-windows-x64-baseline@1.3.6", "", { "os": "win32", "cpu": "x64" }, "sha512-PFUa7JL4lGoyyppeS4zqfuoXXih+gSE0XxhDMrCPVEUev0yhGNd/tbWBvcdpYnUth80owENoGjc8s5Knopv9wA=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.55.3", "", { "os": "android", "cpu": "arm" }, "sha512-qyX8+93kK/7R5BEXPC2PjUt0+fS/VO2BVHjEHyIEWiYn88rcRBHmdLgoJjktBltgAf+NY7RfCGB1SoyKS/p9kg=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.55.3", "", { "os": "android", "cpu": "arm64" }, "sha512-6sHrL42bjt5dHQzJ12Q4vMKfN+kUnZ0atHHnv4V0Wd9JMTk7FDzSY35+7qbz3ypQYMBPANbpGK7JpnWNnhGt8g=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.55.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-1ht2SpGIjEl2igJ9AbNpPIKzb1B5goXOcmtD0RFxnwNuMxqkR6AUaaErZz+4o+FKmzxcSNBOLrzsICZVNYa1Rw=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.55.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-FYZ4iVunXxtT+CZqQoPVwPhH7549e/Gy7PIRRtq4t5f/vt54pX6eG9ebttRH6QSH7r/zxAFA4EZGlQ0h0FvXiA=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.55.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-M/mwDCJ4wLsIgyxv2Lj7Len+UMHd4zAXu4GQ2UaCdksStglWhP61U3uowkaYBQBhVoNpwx5Hputo8eSqM7K82Q=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.55.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-5jZT2c7jBCrMegKYTYTpni8mg8y3uY8gzeq2ndFOANwNuC/xJbVAoGKR9LhMDA0H3nIhvaqUoBEuJoICBudFrA=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.55.3", "", { "os": "linux", "cpu": "arm" }, "sha512-YeGUhkN1oA+iSPzzhEjVPS29YbViOr8s4lSsFaZKLHswgqP911xx25fPOyE9+khmN6W4VeM0aevbDp4kkEoHiA=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.55.3", "", { "os": "linux", "cpu": "arm" }, "sha512-eo0iOIOvcAlWB3Z3eh8pVM8hZ0oVkK3AjEM9nSrkSug2l15qHzF3TOwT0747omI6+CJJvl7drwZepT+re6Fy/w=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.55.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-DJay3ep76bKUDImmn//W5SvpjRN5LmK/ntWyeJs/dcnwiiHESd3N4uteK9FDLf0S0W8E6Y0sVRXpOCoQclQqNg=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.55.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-BKKWQkY2WgJ5MC/ayvIJTHjy0JUGb5efaHCUiG/39sSUvAYRBaO3+/EK0AZT1RF3pSj86O24GLLik9mAYu0IJg=="],
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.55.3", "", { "os": "linux", "cpu": "none" }, "sha512-Q9nVlWtKAG7ISW80OiZGxTr6rYtyDSkauHUtvkQI6TNOJjFvpj4gcH+KaJihqYInnAzEEUetPQubRwHef4exVg=="],
"@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.55.3", "", { "os": "linux", "cpu": "none" }, "sha512-2H5LmhzrpC4fFRNwknzmmTvvyJPHwESoJgyReXeFoYYuIDfBhP29TEXOkCJE/KxHi27mj7wDUClNq78ue3QEBQ=="],
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.55.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9S542V0ie9LCTznPYlvaeySwBeIEa7rDBgLHKZ5S9DBgcqdJYburabm8TqiqG6mrdTzfV5uttQRHcbKff9lWtA=="],
"@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.55.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ukxw+YH3XXpcezLgbJeasgxyTbdpnNAkrIlFGDl7t+pgCxZ89/6n1a+MxlY7CegU+nDgrgdqDelPRNQ/47zs0g=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.55.3", "", { "os": "linux", "cpu": "none" }, "sha512-Iauw9UsTTvlF++FhghFJjqYxyXdggXsOqGpFBylaRopVpcbfyIIsNvkf9oGwfgIcf57z3m8+/oSYTo6HutBFNw=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.55.3", "", { "os": "linux", "cpu": "none" }, "sha512-3OqKAHSEQXKdq9mQ4eajqUgNIK27VZPW3I26EP8miIzuKzCJ3aW3oEn2pzF+4/Hj/Moc0YDsOtBgT5bZ56/vcA=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.55.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-0CM8dSVzVIaqMcXIFej8zZrSFLnGrAE8qlNbbHfTw1EEPnFTg1U1ekI0JdzjPyzSfUsHWtodilQQG/RA55berA=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.55.3", "", { "os": "linux", "cpu": "x64" }, "sha512-+fgJE12FZMIgBaKIAGd45rxf+5ftcycANJRWk8Vz0NnMTM5rADPGuRFTYar+Mqs560xuART7XsX2lSACa1iOmQ=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.55.3", "", { "os": "linux", "cpu": "x64" }, "sha512-tMD7NnbAolWPzQlJQJjVFh/fNH3K/KnA7K8gv2dJWCwwnaK6DFCYST1QXYWfu5V0cDwarWC8Sf/cfMHniNq21A=="],
"@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.55.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-u5KsqxOxjEeIbn7bUK1MPM34jrnPwjeqgyin4/N6e/KzXKfpE9Mi0nCxcQjaM9lLmPcHmn/xx1yOjgTMtu1jWQ=="],
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.55.3", "", { "os": "none", "cpu": "arm64" }, "sha512-vo54aXwjpTtsAnb3ca7Yxs9t2INZg7QdXN/7yaoG7nPGbOBXYXQY41Km+S1Ov26vzOAzLcAjmMdjyEqS1JkVhw=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.55.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-HI+PIVZ+m+9AgpnY3pt6rinUdRYrGHvmVdsNQ4odNqQ/eRF78DVpMR7mOq7nW06QxpczibwBmeQzB68wJ+4W4A=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.55.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-vRByotbdMo3Wdi+8oC2nVxtc3RkkFKrGaok+a62AT8lz/YBuQjaVYAS5Zcs3tPzW43Vsf9J0wehJbUY5xRSekA=="],
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.55.3", "", { "os": "win32", "cpu": "x64" }, "sha512-POZHq7UeuzMJljC5NjKi8vKMFN6/5EOqcX1yGntNLp7rUTpBAXQ1hW8kWPFxYLv07QMcNM75xqVLGPWQq6TKFA=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.55.3", "", { "os": "win32", "cpu": "x64" }, "sha512-aPFONczE4fUFKNXszdvnd2GqKEYQdV5oEsIbKPujJmWlCI9zEsv1Otig8RKK+X9bed9gFUN6LAeN4ZcNuu4zjg=="],
"@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
"@types/node": ["@types/node@25.0.10", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="],
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
"bun": ["bun@1.3.6", "", { "optionalDependencies": { "@oven/bun-darwin-aarch64": "1.3.6", "@oven/bun-darwin-x64": "1.3.6", "@oven/bun-darwin-x64-baseline": "1.3.6", "@oven/bun-linux-aarch64": "1.3.6", "@oven/bun-linux-aarch64-musl": "1.3.6", "@oven/bun-linux-x64": "1.3.6", "@oven/bun-linux-x64-baseline": "1.3.6", "@oven/bun-linux-x64-musl": "1.3.6", "@oven/bun-linux-x64-musl-baseline": "1.3.6", "@oven/bun-windows-x64": "1.3.6", "@oven/bun-windows-x64-baseline": "1.3.6" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "x64", "arm64", ], "bin": { "bun": "bin/bun.exe", "bunx": "bin/bunx.exe" } }, "sha512-Tn98GlZVN2WM7+lg/uGn5DzUao37Yc0PUz7yzYHdeF5hd+SmHQGbCUIKE4Sspdgtxn49LunK3mDNBC2Qn6GJjw=="],
"bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="],
"dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="],
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
"esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="],
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"hono": ["hono@4.11.5", "", {}, "sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g=="],
"jsonwebtoken": ["jsonwebtoken@9.0.3", "", { "dependencies": { "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g=="],
"jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="],
"jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="],
"lodash.includes": ["lodash.includes@4.3.0", "", {}, "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="],
"lodash.isboolean": ["lodash.isboolean@3.0.3", "", {}, "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="],
"lodash.isinteger": ["lodash.isinteger@4.0.4", "", {}, "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="],
"lodash.isnumber": ["lodash.isnumber@3.0.3", "", {}, "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="],
"lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="],
"lodash.isstring": ["lodash.isstring@4.0.1", "", {}, "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="],
"lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"pocketbase": ["pocketbase@0.26.6", "", {}, "sha512-Pl7V4y3DWglYITC4cBpclmuIzePRGsb/sXk/Wyqxznwu5JsHA5IILJY81PT2XQ3OSKCakWjbxjYBqtdcghzKvA=="],
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
"rollup": ["rollup@4.55.3", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.55.3", "@rollup/rollup-android-arm64": "4.55.3", "@rollup/rollup-darwin-arm64": "4.55.3", "@rollup/rollup-darwin-x64": "4.55.3", "@rollup/rollup-freebsd-arm64": "4.55.3", "@rollup/rollup-freebsd-x64": "4.55.3", "@rollup/rollup-linux-arm-gnueabihf": "4.55.3", "@rollup/rollup-linux-arm-musleabihf": "4.55.3", "@rollup/rollup-linux-arm64-gnu": "4.55.3", "@rollup/rollup-linux-arm64-musl": "4.55.3", "@rollup/rollup-linux-loong64-gnu": "4.55.3", "@rollup/rollup-linux-loong64-musl": "4.55.3", "@rollup/rollup-linux-ppc64-gnu": "4.55.3", "@rollup/rollup-linux-ppc64-musl": "4.55.3", "@rollup/rollup-linux-riscv64-gnu": "4.55.3", "@rollup/rollup-linux-riscv64-musl": "4.55.3", "@rollup/rollup-linux-s390x-gnu": "4.55.3", "@rollup/rollup-linux-x64-gnu": "4.55.3", "@rollup/rollup-linux-x64-musl": "4.55.3", "@rollup/rollup-openbsd-x64": "4.55.3", "@rollup/rollup-openharmony-arm64": "4.55.3", "@rollup/rollup-win32-arm64-msvc": "4.55.3", "@rollup/rollup-win32-ia32-msvc": "4.55.3", "@rollup/rollup-win32-x64-gnu": "4.55.3", "@rollup/rollup-win32-x64-msvc": "4.55.3", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-y9yUpfQvetAjiDLtNMf1hL9NXchIJgWt6zIKeoB+tCd3npX08Eqfzg60V9DhIGVMtQ0AlMkFw5xa+AQ37zxnAA=="],
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
"uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="],
"vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="],
}
}
+3
View File
@@ -0,0 +1,3 @@
// Frontend entry point - exports auth module for browser
export { PocketBaseAuth, initPocketBaseAuth } from '../auth-module/frontend';
export type { AuthConfig, AuthState, AuthCallbacks } from '../auth-module/types';
+545
View File
@@ -0,0 +1,545 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mode1 - Auth Module Test</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: #0f172a;
color: #e2e8f0;
padding: 2rem;
min-height: 100vh;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
h1 {
margin-bottom: 2rem;
color: #f1f5f9;
text-align: center;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
margin-bottom: 2rem;
}
@media (max-width: 1200px) {
.grid {
grid-template-columns: 1fr;
}
}
.section {
background: #1e293b;
border: 1px solid #334155;
border-radius: 8px;
padding: 1.5rem;
}
.section h2 {
font-size: 1.25rem;
margin-bottom: 1rem;
color: #f1f5f9;
display: flex;
align-items: center;
gap: 0.5rem;
}
.status-icon {
width: 12px;
height: 12px;
border-radius: 50%;
display: inline-block;
}
.status-icon.success {
background: #22c55e;
}
.status-icon.pending {
background: #f59e0b;
}
.status-icon.error {
background: #ef4444;
}
button {
background: #3b82f6;
color: white;
border: none;
padding: 0.75rem 1.5rem;
border-radius: 6px;
cursor: pointer;
font-size: 0.95rem;
transition: background 0.2s;
width: 100%;
margin-bottom: 0.5rem;
}
button:hover {
background: #2563eb;
}
button:disabled {
background: #64748b;
cursor: not-allowed;
}
.button-group {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.5rem;
}
.output {
background: #0f172a;
border: 1px solid #334155;
border-radius: 6px;
padding: 1rem;
margin-top: 1rem;
font-family: 'Monaco', 'Courier New', monospace;
font-size: 0.85rem;
max-height: 300px;
overflow-y: auto;
color: #94a3b8;
}
.output.success {
border-color: #22c55e;
color: #22c55e;
}
.output.error {
border-color: #ef4444;
color: #ef4444;
}
.output.warning {
border-color: #f59e0b;
color: #f59e0b;
}
.info {
background: #1e293b;
border-left: 4px solid #3b82f6;
padding: 1rem;
border-radius: 4px;
margin-bottom: 1rem;
font-size: 0.9rem;
}
.timestamp {
font-size: 0.8rem;
color: #64748b;
margin-top: 1rem;
text-align: right;
}
@media (max-width: 768px) {
.grid {
grid-template-columns: 1fr;
}
.button-group {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<h1>🔐 Auth Module Test Suite (Mode1)</h1>
<div class="grid">
<!-- Frontend Auth Section -->
<div class="section">
<h2>
<span class="status-icon pending" id="frontendStatus"></span>
Frontend: PocketBase Auth
</h2>
<div class="info">
Tests OAuth2 login, token refresh, and user state management.
</div>
<div class="button-group">
<button onclick="testFrontendInit()">Initialize Auth</button>
<button onclick="testGetAuthState()">Get Auth State</button>
</div>
<button onclick="testFrontendLogout()">Logout</button>
<div class="output" id="frontendOutput"></div>
<div class="timestamp" id="frontendTime"></div>
</div>
<!-- Backend Auth Section -->
<div class="section">
<h2>
<span class="status-icon pending" id="backendStatus"></span>
Backend: Graph Token & PB Validation
</h2>
<div class="info">
Tests Microsoft Graph token acquisition, caching, and PocketBase token validation.
</div>
<div class="button-group">
<button onclick="testGraphToken()">Get Graph Token</button>
<button onclick="testGraphRefresh()">Refresh Graph Token</button>
</div>
<button onclick="testCompareTokens()">Compare PB vs Graph</button>
<button onclick="testPBValidation()">Validate PB Token</button>
<button onclick="testCompareTokens()">Compare PB vs Graph</button>
<div class="output" id="backendOutput"></div>
<div class="timestamp" id="backendTime"></div>
</div>
</div>
<!-- Job Info Section -->
<div class="section">
<h2>
<span class="status-icon pending" id="jobInfoStatus"></span>
Job Info (First 4 Records)
</h2>
<div class="info">
Fetch and display first 4 records from Job_Info_Prod collection.
</div>
<button onclick="testJobInfo()">Fetch Job Info</button>
<div class="output" id="jobInfoOutput"></div>
<div class="timestamp" id="jobInfoTime"></div>
</div>
</div>
<!-- Login container (shown when not authenticated) -->
<div id="loginContainer" class="hidden">
<button id="loginBtn">Login with Microsoft</button>
<div id="loginError" class="hidden"></div>
</div>
<!-- User display (shown when authenticated) -->
<div id="userDisplayName"></div>
<div id="userEmailValue"></div>
<script src="/auth-module.js"></script>
<script>
let pbAuth = null;
let config = null;
// Utility: Log to output
function log(elementId, message, type = 'info') {
const output = document.getElementById(elementId);
if (!output) return;
const timestamp = new Date().toLocaleTimeString();
const line = `[${timestamp}] ${message}`;
output.textContent += (output.textContent ? '\n' : '') + line;
output.scrollTop = output.scrollHeight;
output.className = `output ${type}`;
// Update timestamp
const timeEl = document.getElementById(elementId.replace('Output', 'Time'));
if (timeEl) timeEl.textContent = `Last updated: ${new Date().toLocaleTimeString()}`;
}
function setStatus(elementId, status) {
const icon = document.getElementById(elementId);
if (!icon) return;
icon.className = `status-icon ${status}`;
}
// Test: Load config
async function loadConfig() {
try {
const response = await fetch('./api/auth/config');
if (!response.ok) throw new Error('Failed to load config');
config = await response.json();
document.getElementById('configOutput').textContent = JSON.stringify(config, null, 2);
document.getElementById('configOutput').className = 'output success';
} catch (error) {
log('configOutput', `Error loading config: ${error.message}`, 'error');
}
}
// Test: Initialize Frontend Auth
async function testFrontendInit() {
setStatus('frontendStatus', 'pending');
log('frontendOutput', 'Initializing PocketBaseAuth...');
try {
if (typeof window.AuthModule === 'undefined' || !window.AuthModule.initPocketBaseAuth) {
throw new Error('Auth module not loaded');
}
pbAuth = await window.AuthModule.initPocketBaseAuth('.', {
onAuthSuccess: (state) => {
log('frontendOutput', `✓ Auth success: ${state.user?.email}`, 'success');
setStatus('frontendStatus', 'success');
},
onAuthFailure: (error) => {
log('frontendOutput', `✗ Auth failed: ${error.message}`, 'error');
setStatus('frontendStatus', 'error');
},
onTokenUpdate: (state) => {
log('frontendOutput', `✓ Token refreshed for ${state.user?.email}`, 'success');
},
onUiUpdate: (state) => {
log('frontendOutput', `✓ UI updated: ${state.isAuthenticated ? 'Authenticated' : 'Not authenticated'}`);
},
});
log('frontendOutput', '✓ Frontend auth initialized', 'success');
setStatus('frontendStatus', 'success');
} catch (error) {
log('frontendOutput', `✗ Initialization failed: ${error.message}`, 'error');
setStatus('frontendStatus', 'error');
}
}
// Test: Get Auth State
function testGetAuthState() {
if (!pbAuth) {
log('frontendOutput', '✗ Auth not initialized', 'error');
return;
}
const state = pbAuth.getAuthState();
log('frontendOutput', `Auth State: ${JSON.stringify(state, null, 2)}`, 'success');
}
// Test: Frontend Logout
function testFrontendLogout() {
if (!pbAuth) {
log('frontendOutput', '✗ Auth not initialized', 'error');
return;
}
pbAuth.logout();
log('frontendOutput', '✓ Logged out', 'success');
setStatus('frontendStatus', 'pending');
}
// Test: Get Graph Token
async function testGraphToken() {
setStatus('backendStatus', 'pending');
log('backendOutput', 'Requesting Graph token from backend...');
try {
const response = await fetch('./api/auth/graph/token');
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
if (data.success) {
let output = `✓ Token acquired\n`;
output += `Expires: ${data.expiresOn}\n`;
output += `Valid in cache: ${data.isValid}\n\n`;
if (data.tokenDetails && typeof data.tokenDetails === 'object') {
output += `Token Details:\n`;
output += ` Audience: ${data.tokenDetails.aud}\n`;
output += ` Issuer: ${data.tokenDetails.iss}\n`;
output += ` Scopes: ${data.tokenDetails.scp}\n`;
output += ` App: ${data.tokenDetails.app_displayname}\n`;
output += ` Issued: ${data.tokenDetails.iat}\n`;
output += ` Expires: ${data.tokenDetails.exp}\n\n`;
}
output += `Full Token (first 100 chars):\n${data.fullToken.substring(0, 100)}...`;
log('backendOutput', output, 'success');
setStatus('backendStatus', 'success');
} else {
log('backendOutput', `${data.error}`, 'error');
setStatus('backendStatus', 'error');
}
} catch (error) {
log('backendOutput', `✗ Request failed: ${error.message}`, 'error');
setStatus('backendStatus', 'error');
}
}
// Test: Refresh Graph Token
async function testGraphRefresh() {
setStatus('backendStatus', 'pending');
log('backendOutput', 'Refreshing Graph token...');
try {
const response = await fetch('./api/auth/refresh-graph', { method: 'POST' });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
if (data.success) {
log('backendOutput', `✓ Token refreshed\nExpires: ${data.expiresOn}`, 'success');
setStatus('backendStatus', 'success');
} else {
log('backendOutput', `${data.error}`, 'error');
setStatus('backendStatus', 'error');
}
} catch (error) {
log('backendOutput', `✗ Refresh failed: ${error.message}`, 'error');
setStatus('backendStatus', 'error');
}
}
// Test: Compare tokens
async function testCompareTokens() {
setStatus('backendStatus', 'pending');
log('backendOutput', 'Comparing PocketBase token vs Graph token...');
if (!pbAuth) {
log('backendOutput', '✗ Auth not initialized', 'error');
setStatus('backendStatus', 'error');
return;
}
try {
const state = pbAuth.getAuthState();
const pbToken = state.token || null;
const response = await fetch('./api/auth/compare-tokens', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pbToken }),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
if (data.success && data.comparison) {
let output = `✓ Token Comparison:\n\n`;
output += `GRAPH TOKEN (Backend/App-only):\n`;
output += ` Type: ${data.comparison.graph_token.type}\n`;
output += ` Source: ${data.comparison.graph_token.source}\n`;
output += ` Issuer: ${data.comparison.graph_token.issuer}\n`;
output += ` Audience: ${data.comparison.graph_token.audience}\n`;
output += ` App: ${data.comparison.graph_token.app}\n`;
output += ` Scopes: ${data.comparison.graph_token.scopes}\n`;
output += ` Purpose: ${data.comparison.graph_token.purpose}\n\n`;
output += `POCKETBASE TOKEN (Frontend/User):\n`;
output += ` Type: ${data.comparison.pocketbase_token.type}\n`;
output += ` Source: ${data.comparison.pocketbase_token.source}\n`;
output += ` User: ${data.comparison.pocketbase_token.authenticated_user}\n`;
output += ` Purpose: ${data.comparison.pocketbase_token.purpose}\n\n`;
output += `COMPARISON:\n`;
output += ` Are Different: YES ✓\n`;
output += ` ${data.comparison.explanation}\n`;
log('backendOutput', output, 'success');
setStatus('backendStatus', 'success');
} else {
log('backendOutput', `${data.error}`, 'error');
setStatus('backendStatus', 'error');
}
} catch (error) {
log('backendOutput', `✗ Comparison failed: ${error.message}`, 'error');
setStatus('backendStatus', 'error');
}
}
// Test: Validate PocketBase Token
async function testPBValidation() {
setStatus('backendStatus', 'pending');
log('backendOutput', 'Validating PocketBase token...');
if (!pbAuth) {
log('backendOutput', '✗ Auth not initialized', 'error');
setStatus('backendStatus', 'error');
return;
}
try {
const state = pbAuth.getAuthState();
if (!state.token) {
log('backendOutput', '✗ No token available - user not logged in', 'warning');
setStatus('backendStatus', 'warning');
return;
}
log('backendOutput', `Sending token for user: ${state.user?.email}...`);
const response = await fetch('./api/auth/validate-pb-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pbToken: state.token }),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
if (data.valid) {
log('backendOutput', `✓ Token valid\nUser: ${data.user?.email}\nID: ${data.user?.id}`, 'success');
setStatus('backendStatus', 'success');
} else {
log('backendOutput', `✗ Token invalid: ${data.error}`, 'error');
setStatus('backendStatus', 'error');
}
} catch (error) {
log('backendOutput', `✗ Validation failed: ${error.message}`, 'error');
setStatus('backendStatus', 'error');
}
}
// Test: Fetch Job Info
async function testJobInfo() {
setStatus('jobInfoStatus', 'pending');
log('jobInfoOutput', 'Fetching first 4 records from Job_Info_Prod...');
if (!pbAuth) {
log('jobInfoOutput', '✗ Auth not initialized - cannot fetch records', 'error');
setStatus('jobInfoStatus', 'error');
return;
}
try {
const pb = pbAuth.getPocketBase();
const records = await pb.collection('Job_Info_Prod').getList(1, 4);
if (!records.items || records.items.length === 0) {
log('jobInfoOutput', 'No records found', 'warning');
setStatus('jobInfoStatus', 'warning');
return;
}
let output = `✓ Found ${records.items.length} records:\n\n`;
records.items.forEach((record, index) => {
output += `[${index + 1}] ID: ${record.id}\n`;
output += ` Title: ${record.title || record.name || 'N/A'}\n`;
output += ` Status: ${record.status || 'N/A'}\n`;
output += ` Created: ${new Date(record.created).toLocaleDateString()}\n\n`;
});
log('jobInfoOutput', output, 'success');
setStatus('jobInfoStatus', 'success');
} catch (error) {
log('jobInfoOutput', `✗ Failed to fetch records: ${error.message}`, 'error');
setStatus('jobInfoStatus', 'error');
}
}
</script>
</body>
</html>
+26
View File
@@ -0,0 +1,26 @@
{
"name": "mode1-auth-test",
"version": "1.0.0",
"type": "module",
"private": true,
"scripts": {
"start": "bun run backend/server.ts",
"dev": "bun --watch backend/server.ts",
"build": "vite build",
"prebuild": "vite build"
},
"dependencies": {
"@azure/msal-node": "^5.0.2",
"dotenv": "^17.2.3",
"hono": "^4.10.8",
"pocketbase": "^0.26.5"
},
"devDependencies": {
"@types/bun": "latest",
"typescript": "^5",
"vite": "^7.3.1"
},
"peerDependencies": {
"bun": "latest"
}
}
+17
View File
@@ -0,0 +1,17 @@
import { defineConfig } from 'vite';
export default defineConfig({
build: {
outDir: 'frontend/dist',
emptyOutDir: true,
lib: {
entry: 'frontend/auth.ts',
name: 'AuthModule',
fileName: () => 'auth.js',
formats: ['umd']
}
},
server: {
middlewareMode: true
}
});
+1
View File
@@ -0,0 +1 @@
Mode6Test
+1
View File
@@ -10,6 +10,7 @@ const ORCHESTRATOR_PORT = 3006; // Orchestrator API runs here
// Mode folder mappings - only Mode6Test exists currently
const MODE_FOLDERS: Record<string, string> = {
'Mode1': 'Mode1',
'Mode6Test': 'Mode6Test',
};
-55
View File
@@ -1,55 +0,0 @@
# Mode Template
Base template for creating new Modes. Copy this entire folder and rename it.
## Structure
```
ModeTemplate/
├── backend/
│ ├── server.ts # Hono API server
│ └── modules/
│ └── auth/ # Copy of components/auth
├── frontend/
│ ├── src/
│ │ ├── routes/
│ │ │ ├── +page.svelte
│ │ │ └── +layout.svelte
│ │ ├── lib/
│ │ │ ├── api.ts # API client instance
│ │ │ └── stores/
│ │ │ └── auth.ts
│ │ └── app.html
│ ├── static/
│ ├── svelte.config.js
│ ├── vite.config.ts
│ └── package.json
├── types/ # Copy of components/shared-types
├── package.json
├── .env
└── README.md
```
## Quick Start
1. Copy folder: `cp -r ModeTemplate Mode7YourProject`
2. Update `package.json` name
3. Install deps: `cd Mode7YourProject && bun install`
4. Start backend: `bun run backend/server.ts`
5. Start frontend: `cd frontend && bun run dev`
## Ports
- Backend runs on PORT from env (orchestrator sets to 3005)
- Frontend dev server runs on 5173 (proxies API to backend)
## Adding to Orchestrator
Edit `ModeSwitch/backend/orchestrator.ts`:
```typescript
const MODE_FOLDERS: Record<string, string> = {
'Mode6Test': 'Mode6Test',
'Mode7YourProject': 'Mode7YourProject', // Add this
};
```
@@ -1,28 +0,0 @@
export {
getAuthUrl,
handleCallback,
exchangeCodeForToken,
getMicrosoftUserInfo,
getPocketBaseToken,
getConfigFromEnv,
} from './microsoft-oauth';
export type {
AuthResult,
OAuthConfig
} from './microsoft-oauth';
export {
HEADERS,
CONTENT_TYPES,
STORAGE_KEYS,
pbAuthHeader,
pbHeaders,
isSessionExpired,
} from './types';
export type {
MicrosoftTokens,
PocketBaseTokens,
AuthSession,
} from './types';
@@ -1,208 +0,0 @@
/**
* Microsoft OAuth Module
*
* Handles Microsoft OAuth flow to authenticate users and retrieve:
* - User's email
* - User's display name
* - PocketBase auth token (user must already exist)
*
* Environment Variables Used:
* - MICROSOFT_CLIENT_ID
* - MICROSOFT_CLIENT_SECRET
* - MICROSOFT_TENANT_ID
* - MICROSOFT_REDIRECT_URI
* - MICROSOFT_SCOPES
* - PB_URL
*/
interface MicrosoftTokenResponse {
access_token: string;
token_type: string;
expires_in: number;
scope: string;
refresh_token?: string;
}
interface MicrosoftUserInfo {
id: string;
displayName: string;
mail: string;
userPrincipalName: string;
}
export interface AuthResult {
email: string;
displayName: string;
pocketbaseToken: string;
}
export interface OAuthConfig {
clientId: string;
clientSecret: string;
tenantId: string;
redirectUri: string;
scopes: string;
pbUrl: string;
}
/**
* Build config from process.env
*/
export function getConfigFromEnv(): OAuthConfig {
const clientId = process.env.MICROSOFT_CLIENT_ID;
const clientSecret = process.env.MICROSOFT_CLIENT_SECRET;
const tenantId = process.env.MICROSOFT_TENANT_ID;
const redirectUri = process.env.MICROSOFT_REDIRECT_URI;
const scopes = process.env.MICROSOFT_SCOPES;
const pbUrl = process.env.PB_URL;
if (!clientId || !clientSecret || !tenantId || !redirectUri || !scopes || !pbUrl) {
throw new Error('Missing required OAuth environment variables');
}
return { clientId, clientSecret, tenantId, redirectUri, scopes, pbUrl };
}
/**
* Generate the Microsoft OAuth authorization URL
*/
export function getAuthUrl(config: OAuthConfig): string {
const params = new URLSearchParams({
client_id: config.clientId,
response_type: 'code',
redirect_uri: config.redirectUri,
response_mode: 'query',
scope: config.scopes,
state: crypto.randomUUID(),
});
return `https://login.microsoftonline.com/${config.tenantId}/oauth2/v2.0/authorize?${params}`;
}
/**
* Exchange authorization code for access token
*/
export async function exchangeCodeForToken(
code: string,
config: OAuthConfig
): Promise<MicrosoftTokenResponse> {
const response = await fetch(
`https://login.microsoftonline.com/${config.tenantId}/oauth2/v2.0/token`,
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
client_id: config.clientId,
client_secret: config.clientSecret,
code,
redirect_uri: config.redirectUri,
grant_type: 'authorization_code',
scope: config.scopes,
}),
}
);
if (!response.ok) {
const error = await response.text();
throw new Error(`Token exchange failed: ${error}`);
}
return response.json();
}
/**
* Get user info from Microsoft Graph API
*/
export async function getMicrosoftUserInfo(
accessToken: string
): Promise<MicrosoftUserInfo> {
const response = await fetch('https://graph.microsoft.com/v1.0/me', {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
if (!response.ok) {
const error = await response.text();
throw new Error(`Failed to get user info: ${error}`);
}
return response.json();
}
/**
* Authenticate existing user with PocketBase
* User MUST already exist - no user creation
*/
export async function getPocketBaseToken(
email: string,
pbUrl: string
): Promise<string> {
// Look up user by email - user must exist
const searchResponse = await fetch(
`${pbUrl}/api/collections/users/records?filter=(email='${encodeURIComponent(email)}')`,
{
headers: {
'Content-Type': 'application/json',
},
}
);
if (!searchResponse.ok) {
throw new Error('Failed to query PocketBase');
}
const searchData = await searchResponse.json();
if (!searchData.items || searchData.items.length === 0) {
throw new Error('Access denied: User does not exist');
}
// User exists - authenticate via OAuth
const authResponse = await fetch(`${pbUrl}/api/collections/users/auth-with-oauth2`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
provider: 'microsoft',
}),
});
if (!authResponse.ok) {
const error = await authResponse.text();
throw new Error(`PocketBase auth failed: ${error}`);
}
const data = await authResponse.json();
return data.token;
}
/**
* Complete OAuth flow: code -> user info + PocketBase token
* Denies access if user doesn't exist in PocketBase
*/
export async function handleCallback(
code: string,
config: OAuthConfig
): Promise<AuthResult> {
// 1. Exchange code for Microsoft access token
const tokenResponse = await exchangeCodeForToken(code, config);
// 2. Get user info from Microsoft Graph
const userInfo = await getMicrosoftUserInfo(tokenResponse.access_token);
const email = userInfo.mail || userInfo.userPrincipalName;
const displayName = userInfo.displayName;
// 3. Get PocketBase auth token (user must exist)
const pocketbaseToken = await getPocketBaseToken(email, config.pbUrl);
return {
email,
displayName,
pocketbaseToken,
};
}
@@ -1,99 +0,0 @@
/**
* Auth Constants & Types
*
* Standard naming conventions for auth-related values.
* Use these throughout all modes to maintain consistency.
*/
// ============================================
// TOKEN TYPES
// ============================================
/** Token received from Microsoft OAuth */
export interface MicrosoftTokens {
accessToken: string;
refreshToken?: string;
expiresIn: number;
}
/** Token received from PocketBase */
export interface PocketBaseTokens {
token: string;
// PB tokens don't have separate refresh - they expire and re-auth is needed
}
/** Combined auth state after successful login */
export interface AuthSession {
email: string;
displayName: string;
pbToken: string; // PocketBase auth token
msAccessToken?: string; // Microsoft access token (if needed for Graph API calls)
expiresAt?: number; // Unix timestamp when session expires
}
// ============================================
// HEADER NAMES
// ============================================
export const HEADERS = {
/** Authorization header for PocketBase API calls */
PB_AUTH: 'Authorization',
/** Content type for JSON requests */
CONTENT_TYPE: 'Content-Type',
} as const;
// ============================================
// HEADER VALUES
// ============================================
export const CONTENT_TYPES = {
JSON: 'application/json',
FORM: 'application/x-www-form-urlencoded',
} as const;
// ============================================
// COOKIE/STORAGE KEYS
// ============================================
export const STORAGE_KEYS = {
/** PocketBase token storage key */
PB_TOKEN: 'pb_token',
/** Session data storage key */
SESSION: 'auth_session',
} as const;
// ============================================
// HELPER FUNCTIONS
// ============================================
/**
* Create Authorization header value for PocketBase
*/
export function pbAuthHeader(token: string): string {
return `Bearer ${token}`;
}
/**
* Create headers object for PocketBase API calls
*/
export function pbHeaders(token?: string): Record<string, string> {
const headers: Record<string, string> = {
[HEADERS.CONTENT_TYPE]: CONTENT_TYPES.JSON,
};
if (token) {
headers[HEADERS.PB_AUTH] = pbAuthHeader(token);
}
return headers;
}
/**
* Check if session is expired
*/
export function isSessionExpired(session: AuthSession): boolean {
if (!session.expiresAt) return false;
return Date.now() > session.expiresAt;
}
-72
View File
@@ -1,72 +0,0 @@
/**
* Backend Server
*
* Hono API server with auth routes pre-configured.
*/
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { getAuthUrl, handleCallback, getConfigFromEnv } from './modules/auth';
const app = new Hono();
// CORS for frontend
app.use('/*', cors({
origin: ['http://localhost:5173', 'http://localhost:3005'],
credentials: true,
}));
// Health check
app.get('/health', (c) => c.json({ status: 'ok' }));
// ============================================
// AUTH ROUTES
// ============================================
const authConfig = getConfigFromEnv();
app.get('/auth/login', (c) => {
return c.redirect(getAuthUrl(authConfig));
});
app.get('/auth/callback', async (c) => {
const code = c.req.query('code');
if (!code) {
return c.json({ error: 'No authorization code' }, 400);
}
try {
const result = await handleCallback(code, authConfig);
// Return token and user info
// Frontend should store token and redirect
return c.json(result);
} catch (err) {
const message = err instanceof Error ? err.message : 'Auth failed';
return c.json({ error: message }, 403);
}
});
// ============================================
// API ROUTES
// ============================================
app.get('/api/me', async (c) => {
// TODO: Validate token from Authorization header
// Return current user info
return c.json({ message: 'Implement me' });
});
// ============================================
// START SERVER
// ============================================
const port = Number(process.env.PORT) || 3005;
console.log(`[Server] Starting on port ${port}...`);
export default {
port,
fetch: app.fetch,
};
-27
View File
@@ -1,27 +0,0 @@
{
"lockfileVersion": 1,
"configVersion": 1,
"workspaces": {
"": {
"name": "mode-template",
"dependencies": {
"hono": "^4.0.0",
},
"devDependencies": {
"bun-types": "latest",
"typescript": "^5.0.0",
},
},
},
"packages": {
"@types/node": ["@types/node@25.0.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="],
"bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="],
"hono": ["hono@4.11.4", "", {}, "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
}
}
-175
View File
@@ -1,175 +0,0 @@
// this file is generated — do not edit it
/// <reference types="@sveltejs/kit" />
/**
* Environment variables [loaded by Vite](https://vitejs.dev/guide/env-and-mode.html#env-files) from `.env` files and `process.env`. Like [`$env/dynamic/private`](https://svelte.dev/docs/kit/$env-dynamic-private), this module cannot be imported into client-side code. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://svelte.dev/docs/kit/configuration#env) _and do_ start with [`config.kit.env.privatePrefix`](https://svelte.dev/docs/kit/configuration#env) (if configured).
*
* _Unlike_ [`$env/dynamic/private`](https://svelte.dev/docs/kit/$env-dynamic-private), the values exported from this module are statically injected into your bundle at build time, enabling optimisations like dead code elimination.
*
* ```ts
* import { API_KEY } from '$env/static/private';
* ```
*
* Note that all environment variables referenced in your code should be declared (for example in an `.env` file), even if they don't have a value until the app is deployed:
*
* ```
* MY_FEATURE_FLAG=""
* ```
*
* You can override `.env` values from the command line like so:
*
* ```sh
* MY_FEATURE_FLAG="enabled" npm run dev
* ```
*/
declare module '$env/static/private' {
export const SHELL: string;
export const npm_command: string;
export const COLORTERM: string;
export const HISTCONTROL: string;
export const TERM_PROGRAM_VERSION: string;
export const NODE: string;
export const npm_config_local_prefix: string;
export const PWD: string;
export const LOGNAME: string;
export const XDG_SESSION_TYPE: string;
export const _: string;
export const VSCODE_GIT_ASKPASS_NODE: string;
export const MOTD_SHOWN: string;
export const HOME: string;
export const LANG: string;
export const npm_package_version: string;
export const SSL_CERT_DIR: string;
export const GIT_ASKPASS: string;
export const SSH_CONNECTION: string;
export const npm_lifecycle_script: string;
export const VSCODE_GIT_ASKPASS_EXTRA_ARGS: string;
export const VSCODE_PYTHON_AUTOACTIVATE_GUARD: string;
export const XDG_SESSION_CLASS: string;
export const TERM: string;
export const npm_package_name: string;
export const USER: string;
export const GIT_PAGER: string;
export const VSCODE_GIT_IPC_HANDLE: string;
export const npm_lifecycle_event: string;
export const SHLVL: string;
export const XDG_SESSION_ID: string;
export const npm_config_user_agent: string;
export const npm_execpath: string;
export const XDG_RUNTIME_DIR: string;
export const SSL_CERT_FILE: string;
export const SSH_CLIENT: string;
export const DEBUGINFOD_URLS: string;
export const npm_package_json: string;
export const BUN_INSTALL: string;
export const VSCODE_GIT_ASKPASS_MAIN: string;
export const BROWSER: string;
export const PATH: string;
export const DBUS_SESSION_BUS_ADDRESS: string;
export const MAIL: string;
export const npm_node_execpath: string;
export const OLDPWD: string;
export const TERM_PROGRAM: string;
export const VSCODE_IPC_HOOK_CLI: string;
export const NODE_ENV: string;
}
/**
* Similar to [`$env/static/private`](https://svelte.dev/docs/kit/$env-static-private), except that it only includes environment variables that begin with [`config.kit.env.publicPrefix`](https://svelte.dev/docs/kit/configuration#env) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code.
*
* Values are replaced statically at build time.
*
* ```ts
* import { PUBLIC_BASE_URL } from '$env/static/public';
* ```
*/
declare module '$env/static/public' {
}
/**
* This module provides access to runtime environment variables, as defined by the platform you're running on. For example if you're using [`adapter-node`](https://github.com/sveltejs/kit/tree/main/packages/adapter-node) (or running [`vite preview`](https://svelte.dev/docs/kit/cli)), this is equivalent to `process.env`. This module only includes variables that _do not_ begin with [`config.kit.env.publicPrefix`](https://svelte.dev/docs/kit/configuration#env) _and do_ start with [`config.kit.env.privatePrefix`](https://svelte.dev/docs/kit/configuration#env) (if configured).
*
* This module cannot be imported into client-side code.
*
* ```ts
* import { env } from '$env/dynamic/private';
* console.log(env.DEPLOYMENT_SPECIFIC_VARIABLE);
* ```
*
* > [!NOTE] In `dev`, `$env/dynamic` always includes environment variables from `.env`. In `prod`, this behavior will depend on your adapter.
*/
declare module '$env/dynamic/private' {
export const env: {
SHELL: string;
npm_command: string;
COLORTERM: string;
HISTCONTROL: string;
TERM_PROGRAM_VERSION: string;
NODE: string;
npm_config_local_prefix: string;
PWD: string;
LOGNAME: string;
XDG_SESSION_TYPE: string;
_: string;
VSCODE_GIT_ASKPASS_NODE: string;
MOTD_SHOWN: string;
HOME: string;
LANG: string;
npm_package_version: string;
SSL_CERT_DIR: string;
GIT_ASKPASS: string;
SSH_CONNECTION: string;
npm_lifecycle_script: string;
VSCODE_GIT_ASKPASS_EXTRA_ARGS: string;
VSCODE_PYTHON_AUTOACTIVATE_GUARD: string;
XDG_SESSION_CLASS: string;
TERM: string;
npm_package_name: string;
USER: string;
GIT_PAGER: string;
VSCODE_GIT_IPC_HANDLE: string;
npm_lifecycle_event: string;
SHLVL: string;
XDG_SESSION_ID: string;
npm_config_user_agent: string;
npm_execpath: string;
XDG_RUNTIME_DIR: string;
SSL_CERT_FILE: string;
SSH_CLIENT: string;
DEBUGINFOD_URLS: string;
npm_package_json: string;
BUN_INSTALL: string;
VSCODE_GIT_ASKPASS_MAIN: string;
BROWSER: string;
PATH: string;
DBUS_SESSION_BUS_ADDRESS: string;
MAIL: string;
npm_node_execpath: string;
OLDPWD: string;
TERM_PROGRAM: string;
VSCODE_IPC_HOOK_CLI: string;
NODE_ENV: string;
[key: `PUBLIC_${string}`]: undefined;
[key: `${string}`]: string | undefined;
}
}
/**
* Similar to [`$env/dynamic/private`](https://svelte.dev/docs/kit/$env-dynamic-private), but only includes variables that begin with [`config.kit.env.publicPrefix`](https://svelte.dev/docs/kit/configuration#env) (which defaults to `PUBLIC_`), and can therefore safely be exposed to client-side code.
*
* Note that public dynamic environment variables must all be sent from the server to the client, causing larger network requests — when possible, use `$env/static/public` instead.
*
* ```ts
* import { env } from '$env/dynamic/public';
* console.log(env.PUBLIC_DEPLOYMENT_SPECIFIC_VARIABLE);
* ```
*/
declare module '$env/dynamic/public' {
export const env: {
[key: `PUBLIC_${string}`]: string | undefined;
}
}
@@ -1,31 +0,0 @@
export { matchers } from './matchers.js';
export const nodes = [
() => import('./nodes/0'),
() => import('./nodes/1'),
() => import('./nodes/2'),
() => import('./nodes/3')
];
export const server_loads = [];
export const dictionary = {
"/": [2],
"/callback": [3]
};
export const hooks = {
handleError: (({ error }) => { console.error(error) }),
reroute: (() => {}),
transport: {}
};
export const decoders = Object.fromEntries(Object.entries(hooks.transport).map(([k, v]) => [k, v.decode]));
export const encoders = Object.fromEntries(Object.entries(hooks.transport).map(([k, v]) => [k, v.encode]));
export const hash = false;
export const decode = (type, value) => decoders[type](value);
export { default as root } from '../root.js';
@@ -1 +0,0 @@
export const matchers = {};
@@ -1 +0,0 @@
export { default as component } from "../../../../src/routes/+layout.svelte";
@@ -1 +0,0 @@
export { default as component } from "../../../../node_modules/@sveltejs/kit/src/runtime/components/svelte-5/error.svelte";
@@ -1 +0,0 @@
export { default as component } from "../../../../src/routes/+page.svelte";
@@ -1 +0,0 @@
export { default as component } from "../../../../src/routes/callback/+page.svelte";
@@ -1,31 +0,0 @@
export { matchers } from './matchers.js';
export const nodes = [
() => import('./nodes/0'),
() => import('./nodes/1'),
() => import('./nodes/2'),
() => import('./nodes/3')
];
export const server_loads = [];
export const dictionary = {
"/": [2],
"/callback": [3]
};
export const hooks = {
handleError: (({ error }) => { console.error(error) }),
reroute: (() => {}),
transport: {}
};
export const decoders = Object.fromEntries(Object.entries(hooks.transport).map(([k, v]) => [k, v.decode]));
export const encoders = Object.fromEntries(Object.entries(hooks.transport).map(([k, v]) => [k, v.encode]));
export const hash = false;
export const decode = (type, value) => decoders[type](value);
export { default as root } from '../root.js';
@@ -1 +0,0 @@
export const matchers = {};
@@ -1 +0,0 @@
export { default as component } from "../../../../src/routes/+layout.svelte";
@@ -1 +0,0 @@
export { default as component } from "../../../../node_modules/@sveltejs/kit/src/runtime/components/svelte-5/error.svelte";
@@ -1 +0,0 @@
export { default as component } from "../../../../src/routes/+page.svelte";
@@ -1 +0,0 @@
export { default as component } from "../../../../src/routes/callback/+page.svelte";
@@ -1,3 +0,0 @@
import { asClassComponent } from 'svelte/legacy';
import Root from './root.svelte';
export default asClassComponent(Root);
@@ -1,68 +0,0 @@
<!-- This file is generated by @sveltejs/kit — do not edit it! -->
<svelte:options runes={true} />
<script>
import { setContext, onMount, tick } from 'svelte';
import { browser } from '$app/environment';
// stores
let { stores, page, constructors, components = [], form, data_0 = null, data_1 = null } = $props();
if (!browser) {
// svelte-ignore state_referenced_locally
setContext('__svelte__', stores);
}
if (browser) {
$effect.pre(() => stores.page.set(page));
} else {
// svelte-ignore state_referenced_locally
stores.page.set(page);
}
$effect(() => {
stores;page;constructors;components;form;data_0;data_1;
stores.page.notify();
});
let mounted = $state(false);
let navigated = $state(false);
let title = $state(null);
onMount(() => {
const unsubscribe = stores.page.subscribe(() => {
if (mounted) {
navigated = true;
tick().then(() => {
title = document.title || 'untitled page';
});
}
});
mounted = true;
return unsubscribe;
});
const Pyramid_1=$derived(constructors[1])
</script>
{#if constructors[1]}
{@const Pyramid_0 = constructors[0]}
<!-- svelte-ignore binding_property_non_reactive -->
<Pyramid_0 bind:this={components[0]} data={data_0} {form} params={page.params}>
<!-- svelte-ignore binding_property_non_reactive -->
<Pyramid_1 bind:this={components[1]} data={data_1} {form} params={page.params} />
</Pyramid_0>
{:else}
{@const Pyramid_0 = constructors[0]}
<!-- svelte-ignore binding_property_non_reactive -->
<Pyramid_0 bind:this={components[0]} data={data_0} {form} params={page.params} />
{/if}
{#if mounted}
<div id="svelte-announcer" aria-live="assertive" aria-atomic="true" style="position: absolute; left: 0; top: 0; clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap; width: 1px; height: 1px">
{#if navigated}
{title}
{/if}
</div>
{/if}
@@ -1,53 +0,0 @@
import root from '../root.js';
import { set_building, set_prerendering } from '__sveltekit/environment';
import { set_assets } from '$app/paths/internal/server';
import { set_manifest, set_read_implementation } from '__sveltekit/server';
import { set_private_env, set_public_env } from '../../../node_modules/@sveltejs/kit/src/runtime/shared-server.js';
export const options = {
app_template_contains_nonce: false,
async: false,
csp: {"mode":"auto","directives":{"upgrade-insecure-requests":false,"block-all-mixed-content":false},"reportOnly":{"upgrade-insecure-requests":false,"block-all-mixed-content":false}},
csrf_check_origin: true,
csrf_trusted_origins: [],
embedded: false,
env_public_prefix: 'PUBLIC_',
env_private_prefix: '',
hash_routing: false,
hooks: null, // added lazily, via `get_hooks`
preload_strategy: "modulepreload",
root,
service_worker: false,
service_worker_options: undefined,
templates: {
app: ({ head, body, assets, nonce, env }) => "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>Mode Template</title>\n " + head + "\n </head>\n <body data-sveltekit-preload-data=\"hover\">\n <div style=\"display: contents\">" + body + "</div>\n </body>\n</html>\n",
error: ({ status, message }) => "<!doctype html>\n<html lang=\"en\">\n\t<head>\n\t\t<meta charset=\"utf-8\" />\n\t\t<title>" + message + "</title>\n\n\t\t<style>\n\t\t\tbody {\n\t\t\t\t--bg: white;\n\t\t\t\t--fg: #222;\n\t\t\t\t--divider: #ccc;\n\t\t\t\tbackground: var(--bg);\n\t\t\t\tcolor: var(--fg);\n\t\t\t\tfont-family:\n\t\t\t\t\tsystem-ui,\n\t\t\t\t\t-apple-system,\n\t\t\t\t\tBlinkMacSystemFont,\n\t\t\t\t\t'Segoe UI',\n\t\t\t\t\tRoboto,\n\t\t\t\t\tOxygen,\n\t\t\t\t\tUbuntu,\n\t\t\t\t\tCantarell,\n\t\t\t\t\t'Open Sans',\n\t\t\t\t\t'Helvetica Neue',\n\t\t\t\t\tsans-serif;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tjustify-content: center;\n\t\t\t\theight: 100vh;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.error {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tmax-width: 32rem;\n\t\t\t\tmargin: 0 1rem;\n\t\t\t}\n\n\t\t\t.status {\n\t\t\t\tfont-weight: 200;\n\t\t\t\tfont-size: 3rem;\n\t\t\t\tline-height: 1;\n\t\t\t\tposition: relative;\n\t\t\t\ttop: -0.05rem;\n\t\t\t}\n\n\t\t\t.message {\n\t\t\t\tborder-left: 1px solid var(--divider);\n\t\t\t\tpadding: 0 0 0 1rem;\n\t\t\t\tmargin: 0 0 0 1rem;\n\t\t\t\tmin-height: 2.5rem;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t}\n\n\t\t\t.message h1 {\n\t\t\t\tfont-weight: 400;\n\t\t\t\tfont-size: 1em;\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t@media (prefers-color-scheme: dark) {\n\t\t\t\tbody {\n\t\t\t\t\t--bg: #222;\n\t\t\t\t\t--fg: #ddd;\n\t\t\t\t\t--divider: #666;\n\t\t\t\t}\n\t\t\t}\n\t\t</style>\n\t</head>\n\t<body>\n\t\t<div class=\"error\">\n\t\t\t<span class=\"status\">" + status + "</span>\n\t\t\t<div class=\"message\">\n\t\t\t\t<h1>" + message + "</h1>\n\t\t\t</div>\n\t\t</div>\n\t</body>\n</html>\n"
},
version_hash: "1u12ak4"
};
export async function get_hooks() {
let handle;
let handleFetch;
let handleError;
let handleValidationError;
let init;
let reroute;
let transport;
return {
handle,
handleFetch,
handleError,
handleValidationError,
init,
reroute,
transport
};
}
export { set_assets, set_building, set_manifest, set_prerendering, set_private_env, set_public_env, set_read_implementation };
-42
View File
@@ -1,42 +0,0 @@
// this file is generated — do not edit it
declare module "svelte/elements" {
export interface HTMLAttributes<T> {
'data-sveltekit-keepfocus'?: true | '' | 'off' | undefined | null;
'data-sveltekit-noscroll'?: true | '' | 'off' | undefined | null;
'data-sveltekit-preload-code'?:
| true
| ''
| 'eager'
| 'viewport'
| 'hover'
| 'tap'
| 'off'
| undefined
| null;
'data-sveltekit-preload-data'?: true | '' | 'hover' | 'tap' | 'off' | undefined | null;
'data-sveltekit-reload'?: true | '' | 'off' | undefined | null;
'data-sveltekit-replacestate'?: true | '' | 'off' | undefined | null;
}
}
export {};
declare module "$app/types" {
export interface AppTypes {
RouteId(): "/" | "/callback";
RouteParams(): {
};
LayoutParams(): {
"/": Record<string, never>;
"/callback": Record<string, never>
};
Pathname(): "/" | "/callback" | "/callback/";
ResolvedPathname(): `${"" | `/${string}`}${ReturnType<AppTypes['Pathname']>}`;
Asset(): "/.gitkeep" | string & {};
}
}
@@ -1 +0,0 @@
/* Empty file - SvelteKit requires this */
@@ -1,153 +0,0 @@
{
".svelte-kit/generated/client-optimized/app.js": {
"file": "_app/immutable/entry/app.B9iOASPK.js",
"name": "entry/app",
"src": ".svelte-kit/generated/client-optimized/app.js",
"isEntry": true,
"imports": [
"_CqqhLxdp.js",
"_DZNd3jEa.js",
"_BtkHyJOA.js",
"_fsu08h6h.js",
"_hV77cT_P.js"
],
"dynamicImports": [
".svelte-kit/generated/client-optimized/nodes/0.js",
".svelte-kit/generated/client-optimized/nodes/1.js",
".svelte-kit/generated/client-optimized/nodes/2.js",
".svelte-kit/generated/client-optimized/nodes/3.js"
]
},
".svelte-kit/generated/client-optimized/nodes/0.js": {
"file": "_app/immutable/nodes/0.C7lVdKJN.js",
"name": "nodes/0",
"src": ".svelte-kit/generated/client-optimized/nodes/0.js",
"isEntry": true,
"isDynamicEntry": true,
"imports": [
"_DZNd3jEa.js",
"_BtkHyJOA.js",
"_CqqhLxdp.js",
"_fsu08h6h.js",
"_BRRLaaPq.js"
],
"css": [
"_app/immutable/assets/0.r7T8fV5B.css"
]
},
".svelte-kit/generated/client-optimized/nodes/1.js": {
"file": "_app/immutable/nodes/1.DhhPkK36.js",
"name": "nodes/1",
"src": ".svelte-kit/generated/client-optimized/nodes/1.js",
"isEntry": true,
"isDynamicEntry": true,
"imports": [
"_DZNd3jEa.js",
"_974AMC2H.js",
"_CqqhLxdp.js",
"_CuIyQV9Z.js"
]
},
".svelte-kit/generated/client-optimized/nodes/2.js": {
"file": "_app/immutable/nodes/2.MK_aCw-P.js",
"name": "nodes/2",
"src": ".svelte-kit/generated/client-optimized/nodes/2.js",
"isEntry": true,
"isDynamicEntry": true,
"imports": [
"_DZNd3jEa.js",
"_974AMC2H.js",
"_CqqhLxdp.js",
"_fsu08h6h.js",
"_BRRLaaPq.js"
]
},
".svelte-kit/generated/client-optimized/nodes/3.js": {
"file": "_app/immutable/nodes/3.DVfrbbic.js",
"name": "nodes/3",
"src": ".svelte-kit/generated/client-optimized/nodes/3.js",
"isEntry": true,
"isDynamicEntry": true,
"imports": [
"_DZNd3jEa.js",
"_BtkHyJOA.js",
"_CqqhLxdp.js",
"_fsu08h6h.js",
"_hV77cT_P.js",
"_CuIyQV9Z.js",
"_BRRLaaPq.js"
]
},
"_974AMC2H.js": {
"file": "_app/immutable/chunks/974AMC2H.js",
"name": "legacy",
"imports": [
"_CqqhLxdp.js"
]
},
"_BRRLaaPq.js": {
"file": "_app/immutable/chunks/BRRLaaPq.js",
"name": "auth.svelte",
"imports": [
"_CqqhLxdp.js"
]
},
"_Bgo_ZO3W.js": {
"file": "_app/immutable/chunks/Bgo_ZO3W.js",
"name": "index",
"imports": [
"_CqqhLxdp.js"
]
},
"_BtkHyJOA.js": {
"file": "_app/immutable/chunks/BtkHyJOA.js",
"name": "index-client",
"imports": [
"_CqqhLxdp.js"
]
},
"_CqqhLxdp.js": {
"file": "_app/immutable/chunks/CqqhLxdp.js",
"name": "runtime"
},
"_CuIyQV9Z.js": {
"file": "_app/immutable/chunks/CuIyQV9Z.js",
"name": "entry",
"imports": [
"_CqqhLxdp.js",
"_Bgo_ZO3W.js",
"_BtkHyJOA.js"
]
},
"_DZNd3jEa.js": {
"file": "_app/immutable/chunks/DZNd3jEa.js",
"name": "disclose-version",
"imports": [
"_CqqhLxdp.js"
]
},
"_fsu08h6h.js": {
"file": "_app/immutable/chunks/fsu08h6h.js",
"name": "if",
"imports": [
"_CqqhLxdp.js"
]
},
"_hV77cT_P.js": {
"file": "_app/immutable/chunks/hV77cT_P.js",
"name": "store",
"imports": [
"_Bgo_ZO3W.js",
"_CqqhLxdp.js"
]
},
"node_modules/@sveltejs/kit/src/runtime/client/entry.js": {
"file": "_app/immutable/entry/start.JQZ0kVpy.js",
"name": "entry/start",
"src": "node_modules/@sveltejs/kit/src/runtime/client/entry.js",
"isEntry": true,
"imports": [
"_CuIyQV9Z.js"
]
}
}
@@ -1 +0,0 @@
.app.svelte-12qhfyh{display:flex;flex-direction:column;min-height:100vh}header.svelte-12qhfyh{padding:1rem;background:#f5f5f5;border-bottom:1px solid #ddd}nav.svelte-12qhfyh{display:flex;gap:1rem;align-items:center}nav.svelte-12qhfyh a:where(.svelte-12qhfyh){text-decoration:none;color:#333}main.svelte-12qhfyh{flex:1;padding:1rem}button.svelte-12qhfyh{padding:.5rem 1rem;cursor:pointer}
@@ -1 +0,0 @@
import{i as g,j as d,k as c,l as m,o as i,q as b,g as p,v,w as k,x as h}from"./CqqhLxdp.js";function y(n=!1){const s=g,e=s.l.u;if(!e)return;let f=()=>v(s.s);if(n){let o=0,t={};const _=k(()=>{let l=!1;const r=s.s;for(const a in r)r[a]!==t[a]&&(t[a]=r[a],l=!0);return l&&o++,o});f=()=>p(_)}e.b.length&&d(()=>{u(s,f),i(e.b)}),c(()=>{const o=m(()=>e.m.map(b));return()=>{for(const t of o)typeof t=="function"&&t()}}),e.a.length&&c(()=>{u(s,f),i(e.a)})}function u(n,s){if(n.l.s)for(const e of n.l.s)p(e);s()}h();export{y as i};
@@ -1 +0,0 @@
var S=t=>{throw TypeError(t)};var c=(t,e,i)=>e.has(t)||S("Cannot "+i);var s=(t,e,i)=>(c(t,e,"read from private field"),i?i.call(t):e.get(t)),n=(t,e,i)=>e.has(t)?S("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,i);import{h as d,g,e as h,u as _}from"./CqqhLxdp.js";const o={PB_TOKEN:"pb_token",SESSION:"auth_session"};var a,r,l,u;class f{constructor(){n(this,a,d(null));n(this,r,d(!0));n(this,l,_(()=>this._session!==null));n(this,u,_(()=>this._session?{email:this._session.email,displayName:this._session.displayName}:null))}get _session(){return g(s(this,a))}set _session(e){h(s(this,a),e,!0)}get _loading(){return g(s(this,r))}set _loading(e){h(s(this,r),e,!0)}get isAuthenticated(){return g(s(this,l))}set isAuthenticated(e){h(s(this,l),e)}get session(){return this._session}get loading(){return this._loading}get user(){return g(s(this,u))}set user(e){h(s(this,u),e)}hydrate(){if(typeof localStorage>"u")return;const e=localStorage.getItem(o.SESSION);if(e)try{this._session=JSON.parse(e)}catch{localStorage.removeItem(o.SESSION),localStorage.removeItem(o.PB_TOKEN)}this._loading=!1}login(e){typeof localStorage<"u"&&(localStorage.setItem(o.SESSION,JSON.stringify(e)),localStorage.setItem(o.PB_TOKEN,e.pbToken)),this._session=e,this._loading=!1}logout(){typeof localStorage<"u"&&(localStorage.removeItem(o.SESSION),localStorage.removeItem(o.PB_TOKEN)),this._session=null}redirectToLogin(){typeof window<"u"&&(window.location.href="/auth/login")}}a=new WeakMap,r=new WeakMap,l=new WeakMap,u=new WeakMap;const I=new f;export{I as a};
@@ -1 +0,0 @@
import{n as o,l as a,z as d}from"./CqqhLxdp.js";function p(s,u,e){if(s==null)return u(void 0),o;const t=a(()=>s.subscribe(u,e));return t.unsubscribe?()=>t.unsubscribe():t}const i=[];function _(s,u=o){let e=null;const t=new Set;function c(r){if(d(s,r)&&(s=r,e)){const b=!i.length;for(const n of t)n[1](),i.push(n,s);if(b){for(let n=0;n<i.length;n+=2)i[n][0](i[n+1]);i.length=0}}}function f(r){c(r(s))}function l(r,b=o){const n=[r,b];return t.add(n),t.size===1&&(e=u(c,f)||o),r(s),()=>{t.delete(n),t.size===0&&e&&(e(),e=null)}}return{set:c,update:f,subscribe:l}}function h(s){let u;return p(s,e=>u=e)(),u}export{h as g,p as s,_ as w};
@@ -1 +0,0 @@
import{k as o,i as t,A as c,l}from"./CqqhLxdp.js";function u(n){throw new Error("https://svelte.dev/e/lifecycle_outside_component")}function r(n){t===null&&u(),c&&t.l!==null?a(t).m.push(n):o(()=>{const e=l(n);if(typeof e=="function")return e})}function a(n){var e=n.l;return e.u??(e.u={a:[],b:[],m:[]})}export{r as o};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
var S=Object.defineProperty;var y=a=>{throw TypeError(a)};var D=(a,e,t)=>e in a?S(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var A=(a,e,t)=>D(a,typeof e!="symbol"?e+"":e,t),E=(a,e,t)=>e.has(a)||y("Cannot "+t);var s=(a,e,t)=>(E(a,e,"read from private field"),t?t.call(a):e.get(a)),u=(a,e,t)=>e.has(a)?y("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(a):e.set(a,t),T=(a,e,t,i)=>(E(a,e,"write to private field"),i?i.call(a,t):e.set(a,t),t);import{B as w,C as N,D as k,E as x,F,G as M,H as g,I as B,J as C,K as H,L as I,M as L,N as O,O as P,P as G,Q as J,R as K,S as R}from"./CqqhLxdp.js";var d,l,c,_,v,m,b;class Q{constructor(e,t=!0){A(this,"anchor");u(this,d,new Map);u(this,l,new Map);u(this,c,new Map);u(this,_,new Set);u(this,v,!0);u(this,m,()=>{var e=w;if(s(this,d).has(e)){var t=s(this,d).get(e),i=s(this,l).get(t);if(i)N(i),s(this,_).delete(t);else{var n=s(this,c).get(t);n&&(s(this,l).set(t,n.effect),s(this,c).delete(t),n.fragment.lastChild.remove(),this.anchor.before(n.fragment),i=n.effect)}for(const[f,r]of s(this,d)){if(s(this,d).delete(f),f===e)break;const h=s(this,c).get(r);h&&(k(h.effect),s(this,c).delete(r))}for(const[f,r]of s(this,l)){if(f===t||s(this,_).has(f))continue;const h=()=>{if(Array.from(s(this,d).values()).includes(f)){var p=document.createDocumentFragment();C(r,p),p.append(F()),s(this,c).set(f,{effect:r,fragment:p})}else k(r);s(this,_).delete(f),s(this,l).delete(f)};s(this,v)||!i?(s(this,_).add(f),x(r,h,!1)):h()}}});u(this,b,e=>{s(this,d).delete(e);const t=Array.from(s(this,d).values());for(const[i,n]of s(this,c))t.includes(i)||(k(n.effect),s(this,c).delete(i))});this.anchor=e,T(this,v,t)}ensure(e,t){var i=w,n=H();if(t&&!s(this,l).has(e)&&!s(this,c).has(e))if(n){var f=document.createDocumentFragment(),r=F();f.append(r),s(this,c).set(e,{effect:M(()=>t(r)),fragment:f})}else s(this,l).set(e,M(()=>t(this.anchor)));if(s(this,d).set(i,e),n){for(const[h,o]of s(this,l))h===e?i.skipped_effects.delete(o):i.skipped_effects.add(o);for(const[h,o]of s(this,c))h===e?i.skipped_effects.delete(o.effect):i.skipped_effects.add(o.effect);i.oncommit(s(this,m)),i.ondiscard(s(this,b))}else g&&(this.anchor=B),s(this,m).call(this)}}d=new WeakMap,l=new WeakMap,c=new WeakMap,_=new WeakMap,v=new WeakMap,m=new WeakMap,b=new WeakMap;function q(a,e,t=!1){g&&L();var i=new Q(a),n=t?O:0;function f(r,h){if(g){const p=P(a)===G;if(r===p){var o=J();K(o),i.anchor=o,R(!1),i.ensure(r,h),R(!0);return}}i.ensure(r,h)}I(()=>{var r=!1;e((h,o=!0)=>{r=!0,f(o,h)}),r||f(!1,null)},n)}export{Q as B,q as i};
@@ -1 +0,0 @@
import{s as c,g as l}from"./Bgo_ZO3W.js";import{b as o,d as b,n as a,m as d,g as p,e as g}from"./CqqhLxdp.js";let s=!1,i=Symbol();function m(e,u,r){const n=r[u]??(r[u]={store:null,source:d(void 0),unsubscribe:a});if(n.store!==e&&!(i in r))if(n.unsubscribe(),n.store=e??null,e==null)n.source.v=void 0,n.unsubscribe=a;else{var t=!0;n.unsubscribe=c(e,f=>{t?n.source.v=f:g(n.source,f)}),t=!1}return e&&i in r?l(e):p(n.source)}function y(){const e={};function u(){o(()=>{for(var r in e)e[r].unsubscribe();b(e,i,{enumerable:!1,value:!0})})}return[e,u]}function N(e){var u=s;try{return s=!1,[e(),s]}finally{s=u}}export{m as a,N as c,y as s};
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
import{l as o,a as r}from"../chunks/CuIyQV9Z.js";export{o as load_css,r as start};
@@ -1 +0,0 @@
import{d as F,f as c,a as d,s as M}from"../chunks/DZNd3jEa.js";import{o as A}from"../chunks/BtkHyJOA.js";import{L as q,N as C,F as L,T as w,H as p,U as H,V as R,W as g,S as b,R as T,I as B,p as D,a as O,c as l,s as u,r as v,f as S,t as W}from"../chunks/CqqhLxdp.js";import{B as I,i as P}from"../chunks/fsu08h6h.js";import{a as f}from"../chunks/BRRLaaPq.js";function U(i,o,...t){var r=new I(i);q(()=>{const e=o()??null;r.ensure(e,e&&(a=>e(a,...t)))},C)}function V(i,o){let t=null,r=p;var e;if(p){t=B;for(var a=H(document.head);a!==null&&(a.nodeType!==R||a.data!==i);)a=g(a);if(a===null)b(!1);else{var h=g(a);a.remove(),T(h)}}p||(e=document.head.appendChild(L()));try{q(()=>o(e),w)}finally{r&&(b(!0),T(t))}}var j=c('<meta name="description" content="Mode Template"/>'),z=c('<span> </span> <button class="svelte-12qhfyh">Logout</button>',1),G=c('<button class="svelte-12qhfyh">Login</button>'),J=c('<div class="app svelte-12qhfyh"><header class="svelte-12qhfyh"><nav class="svelte-12qhfyh"><a href="/" class="svelte-12qhfyh">Home</a> <!></nav></header> <main class="svelte-12qhfyh"><!></main></div>');function $(i,o){D(o,!0),A(()=>{f.hydrate()});var t=J();V("12qhfyh",s=>{var n=j();d(s,n)});var r=l(t),e=l(r),a=u(l(e),2);{var h=s=>{var n=z(),m=S(n),k=l(m);v(m);var x=u(m,2);x.__click=()=>f.logout(),W(()=>{var y;return M(k,`Welcome, ${((y=f.user)==null?void 0:y.displayName)??""}`)}),d(s,n)},E=s=>{var n=G();n.__click=()=>f.redirectToLogin(),d(s,n)};P(a,s=>{f.isAuthenticated?s(h):s(E,!1)})}v(e),v(r);var _=u(r,2),N=l(_);U(N,()=>o.children),v(_),v(t),d(i,t),O()}F(["click"]);export{$ as component};
@@ -1 +0,0 @@
import{f as h,a as g,s as e}from"../chunks/DZNd3jEa.js";import{i as l}from"../chunks/974AMC2H.js";import{p as v,f as d,t as _,a as x,c as o,r as p,s as $}from"../chunks/CqqhLxdp.js";import{s as k,p as m}from"../chunks/CuIyQV9Z.js";const b={get error(){return m.error},get status(){return m.status}};k.updated.check;const f=b;var E=h("<h1> </h1> <p> </p>",1);function z(i,c){v(c,!1),l();var t=E(),r=d(t),n=o(r,!0);p(r);var s=$(r,2),u=o(s,!0);p(s),_(()=>{var a;e(n,f.status),e(u,(a=f.error)==null?void 0:a.message)}),g(i,t),x()}export{z as component};
@@ -1 +0,0 @@
import{d as E,f as m,a as o,c as N,s as _}from"../chunks/DZNd3jEa.js";import{i as P}from"../chunks/974AMC2H.js";import{p as S,s as n,f as p,a as W,c as g,r as d,t as j}from"../chunks/CqqhLxdp.js";import{i as u}from"../chunks/fsu08h6h.js";import{a as i}from"../chunks/BRRLaaPq.js";var q=m("<p>Loading...</p>"),z=m("<p> </p> <p> </p>",1),B=m("<p>Please log in to continue.</p> <button>Sign in with Microsoft</button>",1),C=m("<h1>Mode Template</h1> <!>",1);function J(h,b){S(b,!1),P();var f=C(),x=n(p(f),2);{var k=a=>{var s=q();o(a,s)},L=a=>{var s=N(),M=p(s);{var T=t=>{var r=z(),e=p(r),y=g(e);d(e);var l=n(e,2),A=g(l);d(l),j(()=>{var v,c;_(y,`Welcome, ${((v=i.user)==null?void 0:v.displayName)??""}!`),_(A,`Email: ${((c=i.user)==null?void 0:c.email)??""}`)}),o(t,r)},w=t=>{var r=B(),e=n(p(r),2);e.__click=()=>i.redirectToLogin(),o(t,r)};u(M,t=>{i.isAuthenticated?t(T):t(w,!1)},!0)}o(a,s)};u(x,a=>{i.loading?a(k):a(L,!1)})}o(h,f),W()}E(["click"]);export{J as component};
@@ -1 +0,0 @@
import{f as p,a as n,s as y}from"../chunks/DZNd3jEa.js";import{o as $}from"../chunks/BtkHyJOA.js";import{p as k,s as x,f as g,a as M,e as l,h as N,g as u,c as P,r as w,y as A,t as I}from"../chunks/CqqhLxdp.js";import{i as R}from"../chunks/fsu08h6h.js";import{s as S,a as T}from"../chunks/hV77cT_P.js";import{s as j,g as q}from"../chunks/CuIyQV9Z.js";import{a as z}from"../chunks/BRRLaaPq.js";const B=()=>{const e=j;return{page:{subscribe:e.page.subscribe},navigating:{subscribe:e.navigating.subscribe},updated:e.updated}},C={subscribe(e){return B().page.subscribe(e)}};var D=p('<p style="color: red;"> </p> <a href="/">Return home</a>',1),E=p("<p>Please wait...</p>"),F=p("<h1>Authenticating...</h1> <!>",1);function U(e,i){k(i,!0);const f=()=>T(C,"$page",b),[b,v]=S();let r=N(null);$(async()=>{const s=f().url.searchParams,a=s.get("email"),t=s.get("displayName"),o=s.get("token"),m=s.get("error");if(m){l(r,m,!0);return}a&&t&&o?(z.login({email:a,displayName:t,pbToken:o}),q("/")):l(r,"Invalid callback parameters")});var c=F(),h=x(g(c),2);{var _=s=>{var a=D(),t=g(a),o=P(t,!0);w(t),A(2),I(()=>y(o,u(r))),n(s,a)},d=s=>{var a=E();n(s,a)};R(h,s=>{u(r)?s(_):s(d,!1)})}n(e,c),M(),v()}export{U as component};
@@ -1 +0,0 @@
{"version":"1768972126462"}
@@ -1 +0,0 @@
export const env={}
@@ -1,155 +0,0 @@
{
".svelte-kit/generated/server/internal.js": {
"file": "internal.js",
"name": "internal",
"src": ".svelte-kit/generated/server/internal.js",
"isEntry": true,
"imports": [
"_internal.js",
"_environment.js"
]
},
"_auth.svelte.js": {
"file": "chunks/auth.svelte.js",
"name": "auth.svelte",
"imports": [
"_index2.js"
]
},
"_context.js": {
"file": "chunks/context.js",
"name": "context"
},
"_environment.js": {
"file": "chunks/environment.js",
"name": "environment"
},
"_equality.js": {
"file": "chunks/equality.js",
"name": "equality"
},
"_exports.js": {
"file": "chunks/exports.js",
"name": "exports"
},
"_index.js": {
"file": "chunks/index.js",
"name": "index",
"imports": [
"_utils2.js",
"_equality.js"
]
},
"_index2.js": {
"file": "chunks/index2.js",
"name": "index",
"imports": [
"_context.js"
]
},
"_internal.js": {
"file": "chunks/internal.js",
"name": "internal",
"imports": [
"_index2.js",
"_environment.js",
"_utils2.js",
"_equality.js",
"_context.js"
]
},
"_shared.js": {
"file": "chunks/shared.js",
"name": "shared",
"imports": [
"_utils.js"
]
},
"_state.svelte.js": {
"file": "chunks/state.svelte.js",
"name": "state.svelte",
"imports": [
"_utils2.js"
]
},
"_utils.js": {
"file": "chunks/utils.js",
"name": "utils"
},
"_utils2.js": {
"file": "chunks/utils2.js",
"name": "utils"
},
"node_modules/@sveltejs/kit/src/runtime/app/server/remote/index.js": {
"file": "remote-entry.js",
"name": "remote-entry",
"src": "node_modules/@sveltejs/kit/src/runtime/app/server/remote/index.js",
"isEntry": true,
"imports": [
"_shared.js",
"_environment.js"
]
},
"node_modules/@sveltejs/kit/src/runtime/components/svelte-5/error.svelte": {
"file": "entries/fallbacks/error.svelte.js",
"name": "entries/fallbacks/error.svelte",
"src": "node_modules/@sveltejs/kit/src/runtime/components/svelte-5/error.svelte",
"isEntry": true,
"imports": [
"_context.js",
"_state.svelte.js",
"_exports.js",
"_utils.js",
"_index.js"
]
},
"node_modules/@sveltejs/kit/src/runtime/server/index.js": {
"file": "index.js",
"name": "index",
"src": "node_modules/@sveltejs/kit/src/runtime/server/index.js",
"isEntry": true,
"imports": [
"_environment.js",
"_shared.js",
"_exports.js",
"_utils.js",
"_index.js",
"_internal.js"
]
},
"src/routes/+layout.svelte": {
"file": "entries/pages/_layout.svelte.js",
"name": "entries/pages/_layout.svelte",
"src": "src/routes/+layout.svelte",
"isEntry": true,
"imports": [
"_index2.js",
"_auth.svelte.js",
"_context.js"
],
"css": [
"_app/immutable/assets/_layout.r7T8fV5B.css"
]
},
"src/routes/+page.svelte": {
"file": "entries/pages/_page.svelte.js",
"name": "entries/pages/_page.svelte",
"src": "src/routes/+page.svelte",
"isEntry": true,
"imports": [
"_context.js",
"_auth.svelte.js"
]
},
"src/routes/callback/+page.svelte": {
"file": "entries/pages/callback/_page.svelte.js",
"name": "entries/pages/callback/_page.svelte",
"src": "src/routes/callback/+page.svelte",
"isEntry": true,
"imports": [
"_exports.js",
"_utils.js",
"_state.svelte.js"
]
}
}
@@ -1 +0,0 @@
.app.svelte-12qhfyh{display:flex;flex-direction:column;min-height:100vh}header.svelte-12qhfyh{padding:1rem;background:#f5f5f5;border-bottom:1px solid #ddd}nav.svelte-12qhfyh{display:flex;gap:1rem;align-items:center}nav.svelte-12qhfyh a:where(.svelte-12qhfyh){text-decoration:none;color:#333}main.svelte-12qhfyh{flex:1;padding:1rem}button.svelte-12qhfyh{padding:.5rem 1rem;cursor:pointer}
@@ -1,70 +0,0 @@
import { x as derived } from "./index2.js";
const STORAGE_KEYS = { PB_TOKEN: "pb_token", SESSION: "auth_session" };
class AuthStore {
_session = null;
_loading = true;
#isAuthenticated = derived(() => this._session !== null);
get isAuthenticated() {
return this.#isAuthenticated();
}
set isAuthenticated($$value) {
return this.#isAuthenticated($$value);
}
get session() {
return this._session;
}
get loading() {
return this._loading;
}
#user = derived(() => this._session ? {
email: this._session.email,
displayName: this._session.displayName
} : null);
get user() {
return this.#user();
}
set user($$value) {
return this.#user($$value);
}
constructor() {
}
/** Call this in onMount to hydrate from localStorage */
hydrate() {
if (typeof localStorage === "undefined") return;
const stored = localStorage.getItem(STORAGE_KEYS.SESSION);
if (stored) {
try {
this._session = JSON.parse(stored);
} catch {
localStorage.removeItem(STORAGE_KEYS.SESSION);
localStorage.removeItem(STORAGE_KEYS.PB_TOKEN);
}
}
this._loading = false;
}
login(session) {
if (typeof localStorage !== "undefined") {
localStorage.setItem(STORAGE_KEYS.SESSION, JSON.stringify(session));
localStorage.setItem(STORAGE_KEYS.PB_TOKEN, session.pbToken);
}
this._session = session;
this._loading = false;
}
logout() {
if (typeof localStorage !== "undefined") {
localStorage.removeItem(STORAGE_KEYS.SESSION);
localStorage.removeItem(STORAGE_KEYS.PB_TOKEN);
}
this._session = null;
}
/** Redirect to backend auth login */
redirectToLogin() {
if (typeof window !== "undefined") {
window.location.href = "/auth/login";
}
}
}
const auth = new AuthStore();
export {
auth as a
};
@@ -1,70 +0,0 @@
function lifecycle_outside_component(name) {
{
throw new Error(`https://svelte.dev/e/lifecycle_outside_component`);
}
}
const ATTR_REGEX = /[&"<]/g;
const CONTENT_REGEX = /[&<]/g;
function escape_html(value, is_attr) {
const str = String(value ?? "");
const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX;
pattern.lastIndex = 0;
let escaped = "";
let last = 0;
while (pattern.test(str)) {
const i = pattern.lastIndex - 1;
const ch = str[i];
escaped += str.substring(last, i) + (ch === "&" ? "&amp;" : ch === '"' ? "&quot;" : "&lt;");
last = i + 1;
}
return escaped + str.substring(last);
}
var ssr_context = null;
function set_ssr_context(v) {
ssr_context = v;
}
function getContext(key) {
const context_map = get_or_init_context_map();
const result = (
/** @type {T} */
context_map.get(key)
);
return result;
}
function setContext(key, context) {
get_or_init_context_map().set(key, context);
return context;
}
function get_or_init_context_map(name) {
if (ssr_context === null) {
lifecycle_outside_component();
}
return ssr_context.c ??= new Map(get_parent_context(ssr_context) || void 0);
}
function push(fn) {
ssr_context = { p: ssr_context, c: null, r: null };
}
function pop() {
ssr_context = /** @type {SSRContext} */
ssr_context.p;
}
function get_parent_context(ssr_context2) {
let parent = ssr_context2.p;
while (parent !== null) {
const context_map = parent.c;
if (context_map !== null) {
return context_map;
}
parent = parent.p;
}
return null;
}
export {
set_ssr_context as a,
ssr_context as b,
pop as c,
escape_html as e,
getContext as g,
push as p,
setContext as s
};
@@ -1,36 +0,0 @@
const BROWSER = false;
let base = "";
let assets = base;
const app_dir = "_app";
const relative = true;
const initial = { base, assets };
function override(paths) {
base = paths.base;
assets = paths.assets;
}
function reset() {
base = initial.base;
assets = initial.assets;
}
function set_assets(path) {
assets = initial.assets = path;
}
let prerendering = false;
function set_building() {
}
function set_prerendering() {
prerendering = true;
}
export {
BROWSER as B,
assets as a,
base as b,
app_dir as c,
reset as d,
set_building as e,
set_prerendering as f,
override as o,
prerendering as p,
relative as r,
set_assets as s
};
@@ -1,14 +0,0 @@
function equals(value) {
return value === this.v;
}
function safe_not_equal(a, b) {
return a != a ? b == b : a !== b || a !== null && typeof a === "object" || typeof a === "function";
}
function safe_equals(value) {
return !safe_not_equal(value, this.v);
}
export {
safe_not_equal as a,
equals as e,
safe_equals as s
};
@@ -1,174 +0,0 @@
const SCHEME = /^[a-z][a-z\d+\-.]+:/i;
const internal = new URL("sveltekit-internal://");
function resolve(base, path) {
if (path[0] === "/" && path[1] === "/") return path;
let url = new URL(base, internal);
url = new URL(path, url);
return url.protocol === internal.protocol ? url.pathname + url.search + url.hash : url.href;
}
function normalize_path(path, trailing_slash) {
if (path === "/" || trailing_slash === "ignore") return path;
if (trailing_slash === "never") {
return path.endsWith("/") ? path.slice(0, -1) : path;
} else if (trailing_slash === "always" && !path.endsWith("/")) {
return path + "/";
}
return path;
}
function decode_pathname(pathname) {
return pathname.split("%25").map(decodeURI).join("%25");
}
function decode_params(params) {
for (const key in params) {
params[key] = decodeURIComponent(params[key]);
}
return params;
}
function make_trackable(url, callback, search_params_callback, allow_hash = false) {
const tracked = new URL(url);
Object.defineProperty(tracked, "searchParams", {
value: new Proxy(tracked.searchParams, {
get(obj, key) {
if (key === "get" || key === "getAll" || key === "has") {
return (param, ...rest) => {
search_params_callback(param);
return obj[key](param, ...rest);
};
}
callback();
const value = Reflect.get(obj, key);
return typeof value === "function" ? value.bind(obj) : value;
}
}),
enumerable: true,
configurable: true
});
const tracked_url_properties = ["href", "pathname", "search", "toString", "toJSON"];
if (allow_hash) tracked_url_properties.push("hash");
for (const property of tracked_url_properties) {
Object.defineProperty(tracked, property, {
get() {
callback();
return url[property];
},
enumerable: true,
configurable: true
});
}
{
tracked[Symbol.for("nodejs.util.inspect.custom")] = (depth, opts, inspect) => {
return inspect(url, opts);
};
tracked.searchParams[Symbol.for("nodejs.util.inspect.custom")] = (depth, opts, inspect) => {
return inspect(url.searchParams, opts);
};
}
if (!allow_hash) {
disable_hash(tracked);
}
return tracked;
}
function disable_hash(url) {
allow_nodejs_console_log(url);
Object.defineProperty(url, "hash", {
get() {
throw new Error(
"Cannot access event.url.hash. Consider using `page.url.hash` inside a component instead"
);
}
});
}
function disable_search(url) {
allow_nodejs_console_log(url);
for (const property of ["search", "searchParams"]) {
Object.defineProperty(url, property, {
get() {
throw new Error(`Cannot access url.${property} on a page with prerendering enabled`);
}
});
}
}
function allow_nodejs_console_log(url) {
{
url[Symbol.for("nodejs.util.inspect.custom")] = (depth, opts, inspect) => {
return inspect(new URL(url), opts);
};
}
}
function validator(expected) {
function validate(module, file) {
if (!module) return;
for (const key in module) {
if (key[0] === "_" || expected.has(key)) continue;
const values = [...expected.values()];
const hint = hint_for_supported_files(key, file?.slice(file.lastIndexOf("."))) ?? `valid exports are ${values.join(", ")}, or anything with a '_' prefix`;
throw new Error(`Invalid export '${key}'${file ? ` in ${file}` : ""} (${hint})`);
}
}
return validate;
}
function hint_for_supported_files(key, ext = ".js") {
const supported_files = [];
if (valid_layout_exports.has(key)) {
supported_files.push(`+layout${ext}`);
}
if (valid_page_exports.has(key)) {
supported_files.push(`+page${ext}`);
}
if (valid_layout_server_exports.has(key)) {
supported_files.push(`+layout.server${ext}`);
}
if (valid_page_server_exports.has(key)) {
supported_files.push(`+page.server${ext}`);
}
if (valid_server_exports.has(key)) {
supported_files.push(`+server${ext}`);
}
if (supported_files.length > 0) {
return `'${key}' is a valid export in ${supported_files.slice(0, -1).join(", ")}${supported_files.length > 1 ? " or " : ""}${supported_files.at(-1)}`;
}
}
const valid_layout_exports = /* @__PURE__ */ new Set([
"load",
"prerender",
"csr",
"ssr",
"trailingSlash",
"config"
]);
const valid_page_exports = /* @__PURE__ */ new Set([...valid_layout_exports, "entries"]);
const valid_layout_server_exports = /* @__PURE__ */ new Set([...valid_layout_exports]);
const valid_page_server_exports = /* @__PURE__ */ new Set([...valid_layout_server_exports, "actions", "entries"]);
const valid_server_exports = /* @__PURE__ */ new Set([
"GET",
"POST",
"PATCH",
"PUT",
"DELETE",
"OPTIONS",
"HEAD",
"fallback",
"prerender",
"trailingSlash",
"config",
"entries"
]);
const validate_layout_exports = validator(valid_layout_exports);
const validate_page_exports = validator(valid_page_exports);
const validate_layout_server_exports = validator(valid_layout_server_exports);
const validate_page_server_exports = validator(valid_page_server_exports);
const validate_server_exports = validator(valid_server_exports);
export {
SCHEME as S,
decode_params as a,
validate_layout_exports as b,
validate_page_server_exports as c,
disable_search as d,
validate_page_exports as e,
decode_pathname as f,
validate_server_exports as g,
make_trackable as m,
normalize_path as n,
resolve as r,
validate_layout_server_exports as v
};
@@ -1,60 +0,0 @@
import { n as noop } from "./utils2.js";
import { a as safe_not_equal } from "./equality.js";
import "clsx";
const subscriber_queue = [];
function readable(value, start) {
return {
subscribe: writable(value, start).subscribe
};
}
function writable(value, start = noop) {
let stop = null;
const subscribers = /* @__PURE__ */ new Set();
function set(new_value) {
if (safe_not_equal(value, new_value)) {
value = new_value;
if (stop) {
const run_queue = !subscriber_queue.length;
for (const subscriber of subscribers) {
subscriber[1]();
subscriber_queue.push(subscriber, value);
}
if (run_queue) {
for (let i = 0; i < subscriber_queue.length; i += 2) {
subscriber_queue[i][0](subscriber_queue[i + 1]);
}
subscriber_queue.length = 0;
}
}
}
}
function update(fn) {
set(fn(
/** @type {T} */
value
));
}
function subscribe(run, invalidate = noop) {
const subscriber = [run, invalidate];
subscribers.add(subscriber);
if (subscribers.size === 1) {
stop = start(set, update) || noop;
}
run(
/** @type {T} */
value
);
return () => {
subscribers.delete(subscriber);
if (subscribers.size === 0 && stop) {
stop();
stop = null;
}
};
}
return { set, update, subscribe };
}
export {
readable as r,
writable as w
};
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,542 +0,0 @@
import * as devalue from "devalue";
import { t as text_decoder, b as base64_encode, c as base64_decode } from "./utils.js";
import { SvelteKitError } from "@sveltejs/kit/internal";
function set_nested_value(object, path_string, value) {
if (path_string.startsWith("n:")) {
path_string = path_string.slice(2);
value = value === "" ? void 0 : parseFloat(value);
} else if (path_string.startsWith("b:")) {
path_string = path_string.slice(2);
value = value === "on";
}
deep_set(object, split_path(path_string), value);
}
function convert_formdata(data) {
const result = {};
for (let key of data.keys()) {
const is_array = key.endsWith("[]");
let values = data.getAll(key);
if (is_array) key = key.slice(0, -2);
if (values.length > 1 && !is_array) {
throw new Error(`Form cannot contain duplicated keys — "${key}" has ${values.length} values`);
}
values = values.filter(
(entry) => typeof entry === "string" || entry.name !== "" || entry.size > 0
);
if (key.startsWith("n:")) {
key = key.slice(2);
values = values.map((v) => v === "" ? void 0 : parseFloat(
/** @type {string} */
v
));
} else if (key.startsWith("b:")) {
key = key.slice(2);
values = values.map((v) => v === "on");
}
set_nested_value(result, key, is_array ? values : values[0]);
}
return result;
}
const BINARY_FORM_CONTENT_TYPE = "application/x-sveltekit-formdata";
const BINARY_FORM_VERSION = 0;
const HEADER_BYTES = 1 + 4 + 2;
async function deserialize_binary_form(request) {
if (request.headers.get("content-type") !== BINARY_FORM_CONTENT_TYPE) {
const form_data = await request.formData();
return { data: convert_formdata(form_data), meta: {}, form_data };
}
if (!request.body) {
throw deserialize_error("no body");
}
const content_length = parseInt(request.headers.get("content-length") ?? "");
if (Number.isNaN(content_length)) {
throw deserialize_error("invalid Content-Length header");
}
const reader = request.body.getReader();
const chunks = [];
function get_chunk(index) {
if (index in chunks) return chunks[index];
let i = chunks.length;
while (i <= index) {
chunks[i] = reader.read().then((chunk) => chunk.value);
i++;
}
return chunks[index];
}
async function get_buffer(offset, length) {
let start_chunk;
let chunk_start = 0;
let chunk_index;
for (chunk_index = 0; ; chunk_index++) {
const chunk = await get_chunk(chunk_index);
if (!chunk) return null;
const chunk_end = chunk_start + chunk.byteLength;
if (offset >= chunk_start && offset < chunk_end) {
start_chunk = chunk;
break;
}
chunk_start = chunk_end;
}
if (offset + length <= chunk_start + start_chunk.byteLength) {
return start_chunk.subarray(offset - chunk_start, offset + length - chunk_start);
}
const chunks2 = [start_chunk.subarray(offset - chunk_start)];
let cursor = start_chunk.byteLength - offset + chunk_start;
while (cursor < length) {
chunk_index++;
let chunk = await get_chunk(chunk_index);
if (!chunk) return null;
if (chunk.byteLength > length - cursor) {
chunk = chunk.subarray(0, length - cursor);
}
chunks2.push(chunk);
cursor += chunk.byteLength;
}
const buffer = new Uint8Array(length);
cursor = 0;
for (const chunk of chunks2) {
buffer.set(chunk, cursor);
cursor += chunk.byteLength;
}
return buffer;
}
const header = await get_buffer(0, HEADER_BYTES);
if (!header) throw deserialize_error("too short");
if (header[0] !== BINARY_FORM_VERSION) {
throw deserialize_error(`got version ${header[0]}, expected version ${BINARY_FORM_VERSION}`);
}
const header_view = new DataView(header.buffer, header.byteOffset, header.byteLength);
const data_length = header_view.getUint32(1, true);
if (HEADER_BYTES + data_length > content_length) {
throw deserialize_error("data overflow");
}
const file_offsets_length = header_view.getUint16(5, true);
if (HEADER_BYTES + data_length + file_offsets_length > content_length) {
throw deserialize_error("file offset table overflow");
}
const data_buffer = await get_buffer(HEADER_BYTES, data_length);
if (!data_buffer) throw deserialize_error("data too short");
let file_offsets;
let files_start_offset;
if (file_offsets_length > 0) {
const file_offsets_buffer = await get_buffer(HEADER_BYTES + data_length, file_offsets_length);
if (!file_offsets_buffer) throw deserialize_error("file offset table too short");
file_offsets = /** @type {Array<number>} */
JSON.parse(text_decoder.decode(file_offsets_buffer));
files_start_offset = HEADER_BYTES + data_length + file_offsets_length;
}
const [data, meta] = devalue.parse(text_decoder.decode(data_buffer), {
File: ([name, type, size, last_modified, index]) => {
if (files_start_offset + file_offsets[index] + size > content_length) {
throw deserialize_error("file data overflow");
}
return new Proxy(
new LazyFile(
name,
type,
size,
last_modified,
get_chunk,
files_start_offset + file_offsets[index]
),
{
getPrototypeOf() {
return File.prototype;
}
}
);
}
});
void (async () => {
let has_more = true;
while (has_more) {
const chunk = await get_chunk(chunks.length);
has_more = !!chunk;
}
})();
return { data, meta, form_data: null };
}
function deserialize_error(message) {
return new SvelteKitError(400, "Bad Request", `Could not deserialize binary form: ${message}`);
}
class LazyFile {
/** @type {(index: number) => Promise<Uint8Array<ArrayBuffer> | undefined>} */
#get_chunk;
/** @type {number} */
#offset;
/**
* @param {string} name
* @param {string} type
* @param {number} size
* @param {number} last_modified
* @param {(index: number) => Promise<Uint8Array<ArrayBuffer> | undefined>} get_chunk
* @param {number} offset
*/
constructor(name, type, size, last_modified, get_chunk, offset) {
this.name = name;
this.type = type;
this.size = size;
this.lastModified = last_modified;
this.webkitRelativePath = "";
this.#get_chunk = get_chunk;
this.#offset = offset;
this.arrayBuffer = this.arrayBuffer.bind(this);
this.bytes = this.bytes.bind(this);
this.slice = this.slice.bind(this);
this.stream = this.stream.bind(this);
this.text = this.text.bind(this);
}
/** @type {ArrayBuffer | undefined} */
#buffer;
async arrayBuffer() {
this.#buffer ??= await new Response(this.stream()).arrayBuffer();
return this.#buffer;
}
async bytes() {
return new Uint8Array(await this.arrayBuffer());
}
/**
* @param {number=} start
* @param {number=} end
* @param {string=} contentType
*/
slice(start = 0, end = this.size, contentType = this.type) {
if (start < 0) {
start = Math.max(this.size + start, 0);
} else {
start = Math.min(start, this.size);
}
if (end < 0) {
end = Math.max(this.size + end, 0);
} else {
end = Math.min(end, this.size);
}
const size = Math.max(end - start, 0);
const file = new LazyFile(
this.name,
contentType,
size,
this.lastModified,
this.#get_chunk,
this.#offset + start
);
return file;
}
stream() {
let cursor = 0;
let chunk_index = 0;
return new ReadableStream({
start: async (controller) => {
let chunk_start = 0;
let start_chunk = null;
for (chunk_index = 0; ; chunk_index++) {
const chunk = await this.#get_chunk(chunk_index);
if (!chunk) return null;
const chunk_end = chunk_start + chunk.byteLength;
if (this.#offset >= chunk_start && this.#offset < chunk_end) {
start_chunk = chunk;
break;
}
chunk_start = chunk_end;
}
if (this.#offset + this.size <= chunk_start + start_chunk.byteLength) {
controller.enqueue(
start_chunk.subarray(this.#offset - chunk_start, this.#offset + this.size - chunk_start)
);
controller.close();
} else {
controller.enqueue(start_chunk.subarray(this.#offset - chunk_start));
cursor = start_chunk.byteLength - this.#offset + chunk_start;
}
},
pull: async (controller) => {
chunk_index++;
let chunk = await this.#get_chunk(chunk_index);
if (!chunk) {
controller.error("incomplete file data");
controller.close();
return;
}
if (chunk.byteLength > this.size - cursor) {
chunk = chunk.subarray(0, this.size - cursor);
}
controller.enqueue(chunk);
cursor += chunk.byteLength;
if (cursor >= this.size) {
controller.close();
}
}
});
}
async text() {
return text_decoder.decode(await this.arrayBuffer());
}
}
const path_regex = /^[a-zA-Z_$]\w*(\.[a-zA-Z_$]\w*|\[\d+\])*$/;
function split_path(path) {
if (!path_regex.test(path)) {
throw new Error(`Invalid path ${path}`);
}
return path.split(/\.|\[|\]/).filter(Boolean);
}
function check_prototype_pollution(key) {
if (key === "__proto__" || key === "constructor" || key === "prototype") {
throw new Error(
`Invalid key "${key}"`
);
}
}
function deep_set(object, keys, value) {
let current = object;
for (let i = 0; i < keys.length - 1; i += 1) {
const key = keys[i];
check_prototype_pollution(key);
const is_array = /^\d+$/.test(keys[i + 1]);
const exists = Object.hasOwn(current, key);
const inner = current[key];
if (exists && is_array !== Array.isArray(inner)) {
throw new Error(`Invalid array key ${keys[i + 1]}`);
}
if (!exists) {
current[key] = is_array ? [] : {};
}
current = current[key];
}
const final_key = keys[keys.length - 1];
check_prototype_pollution(final_key);
current[final_key] = value;
}
function normalize_issue(issue, server = false) {
const normalized = { name: "", path: [], message: issue.message, server };
if (issue.path !== void 0) {
let name = "";
for (const segment of issue.path) {
const key = (
/** @type {string | number} */
typeof segment === "object" ? segment.key : segment
);
normalized.path.push(key);
if (typeof key === "number") {
name += `[${key}]`;
} else if (typeof key === "string") {
name += name === "" ? key : "." + key;
}
}
normalized.name = name;
}
return normalized;
}
function flatten_issues(issues) {
const result = {};
for (const issue of issues) {
(result.$ ??= []).push(issue);
let name = "";
if (issue.path !== void 0) {
for (const key of issue.path) {
if (typeof key === "number") {
name += `[${key}]`;
} else if (typeof key === "string") {
name += name === "" ? key : "." + key;
}
(result[name] ??= []).push(issue);
}
}
}
return result;
}
function deep_get(object, path) {
let current = object;
for (const key of path) {
if (current == null || typeof current !== "object") {
return current;
}
current = current[key];
}
return current;
}
function create_field_proxy(target, get_input, set_input, get_issues, path = []) {
const get_value = () => {
return deep_get(get_input(), path);
};
return new Proxy(target, {
get(target2, prop) {
if (typeof prop === "symbol") return target2[prop];
if (/^\d+$/.test(prop)) {
return create_field_proxy({}, get_input, set_input, get_issues, [
...path,
parseInt(prop, 10)
]);
}
const key = build_path_string(path);
if (prop === "set") {
const set_func = function(newValue) {
set_input(path, newValue);
return newValue;
};
return create_field_proxy(set_func, get_input, set_input, get_issues, [...path, prop]);
}
if (prop === "value") {
return create_field_proxy(get_value, get_input, set_input, get_issues, [...path, prop]);
}
if (prop === "issues" || prop === "allIssues") {
const issues_func = () => {
const all_issues = get_issues()[key === "" ? "$" : key];
if (prop === "allIssues") {
return all_issues?.map((issue) => ({
path: issue.path,
message: issue.message
}));
}
return all_issues?.filter((issue) => issue.name === key)?.map((issue) => ({
path: issue.path,
message: issue.message
}));
};
return create_field_proxy(issues_func, get_input, set_input, get_issues, [...path, prop]);
}
if (prop === "as") {
const as_func = (type, input_value) => {
const is_array = type === "file multiple" || type === "select multiple" || type === "checkbox" && typeof input_value === "string";
const prefix = type === "number" || type === "range" ? "n:" : type === "checkbox" && !is_array ? "b:" : "";
const base_props = {
name: prefix + key + (is_array ? "[]" : ""),
get "aria-invalid"() {
const issues = get_issues();
return key in issues ? "true" : void 0;
}
};
if (type !== "text" && type !== "select" && type !== "select multiple") {
base_props.type = type === "file multiple" ? "file" : type;
}
if (type === "submit" || type === "hidden") {
return Object.defineProperties(base_props, {
value: { value: input_value, enumerable: true }
});
}
if (type === "select" || type === "select multiple") {
return Object.defineProperties(base_props, {
multiple: { value: is_array, enumerable: true },
value: {
enumerable: true,
get() {
return get_value();
}
}
});
}
if (type === "checkbox" || type === "radio") {
return Object.defineProperties(base_props, {
value: { value: input_value ?? "on", enumerable: true },
checked: {
enumerable: true,
get() {
const value = get_value();
if (type === "radio") {
return value === input_value;
}
if (is_array) {
return (value ?? []).includes(input_value);
}
return value;
}
}
});
}
if (type === "file" || type === "file multiple") {
return Object.defineProperties(base_props, {
multiple: { value: is_array, enumerable: true },
files: {
enumerable: true,
get() {
const value = get_value();
if (value instanceof File) {
if (typeof DataTransfer !== "undefined") {
const fileList = new DataTransfer();
fileList.items.add(value);
return fileList.files;
}
return { 0: value, length: 1 };
}
if (Array.isArray(value) && value.every((f) => f instanceof File)) {
if (typeof DataTransfer !== "undefined") {
const fileList = new DataTransfer();
value.forEach((file) => fileList.items.add(file));
return fileList.files;
}
const fileListLike = { length: value.length };
value.forEach((file, index) => {
fileListLike[index] = file;
});
return fileListLike;
}
return null;
}
}
});
}
return Object.defineProperties(base_props, {
value: {
enumerable: true,
get() {
const value = get_value();
return value != null ? String(value) : "";
}
}
});
};
return create_field_proxy(as_func, get_input, set_input, get_issues, [...path, "as"]);
}
return create_field_proxy({}, get_input, set_input, get_issues, [...path, prop]);
}
});
}
function build_path_string(path) {
let result = "";
for (const segment of path) {
if (typeof segment === "number") {
result += `[${segment}]`;
} else {
result += result === "" ? segment : "." + segment;
}
}
return result;
}
const INVALIDATED_PARAM = "x-sveltekit-invalidated";
const TRAILING_SLASH_PARAM = "x-sveltekit-trailing-slash";
function stringify(data, transport) {
const encoders = Object.fromEntries(Object.entries(transport).map(([k, v]) => [k, v.encode]));
return devalue.stringify(data, encoders);
}
function stringify_remote_arg(value, transport) {
if (value === void 0) return "";
const json_string = stringify(value, transport);
const bytes = new TextEncoder().encode(json_string);
return base64_encode(bytes).replaceAll("=", "").replaceAll("+", "-").replaceAll("/", "_");
}
function parse_remote_arg(string, transport) {
if (!string) return void 0;
const json_string = text_decoder.decode(
// no need to add back `=` characters, atob can handle it
base64_decode(string.replaceAll("-", "+").replaceAll("_", "/"))
);
const decoders = Object.fromEntries(Object.entries(transport).map(([k, v]) => [k, v.decode]));
return devalue.parse(json_string, decoders);
}
function create_remote_key(id, payload) {
return id + "/" + payload;
}
export {
BINARY_FORM_CONTENT_TYPE as B,
INVALIDATED_PARAM as I,
TRAILING_SLASH_PARAM as T,
stringify_remote_arg as a,
create_field_proxy as b,
create_remote_key as c,
deserialize_binary_form as d,
set_nested_value as e,
flatten_issues as f,
deep_set as g,
normalize_issue as n,
parse_remote_arg as p,
stringify as s
};
@@ -1,16 +0,0 @@
import "clsx";
import { n as noop } from "./utils2.js";
import "@sveltejs/kit/internal/server";
const is_legacy = noop.toString().includes("$$") || /function \w+\(\) \{\}/.test(noop.toString());
if (is_legacy) {
({
data: {},
form: null,
error: null,
params: {},
route: { id: null },
state: {},
status: -1,
url: new URL("https://example.com")
});
}
@@ -1,43 +0,0 @@
const text_encoder = new TextEncoder();
const text_decoder = new TextDecoder();
function get_relative_path(from, to) {
const from_parts = from.split(/[/\\]/);
const to_parts = to.split(/[/\\]/);
from_parts.pop();
while (from_parts[0] === to_parts[0]) {
from_parts.shift();
to_parts.shift();
}
let i = from_parts.length;
while (i--) from_parts[i] = "..";
return from_parts.concat(to_parts).join("/");
}
function base64_encode(bytes) {
if (globalThis.Buffer) {
return globalThis.Buffer.from(bytes).toString("base64");
}
let binary = "";
for (let i = 0; i < bytes.length; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
function base64_decode(encoded) {
if (globalThis.Buffer) {
const buffer = globalThis.Buffer.from(encoded, "base64");
return new Uint8Array(buffer);
}
const binary = atob(encoded);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
export {
text_encoder as a,
base64_encode as b,
base64_decode as c,
get_relative_path as g,
text_decoder as t
};
@@ -1,39 +0,0 @@
var is_array = Array.isArray;
var index_of = Array.prototype.indexOf;
var array_from = Array.from;
var define_property = Object.defineProperty;
var get_descriptor = Object.getOwnPropertyDescriptor;
var object_prototype = Object.prototype;
var array_prototype = Array.prototype;
var get_prototype_of = Object.getPrototypeOf;
var is_extensible = Object.isExtensible;
const noop = () => {
};
function run_all(arr) {
for (var i = 0; i < arr.length; i++) {
arr[i]();
}
}
function deferred() {
var resolve;
var reject;
var promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
}
export {
array_prototype as a,
get_prototype_of as b,
is_extensible as c,
deferred as d,
index_of as e,
define_property as f,
get_descriptor as g,
array_from as h,
is_array as i,
noop as n,
object_prototype as o,
run_all as r
};
@@ -1,44 +0,0 @@
import { g as getContext, e as escape_html } from "../../chunks/context.js";
import "clsx";
import "../../chunks/state.svelte.js";
import "@sveltejs/kit/internal";
import "../../chunks/exports.js";
import "../../chunks/utils.js";
import { w as writable } from "../../chunks/index.js";
import "@sveltejs/kit/internal/server";
function create_updated_store() {
const { set, subscribe } = writable(false);
{
return {
subscribe,
// eslint-disable-next-line @typescript-eslint/require-await
check: async () => false
};
}
}
const stores = {
updated: /* @__PURE__ */ create_updated_store()
};
({
check: stores.updated.check
});
function context() {
return getContext("__request__");
}
const page$1 = {
get error() {
return context().page.error;
},
get status() {
return context().page.status;
}
};
const page = page$1;
function Error$1($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
$$renderer2.push(`<h1>${escape_html(page.status)}</h1> <p>${escape_html(page.error?.message)}</p>`);
});
}
export {
Error$1 as default
};
@@ -1,25 +0,0 @@
import { w as head } from "../../chunks/index2.js";
import { a as auth } from "../../chunks/auth.svelte.js";
import { e as escape_html } from "../../chunks/context.js";
function _layout($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { children } = $$props;
head("12qhfyh", $$renderer2, ($$renderer3) => {
$$renderer3.push(`<meta name="description" content="Mode Template"/>`);
});
$$renderer2.push(`<div class="app svelte-12qhfyh"><header class="svelte-12qhfyh"><nav class="svelte-12qhfyh"><a href="/" class="svelte-12qhfyh">Home</a> `);
if (auth.isAuthenticated) {
$$renderer2.push("<!--[-->");
$$renderer2.push(`<span>Welcome, ${escape_html(auth.user?.displayName)}</span> <button class="svelte-12qhfyh">Logout</button>`);
} else {
$$renderer2.push("<!--[!-->");
$$renderer2.push(`<button class="svelte-12qhfyh">Login</button>`);
}
$$renderer2.push(`<!--]--></nav></header> <main class="svelte-12qhfyh">`);
children($$renderer2);
$$renderer2.push(`<!----></main></div>`);
});
}
export {
_layout as default
};
@@ -1,26 +0,0 @@
import { e as escape_html } from "../../chunks/context.js";
import "clsx";
import { a as auth } from "../../chunks/auth.svelte.js";
function _page($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
$$renderer2.push(`<h1>Mode Template</h1> `);
if (auth.loading) {
$$renderer2.push("<!--[-->");
$$renderer2.push(`<p>Loading...</p>`);
} else {
$$renderer2.push("<!--[!-->");
if (auth.isAuthenticated) {
$$renderer2.push("<!--[-->");
$$renderer2.push(`<p>Welcome, ${escape_html(auth.user?.displayName)}!</p> <p>Email: ${escape_html(auth.user?.email)}</p>`);
} else {
$$renderer2.push("<!--[!-->");
$$renderer2.push(`<p>Please log in to continue.</p> <button>Sign in with Microsoft</button>`);
}
$$renderer2.push(`<!--]-->`);
}
$$renderer2.push(`<!--]-->`);
});
}
export {
_page as default
};
@@ -1,19 +0,0 @@
import "clsx";
import "@sveltejs/kit/internal";
import "../../../chunks/exports.js";
import "../../../chunks/utils.js";
import "@sveltejs/kit/internal/server";
import "../../../chunks/state.svelte.js";
function _page($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
$$renderer2.push(`<h1>Authenticating...</h1> `);
{
$$renderer2.push("<!--[!-->");
$$renderer2.push(`<p>Please wait...</p>`);
}
$$renderer2.push(`<!--]-->`);
});
}
export {
_page as default
};
File diff suppressed because it is too large Load Diff
@@ -1,13 +0,0 @@
import { g, o, c, s, a, b } from "./chunks/internal.js";
import { s as s2, e, f } from "./chunks/environment.js";
export {
g as get_hooks,
o as options,
s2 as set_assets,
e as set_building,
c as set_manifest,
f as set_prerendering,
s as set_private_env,
a as set_public_env,
b as set_read_implementation
};
@@ -1,47 +0,0 @@
export const manifest = (() => {
function __memo(fn) {
let value;
return () => value ??= (value = fn());
}
return {
appDir: "_app",
appPath: "_app",
assets: new Set([".gitkeep"]),
mimeTypes: {},
_: {
client: {start:"_app/immutable/entry/start.JQZ0kVpy.js",app:"_app/immutable/entry/app.B9iOASPK.js",imports:["_app/immutable/entry/start.JQZ0kVpy.js","_app/immutable/chunks/CuIyQV9Z.js","_app/immutable/chunks/CqqhLxdp.js","_app/immutable/chunks/Bgo_ZO3W.js","_app/immutable/chunks/BtkHyJOA.js","_app/immutable/entry/app.B9iOASPK.js","_app/immutable/chunks/CqqhLxdp.js","_app/immutable/chunks/DZNd3jEa.js","_app/immutable/chunks/BtkHyJOA.js","_app/immutable/chunks/fsu08h6h.js","_app/immutable/chunks/hV77cT_P.js","_app/immutable/chunks/Bgo_ZO3W.js"],stylesheets:[],fonts:[],uses_env_dynamic_public:false},
nodes: [
__memo(() => import('./nodes/0.js')),
__memo(() => import('./nodes/1.js')),
__memo(() => import('./nodes/2.js')),
__memo(() => import('./nodes/3.js'))
],
remotes: {
},
routes: [
{
id: "/",
pattern: /^\/$/,
params: [],
page: { layouts: [0,], errors: [1,], leaf: 2 },
endpoint: null
},
{
id: "/callback",
pattern: /^\/callback\/?$/,
params: [],
page: { layouts: [0,], errors: [1,], leaf: 3 },
endpoint: null
}
],
prerendered_routes: new Set([]),
matchers: async () => {
return { };
},
server_assets: {}
}
}
})();
@@ -1,47 +0,0 @@
export const manifest = (() => {
function __memo(fn) {
let value;
return () => value ??= (value = fn());
}
return {
appDir: "_app",
appPath: "_app",
assets: new Set([".gitkeep"]),
mimeTypes: {},
_: {
client: {start:"_app/immutable/entry/start.JQZ0kVpy.js",app:"_app/immutable/entry/app.B9iOASPK.js",imports:["_app/immutable/entry/start.JQZ0kVpy.js","_app/immutable/chunks/CuIyQV9Z.js","_app/immutable/chunks/CqqhLxdp.js","_app/immutable/chunks/Bgo_ZO3W.js","_app/immutable/chunks/BtkHyJOA.js","_app/immutable/entry/app.B9iOASPK.js","_app/immutable/chunks/CqqhLxdp.js","_app/immutable/chunks/DZNd3jEa.js","_app/immutable/chunks/BtkHyJOA.js","_app/immutable/chunks/fsu08h6h.js","_app/immutable/chunks/hV77cT_P.js","_app/immutable/chunks/Bgo_ZO3W.js"],stylesheets:[],fonts:[],uses_env_dynamic_public:false},
nodes: [
__memo(() => import('./nodes/0.js')),
__memo(() => import('./nodes/1.js')),
__memo(() => import('./nodes/2.js')),
__memo(() => import('./nodes/3.js'))
],
remotes: {
},
routes: [
{
id: "/",
pattern: /^\/$/,
params: [],
page: { layouts: [0,], errors: [1,], leaf: 2 },
endpoint: null
},
{
id: "/callback",
pattern: /^\/callback\/?$/,
params: [],
page: { layouts: [0,], errors: [1,], leaf: 3 },
endpoint: null
}
],
prerendered_routes: new Set([]),
matchers: async () => {
return { };
},
server_assets: {}
}
}
})();
@@ -1,8 +0,0 @@
export const index = 0;
let component_cache;
export const component = async () => component_cache ??= (await import('../entries/pages/_layout.svelte.js')).default;
export const imports = ["_app/immutable/nodes/0.C7lVdKJN.js","_app/immutable/chunks/DZNd3jEa.js","_app/immutable/chunks/CqqhLxdp.js","_app/immutable/chunks/BtkHyJOA.js","_app/immutable/chunks/fsu08h6h.js","_app/immutable/chunks/BRRLaaPq.js"];
export const stylesheets = ["_app/immutable/assets/0.r7T8fV5B.css"];
export const fonts = [];
@@ -1,8 +0,0 @@
export const index = 1;
let component_cache;
export const component = async () => component_cache ??= (await import('../entries/fallbacks/error.svelte.js')).default;
export const imports = ["_app/immutable/nodes/1.DhhPkK36.js","_app/immutable/chunks/DZNd3jEa.js","_app/immutable/chunks/CqqhLxdp.js","_app/immutable/chunks/974AMC2H.js","_app/immutable/chunks/CuIyQV9Z.js","_app/immutable/chunks/Bgo_ZO3W.js","_app/immutable/chunks/BtkHyJOA.js"];
export const stylesheets = [];
export const fonts = [];
@@ -1,8 +0,0 @@
export const index = 2;
let component_cache;
export const component = async () => component_cache ??= (await import('../entries/pages/_page.svelte.js')).default;
export const imports = ["_app/immutable/nodes/2.MK_aCw-P.js","_app/immutable/chunks/DZNd3jEa.js","_app/immutable/chunks/CqqhLxdp.js","_app/immutable/chunks/974AMC2H.js","_app/immutable/chunks/fsu08h6h.js","_app/immutable/chunks/BRRLaaPq.js"];
export const stylesheets = [];
export const fonts = [];
@@ -1,8 +0,0 @@
export const index = 3;
let component_cache;
export const component = async () => component_cache ??= (await import('../entries/pages/callback/_page.svelte.js')).default;
export const imports = ["_app/immutable/nodes/3.DVfrbbic.js","_app/immutable/chunks/DZNd3jEa.js","_app/immutable/chunks/CqqhLxdp.js","_app/immutable/chunks/BtkHyJOA.js","_app/immutable/chunks/fsu08h6h.js","_app/immutable/chunks/hV77cT_P.js","_app/immutable/chunks/Bgo_ZO3W.js","_app/immutable/chunks/CuIyQV9Z.js","_app/immutable/chunks/BRRLaaPq.js"];
export const stylesheets = [];
export const fonts = [];
@@ -1,540 +0,0 @@
import { get_request_store, with_request_store } from "@sveltejs/kit/internal/server";
import { parse } from "devalue";
import { error, json } from "@sveltejs/kit";
import { a as stringify_remote_arg, f as flatten_issues, b as create_field_proxy, n as normalize_issue, e as set_nested_value, g as deep_set, s as stringify, c as create_remote_key } from "./chunks/shared.js";
import { ValidationError } from "@sveltejs/kit/internal";
import { b as base, c as app_dir, B as BROWSER, p as prerendering } from "./chunks/environment.js";
function create_validator(validate_or_fn, maybe_fn) {
if (!maybe_fn) {
return (arg) => {
if (arg !== void 0) {
error(400, "Bad Request");
}
};
}
if (validate_or_fn === "unchecked") {
return (arg) => arg;
}
if ("~standard" in validate_or_fn) {
return async (arg) => {
const { event, state } = get_request_store();
const result = await validate_or_fn["~standard"].validate(arg);
if (result.issues) {
error(
400,
await state.handleValidationError({
issues: result.issues,
event
})
);
}
return result.value;
};
}
throw new Error(
'Invalid validator passed to remote function. Expected "unchecked" or a Standard Schema (https://standardschema.dev)'
);
}
async function get_response(info, arg, state, get_result) {
await 0;
const cache = get_cache(info, state);
return cache[stringify_remote_arg(arg, state.transport)] ??= get_result();
}
function parse_remote_response(data, transport) {
const revivers = {};
for (const key in transport) {
revivers[key] = transport[key].decode;
}
return parse(data, revivers);
}
async function run_remote_function(event, state, allow_cookies, arg, validate, fn) {
const store = {
event: {
...event,
setHeaders: () => {
throw new Error("setHeaders is not allowed in remote functions");
},
cookies: {
...event.cookies,
set: (name, value, opts) => {
if (!allow_cookies) {
throw new Error("Cannot set cookies in `query` or `prerender` functions");
}
if (opts.path && !opts.path.startsWith("/")) {
throw new Error("Cookies set in remote functions must have an absolute path");
}
return event.cookies.set(name, value, opts);
},
delete: (name, opts) => {
if (!allow_cookies) {
throw new Error("Cannot delete cookies in `query` or `prerender` functions");
}
if (opts.path && !opts.path.startsWith("/")) {
throw new Error("Cookies deleted in remote functions must have an absolute path");
}
return event.cookies.delete(name, opts);
}
}
},
state: {
...state,
is_in_remote_function: true
}
};
const validated = await with_request_store(store, () => validate(arg));
return with_request_store(store, () => fn(validated));
}
function get_cache(info, state = get_request_store().state) {
let cache = state.remote_data?.get(info);
if (cache === void 0) {
cache = {};
(state.remote_data ??= /* @__PURE__ */ new Map()).set(info, cache);
}
return cache;
}
// @__NO_SIDE_EFFECTS__
function command(validate_or_fn, maybe_fn) {
const fn = maybe_fn ?? validate_or_fn;
const validate = create_validator(validate_or_fn, maybe_fn);
const __ = { type: "command", id: "", name: "" };
const wrapper = (arg) => {
const { event, state } = get_request_store();
if (state.is_endpoint_request) {
if (!["POST", "PUT", "PATCH", "DELETE"].includes(event.request.method)) {
throw new Error(
`Cannot call a command (\`${__.name}(${maybe_fn ? "..." : ""})\`) from a ${event.request.method} handler`
);
}
} else if (!event.isRemoteRequest) {
throw new Error(
`Cannot call a command (\`${__.name}(${maybe_fn ? "..." : ""})\`) during server-side rendering`
);
}
state.refreshes ??= {};
const promise = Promise.resolve(run_remote_function(event, state, true, arg, validate, fn));
promise.updates = () => {
throw new Error(`Cannot call '${__.name}(...).updates(...)' on the server`);
};
return (
/** @type {ReturnType<RemoteCommand<Input, Output>>} */
promise
);
};
Object.defineProperty(wrapper, "__", { value: __ });
Object.defineProperty(wrapper, "pending", {
get: () => 0
});
return wrapper;
}
// @__NO_SIDE_EFFECTS__
function form(validate_or_fn, maybe_fn) {
const fn = maybe_fn ?? validate_or_fn;
const schema = !maybe_fn || validate_or_fn === "unchecked" ? null : (
/** @type {any} */
validate_or_fn
);
function create_instance(key) {
const instance = {};
instance.method = "POST";
Object.defineProperty(instance, "enhance", {
value: () => {
return { action: instance.action, method: instance.method };
}
});
const __ = {
type: "form",
name: "",
id: "",
fn: async (data, meta, form_data) => {
const output = {};
output.submission = true;
const { event, state } = get_request_store();
const validated = await schema?.["~standard"].validate(data);
if (meta.validate_only) {
return validated?.issues?.map((issue) => normalize_issue(issue, true)) ?? [];
}
if (validated?.issues !== void 0) {
handle_issues(output, validated.issues, form_data);
} else {
if (validated !== void 0) {
data = validated.value;
}
state.refreshes ??= {};
const issue = create_issues();
try {
output.result = await run_remote_function(
event,
state,
true,
data,
(d) => d,
(data2) => !maybe_fn ? fn() : fn(data2, issue)
);
} catch (e) {
if (e instanceof ValidationError) {
handle_issues(output, e.issues, form_data);
} else {
throw e;
}
}
}
if (!event.isRemoteRequest) {
get_cache(__, state)[""] ??= output;
}
return output;
}
};
Object.defineProperty(instance, "__", { value: __ });
Object.defineProperty(instance, "action", {
get: () => `?/remote=${__.id}`,
enumerable: true
});
Object.defineProperty(instance, "fields", {
get() {
const data = get_cache(__)?.[""];
const issues = flatten_issues(data?.issues ?? []);
return create_field_proxy(
{},
() => data?.input ?? {},
(path, value) => {
if (data?.submission) {
return;
}
const input = path.length === 0 ? value : deep_set(data?.input ?? {}, path.map(String), value);
(get_cache(__)[""] ??= {}).input = input;
},
() => issues
);
}
});
Object.defineProperty(instance, "result", {
get() {
try {
return get_cache(__)?.[""]?.result;
} catch {
return void 0;
}
}
});
Object.defineProperty(instance, "pending", {
get: () => 0
});
Object.defineProperty(instance, "preflight", {
// preflight is a noop on the server
value: () => instance
});
Object.defineProperty(instance, "validate", {
value: () => {
throw new Error("Cannot call validate() on the server");
}
});
if (key == void 0) {
Object.defineProperty(instance, "for", {
/** @type {RemoteForm<any, any>['for']} */
value: (key2) => {
const { state } = get_request_store();
const cache_key = __.id + "|" + JSON.stringify(key2);
let instance2 = (state.form_instances ??= /* @__PURE__ */ new Map()).get(cache_key);
if (!instance2) {
instance2 = create_instance(key2);
instance2.__.id = `${__.id}/${encodeURIComponent(JSON.stringify(key2))}`;
instance2.__.name = __.name;
state.form_instances.set(cache_key, instance2);
}
return instance2;
}
});
}
return instance;
}
return create_instance();
}
function handle_issues(output, issues, form_data) {
output.issues = issues.map((issue) => normalize_issue(issue, true));
if (form_data) {
output.input = {};
for (let key of form_data.keys()) {
if (/^[.\]]?_/.test(key)) continue;
const is_array = key.endsWith("[]");
const values = form_data.getAll(key).filter((value) => typeof value === "string");
if (is_array) key = key.slice(0, -2);
set_nested_value(
/** @type {Record<string, any>} */
output.input,
key,
is_array ? values : values[0]
);
}
}
}
function create_issues() {
return (
/** @type {InvalidField<any>} */
new Proxy(
/** @param {string} message */
(message) => {
if (typeof message !== "string") {
throw new Error(
"`invalid` should now be imported from `@sveltejs/kit` to throw validation issues. The second parameter provided to the form function (renamed to `issue`) is still used to construct issues, e.g. `invalid(issue.field('message'))`. For more info see https://github.com/sveltejs/kit/pulls/14768"
);
}
return create_issue(message);
},
{
get(target, prop) {
if (typeof prop === "symbol") return (
/** @type {any} */
target[prop]
);
return create_issue_proxy(prop, []);
}
}
)
);
function create_issue(message, path = []) {
return {
message,
path
};
}
function create_issue_proxy(key, path) {
const new_path = [...path, key];
const issue_func = (message) => create_issue(message, new_path);
return new Proxy(issue_func, {
get(target, prop) {
if (typeof prop === "symbol") return (
/** @type {any} */
target[prop]
);
if (/^\d+$/.test(prop)) {
return create_issue_proxy(parseInt(prop, 10), new_path);
}
return create_issue_proxy(prop, new_path);
}
});
}
}
// @__NO_SIDE_EFFECTS__
function prerender(validate_or_fn, fn_or_options, maybe_options) {
const maybe_fn = typeof fn_or_options === "function" ? fn_or_options : void 0;
const options = maybe_options ?? (maybe_fn ? void 0 : fn_or_options);
const fn = maybe_fn ?? validate_or_fn;
const validate = create_validator(validate_or_fn, maybe_fn);
const __ = {
type: "prerender",
id: "",
name: "",
has_arg: !!maybe_fn,
inputs: options?.inputs,
dynamic: options?.dynamic
};
const wrapper = (arg) => {
const promise = (async () => {
const { event, state } = get_request_store();
const payload = stringify_remote_arg(arg, state.transport);
const id = __.id;
const url = `${base}/${app_dir}/remote/${id}${payload ? `/${payload}` : ""}`;
if (!state.prerendering && !BROWSER && !event.isRemoteRequest) {
try {
return await get_response(__, arg, state, async () => {
const key = stringify_remote_arg(arg, state.transport);
const cache = get_cache(__, state);
const promise3 = cache[key] ??= fetch(new URL(url, event.url.origin).href).then(
async (response) => {
if (!response.ok) {
throw new Error("Prerendered response not found");
}
const prerendered = await response.json();
if (prerendered.type === "error") {
error(prerendered.status, prerendered.error);
}
return prerendered.result;
}
);
return parse_remote_response(await promise3, state.transport);
});
} catch {
}
}
if (state.prerendering?.remote_responses.has(url)) {
return (
/** @type {Promise<any>} */
state.prerendering.remote_responses.get(url)
);
}
const promise2 = get_response(
__,
arg,
state,
() => run_remote_function(event, state, false, arg, validate, fn)
);
if (state.prerendering) {
state.prerendering.remote_responses.set(url, promise2);
}
const result = await promise2;
if (state.prerendering) {
const body = { type: "result", result: stringify(result, state.transport) };
state.prerendering.dependencies.set(url, {
body: JSON.stringify(body),
response: json(body)
});
}
return result;
})();
promise.catch(() => {
});
return (
/** @type {RemoteResource<Output>} */
promise
);
};
Object.defineProperty(wrapper, "__", { value: __ });
return wrapper;
}
// @__NO_SIDE_EFFECTS__
function query(validate_or_fn, maybe_fn) {
const fn = maybe_fn ?? validate_or_fn;
const validate = create_validator(validate_or_fn, maybe_fn);
const __ = { type: "query", id: "", name: "" };
const wrapper = (arg) => {
if (prerendering) {
throw new Error(
`Cannot call query '${__.name}' while prerendering, as prerendered pages need static data. Use 'prerender' from $app/server instead`
);
}
const { event, state } = get_request_store();
const get_remote_function_result = () => run_remote_function(event, state, false, arg, validate, fn);
const promise = get_response(__, arg, state, get_remote_function_result);
promise.catch(() => {
});
promise.set = (value) => update_refresh_value(get_refresh_context(__, "set", arg), value);
promise.refresh = () => {
const refresh_context = get_refresh_context(__, "refresh", arg);
const is_immediate_refresh = !refresh_context.cache[refresh_context.cache_key];
const value = is_immediate_refresh ? promise : get_remote_function_result();
return update_refresh_value(refresh_context, value, is_immediate_refresh);
};
promise.withOverride = () => {
throw new Error(`Cannot call '${__.name}.withOverride()' on the server`);
};
return (
/** @type {RemoteQuery<Output>} */
promise
);
};
Object.defineProperty(wrapper, "__", { value: __ });
return wrapper;
}
// @__NO_SIDE_EFFECTS__
function batch(validate_or_fn, maybe_fn) {
const fn = maybe_fn ?? validate_or_fn;
const validate = create_validator(validate_or_fn, maybe_fn);
const __ = {
type: "query_batch",
id: "",
name: "",
run: (args) => {
const { event, state } = get_request_store();
return run_remote_function(
event,
state,
false,
args,
(array) => Promise.all(array.map(validate)),
fn
);
}
};
let batching = { args: [], resolvers: [] };
const wrapper = (arg) => {
if (prerendering) {
throw new Error(
`Cannot call query.batch '${__.name}' while prerendering, as prerendered pages need static data. Use 'prerender' from $app/server instead`
);
}
const { event, state } = get_request_store();
const get_remote_function_result = () => {
return new Promise((resolve, reject) => {
batching.args.push(arg);
batching.resolvers.push({ resolve, reject });
if (batching.args.length > 1) return;
setTimeout(async () => {
const batched = batching;
batching = { args: [], resolvers: [] };
try {
const get_result = await run_remote_function(
event,
state,
false,
batched.args,
(array) => Promise.all(array.map(validate)),
fn
);
for (let i = 0; i < batched.resolvers.length; i++) {
try {
batched.resolvers[i].resolve(get_result(batched.args[i], i));
} catch (error2) {
batched.resolvers[i].reject(error2);
}
}
} catch (error2) {
for (const resolver of batched.resolvers) {
resolver.reject(error2);
}
}
}, 0);
});
};
const promise = get_response(__, arg, state, get_remote_function_result);
promise.catch(() => {
});
promise.set = (value) => update_refresh_value(get_refresh_context(__, "set", arg), value);
promise.refresh = () => {
const refresh_context = get_refresh_context(__, "refresh", arg);
const is_immediate_refresh = !refresh_context.cache[refresh_context.cache_key];
const value = is_immediate_refresh ? promise : get_remote_function_result();
return update_refresh_value(refresh_context, value, is_immediate_refresh);
};
promise.withOverride = () => {
throw new Error(`Cannot call '${__.name}.withOverride()' on the server`);
};
return (
/** @type {RemoteQuery<Output>} */
promise
);
};
Object.defineProperty(wrapper, "__", { value: __ });
return wrapper;
}
Object.defineProperty(query, "batch", { value: batch, enumerable: true });
function get_refresh_context(__, action, arg) {
const { state } = get_request_store();
const { refreshes } = state;
if (!refreshes) {
const name = __.type === "query_batch" ? `query.batch '${__.name}'` : `query '${__.name}'`;
throw new Error(
`Cannot call ${action} on ${name} because it is not executed in the context of a command/form remote function`
);
}
const cache = get_cache(__, state);
const cache_key = stringify_remote_arg(arg, state.transport);
const refreshes_key = create_remote_key(__.id, cache_key);
return { __, state, refreshes, refreshes_key, cache, cache_key };
}
function update_refresh_value({ __, refreshes, refreshes_key, cache, cache_key }, value, is_immediate_refresh = false) {
const promise = Promise.resolve(value);
if (!is_immediate_refresh) {
cache[cache_key] = promise;
}
if (__.id) {
refreshes[refreshes_key] = promise;
}
return promise.then(() => {
});
}
export {
command,
form,
prerender,
query
};
@@ -1,58 +0,0 @@
{
"compilerOptions": {
"paths": {
"$lib": [
"../src/lib"
],
"$lib/*": [
"../src/lib/*"
],
"$types": [
"../../types"
],
"$types/*": [
"../../types/*"
],
"$app/types": [
"./types/index.d.ts"
]
},
"rootDirs": [
"..",
"./types"
],
"verbatimModuleSyntax": true,
"isolatedModules": true,
"lib": [
"esnext",
"DOM",
"DOM.Iterable"
],
"moduleResolution": "bundler",
"module": "esnext",
"noEmit": true,
"target": "esnext"
},
"include": [
"ambient.d.ts",
"non-ambient.d.ts",
"./types/**/$types.d.ts",
"../vite.config.js",
"../vite.config.ts",
"../src/**/*.js",
"../src/**/*.ts",
"../src/**/*.svelte",
"../tests/**/*.js",
"../tests/**/*.ts",
"../tests/**/*.svelte"
],
"exclude": [
"../node_modules/**",
"../src/service-worker.js",
"../src/service-worker/**/*.js",
"../src/service-worker.ts",
"../src/service-worker/**/*.ts",
"../src/service-worker.d.ts",
"../src/service-worker/**/*.d.ts"
]
}
@@ -1,4 +0,0 @@
{
"/": [],
"/callback": []
}
@@ -1,24 +0,0 @@
import type * as Kit from '@sveltejs/kit';
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
// @ts-ignore
type MatcherParam<M> = M extends (param : string) => param is infer U ? U extends string ? U : string : string;
type RouteParams = { };
type RouteId = '/';
type MaybeWithVoid<T> = {} extends T ? T | void : T;
export type RequiredKeys<T> = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; }[keyof T];
type OutputDataShape<T> = MaybeWithVoid<Omit<App.PageData, RequiredKeys<T>> & Partial<Pick<App.PageData, keyof T & keyof App.PageData>> & Record<string, any>>
type EnsureDefined<T> = T extends null | undefined ? {} : T;
type OptionalUnion<U extends Record<string, any>, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude<A, keyof U>]?: never } & U : never;
export type Snapshot<T = any> = Kit.Snapshot<T>;
type PageParentData = EnsureDefined<LayoutData>;
type LayoutRouteId = RouteId | "/" | "/callback" | null
type LayoutParams = RouteParams & { }
type LayoutParentData = EnsureDefined<{}>;
export type PageServerData = null;
export type PageData = Expand<PageParentData>;
export type PageProps = { params: RouteParams; data: PageData }
export type LayoutServerData = null;
export type LayoutData = Expand<LayoutParentData>;
export type LayoutProps = { params: LayoutParams; data: LayoutData; children: import("svelte").Snippet }
@@ -1,18 +0,0 @@
import type * as Kit from '@sveltejs/kit';
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
// @ts-ignore
type MatcherParam<M> = M extends (param : string) => param is infer U ? U extends string ? U : string : string;
type RouteParams = { };
type RouteId = '/callback';
type MaybeWithVoid<T> = {} extends T ? T | void : T;
export type RequiredKeys<T> = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; }[keyof T];
type OutputDataShape<T> = MaybeWithVoid<Omit<App.PageData, RequiredKeys<T>> & Partial<Pick<App.PageData, keyof T & keyof App.PageData>> & Record<string, any>>
type EnsureDefined<T> = T extends null | undefined ? {} : T;
type OptionalUnion<U extends Record<string, any>, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude<A, keyof U>]?: never } & U : never;
export type Snapshot<T = any> = Kit.Snapshot<T>;
type PageParentData = EnsureDefined<import('../$types.js').LayoutData>;
export type PageServerData = null;
export type PageData = Expand<PageParentData>;
export type PageProps = { params: RouteParams; data: PageData }
-1
View File
@@ -1 +0,0 @@
/* Empty file - SvelteKit requires this */
-1
View File
@@ -1 +0,0 @@
export const env={}
@@ -1 +0,0 @@
.app.svelte-12qhfyh{display:flex;flex-direction:column;min-height:100vh}header.svelte-12qhfyh{padding:1rem;background:#f5f5f5;border-bottom:1px solid #ddd}nav.svelte-12qhfyh{display:flex;gap:1rem;align-items:center}nav.svelte-12qhfyh a:where(.svelte-12qhfyh){text-decoration:none;color:#333}main.svelte-12qhfyh{flex:1;padding:1rem}button.svelte-12qhfyh{padding:.5rem 1rem;cursor:pointer}
@@ -1 +0,0 @@
import{i as g,j as d,k as c,l as m,o as i,q as b,g as p,v,w as k,x as h}from"./CqqhLxdp.js";function y(n=!1){const s=g,e=s.l.u;if(!e)return;let f=()=>v(s.s);if(n){let o=0,t={};const _=k(()=>{let l=!1;const r=s.s;for(const a in r)r[a]!==t[a]&&(t[a]=r[a],l=!0);return l&&o++,o});f=()=>p(_)}e.b.length&&d(()=>{u(s,f),i(e.b)}),c(()=>{const o=m(()=>e.m.map(b));return()=>{for(const t of o)typeof t=="function"&&t()}}),e.a.length&&c(()=>{u(s,f),i(e.a)})}function u(n,s){if(n.l.s)for(const e of n.l.s)p(e);s()}h();export{y as i};
@@ -1 +0,0 @@
var S=t=>{throw TypeError(t)};var c=(t,e,i)=>e.has(t)||S("Cannot "+i);var s=(t,e,i)=>(c(t,e,"read from private field"),i?i.call(t):e.get(t)),n=(t,e,i)=>e.has(t)?S("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(t):e.set(t,i);import{h as d,g,e as h,u as _}from"./CqqhLxdp.js";const o={PB_TOKEN:"pb_token",SESSION:"auth_session"};var a,r,l,u;class f{constructor(){n(this,a,d(null));n(this,r,d(!0));n(this,l,_(()=>this._session!==null));n(this,u,_(()=>this._session?{email:this._session.email,displayName:this._session.displayName}:null))}get _session(){return g(s(this,a))}set _session(e){h(s(this,a),e,!0)}get _loading(){return g(s(this,r))}set _loading(e){h(s(this,r),e,!0)}get isAuthenticated(){return g(s(this,l))}set isAuthenticated(e){h(s(this,l),e)}get session(){return this._session}get loading(){return this._loading}get user(){return g(s(this,u))}set user(e){h(s(this,u),e)}hydrate(){if(typeof localStorage>"u")return;const e=localStorage.getItem(o.SESSION);if(e)try{this._session=JSON.parse(e)}catch{localStorage.removeItem(o.SESSION),localStorage.removeItem(o.PB_TOKEN)}this._loading=!1}login(e){typeof localStorage<"u"&&(localStorage.setItem(o.SESSION,JSON.stringify(e)),localStorage.setItem(o.PB_TOKEN,e.pbToken)),this._session=e,this._loading=!1}logout(){typeof localStorage<"u"&&(localStorage.removeItem(o.SESSION),localStorage.removeItem(o.PB_TOKEN)),this._session=null}redirectToLogin(){typeof window<"u"&&(window.location.href="/auth/login")}}a=new WeakMap,r=new WeakMap,l=new WeakMap,u=new WeakMap;const I=new f;export{I as a};
@@ -1 +0,0 @@
import{n as o,l as a,z as d}from"./CqqhLxdp.js";function p(s,u,e){if(s==null)return u(void 0),o;const t=a(()=>s.subscribe(u,e));return t.unsubscribe?()=>t.unsubscribe():t}const i=[];function _(s,u=o){let e=null;const t=new Set;function c(r){if(d(s,r)&&(s=r,e)){const b=!i.length;for(const n of t)n[1](),i.push(n,s);if(b){for(let n=0;n<i.length;n+=2)i[n][0](i[n+1]);i.length=0}}}function f(r){c(r(s))}function l(r,b=o){const n=[r,b];return t.add(n),t.size===1&&(e=u(c,f)||o),r(s),()=>{t.delete(n),t.size===0&&e&&(e(),e=null)}}return{set:c,update:f,subscribe:l}}function h(s){let u;return p(s,e=>u=e)(),u}export{h as g,p as s,_ as w};
@@ -1 +0,0 @@
import{k as o,i as t,A as c,l}from"./CqqhLxdp.js";function u(n){throw new Error("https://svelte.dev/e/lifecycle_outside_component")}function r(n){t===null&&u(),c&&t.l!==null?a(t).m.push(n):o(()=>{const e=l(n);if(typeof e=="function")return e})}function a(n){var e=n.l;return e.u??(e.u={a:[],b:[],m:[]})}export{r as o};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
var S=Object.defineProperty;var y=a=>{throw TypeError(a)};var D=(a,e,t)=>e in a?S(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var A=(a,e,t)=>D(a,typeof e!="symbol"?e+"":e,t),E=(a,e,t)=>e.has(a)||y("Cannot "+t);var s=(a,e,t)=>(E(a,e,"read from private field"),t?t.call(a):e.get(a)),u=(a,e,t)=>e.has(a)?y("Cannot add the same private member more than once"):e instanceof WeakSet?e.add(a):e.set(a,t),T=(a,e,t,i)=>(E(a,e,"write to private field"),i?i.call(a,t):e.set(a,t),t);import{B as w,C as N,D as k,E as x,F,G as M,H as g,I as B,J as C,K as H,L as I,M as L,N as O,O as P,P as G,Q as J,R as K,S as R}from"./CqqhLxdp.js";var d,l,c,_,v,m,b;class Q{constructor(e,t=!0){A(this,"anchor");u(this,d,new Map);u(this,l,new Map);u(this,c,new Map);u(this,_,new Set);u(this,v,!0);u(this,m,()=>{var e=w;if(s(this,d).has(e)){var t=s(this,d).get(e),i=s(this,l).get(t);if(i)N(i),s(this,_).delete(t);else{var n=s(this,c).get(t);n&&(s(this,l).set(t,n.effect),s(this,c).delete(t),n.fragment.lastChild.remove(),this.anchor.before(n.fragment),i=n.effect)}for(const[f,r]of s(this,d)){if(s(this,d).delete(f),f===e)break;const h=s(this,c).get(r);h&&(k(h.effect),s(this,c).delete(r))}for(const[f,r]of s(this,l)){if(f===t||s(this,_).has(f))continue;const h=()=>{if(Array.from(s(this,d).values()).includes(f)){var p=document.createDocumentFragment();C(r,p),p.append(F()),s(this,c).set(f,{effect:r,fragment:p})}else k(r);s(this,_).delete(f),s(this,l).delete(f)};s(this,v)||!i?(s(this,_).add(f),x(r,h,!1)):h()}}});u(this,b,e=>{s(this,d).delete(e);const t=Array.from(s(this,d).values());for(const[i,n]of s(this,c))t.includes(i)||(k(n.effect),s(this,c).delete(i))});this.anchor=e,T(this,v,t)}ensure(e,t){var i=w,n=H();if(t&&!s(this,l).has(e)&&!s(this,c).has(e))if(n){var f=document.createDocumentFragment(),r=F();f.append(r),s(this,c).set(e,{effect:M(()=>t(r)),fragment:f})}else s(this,l).set(e,M(()=>t(this.anchor)));if(s(this,d).set(i,e),n){for(const[h,o]of s(this,l))h===e?i.skipped_effects.delete(o):i.skipped_effects.add(o);for(const[h,o]of s(this,c))h===e?i.skipped_effects.delete(o.effect):i.skipped_effects.add(o.effect);i.oncommit(s(this,m)),i.ondiscard(s(this,b))}else g&&(this.anchor=B),s(this,m).call(this)}}d=new WeakMap,l=new WeakMap,c=new WeakMap,_=new WeakMap,v=new WeakMap,m=new WeakMap,b=new WeakMap;function q(a,e,t=!1){g&&L();var i=new Q(a),n=t?O:0;function f(r,h){if(g){const p=P(a)===G;if(r===p){var o=J();K(o),i.anchor=o,R(!1),i.ensure(r,h),R(!0);return}}i.ensure(r,h)}I(()=>{var r=!1;e((h,o=!0)=>{r=!0,f(o,h)}),r||f(!1,null)},n)}export{Q as B,q as i};
@@ -1 +0,0 @@
import{s as c,g as l}from"./Bgo_ZO3W.js";import{b as o,d as b,n as a,m as d,g as p,e as g}from"./CqqhLxdp.js";let s=!1,i=Symbol();function m(e,u,r){const n=r[u]??(r[u]={store:null,source:d(void 0),unsubscribe:a});if(n.store!==e&&!(i in r))if(n.unsubscribe(),n.store=e??null,e==null)n.source.v=void 0,n.unsubscribe=a;else{var t=!0;n.unsubscribe=c(e,f=>{t?n.source.v=f:g(n.source,f)}),t=!1}return e&&i in r?l(e):p(n.source)}function y(){const e={};function u(){o(()=>{for(var r in e)e[r].unsubscribe();b(e,i,{enumerable:!1,value:!0})})}return[e,u]}function N(e){var u=s;try{return s=!1,[e(),s]}finally{s=u}}export{m as a,N as c,y as s};
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More