nlobby-cli 1.4.1 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +47 -32
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var Ut=Object.defineProperty;var g=(s,e)=>()=>(s&&(e=s(s=0)),e);var F=(s,e)=>{for(var t in e)Ut(s,t,{get:e[t],enumerable:!0})};var V={};F(V,{LogLevel:()=>K,Logger:()=>j,logger:()=>o});var K,j,o,b=g(()=>{"use strict";K=(r=>(r[r.DEBUG=0]="DEBUG",r[r.INFO=1]="INFO",r[r.WARN=2]="WARN",r[r.ERROR=3]="ERROR",r))(K||{}),j=class s{static instance;logLevel=1;isProduction=!1;constructor(){this.isProduction=process.env.NODE_ENV==="production"||process.env.MCP_PRODUCTION==="true"||!process.stdout.isTTY}static getInstance(){return s.instance||(s.instance=new s),s.instance}setLogLevel(e){this.logLevel=e}forceProductionMode(){this.isProduction=!0}log(e,t,...n){if(e<this.logLevel||this.isProduction&&e<2)return;let r=new Date().toISOString(),i=K[e],a=`[${r}] [${i}]`;switch(e){case 0:console.debug(a,t,...n);break;case 1:console.info(a,t,...n);break;case 2:console.warn(a,t,...n);break;case 3:console.error(a,t,...n);break}}debug(e,...t){this.log(0,e,...t)}info(e,...t){this.log(1,e,...t)}warn(e,...t){this.log(2,e,...t)}error(e,...t){this.log(3,e,...t)}},o=j.getInstance()});import Pt from"node-fetch";var k,A,T=g(()=>{"use strict";k=class extends Error{response;config;code;constructor(e){super(e),this.name="HttpClientError"}},A=class{defaults;baseURL;requestInterceptors=[];responseSuccessInterceptors=[];responseErrorInterceptors=[];interceptors={request:{use:e=>{this.requestInterceptors.push(e)}},response:{use:(e,t)=>{this.responseSuccessInterceptors.push(e),t&&this.responseErrorInterceptors.push(t)}}};constructor(e){this.baseURL=e.baseURL??"",this.defaults={headers:{...e.headers??{}},timeout:e.timeout??3e4,baseURL:this.baseURL}}async get(e,t){return this.request("GET",e,void 0,t)}async post(e,t,n){return this.request("POST",e,t,n)}async parseBody(e){if((e.headers.get("content-type")??"").includes("application/json"))try{return await e.json()}catch{return await e.text()}return await e.text()}extractHeaders(e){let t={};return e.headers.forEach((n,r)=>{t[r]=n}),t}async runErrorInterceptors(e){for(let t of this.responseErrorInterceptors)await t(e)}async request(e,t,n,r){let i=t.startsWith("http")?t:`${this.baseURL}${t}`;if(r?.params&&Object.keys(r.params).length>0){let p={};for(let[L,R]of Object.entries(r.params))R!==void 0&&(p[L]=R);let f=new URLSearchParams(p).toString();i+=(i.includes("?")?"&":"?")+f}let a={...this.defaults.headers,...r?.headers??{}},c={url:i,method:e,headers:a,timeout:r?.timeout??this.defaults.timeout};for(let p of this.requestInterceptors)c=await p(c);let l={};for(let[p,f]of Object.entries(c.headers))f!==void 0&&(l[p]=f);let u=new AbortController,d=setTimeout(()=>u.abort(),c.timeout),h;try{let p={method:c.method,headers:l,signal:u.signal};n!==void 0&&(p.body=typeof n=="string"?n:JSON.stringify(n)),h=await Pt(c.url,p),clearTimeout(d)}catch(p){clearTimeout(d);let f=new k(p instanceof Error?p.message:"Network error");throw f.config={url:c.url,method:c.method,headers:c.headers,timeout:c.timeout},p instanceof Error&&(p.name==="AbortError"?(f.code="ETIMEDOUT",f.message=`timeout of ${c.timeout}ms exceeded`):p.message.includes("ECONNREFUSED")?f.code="ECONNREFUSED":p.message.includes("ENOTFOUND")&&(f.code="ENOTFOUND")),await this.runErrorInterceptors(f),f}let w=await this.parseBody(h),y=this.extractHeaders(h);if(!h.ok){let p=new k(`Request failed with status code ${h.status}`);throw p.response={status:h.status,statusText:h.statusText,data:w,headers:y},p.config={url:c.url,method:c.method,headers:c.headers,timeout:c.timeout},await this.runErrorInterceptors(p),p}let C={data:w,status:h.status,statusText:h.statusText,headers:y};for(let p of this.responseSuccessInterceptors)C=await p(C);return C}}});import{config as Ot}from"dotenv";function $t(){switch(process.platform){case"darwin":return"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36";case"win32":return"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36";case"linux":default:return"Mozilla/5.0 (X11; CrOS x86_64 10066.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"}}var m,E=g(()=>{"use strict";Ot();m={nlobby:{baseUrl:process.env.NLOBBY_BASE_URL||"https://nlobby.nnn.ed.jp"},mcp:{serverName:process.env.MCP_SERVER_NAME||"nlobby-cli",serverVersion:process.env.MCP_SERVER_VERSION||"1.3.0"},userAgent:process.env.USER_AGENT||$t()}});var M,ue=g(()=>{"use strict";b();M=class{cookies={};constructor(){}parseCookies(e){let t={},n=e.split(";");for(let r of n){let[i,a]=r.trim().split("=");i&&a&&(i==="__Secure-next-auth.session-token"?t.sessionToken=decodeURIComponent(a):i==="__Host-next-auth.csrf-token"?t.csrfToken=decodeURIComponent(a):i==="__Secure-next-auth.callback-url"&&(t.callbackUrl=decodeURIComponent(a)))}return t}setCookies(e){this.cookies=this.parseCookies(e),o.debug("NextAuth cookies parsed:",{hasSessionToken:!!this.cookies.sessionToken,hasCsrfToken:!!this.cookies.csrfToken,hasCallbackUrl:!!this.cookies.callbackUrl})}getCookies(){return this.cookies}getCookieHeader(){let e=[];return this.cookies.sessionToken&&e.push(`__Secure-next-auth.session-token=${encodeURIComponent(this.cookies.sessionToken)}`),this.cookies.csrfToken&&e.push(`__Host-next-auth.csrf-token=${encodeURIComponent(this.cookies.csrfToken)}`),this.cookies.callbackUrl&&e.push(`__Secure-next-auth.callback-url=${encodeURIComponent(this.cookies.callbackUrl)}`),e.join("; ")}isAuthenticated(){return!!this.cookies.sessionToken}getSessionToken(){return this.cookies.sessionToken||null}async decodeSessionToken(){if(!this.cookies.sessionToken)return null;try{return{token:this.cookies.sessionToken}}catch(e){return o.error("Error decoding session token:",e),null}}clear(){this.cookies={}}}});var H,de=g(()=>{"use strict";T();E();b();H=class{httpClient;nextAuth;requestId=1;allCookies="";constructor(e){this.nextAuth=e,this.httpClient=new A({baseURL:`${m.nlobby.baseUrl}/api/trpc`,timeout:15e3,headers:{"Content-Type":"application/json","User-Agent":m.userAgent,Accept:"application/json","Accept-Language":"ja,en-US;q=0.7,en;q=0.3","Accept-Encoding":"gzip, deflate, br",Connection:"keep-alive","Sec-Fetch-Dest":"empty","Sec-Fetch-Mode":"cors","Sec-Fetch-Site":"same-origin"},withCredentials:!0}),this.setupInterceptors()}setAllCookies(e){if(!e||e.trim()===""){o.warn("[WARNING] Empty cookies provided to tRPC client"),this.allCookies="";return}this.allCookies=e,o.info("[SUCCESS] tRPC client cookies updated"),o.info(`[SIZE] tRPC cookie string length: ${e.length}`),this.allCookies===e?o.info("[SUCCESS] tRPC cookie verification successful"):o.error("[ERROR] tRPC cookie verification failed")}setupInterceptors(){this.httpClient.interceptors.request.use(e=>{let t;if(this.allCookies&&this.allCookies.trim()!=="")t=this.allCookies,o.debug("[COOKIE] Using all cookies for tRPC request");else{let i=this.nextAuth.getCookieHeader();i&&i.trim()!==""?(t=i,o.debug("[COOKIE] Using NextAuth cookies for tRPC request")):o.warn("[WARNING] No cookies available for tRPC request")}t&&(e.headers.Cookie=t);let n=this.nextAuth.getSessionToken();n?(e.headers.Authorization=`Bearer ${n}`,o.debug("Added Authorization header with session token")):o.warn("[WARNING] No session token available for Authorization header");let r=this.nextAuth.getCookies().csrfToken;return r&&(e.headers["X-CSRF-Token"]=r,o.debug("Added CSRF token to tRPC request")),o.debug("[REQUEST] tRPC request details:",{url:e.url,method:e.method?.toUpperCase(),hasCookies:!!t,hasCSRF:!!r,hasAuth:!!n,cookieSource:this.allCookies?"allCookies":"nextAuth"}),e}),this.httpClient.interceptors.response.use(e=>(o.debug("[SUCCESS] tRPC response received:",{status:e.status,statusText:e.statusText,hasData:!!e.data}),e),async e=>{let t=e instanceof k?e:null;if(o.error("[ERROR] tRPC request failed:",{status:t?.response?.status,statusText:t?.response?.statusText,message:e instanceof Error?e.message:"Unknown error",url:t?.config?.url}),t?.response?.status===401)throw o.error("[BLOCKED] Authentication failed - NextAuth session may be expired"),new Error("Authentication expired. Please re-authenticate with NextAuth cookies.");if(t?.response?.status===403)throw o.error("[BLOCKED] Access forbidden - insufficient permissions"),new Error("Access forbidden. Check your permissions or re-authenticate.");if(t?.response?.status===404)throw o.error("[BLOCKED] tRPC endpoint not found"),new Error("tRPC endpoint not found. The API may have changed.");return Promise.reject(e)})}getNextRequestId(){return this.requestId++}async call(e,t){let n={id:this.getNextRequestId(),method:e,params:t};try{o.info(`[REQUEST] tRPC call: ${e}`,t?`with params: ${JSON.stringify(t)}`:"without params");let r=this.allCookies||this.nextAuth.getCookieHeader();o.debug(`[COOKIE] Request cookies: ${r?"present":"missing"}`),o.debug("Trying GET approach...");try{let i=this.buildTRPCUrl(e,t);o.debug(`[URL] tRPC GET URL: ${i}`);let a=await this.httpClient.get(i);if(o.debug(`[SUCCESS] tRPC ${e} GET response status: ${a.status}`),a.data.error)throw o.error(`[ERROR] tRPC ${e} GET returned error:`,a.data.error),new Error(`tRPC Error [${a.data.error.code}]: ${a.data.error.message}`);return o.debug(`[SUCCESS] tRPC ${e} GET succeeded`),a.data.result}catch(i){o.debug("[WARNING] GET approach failed, trying POST approach..."),o.debug("[DEBUG] GET error details:",i instanceof Error?i.message:"Unknown error");let a=e;o.debug(`[URL] tRPC POST URL: ${a}`);let c=await this.httpClient.post(a,n,{headers:{"Content-Type":"application/json"}});if(o.debug(`[SUCCESS] tRPC ${e} POST response status: ${c.status}`),c.data.error)throw o.error(`[ERROR] tRPC ${e} POST returned error:`,c.data.error),new Error(`tRPC Error [${c.data.error.code}]: ${c.data.error.message}`);return o.debug(`[SUCCESS] tRPC ${e} POST succeeded`),c.data.result}}catch(r){throw o.error(`[ERROR] tRPC call failed for ${e}:`,{message:r instanceof Error?r.message:"Unknown error",stack:r instanceof Error?r.stack:void 0}),r instanceof k&&(o.error(`[DEBUG] tRPC ${e} fetch error details:`,{status:r.response?.status,statusText:r.response?.statusText,headers:r.response?.headers,data:r.response?.data,url:r.config?.url,method:r.config?.method,timeout:r.config?.timeout,cookies:r.config?.headers?.Cookie?"present":"missing"}),r.response?.status===401?o.error("[BLOCKED] tRPC 401 Unauthorized - session may be expired or invalid"):r.response?.status===403?o.error("[BLOCKED] tRPC 403 Forbidden - insufficient permissions"):r.response?.status===404?o.error("[BLOCKED] tRPC 404 Not Found - endpoint may not exist"):r.response?.status&&r.response.status>=500&&o.error("[BLOCKED] tRPC Server Error - N Lobby backend issue"),r.code==="ECONNREFUSED"?o.error("[NETWORK] Network Error: Connection refused - N Lobby may be down"):r.code==="ETIMEDOUT"?o.error("[TIMEOUT] Network Error: Request timeout - slow network or server overload"):r.code==="ENOTFOUND"&&o.error("[NETWORK] Network Error: DNS lookup failed - check internet connection")),r}}buildTRPCUrl(e,t){let n=e,r=JSON.stringify(t||{}),i=new URLSearchParams({input:r}).toString();return`${n}?${i}`}async getUnreadNewsCount(){return this.call("news.getUnreadNewsCount")}async getNotificationMessages(){return this.call("notification.getMessages")}async updateLastAccess(){return this.call("user.updateLastAccess")}async findMainNavigations(){return this.call("menu.findMainNavigations",{})}async readInterestsWithIcon(){return this.call("interest.readInterestsWithIcon")}async readInterests(){return this.call("interest.readInterests")}async readWeights(){return this.call("interest.readWeights")}async getLobbyCalendarEvents(e,t){return this.call("calendar.getLobbyCalendarEvents",{from:e,to:t})}async healthCheck(){o.info("Running tRPC health check...");let e=[{name:"updateLastAccess",method:()=>this.updateLastAccess()},{name:"getUnreadNewsCount",method:()=>this.getUnreadNewsCount()},{name:"findMainNavigations",method:()=>this.findMainNavigations()}];for(let{name:t,method:n}of e)try{return o.debug(`Trying tRPC method: ${t}`),await n(),o.info(`[SUCCESS] tRPC health check passed with method: ${t}`),!0}catch(r){o.debug(`[ERROR] tRPC method ${t} failed:`,r instanceof Error?r.message:"Unknown error");continue}return o.error("[ERROR] All tRPC health check methods failed"),!1}}});async function U(s,e){try{o.info("[NETWORK] Fetching HTML using HTTP client (proven method)..."),o.debug(`[URL] URL: ${m.nlobby.baseUrl+e}`),o.info("[COOKIE] Cookies:",s.httpClient.defaults.headers.Cookie?"present":"missing");let t=await s.httpClient.get(e,{headers:{Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","Accept-Language":"ja,en-US;q=0.7,en;q=0.3","Accept-Encoding":"gzip, deflate, br",Connection:"keep-alive","Upgrade-Insecure-Requests":"1","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"none","Cache-Control":"max-age=0","User-Agent":m.userAgent},withCredentials:!0});if(o.info(`[SUCCESS] HTTP response: ${t.status} ${t.statusText}`),o.info(`[DATA] Content length: ${typeof t.data=="string"?t.data.length:"unknown"}`),o.info(`[DATA] Content type: ${t.headers["content-type"]||"unknown"}`),typeof t.data=="string"){let n=t.data,r=n.toLowerCase();if(r.includes("\u30ED\u30B0\u30A4\u30F3")||r.includes("login")?o.warn("[WARNING] WARNING: Page contains login keywords - authentication may have failed"):(r.includes("news")||r.includes("\u304A\u77E5\u3089\u305B"))&&o.info("[SUCCESS] Page appears to contain news content"),r.includes("unauthorized")||r.includes("access denied"))throw new Error("Access denied - authentication failed");return o.info(`[TARGET] HTML retrieved successfully: ${n.length} characters`),n}else throw new Error(`Non-string response received: ${typeof t.data}`)}catch(t){throw o.error("[ERROR] HTTP fetch error:",t instanceof Error?t.message:"Unknown error"),t instanceof k&&o.debug("[DEBUG] HTTP Error Details:",{status:t.response?.status,statusText:t.response?.statusText,url:t.config?.url,hasData:!!t.response?.data}),t}}var X=g(()=>{"use strict";E();b();T()});import*as pe from"cheerio";function _t(s){if(!s)return"";try{return s.replace(/\\u003c/g,"<").replace(/\\u003e/g,">").replace(/\\u0026/g,"&").replace(/\\"/g,'"').replace(/\\\\/g,"\\")}catch{return s}}function ge(s,e=""){if(!s||typeof s!="object")return null;let t=s;if(t.id&&t.title&&(t.publishedAt||t.description||t.menuName))return o.info(`[INFO] Found news object at path: ${e}`),s;if(t.news&&typeof t.news=="object")return o.info(`[INFO] Found news property at path: ${e}.news`),t.news;for(let[n,r]of Object.entries(t))if(r&&typeof r=="object"){let i=e?`${e}.${n}`:n,a=ge(r,i);if(a)return a}return null}function q(s,e=""){if(!s||typeof s!="object")return[];if(Array.isArray(s)){if(s.length>0){let n=s[0];if(n&&typeof n=="object"&&["title","name","content","publishedAt","menuName","createdAt","updatedAt","id"].some(a=>a in n))return o.info(`[INFO] Found potential news array at path: ${e}, length: ${s.length}`),s}return[]}let t=[];for(let[n,r]of Object.entries(s)){let i=["news","announcements","data","items","list","content","notifications","posts","feed","results"],a=e?`${e}.${n}`:n;i.includes(n.toLowerCase())&&o.info(`[INFO] Searching priority key: ${a}`);let c=q(r,a);t.push(...c)}return t}function G(s){return s.map((e,t)=>{let n=e,r=new Date;n.publishedAt?r=new Date(n.publishedAt):n.createdAt?r=new Date(n.createdAt):n.updatedAt?r=new Date(n.updatedAt):n.date&&(r=new Date(n.date));let i=n.title||n.name||n.subject||n.heading||`News Item ${t+1}`,a=n.content||n.description||n.body||n.text||n.summary||"",c=n.category||n.menuName||n.type||n.classification||"General",l="medium";n.isImportant===!0||n.important===!0||n.priority==="high"||n.urgent===!0?l="high":(n.priority==="low"||n.minor===!0)&&(l="low");let u=n.id||t,d=`${m.nlobby.baseUrl}/news/${u}`;return{id:n.id?.toString()||t.toString(),title:i,content:a,publishedAt:r,category:c,priority:l,targetAudience:n.targetAudience||["student"],url:d,menuName:n.menuName,isImportant:!!n.isImportant,isUnread:!!n.isUnread,...Object.fromEntries(Object.entries(n).filter(([w])=>!["id","title","content","publishedAt","category","priority","url"].includes(w)))}})}function Ft(s){try{o.info("[TARGET] Starting Cheerio-based DOM parsing...");let e=pe.load(s),t=e('div[role="presentation"]');if(o.info(`[INFO] Found ${t.length} div[role="presentation"] elements`),t.length<2)return o.info('[WARNING] Less than 2 div[role="presentation"] elements found'),[];let n=e(t[1]);o.info('[SUCCESS] Located second div[role="presentation"] element');let r=n.find('div[role="row"]');o.info(`[INFO] Found ${r.length} DataGrid rows`);let i=[];return r.each((a,c)=>{try{let l=e(c),u=l.attr("data-id");if(!u)return;let d=l.find('div[role="gridcell"]'),h="",w="",y=new Date,S=!1,C=!1,p="";if(d.each((f,L)=>{let R=e(L);switch(R.attr("data-field")){case"title":{let N=R.find("a");if(N.length>0){let x=N.attr("href");x&&x.startsWith("/news/")?p=`${m.nlobby.baseUrl}${x}`:p=`${m.nlobby.baseUrl}/news/${u}`;let le=N.find("span");h=le.length>0?le.text().trim():N.text().trim()}else h=R.text().trim(),p=`${m.nlobby.baseUrl}/news/${u}`;break}case"menuName":w=R.text().trim();break;case"isImportant":{S=R.text().trim().length>0||R.find("*").length>0;break}case"isUnread":{let N=R.text().trim();C=N.includes("\u672A\u8AAD")||N.length>0;break}case"publishedAt":{let N=R.text().trim();if(N){let x=new Date(N.replace(/\//g,"-"));isNaN(x.getTime())||(y=x)}break}}}),h){let f=p||`${m.nlobby.baseUrl}/news/${u}`,L={id:u,title:h,content:"",publishedAt:y,category:w||"General",priority:S?"high":"medium",targetAudience:["student"],url:f,menuName:w,isImportant:S,isUnread:C};i.push(L)}}catch(l){o.error(`[ERROR] Error parsing row ${a}:`,l instanceof Error?l.message:"Unknown error")}}),o.info(`[TARGET] Cheerio parsing completed: ${i.length} news items extracted`),i}catch(e){return o.error("[ERROR] Cheerio parsing failed:",e instanceof Error?e.message:"Unknown error"),[]}}function jt(s){let e=[];try{o.info("[INFO] Starting HTML parsing...");let t=s.match(/self\.__next_f\.push\((\[.*?\])\)/g);if(t&&t.length>0){o.info(`[SUCCESS] Found ${t.length} self.__next_f.push() calls`);for(let i=0;i<t.length;i++){let a=t[i];try{let c=a.match(/self\.__next_f\.push\((\[.*?\])\)/);if(!c)continue;let l=JSON.parse(c[1]);if(l.length>=2&&typeof l[1]=="string"){let d=l[1],h=d.match(/^(\d+):(.*)/);if(h)try{let w=h[2],y=JSON.parse(w);if(Array.isArray(y))for(let S=0;S<y.length;S++){let C=y[S];if(Array.isArray(C)&&C.length>=4&&C[3]&&typeof C[3]=="object"){let p=C[3];if(p.news&&Array.isArray(p.news)&&p.news.length>0){let f=p.news[0];if(f&&typeof f=="object"&&(f.id||f.title||f.microCmsId))return G(p.news)}}}}catch{}else try{let w=JSON.parse(d),y=q(w,`push_call_${i+1}_fallback`);if(y&&y.length>0)return G(y)}catch{}}let u=q(l,`push_call_${i+1}_direct`);if(u&&u.length>0)return G(u)}catch{}}}let n=Ft(s);if(n&&n.length>0)return n;let r=[s.match(/window\.__NEXT_DATA__\s*=\s*({.*?})\s*(?:;|<\/script>)/s),s.match(/<script id="__NEXT_DATA__"[^>]*>([^<]*)<\/script>/s)];for(let i of r)if(i)try{let a=i[1]||i[0],c=JSON.parse(a),l=q(c,"__NEXT_DATA__");if(l&&l.length>0)return G(l)}catch{}}catch(t){o.error("[ERROR] Error parsing news from HTML:",t)}return e}function Mt(s,e){try{let t=s.match(/self\.__next_f\.push\((\[.*?\])\)/g);if(!t||t.length===0)return null;let n=null,r="",i=new Map;for(let c=0;c<t.length;c++){let l=t[c];try{let u=l.match(/self\.__next_f\.push\((\[.*?\])\)/);if(!u)continue;let d=JSON.parse(u[1]);if(d.length>=2&&typeof d[1]=="string"&&d[1].match(/^\d+:T\d+,?$/)){let h=d[1].replace(/,$/,"");if(c+1<t.length){let y=t[c+1].match(/self\.__next_f\.push\((\[.*?\])\)/);if(y){let S=JSON.parse(y[1]);S.length>=2&&typeof S[1]=="string"&&i.set(h,S[1])}}continue}if(d.length>=2&&typeof d[1]=="string"){let w=d[1].match(/^(\d+):(.*)/);if(w)try{let y=w[2],S=JSON.parse(y),C=ge(S);C&&(n=C)}catch{}}}catch{}}if(!n)return null;if(n.description){for(let[c,l]of i)if(n.description.includes(c)){r=l;break}}return!r&&i.size>0&&(r=Array.from(i.values())[0]),{id:n.id||e,microCmsId:n.microCmsId,title:n.title||"No Title",content:_t(r)||n.description||"",description:n.description,publishedAt:n.publishedAt?new Date(n.publishedAt):new Date,menuName:n.menuName||[],isImportant:n.isImportant||!1,isByMentor:n.isByMentor||!1,attachments:n.attachments||[],relatedEvents:n.relatedEvents||[],targetUserQueryId:n.targetUserQueryId,url:`${m.nlobby.baseUrl}/news/${e}`}}catch(t){return o.error("[ERROR] Error parsing news detail from HTML:",t),null}}async function me(s){o.info("[INFO] Starting getNews with HTTP client..."),o.info("[STATUS] Current authentication status:",s.getCookieStatus());try{let e=await U(s,"/news"),t=jt(e);if(t&&t.length>0)return o.info(`[SUCCESS] Retrieved ${t.length} news items from HTML`),t;{let n=`HTML scraping returned no data. Debug info:
|
|
3
|
-
- Authentication status: ${s.nextAuth.isAuthenticated()?"authenticated":"not authenticated"}
|
|
4
|
-
-
|
|
2
|
+
var Ft=Object.defineProperty;var g=(o,e)=>()=>(o&&(e=o(o=0)),e);var j=(o,e)=>{for(var t in e)Ft(o,t,{get:e[t],enumerable:!0})};import jt from"node-fetch";var C,A,T=g(()=>{"use strict";C=class extends Error{response;config;code;constructor(e){super(e),this.name="HttpClientError"}},A=class{defaults;baseURL;requestInterceptors=[];responseSuccessInterceptors=[];responseErrorInterceptors=[];interceptors={request:{use:e=>{this.requestInterceptors.push(e)}},response:{use:(e,t)=>{this.responseSuccessInterceptors.push(e),t&&this.responseErrorInterceptors.push(t)}}};constructor(e){this.baseURL=e.baseURL??"",this.defaults={headers:{...e.headers??{}},timeout:e.timeout??3e4,baseURL:this.baseURL}}async get(e,t){return this.request("GET",e,void 0,t)}async post(e,t,n){return this.request("POST",e,t,n)}async parseBody(e){if((e.headers.get("content-type")??"").includes("application/json"))try{return await e.json()}catch{return await e.text()}return await e.text()}extractHeaders(e){let t={};return e.headers.forEach((n,r)=>{t[r]=n}),t}async runErrorInterceptors(e){for(let t of this.responseErrorInterceptors)await t(e)}async request(e,t,n,r){let s=t.startsWith("http")?t:`${this.baseURL}${t}`;if(r?.params&&Object.keys(r.params).length>0){let p={};for(let[O,N]of Object.entries(r.params))N!==void 0&&(p[O]=N);let f=new URLSearchParams(p).toString();s+=(s.includes("?")?"&":"?")+f}let a={...this.defaults.headers,...r?.headers??{}},c={url:s,method:e,headers:a,timeout:r?.timeout??this.defaults.timeout};for(let p of this.requestInterceptors)c=await p(c);let l={};for(let[p,f]of Object.entries(c.headers))f!==void 0&&(l[p]=f);let u=new AbortController,d=setTimeout(()=>u.abort(),c.timeout),h;try{let p={method:c.method,headers:l,signal:u.signal};n!==void 0&&(p.body=typeof n=="string"?n:JSON.stringify(n)),h=await jt(c.url,p),clearTimeout(d)}catch(p){clearTimeout(d);let f=new C(p instanceof Error?p.message:"Network error");throw f.config={url:c.url,method:c.method,headers:c.headers,timeout:c.timeout},p instanceof Error&&(p.name==="AbortError"?(f.code="ETIMEDOUT",f.message=`timeout of ${c.timeout}ms exceeded`):p.message.includes("ECONNREFUSED")?f.code="ECONNREFUSED":p.message.includes("ENOTFOUND")&&(f.code="ENOTFOUND")),await this.runErrorInterceptors(f),f}let w=await this.parseBody(h),y=this.extractHeaders(h);if(!h.ok){let p=new C(`Request failed with status code ${h.status}`);throw p.response={status:h.status,statusText:h.statusText,data:w,headers:y},p.config={url:c.url,method:c.method,headers:c.headers,timeout:c.timeout},await this.runErrorInterceptors(p),p}let b={data:w,status:h.status,statusText:h.statusText,headers:y};for(let p of this.responseSuccessInterceptors)b=await p(b);return b}}});import{config as Mt}from"dotenv";function Ht(){switch(process.platform){case"darwin":return"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36";case"win32":return"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36";case"linux":default:return"Mozilla/5.0 (X11; CrOS x86_64 10066.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"}}var m,E=g(()=>{"use strict";Mt();m={nlobby:{baseUrl:process.env.NLOBBY_BASE_URL||"https://nlobby.nnn.ed.jp"},mcp:{serverName:process.env.MCP_SERVER_NAME||"nlobby-cli",serverVersion:process.env.MCP_SERVER_VERSION||"1.3.0"},userAgent:process.env.USER_AGENT||Ht()}});var de={};j(de,{LogLevel:()=>K,Logger:()=>M,logger:()=>i});var K,M,i,S=g(()=>{"use strict";K=(r=>(r[r.DEBUG=0]="DEBUG",r[r.INFO=1]="INFO",r[r.WARN=2]="WARN",r[r.ERROR=3]="ERROR",r))(K||{}),M=class o{static instance;logLevel;constructor(){let e=process.env.NLOBBY_DEBUG==="true"||process.env.DEBUG==="true";this.logLevel=e?0:2}static getInstance(){return o.instance||(o.instance=new o),o.instance}setLogLevel(e){this.logLevel=e}forceProductionMode(){}log(e,t,...n){if(e<this.logLevel)return;let r=new Date().toISOString(),s=K[e],a=n.length>0?`[${r}] [${s}] ${t} ${n.map(c=>typeof c=="object"?JSON.stringify(c):String(c)).join(" ")}`:`[${r}] [${s}] ${t}`;process.stderr.write(a+`
|
|
3
|
+
`)}debug(e,...t){this.log(0,e,...t)}info(e,...t){this.log(1,e,...t)}warn(e,...t){this.log(2,e,...t)}error(e,...t){this.log(3,e,...t)}},i=M.getInstance()});var H,pe=g(()=>{"use strict";S();H=class{cookies={};constructor(){}parseCookies(e){let t={},n=e.split(";");for(let r of n){let[s,a]=r.trim().split("=");s&&a&&(s==="__Secure-next-auth.session-token"?t.sessionToken=decodeURIComponent(a):s==="__Host-next-auth.csrf-token"?t.csrfToken=decodeURIComponent(a):s==="__Secure-next-auth.callback-url"&&(t.callbackUrl=decodeURIComponent(a)))}return t}setCookies(e){this.cookies=this.parseCookies(e),i.debug("NextAuth cookies parsed:",{hasSessionToken:!!this.cookies.sessionToken,hasCsrfToken:!!this.cookies.csrfToken,hasCallbackUrl:!!this.cookies.callbackUrl})}getCookies(){return this.cookies}getCookieHeader(){let e=[];return this.cookies.sessionToken&&e.push(`__Secure-next-auth.session-token=${encodeURIComponent(this.cookies.sessionToken)}`),this.cookies.csrfToken&&e.push(`__Host-next-auth.csrf-token=${encodeURIComponent(this.cookies.csrfToken)}`),this.cookies.callbackUrl&&e.push(`__Secure-next-auth.callback-url=${encodeURIComponent(this.cookies.callbackUrl)}`),e.join("; ")}isAuthenticated(){return!!this.cookies.sessionToken}getSessionToken(){return this.cookies.sessionToken||null}async decodeSessionToken(){if(!this.cookies.sessionToken)return null;try{return{token:this.cookies.sessionToken}}catch(e){return i.error("Error decoding session token:",e),null}}clear(){this.cookies={}}}});var G,ge=g(()=>{"use strict";T();E();S();G=class{httpClient;nextAuth;requestId=1;allCookies="";constructor(e){this.nextAuth=e,this.httpClient=new A({baseURL:`${m.nlobby.baseUrl}/api/trpc`,timeout:15e3,headers:{"Content-Type":"application/json","User-Agent":m.userAgent,Accept:"application/json","Accept-Language":"ja,en-US;q=0.7,en;q=0.3","Accept-Encoding":"gzip, deflate, br",Connection:"keep-alive","Sec-Fetch-Dest":"empty","Sec-Fetch-Mode":"cors","Sec-Fetch-Site":"same-origin"},withCredentials:!0}),this.setupInterceptors()}setAllCookies(e){if(!e||e.trim()===""){i.warn("[WARNING] Empty cookies provided to tRPC client"),this.allCookies="";return}this.allCookies=e,i.info("[SUCCESS] tRPC client cookies updated"),i.info(`[SIZE] tRPC cookie string length: ${e.length}`),this.allCookies===e?i.info("[SUCCESS] tRPC cookie verification successful"):i.error("[ERROR] tRPC cookie verification failed")}setupInterceptors(){this.httpClient.interceptors.request.use(e=>{let t;if(this.allCookies&&this.allCookies.trim()!=="")t=this.allCookies,i.debug("[COOKIE] Using all cookies for tRPC request");else{let s=this.nextAuth.getCookieHeader();s&&s.trim()!==""?(t=s,i.debug("[COOKIE] Using NextAuth cookies for tRPC request")):i.warn("[WARNING] No cookies available for tRPC request")}t&&(e.headers.Cookie=t);let n=this.nextAuth.getSessionToken();n?(e.headers.Authorization=`Bearer ${n}`,i.debug("Added Authorization header with session token")):i.warn("[WARNING] No session token available for Authorization header");let r=this.nextAuth.getCookies().csrfToken;return r&&(e.headers["X-CSRF-Token"]=r,i.debug("Added CSRF token to tRPC request")),i.debug("[REQUEST] tRPC request details:",{url:e.url,method:e.method?.toUpperCase(),hasCookies:!!t,hasCSRF:!!r,hasAuth:!!n,cookieSource:this.allCookies?"allCookies":"nextAuth"}),e}),this.httpClient.interceptors.response.use(e=>(i.debug("[SUCCESS] tRPC response received:",{status:e.status,statusText:e.statusText,hasData:!!e.data}),e),async e=>{let t=e instanceof C?e:null;if(i.error("[ERROR] tRPC request failed:",{status:t?.response?.status,statusText:t?.response?.statusText,message:e instanceof Error?e.message:"Unknown error",url:t?.config?.url}),t?.response?.status===401)throw i.error("[BLOCKED] Authentication failed - NextAuth session may be expired"),new Error("Authentication expired. Please re-authenticate with NextAuth cookies.");if(t?.response?.status===403)throw i.error("[BLOCKED] Access forbidden - insufficient permissions"),new Error("Access forbidden. Check your permissions or re-authenticate.");if(t?.response?.status===404)throw i.error("[BLOCKED] tRPC endpoint not found"),new Error("tRPC endpoint not found. The API may have changed.");return Promise.reject(e)})}getNextRequestId(){return this.requestId++}async call(e,t){let n={id:this.getNextRequestId(),method:e,params:t};try{i.info(`[REQUEST] tRPC call: ${e}`,t?`with params: ${JSON.stringify(t)}`:"without params");let r=this.allCookies||this.nextAuth.getCookieHeader();i.debug(`[COOKIE] Request cookies: ${r?"present":"missing"}`),i.debug("Trying GET approach...");try{let s=this.buildTRPCUrl(e,t);i.debug(`[URL] tRPC GET URL: ${s}`);let a=await this.httpClient.get(s);if(i.debug(`[SUCCESS] tRPC ${e} GET response status: ${a.status}`),a.data.error)throw i.error(`[ERROR] tRPC ${e} GET returned error:`,a.data.error),new Error(`tRPC Error [${a.data.error.code}]: ${a.data.error.message}`);return i.debug(`[SUCCESS] tRPC ${e} GET succeeded`),a.data.result}catch(s){i.debug("[WARNING] GET approach failed, trying POST approach..."),i.debug("[DEBUG] GET error details:",s instanceof Error?s.message:"Unknown error");let a=e;i.debug(`[URL] tRPC POST URL: ${a}`);let c=await this.httpClient.post(a,n,{headers:{"Content-Type":"application/json"}});if(i.debug(`[SUCCESS] tRPC ${e} POST response status: ${c.status}`),c.data.error)throw i.error(`[ERROR] tRPC ${e} POST returned error:`,c.data.error),new Error(`tRPC Error [${c.data.error.code}]: ${c.data.error.message}`);return i.debug(`[SUCCESS] tRPC ${e} POST succeeded`),c.data.result}}catch(r){throw i.error(`[ERROR] tRPC call failed for ${e}:`,{message:r instanceof Error?r.message:"Unknown error",stack:r instanceof Error?r.stack:void 0}),r instanceof C&&(i.error(`[DEBUG] tRPC ${e} fetch error details:`,{status:r.response?.status,statusText:r.response?.statusText,headers:r.response?.headers,data:r.response?.data,url:r.config?.url,method:r.config?.method,timeout:r.config?.timeout,cookies:r.config?.headers?.Cookie?"present":"missing"}),r.response?.status===401?i.error("[BLOCKED] tRPC 401 Unauthorized - session may be expired or invalid"):r.response?.status===403?i.error("[BLOCKED] tRPC 403 Forbidden - insufficient permissions"):r.response?.status===404?i.error("[BLOCKED] tRPC 404 Not Found - endpoint may not exist"):r.response?.status&&r.response.status>=500&&i.error("[BLOCKED] tRPC Server Error - N Lobby backend issue"),r.code==="ECONNREFUSED"?i.error("[NETWORK] Network Error: Connection refused - N Lobby may be down"):r.code==="ETIMEDOUT"?i.error("[TIMEOUT] Network Error: Request timeout - slow network or server overload"):r.code==="ENOTFOUND"&&i.error("[NETWORK] Network Error: DNS lookup failed - check internet connection")),r}}buildTRPCUrl(e,t){let n=e,r=JSON.stringify(t||{}),s=new URLSearchParams({input:r}).toString();return`/${n}?${s}`}async getUnreadNewsCount(){return this.call("news.getUnreadNewsCount")}async getNotificationMessages(){return this.call("notification.getMessages")}async updateLastAccess(){return this.call("user.updateLastAccess")}async findMainNavigations(){return this.call("menu.findMainNavigations",{})}async readInterestsWithIcon(){return this.call("interest.readInterestsWithIcon")}async readInterests(){return this.call("interest.readInterests")}async readWeights(){return this.call("interest.readWeights")}async getLobbyCalendarEvents(e,t){return this.call("calendar.getLobbyCalendarEvents",{from:e,to:t})}async healthCheck(){i.info("Running tRPC health check...");let e=[{name:"updateLastAccess",method:()=>this.updateLastAccess()},{name:"getUnreadNewsCount",method:()=>this.getUnreadNewsCount()},{name:"findMainNavigations",method:()=>this.findMainNavigations()}];for(let{name:t,method:n}of e)try{return i.debug(`Trying tRPC method: ${t}`),await n(),i.info(`[SUCCESS] tRPC health check passed with method: ${t}`),!0}catch(r){i.debug(`[ERROR] tRPC method ${t} failed:`,r instanceof Error?r.message:"Unknown error");continue}return i.error("[ERROR] All tRPC health check methods failed"),!1}}});async function $(o,e){try{i.info("[NETWORK] Fetching HTML using HTTP client (proven method)..."),i.debug(`[URL] URL: ${m.nlobby.baseUrl+e}`),i.info("[COOKIE] Cookies:",o.httpClient.defaults.headers.Cookie?"present":"missing");let t=await o.httpClient.get(e,{headers:{Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","Accept-Language":"ja,en-US;q=0.7,en;q=0.3","Accept-Encoding":"gzip, deflate, br",Connection:"keep-alive","Upgrade-Insecure-Requests":"1","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"none","Cache-Control":"max-age=0","User-Agent":m.userAgent},withCredentials:!0});if(i.info(`[SUCCESS] HTTP response: ${t.status} ${t.statusText}`),i.info(`[DATA] Content length: ${typeof t.data=="string"?t.data.length:"unknown"}`),i.info(`[DATA] Content type: ${t.headers["content-type"]||"unknown"}`),typeof t.data=="string"){let n=t.data,r=n.toLowerCase();if(r.includes("\u30ED\u30B0\u30A4\u30F3")||r.includes("login")?i.warn("[WARNING] WARNING: Page contains login keywords - authentication may have failed"):(r.includes("news")||r.includes("\u304A\u77E5\u3089\u305B"))&&i.info("[SUCCESS] Page appears to contain news content"),r.includes("unauthorized")||r.includes("access denied"))throw new Error("Access denied - authentication failed");return i.info(`[TARGET] HTML retrieved successfully: ${n.length} characters`),n}else throw new Error(`Non-string response received: ${typeof t.data}`)}catch(t){throw i.error("[ERROR] HTTP fetch error:",t instanceof Error?t.message:"Unknown error"),t instanceof C&&i.debug("[DEBUG] HTTP Error Details:",{status:t.response?.status,statusText:t.response?.statusText,url:t.config?.url,hasData:!!t.response?.data}),t}}var V=g(()=>{"use strict";E();S();T()});import*as me from"cheerio";function Gt(o){if(!o)return"";try{return o.replace(/\\u003c/g,"<").replace(/\\u003e/g,">").replace(/\\u0026/g,"&").replace(/\\"/g,'"').replace(/\\\\/g,"\\")}catch{return o}}function he(o,e=""){if(!o||typeof o!="object")return null;let t=o;if(t.id&&t.title&&(t.publishedAt||t.description||t.menuName))return i.info(`[INFO] Found news object at path: ${e}`),o;if(t.news&&typeof t.news=="object")return i.info(`[INFO] Found news property at path: ${e}.news`),t.news;for(let[n,r]of Object.entries(t))if(r&&typeof r=="object"){let s=e?`${e}.${n}`:n,a=he(r,s);if(a)return a}return null}function J(o,e=""){if(!o||typeof o!="object")return[];if(Array.isArray(o)){if(o.length>0){let n=o[0];if(n&&typeof n=="object"&&["title","name","content","publishedAt","menuName","createdAt","updatedAt","id"].some(a=>a in n))return i.info(`[INFO] Found potential news array at path: ${e}, length: ${o.length}`),o}return[]}let t=[];for(let[n,r]of Object.entries(o)){let s=["news","announcements","data","items","list","content","notifications","posts","feed","results"],a=e?`${e}.${n}`:n;s.includes(n.toLowerCase())&&i.info(`[INFO] Searching priority key: ${a}`);let c=J(r,a);t.push(...c)}return t}function q(o){return o.map((e,t)=>{let n=e,r=new Date;n.publishedAt?r=new Date(n.publishedAt):n.createdAt?r=new Date(n.createdAt):n.updatedAt?r=new Date(n.updatedAt):n.date&&(r=new Date(n.date));let s=n.title||n.name||n.subject||n.heading||`News Item ${t+1}`,a=n.content||n.description||n.body||n.text||n.summary||"",c=n.category||n.menuName||n.type||n.classification||"General",l="medium";n.isImportant===!0||n.important===!0||n.priority==="high"||n.urgent===!0?l="high":(n.priority==="low"||n.minor===!0)&&(l="low");let u=n.id||t,d=`${m.nlobby.baseUrl}/news/${u}`;return{id:n.id?.toString()||t.toString(),title:s,content:a,publishedAt:r,category:c,priority:l,targetAudience:n.targetAudience||["student"],url:d,menuName:n.menuName,isImportant:!!n.isImportant,isUnread:!!n.isUnread,...Object.fromEntries(Object.entries(n).filter(([w])=>!["id","title","content","publishedAt","category","priority","url"].includes(w)))}})}function qt(o){try{i.info("[TARGET] Starting Cheerio-based DOM parsing...");let e=me.load(o),t=e('div[role="presentation"]');if(i.info(`[INFO] Found ${t.length} div[role="presentation"] elements`),t.length<2)return i.info('[WARNING] Less than 2 div[role="presentation"] elements found'),[];let n=e(t[1]);i.info('[SUCCESS] Located second div[role="presentation"] element');let r=n.find('div[role="row"]');i.info(`[INFO] Found ${r.length} DataGrid rows`);let s=[];return r.each((a,c)=>{try{let l=e(c),u=l.attr("data-id");if(!u)return;let d=l.find('div[role="gridcell"]'),h="",w="",y=new Date,k=!1,b=!1,p="";if(d.each((f,O)=>{let N=e(O);switch(N.attr("data-field")){case"title":{let R=N.find("a");if(R.length>0){let x=R.attr("href");x&&x.startsWith("/news/")?p=`${m.nlobby.baseUrl}${x}`:p=`${m.nlobby.baseUrl}/news/${u}`;let ue=R.find("span");h=ue.length>0?ue.text().trim():R.text().trim()}else h=N.text().trim(),p=`${m.nlobby.baseUrl}/news/${u}`;break}case"menuName":w=N.text().trim();break;case"isImportant":{k=N.text().trim().length>0||N.find("*").length>0;break}case"isUnread":{let R=N.text().trim();b=R.includes("\u672A\u8AAD")||R.length>0;break}case"publishedAt":{let R=N.text().trim();if(R){let x=new Date(R.replace(/\//g,"-"));isNaN(x.getTime())||(y=x)}break}}}),h){let f=p||`${m.nlobby.baseUrl}/news/${u}`,O={id:u,title:h,content:"",publishedAt:y,category:w||"General",priority:k?"high":"medium",targetAudience:["student"],url:f,menuName:w,isImportant:k,isUnread:b};s.push(O)}}catch(l){i.error(`[ERROR] Error parsing row ${a}:`,l instanceof Error?l.message:"Unknown error")}}),i.info(`[TARGET] Cheerio parsing completed: ${s.length} news items extracted`),s}catch(e){return i.error("[ERROR] Cheerio parsing failed:",e instanceof Error?e.message:"Unknown error"),[]}}function Jt(o){let e=[];try{i.info("[INFO] Starting HTML parsing...");let t=o.match(/self\.__next_f\.push\((\[.*?\])\)/g);if(t&&t.length>0){i.info(`[SUCCESS] Found ${t.length} self.__next_f.push() calls`);for(let s=0;s<t.length;s++){let a=t[s];try{let c=a.match(/self\.__next_f\.push\((\[.*?\])\)/);if(!c)continue;let l=JSON.parse(c[1]);if(l.length>=2&&typeof l[1]=="string"){let d=l[1],h=d.match(/^(\d+):(.*)/);if(h)try{let w=h[2],y=JSON.parse(w);if(Array.isArray(y))for(let k=0;k<y.length;k++){let b=y[k];if(Array.isArray(b)&&b.length>=4&&b[3]&&typeof b[3]=="object"){let p=b[3];if(p.news&&Array.isArray(p.news)&&p.news.length>0){let f=p.news[0];if(f&&typeof f=="object"&&(f.id||f.title||f.microCmsId))return q(p.news)}}}}catch{}else try{let w=JSON.parse(d),y=J(w,`push_call_${s+1}_fallback`);if(y&&y.length>0)return q(y)}catch{}}let u=J(l,`push_call_${s+1}_direct`);if(u&&u.length>0)return q(u)}catch{}}}let n=qt(o);if(n&&n.length>0)return n;let r=[o.match(/window\.__NEXT_DATA__\s*=\s*({.*?})\s*(?:;|<\/script>)/s),o.match(/<script id="__NEXT_DATA__"[^>]*>([^<]*)<\/script>/s)];for(let s of r)if(s)try{let a=s[1]||s[0],c=JSON.parse(a),l=J(c,"__NEXT_DATA__");if(l&&l.length>0)return q(l)}catch{}}catch(t){i.error("[ERROR] Error parsing news from HTML:",t)}return e}function Bt(o,e){try{let t=o.match(/self\.__next_f\.push\((\[.*?\])\)/g);if(!t||t.length===0)return null;let n=null,r="",s=new Map;for(let c=0;c<t.length;c++){let l=t[c];try{let u=l.match(/self\.__next_f\.push\((\[.*?\])\)/);if(!u)continue;let d=JSON.parse(u[1]);if(d.length>=2&&typeof d[1]=="string"&&d[1].match(/^\d+:T\d+,?$/)){let h=d[1].replace(/,$/,"");if(c+1<t.length){let y=t[c+1].match(/self\.__next_f\.push\((\[.*?\])\)/);if(y){let k=JSON.parse(y[1]);k.length>=2&&typeof k[1]=="string"&&s.set(h,k[1])}}continue}if(d.length>=2&&typeof d[1]=="string"){let w=d[1].match(/^(\d+):(.*)/);if(w)try{let y=w[2],k=JSON.parse(y),b=he(k);b&&(n=b)}catch{}}}catch{}}if(!n)return null;if(n.description){for(let[c,l]of s)if(n.description.includes(c)){r=l;break}}return!r&&s.size>0&&(r=Array.from(s.values())[0]),{id:n.id||e,microCmsId:n.microCmsId,title:n.title||"No Title",content:Gt(r)||n.description||"",description:n.description,publishedAt:n.publishedAt?new Date(n.publishedAt):new Date,menuName:n.menuName||[],isImportant:n.isImportant||!1,isByMentor:n.isByMentor||!1,attachments:n.attachments||[],relatedEvents:n.relatedEvents||[],targetUserQueryId:n.targetUserQueryId,url:`${m.nlobby.baseUrl}/news/${e}`}}catch(t){return i.error("[ERROR] Error parsing news detail from HTML:",t),null}}async function fe(o){i.info("[INFO] Starting getNews with HTTP client..."),i.info("[STATUS] Current authentication status:",o.getCookieStatus());try{let e=await $(o,"/news"),t=Jt(e);if(t&&t.length>0)return i.info(`[SUCCESS] Retrieved ${t.length} news items from HTML`),t;{let n=`HTML scraping returned no data. Debug info:
|
|
4
|
+
- Authentication status: ${o.nextAuth.isAuthenticated()?"authenticated":"not authenticated"}
|
|
5
|
+
- HTTP cookies: ${o.httpClient.defaults.headers.Cookie?"present":"missing"}
|
|
5
6
|
- HTML length: ${e.length} characters
|
|
6
7
|
|
|
7
8
|
Troubleshooting steps:
|
|
8
9
|
1. Run 'health_check' to verify connection
|
|
9
|
-
2. Ensure you are properly authenticated using 'set_cookies'`;throw new Error(n)}}catch(e){throw o.error("[ERROR] getNews failed:",e),e instanceof Error?e:new Error(`Failed to fetch news: ${e instanceof Error?e.message:"Unknown error"}`)}}async function he(s,e){o.info(`[INFO] Fetching news detail for ID: ${e}`);try{let t=`/news/${e}`,n=await U(s,t),r=Mt(n,e);if(r)return r;throw new Error(`Failed to parse news detail from HTML for news ID: ${e}`)}catch(t){throw o.error(`[ERROR] getNewsDetail failed for ID ${e}:`,t),t instanceof Error?t:new Error(`Failed to fetch news detail for ID ${e}: ${t instanceof Error?t.message:"Unknown error"}`)}}async function fe(s,e){o.info(`[INFO] Marking news article ${e} as read`);try{let t=await s.httpClient.post("/api/trpc/news.upsertBrowsingHistory",`"${e}"`,{headers:{"Content-Type":"application/json",Authorization:s.nextAuth.getCookieHeader(),Referer:`https://nlobby.nnn.ed.jp/news/${e}`}});return o.info(`[SUCCESS] News article ${e} marked as read`),t.data}catch(t){throw o.error(`[ERROR] Failed to mark news ${e} as read:`,t),t}}async function ye(s){o.info("[INFO] Fetching unread news info...");try{let e=await s.trpcClient.call("news.getUnreadNewsInfo");return o.info("[SUCCESS] getUnreadNewsInfo succeeded"),e}catch(e){throw o.error("[ERROR] getUnreadNewsInfo failed:",e),e}}var we=g(()=>{"use strict";X();E();b()});var W={};F(W,{CalendarType:()=>B});var B,v=g(()=>{"use strict";B=(t=>(t.PERSONAL="personal",t.SCHOOL="school",t))(B||{})});function Q(){let s=new Date,e=new Date(s);e.setHours(0,0,0,0);let t=new Date(s);return t.setDate(t.getDate()+7),t.setHours(23,59,59,999),{from:e,to:t}}function Ht(s){return s.map(e=>{let t=e,n,r;t.startDateTime?(n=new Date(t.startDateTime),r=t.endDateTime?new Date(t.endDateTime):new Date(n.getTime()+3600*1e3)):t.start?(t.start.dateTime?n=new Date(t.start.dateTime):t.start.date?n=new Date(t.start.date+"T00:00:00"):n=new Date,t.end&&t.end.dateTime?r=new Date(t.end.dateTime):t.end&&t.end.date?(r=new Date(t.end.date+"T23:59:59"),r.setDate(r.getDate()-1)):r=new Date(n.getTime()+3600*1e3)):(n=new Date,r=new Date(n.getTime()+3600*1e3));let i="event",a=(t.summary||"").toLowerCase();a.includes("\u6388\u696D")||a.includes("class")?i="class":a.includes("mtg")||a.includes("\u30DF\u30FC\u30C6\u30A3\u30F3\u30B0")||a.includes("meeting")||a.includes("\u9762\u8AC7")?i="meeting":(a.includes("\u8A66\u9A13")||a.includes("exam")||a.includes("\u30C6\u30B9\u30C8"))&&(i="exam");let c=[];return t.attendees&&Array.isArray(t.attendees)&&(c=t.attendees.map(u=>u.email).filter(Boolean)),{id:t.id||t.microCmsId||Math.random().toString(),title:t.summary||t.title||"No Title",description:t.description||"",startTime:n,endTime:r,location:t.location||"",type:i,participants:c}})}async function P(s,e,t){let{CalendarType:n}=await Promise.resolve().then(()=>(v(),W));try{o.info(`[INFO] Fetching Google Calendar events for ${e}...`);let r=Q(),i=t||r;o.info(`[INFO] Date range: ${i.from.toISOString()} to ${i.to.toISOString()}`);let a=e===n.PERSONAL?"/api/trpc/calendar.getGoogleCalendarEvents":"/api/trpc/calendar.getLobbyCalendarEvents",c={from:i.from.toISOString(),to:i.to.toISOString()},l=await s.httpClient.get(a,{params:{input:JSON.stringify(c)},headers:{Accept:"application/json","Content-Type":"application/json"},withCredentials:!0}),u=[],d=l.data;if(d?.result?.data?.gcal)u=d.result.data.gcal;else if(d?.result?.data?.lcal)u=d.result.data.lcal;else if(d?.result?.data&&Array.isArray(d.result.data))u=d.result.data;else if(d?.data?.gcal)u=d.data.gcal;else if(d?.data&&Array.isArray(d.data))u=d.data;else if(d?.gcal)u=d.gcal;else if(Array.isArray(d))u=d;else throw new Error(`Invalid calendar response format for ${e} calendar.`);if(!Array.isArray(u))throw new Error(`Calendar events is not an array: ${typeof u}`);return u}catch(r){throw o.error("[ERROR] Error fetching Google Calendar events:",r),r instanceof k&&r.response?.status===401?new Error("Authentication required. Please use the set_cookies tool to provide valid NextAuth.js session cookies from N Lobby."):r}}async function Z(s,e,t){try{o.info(`[INFO] Fetching ${e} calendar events...`);let n=await P(s,e,t),r=Ht(n);return o.info(`[SUCCESS] Retrieved ${r.length} schedule items`),r}catch(n){throw o.error("[ERROR] Error fetching schedule:",n),new Error(`Failed to fetch ${e} calendar: ${n instanceof Error?n.message:"Unknown error"}`)}}async function be(s,e){let{CalendarType:t}=await Promise.resolve().then(()=>(v(),W)),n;if(e){let r=new Date(e);if(isNaN(r.getTime()))throw new Error(`Invalid date format: ${e}`);let i=new Date(r);i.setHours(0,0,0,0);let a=new Date(r);a.setHours(23,59,59,999),n={from:i,to:a}}else n=Q();return Z(s,t.PERSONAL,n)}async function Ce(s,e){let{CalendarType:t}=await Promise.resolve().then(()=>(v(),W)),n=e||Q(),r={personal:{success:!1,count:0},school:{success:!1,count:0}};try{let i=await P(s,t.PERSONAL,n);r.personal.success=!0,r.personal.count=i.length}catch(i){r.personal.error=i instanceof Error?i.message:"Unknown error"}try{let i=await P(s,t.SCHOOL,n);r.school.success=!0,r.school.count=i.length}catch(i){r.school.error=i instanceof Error?i.message:"Unknown error"}return r}async function ke(s){o.info("[INFO] Fetching lobby calendar filters...");try{let e=await s.trpcClient.call("calendar.getLobbyCalendarFilters",{});return o.info("[SUCCESS] getLobbyCalendarFilters succeeded"),e&&typeof e=="object"&&"result"in e?e.result?.filter||[]:Array.isArray(e)?e:[]}catch(e){throw o.error("[ERROR] getLobbyCalendarFilters failed:",e),e}}function Se(s,e){let t=typeof s=="string"?new Date(s):s,n=typeof e=="string"?new Date(e):e;if(isNaN(t.getTime())||isNaN(n.getTime()))throw new Error("Invalid date format provided");if((n.getTime()-t.getTime())/(1e3*60*60*24)<1)throw new Error('To date must be at least 1 day after from date. For single day queries, use period="today" or single from_date parameter.');return{from:t,to:n}}function Re(s){let e=typeof s=="string"?new Date(s):s;if(isNaN(e.getTime()))throw new Error("Invalid date format provided");let t=new Date(e);t.setHours(0,0,0,0);let n=new Date(e);return n.setHours(23,59,59,999),{from:t,to:n}}function Ne(s){let e=s?typeof s=="string"?new Date(s):s:new Date;e.setHours(0,0,0,0);let t=new Date(e);return t.setDate(t.getDate()+6),t.setHours(23,59,59,999),{from:e,to:t}}function Ee(s,e){let t=new Date,n=s||t.getFullYear(),r=e!==void 0?e:t.getMonth(),i=new Date(n,r,1,0,0,0,0),a=new Date(n,r+1,0,23,59,59,999);return{from:i,to:a}}var xe=g(()=>{"use strict";b();T()});function Ae(s,e=""){if(!s||typeof s!="object")return null;if(s.educationProcessName&&s.termYears&&Array.isArray(s.termYears))return o.info(`[INFO] Found education data at path: ${e}`),s;for(let[t,n]of Object.entries(s))if(n&&typeof n=="object"){let r=e?`${e}.${t}`:t,i=Ae(n,r);if(i)return i}return null}function Gt(s){return s.allCount===0?0:Math.round(s.count/s.allCount*100)}function qt(s){let e=s.filter(n=>n.score!==null&&n.progress===100);if(e.length===0)return null;let t=e.reduce((n,r)=>n+(r.score||0),0);return Math.round(t/e.length)}function Bt(s){let e=[];for(let t of s.termYears)for(let n of t.courses){let r=Gt(n.report),i=qt(n.reportDetails),a=n.acquired.acquisitionStatus===1,c=n.subjectStatus===1||n.subjectStatus===2,l={...n,termYear:t.termYear,grade:t.grade,term:t.term,progressPercentage:r,averageScore:i,isCompleted:a,isInProgress:c};e.push(l)}return e}async function Te(s){o.info("[INFO] Starting getRequiredCourses...");try{let e=await s.trpcClient.call("requiredCourse.getRequiredCourses"),t=null,n=e;if(n&&n.result&&n.result.data)t=n.result.data;else if(n&&n.data)t=n.data;else if(n&&n.educationProcessName&&n.termYears)t=n;else{if(n&&Array.isArray(n))return n;if(n){let r=Ae(n);r&&(t=r)}}if(t){let r=Bt(t);return o.info(`[SUCCESS] Total courses extracted: ${r.length}`),r}else throw new Error("Unexpected response format from required courses endpoint.")}catch(e){throw o.error("[ERROR] getRequiredCourses failed:",e),e instanceof Error?e:new Error(`Failed to fetch required courses: ${e instanceof Error?e.message:"Unknown error"}`)}}async function ve(s,e){try{let t=e?{subject:e}:{},n=await s.httpClient.get("/api/learning-resources",{params:t});if(!n.data.success)throw new Error(n.data.error||"Failed to fetch learning resources");return n.data.data||[]}catch(t){throw o.error("Error fetching learning resources:",t),new Error("Authentication required. Please use the set_cookies tool to provide valid NextAuth.js session cookies from N Lobby.")}}async function De(s,e){o.info("[INFO] Checking if date is exam day...");let n=(e||new Date).toISOString();try{let r=await s.trpcClient.call("exam.isExamDay",n);return o.info(`[SUCCESS] isExamDay result: ${r}`),r===!0}catch(r){throw o.error("[ERROR] isExamDay failed:",r),r}}async function Ie(s){o.info("[INFO] Finishing exam day mode...");try{let e=await s.httpClient.post("/api/trpc/exam.finishExamDayMode","{}",{headers:{"Content-Type":"application/json",Cookie:s.nextAuth.getCookieHeader()}});return o.info("[SUCCESS] finishExamDayMode succeeded"),e.data?.result?.data===!0}catch(e){throw o.error("[ERROR] finishExamDayMode failed:",e),e}}async function Le(s){o.info("[INFO] Fetching exam one-time password...");try{let e=await s.trpcClient.call("auth.student.examOneTimePasswordDisplay");return o.info("[SUCCESS] getExamOneTimePassword succeeded"),e}catch(e){throw o.error("[ERROR] getExamOneTimePassword failed:",e),e}}var Ue=g(()=>{"use strict";b()});import Pe from"node:fs/promises";import Wt from"node:os";import Oe from"node:path";import $e from"puppeteer";function zt(s){if(typeof s!="string"||s.length===0)return null;let e=s.trim(),t=e.indexOf(":");if(t>0&&t<20){let r=e.slice(0,t);/^[a-z0-9]+$/i.test(r)&&(e=e.slice(t+1))}e=e.trim();let n=e.replace(/"/g,'"').replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&");try{return JSON.parse(n)}catch{return null}}function O(s,e){if(s==null)return null;if(typeof s=="string"){let t=zt(s);return t?O(t,e):null}if(Array.isArray(s)){let t=s;if(e.has(t))return null;e.add(t);for(let n of s){let r=O(n,e);if(r)return r}return null}if(typeof s=="object"){let t=s;if(e.has(t))return null;if(e.add(t),Object.prototype.hasOwnProperty.call(t,"session")&&t.session&&typeof t.session=="object")return t.session;for(let n of Object.values(t)){let r=O(n,e);if(r)return r}}return null}function Jt(s){let e=/self\.__next_f\.push\((\[[\s\S]*?\])\)/g,t;for(;(t=e.exec(s))!==null;){let r=t[1];if(r)try{let i=JSON.parse(r),a=O(i,new WeakSet);if(a)return o.info("[SUCCESS] Found session data in Next.js flight payload"),a}catch{}}let n=[/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/,/window\.__NEXT_DATA__\s*=\s*({[\s\S]*?})(?:;|\s*<\/script>)/];for(let r of n){let i=s.match(r);if(!(!i||!i[1]))try{let a=JSON.parse(i[1]),c=O(a,new WeakSet);if(c)return o.info("[SUCCESS] Found session data in __NEXT_DATA__ payload"),c}catch{}}return null}function Yt(s){let e=s.user??{},t=e.kmsLogin??{},n=t.content??{},r;return typeof e.image=="string"?r=e.image!=="$undefined"?e.image:null:e.image===null&&(r=null),{name:typeof e.name=="string"?e.name:null,email:typeof e.email=="string"?e.email:null,role:typeof e.role=="string"?e.role:null,image:r,userId:typeof n.userId=="string"?n.userId:void 0,studentNo:typeof n.studentNo=="string"?n.studentNo:void 0,schoolCorporationType:typeof n.schoolCorporationType=="number"?n.schoolCorporationType:void 0,grade:typeof n.grade=="number"?n.grade:void 0,term:typeof n.term=="number"?n.term:void 0,isLobbyAdmin:typeof n.isLobbyAdmin=="boolean"?n.isLobbyAdmin:void 0,firstLoginFlg:typeof n.firstLoginFlg=="number"?n.firstLoginFlg:void 0,kmsLoginSuccess:typeof t.success=="boolean"?t.success:void 0,staffDepartments:Array.isArray(n.staffDepartments)?n.staffDepartments:void 0,studentOrganizations:Array.isArray(n.studentOrganizations)?n.studentOrganizations:void 0,rawSession:s}}function Kt(s){let e=s.charAt(2)?.toUpperCase();return!e||e==="N"||!/[A-Z]/.test(e)?"secure.nnn.ed.jp":`${e.toLowerCase()}-secure.nnn.ed.jp`}function Vt(s,e){let t=[];for(let n of s.split(";")){let r=n.trim();if(!r)continue;let i=r.indexOf("=");if(i<=0)continue;let a=r.slice(0,i),c=r.slice(i+1);t.push({name:a,value:c,domain:e,path:"/",secure:!0,httpOnly:a.startsWith("__Secure-")||a.startsWith("__Host-")||a.toLowerCase().includes("session"),sameSite:"Lax"})}return t}async function Xt(){let s=["--no-sandbox","--disable-setuid-sandbox"],e=[process.env.PUPPETEER_EXECUTABLE_PATH,process.env.CHROME_PATH].filter(c=>!!c&&c.trim().length>0);for(let c of e)try{return await $e.launch({headless:!0,executablePath:c,args:s})}catch{}let t=[],n=async(c,l)=>{try{return o.info(`[STUDENT_CARD] Trying browser launch via ${l}`),await $e.launch(c)}catch(u){return u instanceof Error&&t.push(u),null}},r=await n({headless:!0,args:s},"default Puppeteer bundle");if(r)return r;let i=await n({headless:!0,channel:"chrome",args:s},"system Chrome channel");if(i)return i;let a=t.map(c=>c.message).join(`
|
|
10
|
+
2. Ensure you are properly authenticated using 'set_cookies'`;throw new Error(n)}}catch(e){throw i.error("[ERROR] getNews failed:",e),e instanceof Error?e:new Error(`Failed to fetch news: ${e instanceof Error?e.message:"Unknown error"}`)}}async function ye(o,e){i.info(`[INFO] Fetching news detail for ID: ${e}`);try{let t=`/news/${e}`,n=await $(o,t),r=Bt(n,e);if(r)return r;throw new Error(`Failed to parse news detail from HTML for news ID: ${e}`)}catch(t){throw i.error(`[ERROR] getNewsDetail failed for ID ${e}:`,t),t instanceof Error?t:new Error(`Failed to fetch news detail for ID ${e}: ${t instanceof Error?t.message:"Unknown error"}`)}}async function we(o,e){i.info(`[INFO] Marking news article ${e} as read`);try{let t=await o.httpClient.post("/api/trpc/news.upsertBrowsingHistory",`"${e}"`,{headers:{"Content-Type":"application/json",Authorization:o.nextAuth.getCookieHeader(),Referer:`https://nlobby.nnn.ed.jp/news/${e}`}});return i.info(`[SUCCESS] News article ${e} marked as read`),t.data}catch(t){throw i.error(`[ERROR] Failed to mark news ${e} as read:`,t),t}}async function be(o){i.info("[INFO] Fetching unread news info...");try{let e=await o.trpcClient.call("news.getUnreadNewsInfo");return i.info("[SUCCESS] getUnreadNewsInfo succeeded"),e}catch(e){throw i.error("[ERROR] getUnreadNewsInfo failed:",e),e}}var Ce=g(()=>{"use strict";V();E();S()});var z={};j(z,{CalendarType:()=>B});var B,v=g(()=>{"use strict";B=(t=>(t.PERSONAL="personal",t.SCHOOL="school",t))(B||{})});function X(){let o=new Date,e=new Date(o);e.setHours(0,0,0,0);let t=new Date(o);return t.setDate(t.getDate()+7),t.setHours(23,59,59,999),{from:e,to:t}}function zt(o){return o.map(e=>{let t=e,n,r;t.startDateTime?(n=new Date(t.startDateTime),r=t.endDateTime?new Date(t.endDateTime):new Date(n.getTime()+3600*1e3)):t.start?(t.start.dateTime?n=new Date(t.start.dateTime):t.start.date?n=new Date(t.start.date+"T00:00:00"):n=new Date,t.end&&t.end.dateTime?r=new Date(t.end.dateTime):t.end&&t.end.date?(r=new Date(t.end.date+"T23:59:59"),r.setDate(r.getDate()-1)):r=new Date(n.getTime()+3600*1e3)):(n=new Date,r=new Date(n.getTime()+3600*1e3));let s="event",a=(t.summary||"").toLowerCase();a.includes("\u6388\u696D")||a.includes("class")?s="class":a.includes("mtg")||a.includes("\u30DF\u30FC\u30C6\u30A3\u30F3\u30B0")||a.includes("meeting")||a.includes("\u9762\u8AC7")?s="meeting":(a.includes("\u8A66\u9A13")||a.includes("exam")||a.includes("\u30C6\u30B9\u30C8"))&&(s="exam");let c=[];return t.attendees&&Array.isArray(t.attendees)&&(c=t.attendees.map(u=>u.email).filter(Boolean)),{id:t.id||t.microCmsId||Math.random().toString(),title:t.summary||t.title||"No Title",description:t.description||"",startTime:n,endTime:r,location:t.location||"",type:s,participants:c}})}async function U(o,e,t){let{CalendarType:n}=await Promise.resolve().then(()=>(v(),z));try{i.info(`[INFO] Fetching Google Calendar events for ${e}...`);let r=X(),s=t||r;i.info(`[INFO] Date range: ${s.from.toISOString()} to ${s.to.toISOString()}`);let a=e===n.PERSONAL?"/api/trpc/calendar.getGoogleCalendarEvents":"/api/trpc/calendar.getLobbyCalendarEvents",c={from:s.from.toISOString(),to:s.to.toISOString()},l=await o.httpClient.get(a,{params:{input:JSON.stringify(c)},headers:{Accept:"application/json","Content-Type":"application/json"},withCredentials:!0}),u=[],d=l.data;if(d?.result?.data?.gcal)u=d.result.data.gcal;else if(d?.result?.data?.lcal)u=d.result.data.lcal;else if(d?.result?.data&&Array.isArray(d.result.data))u=d.result.data;else if(d?.data?.gcal)u=d.data.gcal;else if(d?.data&&Array.isArray(d.data))u=d.data;else if(d?.gcal)u=d.gcal;else if(Array.isArray(d))u=d;else throw new Error(`Invalid calendar response format for ${e} calendar.`);if(!Array.isArray(u))throw new Error(`Calendar events is not an array: ${typeof u}`);return u}catch(r){throw i.error("[ERROR] Error fetching Google Calendar events:",r),r instanceof C&&r.response?.status===401?new Error("Authentication required. Please use the set_cookies tool to provide valid NextAuth.js session cookies from N Lobby."):r}}async function Q(o,e,t){try{i.info(`[INFO] Fetching ${e} calendar events...`);let n=await U(o,e,t),r=zt(n);return i.info(`[SUCCESS] Retrieved ${r.length} schedule items`),r}catch(n){throw i.error("[ERROR] Error fetching schedule:",n),new Error(`Failed to fetch ${e} calendar: ${n instanceof Error?n.message:"Unknown error"}`)}}async function Se(o,e){let{CalendarType:t}=await Promise.resolve().then(()=>(v(),z)),n;if(e){let r=new Date(e);if(isNaN(r.getTime()))throw new Error(`Invalid date format: ${e}`);let s=new Date(r);s.setHours(0,0,0,0);let a=new Date(r);a.setHours(23,59,59,999),n={from:s,to:a}}else n=X();return Q(o,t.PERSONAL,n)}async function ke(o,e){let{CalendarType:t}=await Promise.resolve().then(()=>(v(),z)),n=e||X(),r={personal:{success:!1,count:0},school:{success:!1,count:0}};try{let s=await U(o,t.PERSONAL,n);r.personal.success=!0,r.personal.count=s.length}catch(s){r.personal.error=s instanceof Error?s.message:"Unknown error"}try{let s=await U(o,t.SCHOOL,n);r.school.success=!0,r.school.count=s.length}catch(s){r.school.error=s instanceof Error?s.message:"Unknown error"}return r}async function Ne(o){i.info("[INFO] Fetching lobby calendar filters...");try{let e=await o.trpcClient.call("calendar.getLobbyCalendarFilters",{});return i.info("[SUCCESS] getLobbyCalendarFilters succeeded"),e&&typeof e=="object"&&"result"in e?e.result?.filter||[]:Array.isArray(e)?e:[]}catch(e){throw i.error("[ERROR] getLobbyCalendarFilters failed:",e),e}}function Re(o,e){let t=typeof o=="string"?new Date(o):o,n=typeof e=="string"?new Date(e):e;if(isNaN(t.getTime())||isNaN(n.getTime()))throw new Error("Invalid date format provided");if((n.getTime()-t.getTime())/(1e3*60*60*24)<1)throw new Error('To date must be at least 1 day after from date. For single day queries, use period="today" or single from_date parameter.');return{from:t,to:n}}function Ee(o){let e=typeof o=="string"?new Date(o):o;if(isNaN(e.getTime()))throw new Error("Invalid date format provided");let t=new Date(e);t.setHours(0,0,0,0);let n=new Date(e);return n.setHours(23,59,59,999),{from:t,to:n}}function xe(o){let e=o?typeof o=="string"?new Date(o):o:new Date;e.setHours(0,0,0,0);let t=new Date(e);return t.setDate(t.getDate()+6),t.setHours(23,59,59,999),{from:e,to:t}}function Ae(o,e){let t=new Date,n=o||t.getFullYear(),r=e!==void 0?e:t.getMonth(),s=new Date(n,r,1,0,0,0,0),a=new Date(n,r+1,0,23,59,59,999);return{from:s,to:a}}var Te=g(()=>{"use strict";S();T()});function ve(o,e=""){if(!o||typeof o!="object")return null;if(o.educationProcessName&&o.termYears&&Array.isArray(o.termYears))return i.info(`[INFO] Found education data at path: ${e}`),o;for(let[t,n]of Object.entries(o))if(n&&typeof n=="object"){let r=e?`${e}.${t}`:t,s=ve(n,r);if(s)return s}return null}function Yt(o){return o.allCount===0?0:Math.round(o.count/o.allCount*100)}function Wt(o){let e=o.filter(n=>n.score!==null&&n.progress===100);if(e.length===0)return null;let t=e.reduce((n,r)=>n+(r.score||0),0);return Math.round(t/e.length)}function Kt(o){let e=[];for(let t of o.termYears)for(let n of t.courses){let r=Yt(n.report),s=Wt(n.reportDetails),a=n.acquired.acquisitionStatus===1,c=n.subjectStatus===1||n.subjectStatus===2,l={...n,termYear:t.termYear,grade:t.grade,term:t.term,progressPercentage:r,averageScore:s,isCompleted:a,isInProgress:c};e.push(l)}return e}async function De(o){i.info("[INFO] Starting getRequiredCourses...");try{let e=await o.trpcClient.call("requiredCourse.getRequiredCourses"),t=null,n=e;if(n&&n.result&&n.result.data)t=n.result.data;else if(n&&n.data)t=n.data;else if(n&&n.educationProcessName&&n.termYears)t=n;else{if(n&&Array.isArray(n))return n;if(n){let r=ve(n);r&&(t=r)}}if(t){let r=Kt(t);return i.info(`[SUCCESS] Total courses extracted: ${r.length}`),r}else throw new Error("Unexpected response format from required courses endpoint.")}catch(e){throw i.error("[ERROR] getRequiredCourses failed:",e),e instanceof Error?e:new Error(`Failed to fetch required courses: ${e instanceof Error?e.message:"Unknown error"}`)}}async function Ie(o,e){try{let t=e?{subject:e}:{},n=await o.httpClient.get("/api/learning-resources",{params:t});if(!n.data.success)throw new Error(n.data.error||"Failed to fetch learning resources");return n.data.data||[]}catch(t){throw i.error("Error fetching learning resources:",t),new Error("Authentication required. Please use the set_cookies tool to provide valid NextAuth.js session cookies from N Lobby.")}}async function Le(o,e){i.info("[INFO] Checking if date is exam day...");let n=(e||new Date).toISOString();try{let r=await o.trpcClient.call("exam.isExamDay",n);return i.info(`[SUCCESS] isExamDay result: ${r}`),r===!0}catch(r){throw i.error("[ERROR] isExamDay failed:",r),r}}async function Oe(o){i.info("[INFO] Finishing exam day mode...");try{let e=await o.httpClient.post("/api/trpc/exam.finishExamDayMode","{}",{headers:{"Content-Type":"application/json",Cookie:o.nextAuth.getCookieHeader()}});return i.info("[SUCCESS] finishExamDayMode succeeded"),e.data?.result?.data===!0}catch(e){throw i.error("[ERROR] finishExamDayMode failed:",e),e}}async function $e(o){i.info("[INFO] Fetching exam one-time password...");try{let e=await o.trpcClient.call("auth.student.examOneTimePasswordDisplay");return i.info("[SUCCESS] getExamOneTimePassword succeeded"),e}catch(e){throw i.error("[ERROR] getExamOneTimePassword failed:",e),e}}var Ue=g(()=>{"use strict";S()});import Pe from"node:fs/promises";import Vt from"node:os";import _e from"node:path";import Fe from"puppeteer";function Xt(o){if(typeof o!="string"||o.length===0)return null;let e=o.trim(),t=e.indexOf(":");if(t>0&&t<20){let r=e.slice(0,t);/^[a-z0-9]+$/i.test(r)&&(e=e.slice(t+1))}e=e.trim();let n=e.replace(/"/g,'"').replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&");try{return JSON.parse(n)}catch{return null}}function P(o,e){if(o==null)return null;if(typeof o=="string"){let t=Xt(o);return t?P(t,e):null}if(Array.isArray(o)){let t=o;if(e.has(t))return null;e.add(t);for(let n of o){let r=P(n,e);if(r)return r}return null}if(typeof o=="object"){let t=o;if(e.has(t))return null;if(e.add(t),Object.prototype.hasOwnProperty.call(t,"session")&&t.session&&typeof t.session=="object")return t.session;for(let n of Object.values(t)){let r=P(n,e);if(r)return r}}return null}function Qt(o){let e=/self\.__next_f\.push\((\[[\s\S]*?\])\)/g,t;for(;(t=e.exec(o))!==null;){let r=t[1];if(r)try{let s=JSON.parse(r),a=P(s,new WeakSet);if(a)return i.info("[SUCCESS] Found session data in Next.js flight payload"),a}catch{}}let n=[/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/,/window\.__NEXT_DATA__\s*=\s*({[\s\S]*?})(?:;|\s*<\/script>)/];for(let r of n){let s=o.match(r);if(!(!s||!s[1]))try{let a=JSON.parse(s[1]),c=P(a,new WeakSet);if(c)return i.info("[SUCCESS] Found session data in __NEXT_DATA__ payload"),c}catch{}}return null}function Zt(o){let e=o.user??{},t=e.kmsLogin??{},n=t.content??{},r;return typeof e.image=="string"?r=e.image!=="$undefined"?e.image:null:e.image===null&&(r=null),{name:typeof e.name=="string"?e.name:null,email:typeof e.email=="string"?e.email:null,role:typeof e.role=="string"?e.role:null,image:r,userId:typeof n.userId=="string"?n.userId:void 0,studentNo:typeof n.studentNo=="string"?n.studentNo:void 0,schoolCorporationType:typeof n.schoolCorporationType=="number"?n.schoolCorporationType:void 0,grade:typeof n.grade=="number"?n.grade:void 0,term:typeof n.term=="number"?n.term:void 0,isLobbyAdmin:typeof n.isLobbyAdmin=="boolean"?n.isLobbyAdmin:void 0,firstLoginFlg:typeof n.firstLoginFlg=="number"?n.firstLoginFlg:void 0,kmsLoginSuccess:typeof t.success=="boolean"?t.success:void 0,staffDepartments:Array.isArray(n.staffDepartments)?n.staffDepartments:void 0,studentOrganizations:Array.isArray(n.studentOrganizations)?n.studentOrganizations:void 0,rawSession:o}}function en(o){let e=o.charAt(2)?.toUpperCase();return!e||e==="N"||!/[A-Z]/.test(e)?"secure.nnn.ed.jp":`${e.toLowerCase()}-secure.nnn.ed.jp`}function tn(o,e){let t=[];for(let n of o.split(";")){let r=n.trim();if(!r)continue;let s=r.indexOf("=");if(s<=0)continue;let a=r.slice(0,s),c=r.slice(s+1);t.push({name:a,value:c,domain:e,path:"/",secure:!0,httpOnly:a.startsWith("__Secure-")||a.startsWith("__Host-")||a.toLowerCase().includes("session"),sameSite:"Lax"})}return t}async function nn(){let o=["--no-sandbox","--disable-setuid-sandbox"],e=[process.env.PUPPETEER_EXECUTABLE_PATH,process.env.CHROME_PATH].filter(c=>!!c&&c.trim().length>0);for(let c of e)try{return await Fe.launch({headless:!0,executablePath:c,args:o})}catch{}let t=[],n=async(c,l)=>{try{return i.info(`[STUDENT_CARD] Trying browser launch via ${l}`),await Fe.launch(c)}catch(u){return u instanceof Error&&t.push(u),null}},r=await n({headless:!0,args:o},"default Puppeteer bundle");if(r)return r;let s=await n({headless:!0,channel:"chrome",args:o},"system Chrome channel");if(s)return s;let a=t.map(c=>c.message).join(`
|
|
10
11
|
`);throw new Error(`Failed to launch a browser instance for screenshot capture. Please install Chrome via "npx puppeteer browsers install chrome".
|
|
11
|
-
${a}`)}async function
|
|
12
|
-
`)}async function
|
|
12
|
+
${a}`)}async function rn(o){i.info("[STUDENT_CARD] Launching headless browser for student card capture");let e=await nn();try{let t=await e.newPage();await t.setViewport({width:1280,height:720}),await t.setUserAgent(m.userAgent),o.cookies.length>0&&await t.setCookie(...o.cookies),await t.goto(o.startUrl,{waitUntil:"networkidle2",timeout:6e4}),await t.waitForSelector(o.waitForSelector,{timeout:6e4}),await new Promise(u=>setTimeout(u,1e3));let n=await t.$(o.waitForSelector);if(!n)throw new Error(`Failed to locate element ${o.waitForSelector} for screenshot`);let r=await n.screenshot({type:"png"}),s=_e.join(Vt.tmpdir(),"nlobby-student-card");await Pe.mkdir(s,{recursive:!0});let a=_e.join(s,o.screenshotName);await Pe.writeFile(a,r);let c=await n.boundingBox(),l=c?{width:Math.round(c.width),height:Math.round(c.height)}:void 0;return{base64:r.toString("base64"),path:a,finalUrl:t.url(),elementSize:l}}finally{await e.close()}}async function je(o){try{let e=await o.httpClient.get("/api/user");if(!e.data.success)throw new Error(e.data.error||"Failed to fetch user info");return e.data.data}catch(e){throw i.error("Error fetching user info:",e),new Error("Authentication required. Please use the set_cookies tool to provide valid NextAuth.js session cookies from N Lobby.")}}async function Z(o,e="/"){i.info(`[INFO] Extracting account information from Next.js script at ${e}`);try{let t=await $(o,e),n=Qt(t);if(!n)throw new Error("Could not locate session data in Next.js flight scripts. Authentication might be required or the page structure may have changed.");let r=Zt(n);return i.info("[SUCCESS] Account information extracted successfully"),r}catch(t){throw i.error("Error extracting account info from script:",t),new Error(`Failed to extract account information: ${t instanceof Error?t.message:"Unknown error"}`)}}async function Me(o){let t=(await Z(o,"/")).studentNo;if(!t||t.length<3)throw new Error("Student number is missing from account information. Ensure you are authenticated and try again.");let n=en(t),r=`https://${n}/mypage/student_card/index`,s=`https://nlobby.nnn.ed.jp/mypage/v1/callback?redirect_uri=${encodeURIComponent(r)}`,a=o.httpClient.defaults.headers.Cookie;if(!a)throw new Error("Authentication cookies are not set. Use the set_cookies tool or interactive_login first.");let c=tn(a,"nlobby.nnn.ed.jp");if(c.length===0)throw new Error("Failed to parse authentication cookies for browser session.");let l=await rn({startUrl:s,waitForSelector:"#main",screenshotName:`student-card-${Date.now()}.png`,cookies:c});return{base64:l.base64,path:l.path,studentNo:t,secureHost:n,callbackUrl:s,finalUrl:l.finalUrl,elementSize:l.elementSize}}async function He(o){i.info("[INFO] Updating last access...");try{return await o.httpClient.post("/api/trpc/user.updateLastAccess","{}",{headers:{"Content-Type":"application/json",Cookie:o.nextAuth.getCookieHeader()}}),i.info("[SUCCESS] updateLastAccess succeeded"),!0}catch(e){throw i.error("[ERROR] updateLastAccess failed:",e),e}}var Ge=g(()=>{"use strict";V();E();S()});async function qe(o){i.info("[INFO] Fetching main navigations...");try{let e=await o.trpcClient.call("menu.findMainNavigations",{});return i.info("[SUCCESS] getMainNavigations succeeded"),e&&typeof e=="object"&&"menus"in e?e.menus||[]:Array.isArray(e)?e:[]}catch(e){throw i.error("[ERROR] getMainNavigations failed:",e),e}}async function Je(o){i.info("[INFO] Fetching notification messages...");try{let e=await o.trpcClient.call("notification.getMessages");return i.info("[SUCCESS] getNotificationMessages succeeded"),Array.isArray(e)?e:[]}catch(e){throw i.error("[ERROR] getNotificationMessages failed:",e),e}}async function Be(o,e=!1){let t=e?"interest.readInterestsWithIcon":"interest.readInterests";i.info(`[INFO] Fetching user interests (${t})...`);try{let n=await o.trpcClient.call(t);return i.info("[SUCCESS] getUserInterests succeeded"),n&&typeof n=="object"&&"interests"in n?n.interests||[]:Array.isArray(n)?n:[]}catch(n){throw i.error("[ERROR] getUserInterests failed:",n),n}}async function ze(o){i.info("[INFO] Fetching interest weights...");try{let e=await o.trpcClient.call("interest.readWeights");return i.info("[SUCCESS] getInterestWeights succeeded"),e&&typeof e=="object"&&"weights"in e?e.weights||[]:Array.isArray(e)?e:[]}catch(e){throw i.error("[ERROR] getInterestWeights failed:",e),e}}var Ye=g(()=>{"use strict";S()});async function We(o){i.info("[INFO] Running N Lobby API health check...");let e=[{name:"tRPC lightweight endpoint",test:async()=>{try{let t=await o.trpcClient.getUnreadNewsCount();return typeof t=="number"&&t>=0}catch{return!1}}},{name:"tRPC batch health check",test:async()=>{try{return await o.trpcClient.healthCheck()}catch{return!1}}},{name:"HTML news page access",test:async()=>{try{let t=await o.httpClient.get("/news",{headers:{Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"},withCredentials:!0,timeout:8e3});if(t.status===200&&typeof t.data=="string"){let n=t.data.toLowerCase(),r=n.includes("\u30ED\u30B0\u30A4\u30F3")||n.includes("login")||n.includes("sign-in"),s=n.includes("news")||n.includes("\u304A\u77E5\u3089\u305B")||n.includes("nlobby");return!r&&s}return!1}catch{return!1}}},{name:"Basic server connectivity",test:async()=>{try{return(await o.httpClient.get("/",{timeout:5e3,withCredentials:!0})).status===200}catch{return!1}}}];for(let t=0;t<e.length;t++){let n=e[t];i.info(`[STEP${t+1}] Testing ${n.name}...`);try{if(await n.test())return i.info(`[SUCCESS] ${n.name} passed`),t<3?(i.info("[SUCCESS] Health check passed - authentication and connectivity verified"),!0):(i.info("[WARNING] Health check passed with limited functionality"),!0);i.info(`[ERROR] ${n.name} failed`)}catch(r){i.info(`[ERROR] ${n.name} failed with error:`,r instanceof Error?r.message:"Unknown error")}}return i.info("[ERROR] All health check methods failed"),!1}async function Ke(o,e="/news"){let t=[];t.push("[INFO] N Lobby Connection Debug Report"),t.push("=".repeat(50)),t.push(""),t.push("[STATUS] Authentication Status:"),t.push(o.getCookieStatus()),t.push(""),t.push(`[NETWORK] Testing Basic Connectivity to ${e}:`);try{let s=Date.now(),a=await o.httpClient.get(e,{headers:{Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","User-Agent":m.userAgent},withCredentials:!0,timeout:1e4}),c=Date.now();if(t.push(`[SUCCESS] Response received (${c-s}ms)`),t.push(`[STATUS] Status: ${a.status} ${a.statusText}`),t.push(`[SIZE] Content Length: ${typeof a.data=="string"?a.data.length:"unknown"}`),typeof a.data=="string"){let l=a.data.toLowerCase();t.push(""),t.push("[INFO] Content Analysis:"),(l.includes("\u30ED\u30B0\u30A4\u30F3")||l.includes("login")||l.includes("sign-in"))&&t.push("[WARNING] Contains login keywords - may need authentication"),(l.includes("unauthorized")||l.includes("access denied"))&&t.push("[BLOCKED] Access denied detected"),(l.includes("news")||l.includes("announcement")||l.includes("\u304A\u77E5\u3089\u305B"))&&t.push("[SUCCESS] Contains news/announcement content")}}catch(s){t.push("[ERROR] Basic connectivity failed"),s instanceof C?t.push(`[STATUS] Error Status: ${s.response?.status||"unknown"}`):t.push(`[DATA] Error: ${s instanceof Error?s.message:"Unknown error"}`)}t.push(""),t.push("[NETWORK] Network Information:"),t.push(`[URL] Base URL: ${o.httpClient.defaults.baseURL??""}`),t.push(`[TIMEOUT] Timeout: ${o.httpClient.defaults.timeout}ms`),t.push(""),t.push("=".repeat(50)),t.push("[TARGET] Recommendations:");let n=!!o.httpClient.defaults.headers.Cookie,r=o.nextAuth.isAuthenticated();return!n&&!r?t.push("1. Run interactive_login to authenticate"):n&&r&&(t.push("1. Authentication looks good - issue may be server-side"),t.push("2. Try different endpoints or wait and retry")),t.join(`
|
|
13
|
+
`)}async function Ve(o,e="/news",t=1e3){try{i.info(`[INFO] Testing page content for ${e}...`);let n=await o.httpClient.get(e,{headers:{Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Accept-Language":"ja,en-US;q=0.7,en;q=0.3","User-Agent":m.userAgent},withCredentials:!0,timeout:1e4});if(typeof n.data=="string"){let r=n.data,s=r.substring(0,t),a=[];a.push(`Status: ${n.status} ${n.statusText}`),a.push(`Content Length: ${r.length} characters`),a.push(`Content Type: ${n.headers["content-type"]||"unknown"}`),a.push("");let c=r.toLowerCase();c.includes("\u30ED\u30B0\u30A4\u30F3")||c.includes("login")?a.push("[WARNING] Page contains login keywords - may not be authenticated"):(c.includes("news")||c.includes("\u304A\u77E5\u3089\u305B"))&&a.push("[SUCCESS] Page appears to contain news content"),a.push(""),a.push("[DATA] Content Sample:"),a.push("-".repeat(50));let l=a.join(`
|
|
13
14
|
`)+`
|
|
14
|
-
`+
|
|
15
|
+
`+s;return r.length>t?l+`
|
|
15
16
|
|
|
16
|
-
... (${r.length-t} more characters)`:l}else return`Non-string response received: ${typeof n.data}`}catch(n){return
|
|
17
|
+
... (${r.length-t} more characters)`:l}else return`Non-string response received: ${typeof n.data}`}catch(n){return i.error(`[ERROR] Failed to test page content for ${e}:`,n),n instanceof C?`Error ${n.response?.status||"unknown"}: ${n.message||"Unknown error"}`:`Error: ${n instanceof Error?n.message:"Unknown error"}`}}async function Xe(o,e,t){try{i.info(`[INFO] Testing tRPC endpoint: ${e}`);let n=await o.trpcClient.call(e,t);return i.info(`[SUCCESS] tRPC endpoint ${e} succeeded`),{success:!0,method:e,params:t,result:n,timestamp:new Date().toISOString()}}catch(n){i.error(`[ERROR] tRPC endpoint ${e} failed:`,n);let r={success:!1,method:e,params:t,error:n instanceof Error?n.message:"Unknown error",timestamp:new Date().toISOString()};return n instanceof C&&(r.status=n.response?.status,r.statusText=n.response?.statusText,r.responseData=n.response?.data),r}}var Qe=g(()=>{"use strict";E();S();T()});import ee from"node:fs";import on from"node:os";import Ze from"node:path";function sn(){try{return ee.readFileSync(te,"utf8")}catch{return null}}function ne(o){try{let e=Ze.dirname(te);ee.mkdirSync(e,{recursive:!0}),ee.writeFileSync(te,o,"utf8")}catch(e){i.warn("[WARNING] Failed to save session to disk:",e)}}var te,D,Y=g(()=>{"use strict";T();E();S();pe();ge();Ce();Te();Ue();Ge();Ye();Qe();te=Ze.join(on.homedir(),".nlobby","session");D=class{httpClient;nextAuth;trpcClient;session=null;constructor(){this.nextAuth=new H,this.trpcClient=new G(this.nextAuth),this.httpClient=new A({baseURL:m.nlobby.baseUrl,timeout:1e4,headers:{"Content-Type":"application/json","User-Agent":m.userAgent}}),this.setupInterceptors();let e=sn();e&&(i.info("[INFO] Loaded session from disk"),this.setCookiesInternal(e))}setupInterceptors(){this.httpClient.interceptors.request.use(e=>(this.session&&(e.headers.Authorization=`Bearer ${this.session.accessToken}`),e)),this.httpClient.interceptors.response.use(e=>e,async e=>{if(e instanceof Error&&"response"in e&&e.response?.status===401&&this.session)throw new Error("Authentication expired. Please re-authenticate.");return Promise.reject(e)})}setCookiesInternal(e){!e||e.trim()===""||(this.httpClient.defaults.headers.Cookie=e,this.nextAuth.setCookies(e),this.trpcClient.setAllCookies(e))}setSession(e){this.session=e}setCookies(e){if(!e||e.trim()===""){i.warn("[WARNING] Empty cookies provided to setCookies");return}i.debug("[COOKIE] Setting cookies for all clients..."),this.setCookiesInternal(e),i.info("[SUCCESS] HTTP client cookies set"),i.info("[SUCCESS] NextAuth cookies set"),i.info("[SUCCESS] tRPC client cookies set")}getCookieStatus(){let e=!!this.httpClient.defaults.headers.Cookie,t=this.nextAuth.isAuthenticated(),n=this.nextAuth.getCookies(),r=!!this.trpcClient.allCookies,s=this.httpClient.defaults.headers.Cookie,a=typeof s=="string"?s.length:0,c=this.trpcClient.allCookies?.length||0,l=this.nextAuth.getCookieHeader()?.length||0,u=a===c&&c>0;return`[INFO] Authentication Status:
|
|
17
18
|
[HTTP] HTTP client: ${e?"[SUCCESS] cookies set":"[ERROR] no cookies"} (${a} chars)
|
|
18
19
|
[DEBUG] tRPC client: ${r?"[SUCCESS] cookies set":"[ERROR] no cookies"} (${c} chars)
|
|
19
20
|
[AUTH] NextAuth: ${t?"[SUCCESS] authenticated":"[ERROR] not authenticated"} (${l} chars)
|
|
@@ -22,7 +23,7 @@ ${a}`)}async function Qt(s){o.info("[STUDENT_CARD] Launching headless browser fo
|
|
|
22
23
|
- Callback URL: ${n.callbackUrl?"[SUCCESS] present":"[ERROR] missing"}
|
|
23
24
|
|
|
24
25
|
Cookie Synchronization: ${u?"[SUCCESS] synchronized":"[ERROR] not synchronized"}
|
|
25
|
-
${!u&&e?"[WARNING] Cookie length mismatch detected - may cause authentication issues":""}`}async getNews(){return me(this)}async getNewsDetail(e){return he(this,e)}async markNewsAsRead(e){return fe(this,e)}async getUnreadNewsInfo(){return ye(this)}async getSchedule(e,t){return Z(this,e,t)}async getGoogleCalendarEvents(e,t){return P(this,e,t)}async getScheduleByDate(e){return be(this,e)}async testCalendarEndpoints(e){return Ce(this,e)}async getLobbyCalendarFilters(){return ke(this)}createDateRange(e,t){return Se(e,t)}createSingleDayRange(e){return Re(e)}createWeekDateRange(e){return Ne(e)}createMonthDateRange(e,t){return Ee(e,t)}async getRequiredCourses(){return Te(this)}async getLearningResources(e){return ve(this,e)}async isExamDay(e){return De(this,e)}async finishExamDayMode(){return Ie(this)}async getExamOneTimePassword(){return Le(this)}async getUserInfo(){return _e(this)}async getAccountInfoFromScript(e="/"){return ee(this,e)}async getStudentCardScreenshot(){return Fe(this)}async updateLastAccess(){return je(this)}async getMainNavigations(){return He(this)}async getNotificationMessages(){return Ge(this)}async getUserInterests(e=!1){return qe(this,e)}async getInterestWeights(){return Be(this)}async healthCheck(){return ze(this)}async debugConnection(e="/news"){return Je(this,e)}async testPageContent(e="/news",t=1e3){return Ye(this,e,t)}async testTrpcEndpoint(e,t){return Ke(this,e,t)}}});import tn from"puppeteer";var I,se=g(()=>{"use strict";E();b();I=class{browser=null;page=null;async initializeBrowser(){try{if(o.info("Initializing browser for authentication..."),this.browser){try{await this.browser.close()}catch(e){o.warn("Error closing existing browser:",e)}this.browser=null,this.page=null}this.browser=await tn.launch({headless:!1,defaultViewport:{width:1280,height:800},ignoreDefaultArgs:["--disable-extensions","--disable-default-apps"],args:["--no-sandbox","--disable-setuid-sandbox","--disable-dev-shm-usage","--disable-gpu","--no-first-run","--no-default-browser-check","--no-pings","--password-store=basic","--use-mock-keychain","--memory-pressure-off","--max_old_space_size=4096",'--js-flags="--max-old-space-size=4096"',"--disable-background-timer-throttling","--disable-renderer-backgrounding","--disable-backgrounding-occluded-windows","--disable-background-mode","--disable-default-apps","--disable-sync","--disable-translate","--disable-infobars","--disable-notifications","--disable-popup-blocking","--enable-async-dns","--enable-simple-cache-backend","--enable-tcp-fast-open","--prerender-from-omnibox=disabled","--disable-features=VizDisplayCompositor,TranslateUI","--disable-search-engine-choice-screen","--disable-component-update","--allow-running-insecure-content","--disable-hang-monitor","--disable-prompt-on-repost","--disable-client-side-phishing-detection","--disable-domain-reliability","--disable-logging","--disable-login-animations","--disable-modal-animations","--disable-motion-blur","--disable-smooth-scrolling","--disable-threaded-animation","--disable-threaded-scrolling","--disable-checker-imaging","--disable-new-profile-management","--disable-new-avatar-menu","--disable-new-bookmark-apps"],timeout:6e4,protocolTimeout:6e4,slowMo:250}),this.page=await this.browser.newPage(),await this.page.setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"),await this.page.setDefaultNavigationTimeout(6e4),await this.page.setDefaultTimeout(3e4),this.page.on("error",e=>{o.error("Page error:",e)}),this.page.on("pageerror",e=>{o.error("Page JavaScript error:",e)}),this.page.on("console",e=>{e.type()==="error"&&o.error("Browser console error:",e.text())}),this.page.on("framedetached",e=>{o.warn("Frame detached:",e.url())}),this.browser.on("disconnected",()=>{o.error("Browser disconnected unexpectedly"),this.browser=null,this.page=null}),this.browser.on("targetcreated",e=>{o.info("New browser target created:",e.url())}),this.browser.on("targetdestroyed",e=>{o.info("Browser target destroyed:",e.url())}),await this.page.setJavaScriptEnabled(!0),await this.page.setCacheEnabled(!1),await this.page.setRequestInterception(!0),this.page.on("request",e=>{let t=e.resourceType();["image","media","font","stylesheet"].includes(t)?t==="image"&&(e.url().includes("accounts.google.com")||e.url().includes("gstatic.com")||e.url().includes("googleapis.com"))?e.continue():e.abort():e.continue()}),o.info("Browser initialized successfully")}catch(e){if(o.error("Failed to initialize browser:",e),this.browser){try{await this.browser.close()}catch(t){o.warn("Error closing browser after initialization failure:",t)}this.browser=null,this.page=null}throw new Error("Failed to initialize browser for authentication")}}async setupPageConfiguration(){if(!this.page)throw new Error("Page not initialized");await this.page.setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"),await this.page.setDefaultNavigationTimeout(6e4),await this.page.setDefaultTimeout(3e4),this.page.on("error",e=>{o.error("Page error:",e)}),this.page.on("pageerror",e=>{o.error("Page JavaScript error:",e)}),this.page.on("console",e=>{e.type()==="error"&&o.error("Browser console error:",e.text())}),await this.page.setJavaScriptEnabled(!0),await this.page.setCacheEnabled(!1),await this.page.setRequestInterception(!0),this.page.on("request",e=>{let t=e.resourceType();["image","media","font","stylesheet"].includes(t)?t==="image"&&(e.url().includes("accounts.google.com")||e.url().includes("gstatic.com")||e.url().includes("googleapis.com"))?e.continue():e.abort():e.continue()})}async checkBrowserHealth(){try{return!this.browser||!this.browser.isConnected()?(o.warn("Browser is not connected"),!1):!this.page||this.page.isClosed()?(o.warn("Page is closed"),!1):(await this.page.evaluate(()=>document.readyState),!0)}catch(e){return o.warn("Browser health check failed:",e),!1}}async extractCookies(){if(!this.page)throw new Error("Page not initialized");try{o.info("Extracting cookies from N Lobby session...");let e=await this.page.cookies(),t,n,r,i=[];for(let c of e){let l=`${c.name}=${c.value}`;i.push(l),c.name==="__Secure-next-auth.session-token"?t=c.value:c.name==="__Host-next-auth.csrf-token"?n=c.value:c.name==="__Secure-next-auth.callback-url"&&(r=decodeURIComponent(c.value))}let a=i.join("; ");return o.info(`Extracted ${e.length} cookies from N Lobby session`),o.info(`Session token: ${t?"present":"missing"}`),o.info(`CSRF token: ${n?"present":"missing"}`),{sessionToken:t,csrfToken:n,callbackUrl:r,allCookies:a}}catch(e){throw o.error("Failed to extract cookies:",e),new Error("Failed to extract authentication cookies")}}async takeScreenshot(e="nlobby-auth-screenshot.png"){if(!this.page)throw new Error("Page not initialized");let t=`/tmp/${e}`;return await this.page.screenshot({path:t,fullPage:!0}),o.info(`Screenshot saved to ${t}`),t}async getCurrentUrl(){if(!this.page)throw new Error("Page not initialized");return this.page.url()}async getPageTitle(){if(!this.page)throw new Error("Page not initialized");return this.page.title()}async waitForRedirectWithRetry(e,t){let i=e.replace("https://","").replace("http://","");for(let a=1;a<=3;a++)try{(!this.browser||!this.browser.isConnected())&&(o.error("Browser crashed or disconnected, reinitializing..."),await this.initializeBrowser()),o.info(`Waiting for redirect back to N Lobby (attempt ${a}/3)...`),await this.page.waitForFunction(c=>window.location.href.includes(c),{timeout:t/3},i),o.info("Successfully redirected back to N Lobby");return}catch(c){if(a===3)throw o.error("All redirect attempts failed:",c),new Error(`Failed to detect redirect after 3 attempts: ${c instanceof Error?c.message:"Unknown error"}`);o.warn(`Redirect attempt ${a} failed, retrying in 2000ms...`),await new Promise(l=>setTimeout(l,2e3));try{!this.browser||!this.browser.isConnected()?(o.error("Browser crashed, reinitializing..."),await this.initializeBrowser(),await this.page.goto(e,{waitUntil:"networkidle2",timeout:3e4})):await this.page.evaluate(()=>document.readyState)}catch{o.warn("Page became inaccessible, creating new page..."),this.browser&&this.browser.isConnected()&&(this.page=await this.browser.newPage(),await this.setupPageConfiguration())}}}async waitForLoginCompletionWithRetry(e){for(let r=1;r<=3;r++)try{(!this.browser||!this.browser.isConnected())&&(o.error("Browser crashed during login detection, reinitializing..."),await this.initializeBrowser(),await this.page.goto(m.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4})),o.info(`Waiting for login completion (attempt ${r}/3)...`),await this.page.waitForFunction(()=>document.querySelector('[data-testid="user-menu"], .user-profile, .logout-btn')!==null||document.cookie.includes("next-auth.session-token")||window.location.pathname.includes("/home")||window.location.pathname.includes("/dashboard"),{timeout:e/3}),o.info("Login completion detected");return}catch(i){if(r===3)throw o.error("All login detection attempts failed:",i),new Error(`Failed to detect login completion after 3 attempts: ${i instanceof Error?i.message:"Unknown error"}`);o.warn(`Login detection attempt ${r} failed, retrying in 2000ms...`),await new Promise(a=>setTimeout(a,2e3));try{!this.browser||!this.browser.isConnected()?(o.error("Browser crashed during login detection, reinitializing..."),await this.initializeBrowser(),await this.page.goto(m.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4})):await this.page.evaluate(()=>document.readyState)}catch{o.warn("Page became inaccessible during login detection, creating new page..."),this.browser&&this.browser.isConnected()&&(this.page=await this.browser.newPage(),await this.setupPageConfiguration(),await this.page.goto(m.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4}))}}}async close(){try{this.page&&(await this.page.close(),this.page=null),this.browser&&(await this.browser.close(),this.browser=null),o.info("Browser closed successfully")}catch(e){o.error("Error closing browser:",e)}}async interactiveLogin(){if(await this.checkBrowserHealth()||(o.warn("Browser unhealthy, reinitializing..."),await this.initializeBrowser()),!this.browser||!this.page)throw new Error("Browser not initialized. Call initializeBrowser() first.");try{return o.info("Starting interactive login process..."),await this.page.goto(m.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4}),o.info("N Lobby page loaded. Please complete the login process in the browser window."),o.info("The browser will remain open for you to login manually."),await this.waitForLoginCompletionWithRetry(3e5),o.info("Login detected! Extracting cookies..."),await this.extractCookies()}catch(t){if(o.error("Interactive login failed:",t),this.page)try{let n=await this.page.url(),r=await this.page.title();o.error(`Current URL: ${n}`),o.error(`Page title: ${r}`),await this.takeScreenshot("interactive-login-failure-debug.png")}catch(n){o.error("Failed to capture debug information:",n)}throw new Error(`Interactive login failed: ${t instanceof Error?t.message:"Unknown error"}`)}}}});import{createHash as nn}from"crypto";var J,Qe=g(()=>{"use strict";b();J=class{credentialStore=new Map;SESSION_TIMEOUT=7200*1e3;hashEmail(e){return nn("sha256").update(e).digest("hex")}validateEmail(e){if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e))return{valid:!1,userType:"unknown",message:"Invalid email format"};let n=e.split("@")[1].toLowerCase();return n==="nnn.ed.jp"?{valid:!0,userType:"student"}:n==="nnn.ac.jp"?{valid:!0,userType:"staff"}:n==="gmail.com"||n==="yahoo.com"||n==="outlook.com"||n==="hotmail.com"?{valid:!0,userType:"parent"}:{valid:!0,userType:"parent"}}storeSession(e){let t=this.hashEmail(e),n={emailHash:t,timestamp:Date.now(),sessionValid:!0};this.credentialStore.set(t,n),o.info(`Session stored for user: ${e.split("@")[0]}@***`)}hasValidSession(e){let t=this.hashEmail(e),n=this.credentialStore.get(t);return n?Date.now()-n.timestamp>this.SESSION_TIMEOUT?(this.credentialStore.delete(t),!1):n.sessionValid:!1}invalidateSession(e){let t=this.hashEmail(e);this.credentialStore.delete(t),o.info(`Session invalidated for user: ${e.split("@")[0]}@***`)}getLoginGuidance(e){switch(e){case"student":return`
|
|
26
|
+
${!u&&e?"[WARNING] Cookie length mismatch detected - may cause authentication issues":""}`}async getNews(){return fe(this)}async getNewsDetail(e){return ye(this,e)}async markNewsAsRead(e){return we(this,e)}async getUnreadNewsInfo(){return be(this)}async getSchedule(e,t){return Q(this,e,t)}async getGoogleCalendarEvents(e,t){return U(this,e,t)}async getScheduleByDate(e){return Se(this,e)}async testCalendarEndpoints(e){return ke(this,e)}async getLobbyCalendarFilters(){return Ne(this)}createDateRange(e,t){return Re(e,t)}createSingleDayRange(e){return Ee(e)}createWeekDateRange(e){return xe(e)}createMonthDateRange(e,t){return Ae(e,t)}async getRequiredCourses(){return De(this)}async getLearningResources(e){return Ie(this,e)}async isExamDay(e){return Le(this,e)}async finishExamDayMode(){return Oe(this)}async getExamOneTimePassword(){return $e(this)}async getUserInfo(){return je(this)}async getAccountInfoFromScript(e="/"){return Z(this,e)}async getStudentCardScreenshot(){return Me(this)}async updateLastAccess(){return He(this)}async getMainNavigations(){return qe(this)}async getNotificationMessages(){return Je(this)}async getUserInterests(e=!1){return Be(this,e)}async getInterestWeights(){return ze(this)}async healthCheck(){return We(this)}async debugConnection(e="/news"){return Ke(this,e)}async testPageContent(e="/news",t=1e3){return Ve(this,e,t)}async testTrpcEndpoint(e,t){return Xe(this,e,t)}}});import an from"puppeteer";var I,re=g(()=>{"use strict";E();S();I=class{browser=null;page=null;async initializeBrowser(){try{if(i.info("Initializing browser for authentication..."),this.browser){try{await this.browser.close()}catch(e){i.warn("Error closing existing browser:",e)}this.browser=null,this.page=null}this.browser=await an.launch({headless:!1,defaultViewport:{width:1280,height:800},ignoreDefaultArgs:["--disable-extensions","--disable-default-apps"],args:["--no-sandbox","--disable-setuid-sandbox","--disable-dev-shm-usage","--disable-gpu","--no-first-run","--no-default-browser-check","--no-pings","--password-store=basic","--use-mock-keychain","--memory-pressure-off","--max_old_space_size=4096",'--js-flags="--max-old-space-size=4096"',"--disable-background-timer-throttling","--disable-renderer-backgrounding","--disable-backgrounding-occluded-windows","--disable-background-mode","--disable-default-apps","--disable-sync","--disable-translate","--disable-infobars","--disable-notifications","--disable-popup-blocking","--enable-async-dns","--enable-simple-cache-backend","--enable-tcp-fast-open","--prerender-from-omnibox=disabled","--disable-features=VizDisplayCompositor,TranslateUI","--disable-search-engine-choice-screen","--disable-component-update","--allow-running-insecure-content","--disable-hang-monitor","--disable-prompt-on-repost","--disable-client-side-phishing-detection","--disable-domain-reliability","--disable-logging","--disable-login-animations","--disable-modal-animations","--disable-motion-blur","--disable-smooth-scrolling","--disable-threaded-animation","--disable-threaded-scrolling","--disable-checker-imaging","--disable-new-profile-management","--disable-new-avatar-menu","--disable-new-bookmark-apps"],timeout:6e4,protocolTimeout:6e4,slowMo:250}),this.page=await this.browser.newPage(),await this.page.setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"),await this.page.setDefaultNavigationTimeout(6e4),await this.page.setDefaultTimeout(3e4),this.page.on("error",e=>{i.error("Page error:",e)}),this.page.on("pageerror",e=>{i.error("Page JavaScript error:",e)}),this.page.on("console",e=>{e.type()==="error"&&i.error("Browser console error:",e.text())}),this.page.on("framedetached",e=>{i.warn("Frame detached:",e.url())}),this.browser.on("disconnected",()=>{i.error("Browser disconnected unexpectedly"),this.browser=null,this.page=null}),this.browser.on("targetcreated",e=>{i.info("New browser target created:",e.url())}),this.browser.on("targetdestroyed",e=>{i.info("Browser target destroyed:",e.url())}),await this.page.setJavaScriptEnabled(!0),await this.page.setCacheEnabled(!1),await this.page.setRequestInterception(!0),this.page.on("request",e=>{let t=e.resourceType();["image","media","font","stylesheet"].includes(t)?t==="image"&&(e.url().includes("accounts.google.com")||e.url().includes("gstatic.com")||e.url().includes("googleapis.com"))?e.continue():e.abort():e.continue()}),i.info("Browser initialized successfully")}catch(e){if(i.error("Failed to initialize browser:",e),this.browser){try{await this.browser.close()}catch(t){i.warn("Error closing browser after initialization failure:",t)}this.browser=null,this.page=null}throw new Error("Failed to initialize browser for authentication")}}async setupPageConfiguration(){if(!this.page)throw new Error("Page not initialized");await this.page.setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"),await this.page.setDefaultNavigationTimeout(6e4),await this.page.setDefaultTimeout(3e4),this.page.on("error",e=>{i.error("Page error:",e)}),this.page.on("pageerror",e=>{i.error("Page JavaScript error:",e)}),this.page.on("console",e=>{e.type()==="error"&&i.error("Browser console error:",e.text())}),await this.page.setJavaScriptEnabled(!0),await this.page.setCacheEnabled(!1),await this.page.setRequestInterception(!0),this.page.on("request",e=>{let t=e.resourceType();["image","media","font","stylesheet"].includes(t)?t==="image"&&(e.url().includes("accounts.google.com")||e.url().includes("gstatic.com")||e.url().includes("googleapis.com"))?e.continue():e.abort():e.continue()})}async checkBrowserHealth(){try{return!this.browser||!this.browser.isConnected()?(i.warn("Browser is not connected"),!1):!this.page||this.page.isClosed()?(i.warn("Page is closed"),!1):(await this.page.evaluate(()=>document.readyState),!0)}catch(e){return i.warn("Browser health check failed:",e),!1}}async extractCookies(){if(!this.page)throw new Error("Page not initialized");try{i.info("Extracting cookies from N Lobby session...");let e=await this.page.cookies(),t,n,r,s=[];for(let c of e){let l=`${c.name}=${c.value}`;s.push(l),c.name==="__Secure-next-auth.session-token"?t=c.value:c.name==="__Host-next-auth.csrf-token"?n=c.value:c.name==="__Secure-next-auth.callback-url"&&(r=decodeURIComponent(c.value))}let a=s.join("; ");return i.info(`Extracted ${e.length} cookies from N Lobby session`),i.info(`Session token: ${t?"present":"missing"}`),i.info(`CSRF token: ${n?"present":"missing"}`),{sessionToken:t,csrfToken:n,callbackUrl:r,allCookies:a}}catch(e){throw i.error("Failed to extract cookies:",e),new Error("Failed to extract authentication cookies")}}async takeScreenshot(e="nlobby-auth-screenshot.png"){if(!this.page)throw new Error("Page not initialized");let t=`/tmp/${e}`;return await this.page.screenshot({path:t,fullPage:!0}),i.info(`Screenshot saved to ${t}`),t}async getCurrentUrl(){if(!this.page)throw new Error("Page not initialized");return this.page.url()}async getPageTitle(){if(!this.page)throw new Error("Page not initialized");return this.page.title()}async waitForRedirectWithRetry(e,t){let s=e.replace("https://","").replace("http://","");for(let a=1;a<=3;a++)try{(!this.browser||!this.browser.isConnected())&&(i.error("Browser crashed or disconnected, reinitializing..."),await this.initializeBrowser()),i.info(`Waiting for redirect back to N Lobby (attempt ${a}/3)...`),await this.page.waitForFunction(c=>window.location.href.includes(c),{timeout:t/3},s),i.info("Successfully redirected back to N Lobby");return}catch(c){if(a===3)throw i.error("All redirect attempts failed:",c),new Error(`Failed to detect redirect after 3 attempts: ${c instanceof Error?c.message:"Unknown error"}`);i.warn(`Redirect attempt ${a} failed, retrying in 2000ms...`),await new Promise(l=>setTimeout(l,2e3));try{!this.browser||!this.browser.isConnected()?(i.error("Browser crashed, reinitializing..."),await this.initializeBrowser(),await this.page.goto(e,{waitUntil:"networkidle2",timeout:3e4})):await this.page.evaluate(()=>document.readyState)}catch{i.warn("Page became inaccessible, creating new page..."),this.browser&&this.browser.isConnected()&&(this.page=await this.browser.newPage(),await this.setupPageConfiguration())}}}async waitForLoginCompletionWithRetry(e){for(let r=1;r<=3;r++)try{(!this.browser||!this.browser.isConnected())&&(i.error("Browser crashed during login detection, reinitializing..."),await this.initializeBrowser(),await this.page.goto(m.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4})),i.info(`Waiting for login completion (attempt ${r}/3)...`),await this.page.waitForFunction(()=>document.querySelector('[data-testid="user-menu"], .user-profile, .logout-btn')!==null||document.cookie.includes("next-auth.session-token")||window.location.pathname.includes("/home")||window.location.pathname.includes("/dashboard"),{timeout:e/3}),i.info("Login completion detected");return}catch(s){if(r===3)throw i.error("All login detection attempts failed:",s),new Error(`Failed to detect login completion after 3 attempts: ${s instanceof Error?s.message:"Unknown error"}`);i.warn(`Login detection attempt ${r} failed, retrying in 2000ms...`),await new Promise(a=>setTimeout(a,2e3));try{!this.browser||!this.browser.isConnected()?(i.error("Browser crashed during login detection, reinitializing..."),await this.initializeBrowser(),await this.page.goto(m.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4})):await this.page.evaluate(()=>document.readyState)}catch{i.warn("Page became inaccessible during login detection, creating new page..."),this.browser&&this.browser.isConnected()&&(this.page=await this.browser.newPage(),await this.setupPageConfiguration(),await this.page.goto(m.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4}))}}}async close(){try{this.page&&(await this.page.close(),this.page=null),this.browser&&(await this.browser.close(),this.browser=null),i.info("Browser closed successfully")}catch(e){i.error("Error closing browser:",e)}}async interactiveLogin(){if(await this.checkBrowserHealth()||(i.warn("Browser unhealthy, reinitializing..."),await this.initializeBrowser()),!this.browser||!this.page)throw new Error("Browser not initialized. Call initializeBrowser() first.");try{return i.info("Starting interactive login process..."),await this.page.goto(m.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4}),i.info("N Lobby page loaded. Please complete the login process in the browser window."),i.info("The browser will remain open for you to login manually."),await this.waitForLoginCompletionWithRetry(3e5),i.info("Login detected! Extracting cookies..."),await this.extractCookies()}catch(t){if(i.error("Interactive login failed:",t),this.page)try{let n=await this.page.url(),r=await this.page.title();i.error(`Current URL: ${n}`),i.error(`Page title: ${r}`),await this.takeScreenshot("interactive-login-failure-debug.png")}catch(n){i.error("Failed to capture debug information:",n)}throw new Error(`Interactive login failed: ${t instanceof Error?t.message:"Unknown error"}`)}}}});import{createHash as cn}from"crypto";var L,oe=g(()=>{"use strict";S();L=class{credentialStore=new Map;SESSION_TIMEOUT=7200*1e3;hashEmail(e){return cn("sha256").update(e).digest("hex")}validateEmail(e){if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e))return{valid:!1,userType:"unknown",message:"Invalid email format"};let n=e.split("@")[1].toLowerCase();return n==="nnn.ed.jp"?{valid:!0,userType:"student"}:n==="nnn.ac.jp"?{valid:!0,userType:"staff"}:n==="gmail.com"||n==="yahoo.com"||n==="outlook.com"||n==="hotmail.com"?{valid:!0,userType:"parent"}:{valid:!0,userType:"parent"}}storeSession(e){let t=this.hashEmail(e),n={emailHash:t,timestamp:Date.now(),sessionValid:!0};this.credentialStore.set(t,n),i.info(`Session stored for user: ${e.split("@")[0]}@***`)}hasValidSession(e){let t=this.hashEmail(e),n=this.credentialStore.get(t);return n?Date.now()-n.timestamp>this.SESSION_TIMEOUT?(this.credentialStore.delete(t),!1):n.sessionValid:!1}invalidateSession(e){let t=this.hashEmail(e);this.credentialStore.delete(t),i.info(`Session invalidated for user: ${e.split("@")[0]}@***`)}getLoginGuidance(e){switch(e){case"student":return`
|
|
26
27
|
[STUDENT] Student Login Guide:
|
|
27
28
|
- Use your @nnn.ed.jp email address
|
|
28
29
|
- Use your N High School password
|
|
@@ -72,19 +73,19 @@ ${!u&&e?"[WARNING] Cookie length mismatch detected - may cause authentication is
|
|
|
72
73
|
[PRO-TIP] Pro Tips:
|
|
73
74
|
- Use 'interactive_login' if automated login fails
|
|
74
75
|
- The browser window will stay open for manual completion
|
|
75
|
-
- You can close the browser once login is complete`}cleanupExpiredSessions(){let e=Date.now(),t=0;for(let[n,r]of this.credentialStore.entries())e-r.timestamp>this.SESSION_TIMEOUT&&(this.credentialStore.delete(n),t++);t>0&&o.info(`Cleaned up ${t} expired sessions`)}getSessionStats(){let e=Date.now(),t=0;for(let n of this.credentialStore.values())e-n.timestamp>this.SESSION_TIMEOUT&&t++;return{total:this.credentialStore.size,expired:t}}}});var ie={};F(ie,{NLobbyMCPServer:()=>oe});import{Server as rn}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as sn}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as on,ErrorCode as $,ListResourcesRequestSchema as an,ListToolsRequestSchema as cn,McpError as _,ReadResourceRequestSchema as ln,ListPromptsRequestSchema as un,GetPromptRequestSchema as dn}from"@modelcontextprotocol/sdk/types.js";var oe,ae=g(()=>{"use strict";z();E();se();Qe();v();b();oe=class{server;api;browserAuth;credentialManager;constructor(){this.server=new rn({name:m.mcp.serverName,version:m.mcp.serverVersion},{capabilities:{resources:{},tools:{},prompts:{}}}),this.api=new D,this.browserAuth=new I,this.credentialManager=new J,this.setupHandlers()}setupHandlers(){this.server.setRequestHandler(an,async()=>({resources:[{uri:"nlobby://news",name:"School News",description:"Latest school news and notices",mimeType:"application/json"},{uri:"nlobby://schedule",name:"School Schedule",description:"Daily class schedule and events",mimeType:"application/json"},{uri:"nlobby://user-profile",name:"User Profile",description:"Current user information and preferences",mimeType:"application/json"},{uri:"nlobby://required-courses",name:"Required Courses",description:"Required courses and academic information",mimeType:"application/json"}]})),this.server.setRequestHandler(ln,async e=>{let{uri:t}=e.params;try{switch(t){case"nlobby://news":{let n=await this.api.getNews();return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}case"nlobby://schedule":{let n=await this.api.getSchedule("personal");return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}case"nlobby://user-profile":{let n=await this.api.getUserInfo();return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}case"nlobby://required-courses":{let n=await this.api.getRequiredCourses();return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}default:throw new _($.InvalidRequest,`Unknown resource: ${t}`)}}catch(n){throw new _($.InternalError,`Failed to read resource: ${n instanceof Error?n.message:"Unknown error"}`)}}),this.server.setRequestHandler(cn,async()=>({tools:[{name:"get_news",description:"Retrieve school news",inputSchema:{type:"object",properties:{category:{type:"string",description:"Filter by category (optional)"},limit:{type:"number",description:"Maximum number of news items to retrieve (optional, default: 10)",minimum:1,default:10},sort:{type:"string",description:"Sort order: 'newest' (default), 'oldest', 'title-asc', 'title-desc'",enum:["newest","oldest","title-asc","title-desc"]}}}},{name:"get_news_detail",description:"Retrieve detailed information for a specific news article",inputSchema:{type:"object",properties:{newsId:{type:"string",description:"The ID of the news article to retrieve"},markAsRead:{type:"boolean",description:"Mark the news article as read (optional, default: false)",default:!1}},required:["newsId"]}},{name:"get_account_info",description:"Extract account information by parsing Next.js flight data from a rendered page",inputSchema:{type:"object",properties:{}}},{name:"get_student_card_screenshot",description:"Capture a screenshot of the student ID card by following the secure portal redirect flow",inputSchema:{type:"object",properties:{}}},{name:"get_required_courses",description:"Retrieve required courses information with detailed progress tracking",inputSchema:{type:"object",properties:{grade:{type:"number",description:"Filter by grade level (1, 2, or 3) (optional)"},semester:{type:"string",description:'Filter by term year (e.g., "2024", "2025") (optional)'},category:{type:"string",description:'Filter by curriculum category (e.g., "\u56FD\u8A9E", "\u6570\u5B66", "\u82F1\u8A9E") (optional)'}}}},{name:"get_schedule",description:"Get school schedule for a specific date (backward compatibility)",inputSchema:{type:"object",properties:{date:{type:"string",description:"Date in YYYY-MM-DD format (optional, defaults to today)"}}}},{name:"get_calendar_events",description:"Get calendar events with advanced options",inputSchema:{type:"object",properties:{calendar_type:{type:"string",enum:["personal","school"],description:"Type of calendar to retrieve (personal or school)",default:"personal"},from_date:{type:"string",description:"Start date in YYYY-MM-DD format (optional). If only from_date is provided, it will be treated as a single day."},to_date:{type:"string",description:"End date in YYYY-MM-DD format (optional). Must be at least 1 day after from_date when both are provided."},period:{type:"string",enum:["today","week","month"],description:'Predefined period (optional, overrides from/to dates). Use "today" for single day queries.'}}}},{name:"test_calendar_endpoints",description:"Test both personal and school calendar endpoints",inputSchema:{type:"object",properties:{from_date:{type:"string",description:"Start date in YYYY-MM-DD format (optional). If only from_date is provided, it will be treated as a single day."},to_date:{type:"string",description:"End date in YYYY-MM-DD format (optional). Must be at least 1 day after from_date when both are provided."}}}},{name:"set_cookies",description:"Set authentication cookies for N Lobby access",inputSchema:{type:"object",properties:{cookies:{type:"string",description:"Cookie string from authenticated N Lobby session"}},required:["cookies"]}},{name:"check_cookies",description:"Check if authentication cookies are set",inputSchema:{type:"object",properties:{}}},{name:"health_check",description:"Check if N Lobby API connection is working",inputSchema:{type:"object",properties:{}}},{name:"debug_connection",description:"Debug N Lobby connection with detailed information",inputSchema:{type:"object",properties:{endpoint:{type:"string",description:"Endpoint to test (default: /news)",default:"/news"}}}},{name:"test_page_content",description:"Test page content retrieval and show sample content",inputSchema:{type:"object",properties:{endpoint:{type:"string",description:"Endpoint to test (default: /news)",default:"/news"},length:{type:"number",description:"Number of characters to show (default: 1000)",default:1e3}}}},{name:"test_trpc_endpoint",description:"Test specific tRPC endpoint with detailed response",inputSchema:{type:"object",properties:{method:{type:"string",description:"tRPC method to test (e.g., news.getUnreadNewsCount, user.updateLastAccess)",default:"user.updateLastAccess"},params:{type:"string",description:"JSON string of parameters (optional)"}}}},{name:"verify_authentication",description:"Verify authentication status and cookie synchronization across all clients",inputSchema:{type:"object",properties:{}}},{name:"interactive_login",description:"Open browser for manual login to N Lobby (no credentials required)",inputSchema:{type:"object",properties:{}}},{name:"login_help",description:"Get help and troubleshooting tips for N Lobby login",inputSchema:{type:"object",properties:{email:{type:"string",description:"Your email address (optional, for personalized help)"}}}},{name:"mark_news_as_read",description:"Mark news articles as read",inputSchema:{type:"object",properties:{ids:{type:"array",items:{type:"string"},description:"Array of news article IDs to mark as read"}},required:["ids"]}},{name:"check_exam_day",description:"Check if the specified date (or today if omitted) is an exam day",inputSchema:{type:"object",properties:{date:{type:"string",description:"Date in YYYY-MM-DD format (optional, defaults to today)"}}}},{name:"finish_exam_day_mode",description:"Finish exam day mode",inputSchema:{type:"object",properties:{}}},{name:"get_exam_otp",description:"Get one-time password for exam",inputSchema:{type:"object",properties:{}}},{name:"update_last_access",description:"Update the last access timestamp for the current user",inputSchema:{type:"object",properties:{}}},{name:"get_navigation_menus",description:"Get main navigation menu list",inputSchema:{type:"object",properties:{}}},{name:"get_unread_news_info",description:"Get unread news information including count and important news flags",inputSchema:{type:"object",properties:{}}},{name:"get_notifications",description:"Get notification messages",inputSchema:{type:"object",properties:{}}},{name:"get_user_interests",description:"Get user interest tags (optionally with icon information)",inputSchema:{type:"object",properties:{with_icon:{type:"boolean",description:"Whether to include icon information (optional, default: false)",default:!1}}}},{name:"get_interest_weights",description:"Get interest weight scale definitions",inputSchema:{type:"object",properties:{}}},{name:"get_calendar_filters",description:"Get lobby calendar filter list",inputSchema:{type:"object",properties:{}}}]})),this.server.setRequestHandler(on,async e=>{let{name:t,arguments:n}=e.params;try{switch(t){case"get_news":try{let{category:r,limit:i=10,sort:a="newest"}=n,c=await this.api.getNews(),l=r?c.filter(u=>u.category===r):c;switch(a){case"oldest":l.sort((u,d)=>new Date(u.publishedAt||0).getTime()-new Date(d.publishedAt||0).getTime());break;case"title-asc":l.sort((u,d)=>(u.title||"").localeCompare(d.title||""));break;case"title-desc":l.sort((u,d)=>(d.title||"").localeCompare(u.title||""));break;case"newest":default:l.sort((u,d)=>new Date(d.publishedAt||0).getTime()-new Date(u.publishedAt||0).getTime());break}return i>0&&(l=l.slice(0,i)),{content:[{type:"text",text:JSON.stringify(l,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}
|
|
76
|
+
- You can close the browser once login is complete`}cleanupExpiredSessions(){let e=Date.now(),t=0;for(let[n,r]of this.credentialStore.entries())e-r.timestamp>this.SESSION_TIMEOUT&&(this.credentialStore.delete(n),t++);t>0&&i.info(`Cleaned up ${t} expired sessions`)}getSessionStats(){let e=Date.now(),t=0;for(let n of this.credentialStore.values())e-n.timestamp>this.SESSION_TIMEOUT&&t++;return{total:this.credentialStore.size,expired:t}}}});var ie={};j(ie,{NLobbyMCPServer:()=>se});import{Server as ln}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as un}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as dn,ErrorCode as _,ListResourcesRequestSchema as pn,ListToolsRequestSchema as gn,McpError as F,ReadResourceRequestSchema as mn,ListPromptsRequestSchema as hn,GetPromptRequestSchema as fn}from"@modelcontextprotocol/sdk/types.js";var se,ae=g(()=>{"use strict";Y();E();re();oe();v();S();se=class{server;api;browserAuth;credentialManager;constructor(){this.server=new ln({name:m.mcp.serverName,version:m.mcp.serverVersion},{capabilities:{resources:{},tools:{},prompts:{}}}),this.api=new D,this.browserAuth=new I,this.credentialManager=new L,this.setupHandlers()}setupHandlers(){this.server.setRequestHandler(pn,async()=>({resources:[{uri:"nlobby://news",name:"School News",description:"Latest school news and notices",mimeType:"application/json"},{uri:"nlobby://schedule",name:"School Schedule",description:"Daily class schedule and events",mimeType:"application/json"},{uri:"nlobby://user-profile",name:"User Profile",description:"Current user information and preferences",mimeType:"application/json"},{uri:"nlobby://required-courses",name:"Required Courses",description:"Required courses and academic information",mimeType:"application/json"}]})),this.server.setRequestHandler(mn,async e=>{let{uri:t}=e.params;try{switch(t){case"nlobby://news":{let n=await this.api.getNews();return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}case"nlobby://schedule":{let n=await this.api.getSchedule("personal");return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}case"nlobby://user-profile":{let n=await this.api.getUserInfo();return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}case"nlobby://required-courses":{let n=await this.api.getRequiredCourses();return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}default:throw new F(_.InvalidRequest,`Unknown resource: ${t}`)}}catch(n){throw new F(_.InternalError,`Failed to read resource: ${n instanceof Error?n.message:"Unknown error"}`)}}),this.server.setRequestHandler(gn,async()=>({tools:[{name:"get_news",description:"Retrieve school news",inputSchema:{type:"object",properties:{category:{type:"string",description:"Filter by category (optional)"},limit:{type:"number",description:"Maximum number of news items to retrieve (optional, default: 10)",minimum:1,default:10},sort:{type:"string",description:"Sort order: 'newest' (default), 'oldest', 'title-asc', 'title-desc'",enum:["newest","oldest","title-asc","title-desc"]}}}},{name:"get_news_detail",description:"Retrieve detailed information for a specific news article",inputSchema:{type:"object",properties:{newsId:{type:"string",description:"The ID of the news article to retrieve"},markAsRead:{type:"boolean",description:"Mark the news article as read (optional, default: false)",default:!1}},required:["newsId"]}},{name:"get_account_info",description:"Extract account information by parsing Next.js flight data from a rendered page",inputSchema:{type:"object",properties:{}}},{name:"get_student_card_screenshot",description:"Capture a screenshot of the student ID card by following the secure portal redirect flow",inputSchema:{type:"object",properties:{}}},{name:"get_required_courses",description:"Retrieve required courses information with detailed progress tracking",inputSchema:{type:"object",properties:{grade:{type:"number",description:"Filter by grade level (1, 2, or 3) (optional)"},semester:{type:"string",description:'Filter by term year (e.g., "2024", "2025") (optional)'},category:{type:"string",description:'Filter by curriculum category (e.g., "\u56FD\u8A9E", "\u6570\u5B66", "\u82F1\u8A9E") (optional)'}}}},{name:"get_schedule",description:"Get school schedule for a specific date (backward compatibility)",inputSchema:{type:"object",properties:{date:{type:"string",description:"Date in YYYY-MM-DD format (optional, defaults to today)"}}}},{name:"get_calendar_events",description:"Get calendar events with advanced options",inputSchema:{type:"object",properties:{calendar_type:{type:"string",enum:["personal","school"],description:"Type of calendar to retrieve (personal or school)",default:"personal"},from_date:{type:"string",description:"Start date in YYYY-MM-DD format (optional). If only from_date is provided, it will be treated as a single day."},to_date:{type:"string",description:"End date in YYYY-MM-DD format (optional). Must be at least 1 day after from_date when both are provided."},period:{type:"string",enum:["today","week","month"],description:'Predefined period (optional, overrides from/to dates). Use "today" for single day queries.'}}}},{name:"test_calendar_endpoints",description:"Test both personal and school calendar endpoints",inputSchema:{type:"object",properties:{from_date:{type:"string",description:"Start date in YYYY-MM-DD format (optional). If only from_date is provided, it will be treated as a single day."},to_date:{type:"string",description:"End date in YYYY-MM-DD format (optional). Must be at least 1 day after from_date when both are provided."}}}},{name:"set_cookies",description:"Set authentication cookies for N Lobby access",inputSchema:{type:"object",properties:{cookies:{type:"string",description:"Cookie string from authenticated N Lobby session"}},required:["cookies"]}},{name:"check_cookies",description:"Check if authentication cookies are set",inputSchema:{type:"object",properties:{}}},{name:"health_check",description:"Check if N Lobby API connection is working",inputSchema:{type:"object",properties:{}}},{name:"debug_connection",description:"Debug N Lobby connection with detailed information",inputSchema:{type:"object",properties:{endpoint:{type:"string",description:"Endpoint to test (default: /news)",default:"/news"}}}},{name:"test_page_content",description:"Test page content retrieval and show sample content",inputSchema:{type:"object",properties:{endpoint:{type:"string",description:"Endpoint to test (default: /news)",default:"/news"},length:{type:"number",description:"Number of characters to show (default: 1000)",default:1e3}}}},{name:"test_trpc_endpoint",description:"Test specific tRPC endpoint with detailed response",inputSchema:{type:"object",properties:{method:{type:"string",description:"tRPC method to test (e.g., news.getUnreadNewsCount, user.updateLastAccess)",default:"user.updateLastAccess"},params:{type:"string",description:"JSON string of parameters (optional)"}}}},{name:"verify_authentication",description:"Verify authentication status and cookie synchronization across all clients",inputSchema:{type:"object",properties:{}}},{name:"interactive_login",description:"Open browser for manual login to N Lobby (no credentials required)",inputSchema:{type:"object",properties:{}}},{name:"login_help",description:"Get help and troubleshooting tips for N Lobby login",inputSchema:{type:"object",properties:{email:{type:"string",description:"Your email address (optional, for personalized help)"}}}},{name:"mark_news_as_read",description:"Mark news articles as read",inputSchema:{type:"object",properties:{ids:{type:"array",items:{type:"string"},description:"Array of news article IDs to mark as read"}},required:["ids"]}},{name:"check_exam_day",description:"Check if the specified date (or today if omitted) is an exam day",inputSchema:{type:"object",properties:{date:{type:"string",description:"Date in YYYY-MM-DD format (optional, defaults to today)"}}}},{name:"finish_exam_day_mode",description:"Finish exam day mode",inputSchema:{type:"object",properties:{}}},{name:"get_exam_otp",description:"Get one-time password for exam",inputSchema:{type:"object",properties:{}}},{name:"update_last_access",description:"Update the last access timestamp for the current user",inputSchema:{type:"object",properties:{}}},{name:"get_navigation_menus",description:"Get main navigation menu list",inputSchema:{type:"object",properties:{}}},{name:"get_unread_news_info",description:"Get unread news information including count and important news flags",inputSchema:{type:"object",properties:{}}},{name:"get_notifications",description:"Get notification messages",inputSchema:{type:"object",properties:{}}},{name:"get_user_interests",description:"Get user interest tags (optionally with icon information)",inputSchema:{type:"object",properties:{with_icon:{type:"boolean",description:"Whether to include icon information (optional, default: false)",default:!1}}}},{name:"get_interest_weights",description:"Get interest weight scale definitions",inputSchema:{type:"object",properties:{}}},{name:"get_calendar_filters",description:"Get lobby calendar filter list",inputSchema:{type:"object",properties:{}}}]})),this.server.setRequestHandler(dn,async e=>{let{name:t,arguments:n}=e.params;try{switch(t){case"get_news":try{let{category:r,limit:s=10,sort:a="newest"}=n,c=await this.api.getNews(),l=r?c.filter(u=>u.category===r):c;switch(a){case"oldest":l.sort((u,d)=>new Date(u.publishedAt||0).getTime()-new Date(d.publishedAt||0).getTime());break;case"title-asc":l.sort((u,d)=>(u.title||"").localeCompare(d.title||""));break;case"title-desc":l.sort((u,d)=>(d.title||"").localeCompare(u.title||""));break;case"newest":default:l.sort((u,d)=>new Date(d.publishedAt||0).getTime()-new Date(u.publishedAt||0).getTime());break}return s>0&&(l=l.slice(0,s)),{content:[{type:"text",text:JSON.stringify(l,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}
|
|
76
77
|
|
|
77
78
|
To authenticate:
|
|
78
79
|
1. Login to N Lobby in your browser
|
|
79
80
|
2. Open Developer Tools (F12)
|
|
80
81
|
3. Go to Application/Storage tab
|
|
81
82
|
4. Copy cookies and use the set_cookies tool
|
|
82
|
-
5. Use health_check to verify connection`}]}}case"get_news_detail":try{let{newsId:r,markAsRead:
|
|
83
|
+
5. Use health_check to verify connection`}]}}case"get_news_detail":try{let{newsId:r,markAsRead:s=!1}=n,a=await this.api.getNewsDetail(r);if(s)try{await this.api.markNewsAsRead(r)}catch(c){i.error(`Failed to mark news ${r} as read:`,c)}return{content:[{type:"text",text:JSON.stringify(a,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_account_info":try{let r=await this.api.getAccountInfoFromScript();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_student_card_screenshot":try{let r=await this.api.getStudentCardScreenshot();return{content:[{type:"text",text:JSON.stringify({message:"Student card screenshot captured successfully. Image data attached as base64.",filePath:r.path,studentNo:r.studentNo,secureHost:r.secureHost,callbackUrl:r.callbackUrl,finalUrl:r.finalUrl,elementSize:r.elementSize},null,2)},{type:"image",mimeType:"image/png",data:r.base64}]}}catch(r){return{content:[{type:"text",text:`Error capturing student card screenshot: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_required_courses":try{let{grade:r,semester:s,category:a}=n,l=await this.api.getRequiredCourses();if(r!==void 0){let d=r===1?"1\u5E74\u6B21":r===2?"2\u5E74\u6B21":r===3?"3\u5E74\u6B21":`${r}\u5E74\u6B21`;l=l.filter(h=>h.grade===d)}s&&(l=l.filter(d=>d.termYear&&d.termYear.toString().includes(s))),a&&(l=l.filter(d=>d.curriculumName&&d.curriculumName.toLowerCase().includes(a.toLowerCase())));let u={totalCourses:l.length,filters:{grade:r,semester:s,category:a},coursesByGrade:this.groupCoursesByGrade(l),coursesByCurriculum:this.groupCoursesByCurriculum(l),completedCourses:l.filter(d=>d.isCompleted).length,inProgressCourses:l.filter(d=>d.isInProgress).length,courses:l};return{content:[{type:"text",text:JSON.stringify(u,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_schedule":try{let{date:r}=n,s=await this.api.getScheduleByDate(r);return{content:[{type:"text",text:JSON.stringify(s,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_calendar_events":try{let{calendar_type:r,from_date:s,to_date:a,period:c}=n,l=r==="school"?"school":"personal",u;if(c)switch(c){case"today":{let h=new Date;u=this.api.createSingleDayRange(h);break}case"week":u=this.api.createWeekDateRange();break;case"month":u=this.api.createMonthDateRange();break;default:throw new Error(`Invalid period: ${c}`)}else s&&a?u=this.api.createDateRange(s,a):s&&(u=this.api.createSingleDayRange(s));let d=await this.api.getSchedule(l,u);return{content:[{type:"text",text:`[DATE] Calendar Events (${r||"personal"})${u?` from ${u.from.toDateString()} to ${u.to.toDateString()}`:" (current week)"}
|
|
83
84
|
|
|
84
|
-
${JSON.stringify(d,null,2)}`}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"test_calendar_endpoints":try{let{from_date:r,to_date:
|
|
85
|
-
`)}]}}catch(r){return{content:[{type:"text",text:`Error testing calendar endpoints: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"set_cookies":{let{cookies:r}=n;return this.api.setCookies(r),{content:[{type:"text",text:"Authentication cookies have been set. You can now access real N Lobby data."}]}}case"check_cookies":return{content:[{type:"text",text:`Cookie status: ${this.api.getCookieStatus()}`}]};case"health_check":return{content:[{type:"text",text:`N Lobby API connection: ${await this.api.healthCheck()?"healthy":"failed"}`}]};case"debug_connection":{let{endpoint:r}=n;return{content:[{type:"text",text:await this.api.debugConnection(r||"/news")}]}}case"test_page_content":{let{endpoint:r,length:
|
|
85
|
+
${JSON.stringify(d,null,2)}`}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"test_calendar_endpoints":try{let{from_date:r,to_date:s}=n,a;r&&s?a=this.api.createDateRange(r,s):r&&(a=this.api.createSingleDayRange(r));let c=await this.api.testCalendarEndpoints(a);return{content:[{type:"text",text:["[TEST] Calendar Endpoints Test Results","=".repeat(40),"",`[DATE] Test Period: ${a?`${a.from.toDateString()} to ${a.to.toDateString()}`:"Current week (default)"}`,"","[PERSONAL] Personal Calendar:",` Status: ${c.personal.success?"[SUCCESS] Success":"[ERROR] Failed"}`,` Events: ${c.personal.count}`,c.personal.error?` Error: ${c.personal.error}`:"","","[SCHOOL] School Calendar:",` Status: ${c.school.success?"[SUCCESS] Success":"[ERROR] Failed"}`,` Events: ${c.school.count}`,c.school.error?` Error: ${c.school.error}`:"","","[STATUS] Summary:"," Total Endpoints: 2",` Successful: ${(c.personal.success?1:0)+(c.school.success?1:0)}`,` Failed: ${(c.personal.success?0:1)+(c.school.success?0:1)}`,` Total Events: ${c.personal.count+c.school.count}`].filter(Boolean).join(`
|
|
86
|
+
`)}]}}catch(r){return{content:[{type:"text",text:`Error testing calendar endpoints: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"set_cookies":{let{cookies:r}=n;return this.api.setCookies(r),{content:[{type:"text",text:"Authentication cookies have been set. You can now access real N Lobby data."}]}}case"check_cookies":return{content:[{type:"text",text:`Cookie status: ${this.api.getCookieStatus()}`}]};case"health_check":return{content:[{type:"text",text:`N Lobby API connection: ${await this.api.healthCheck()?"healthy":"failed"}`}]};case"debug_connection":{let{endpoint:r}=n;return{content:[{type:"text",text:await this.api.debugConnection(r||"/news")}]}}case"test_page_content":{let{endpoint:r,length:s}=n,a=await this.api.testPageContent(r||"/news",s||1e3);return{content:[{type:"text",text:`Sample content from ${r||"/news"}:
|
|
86
87
|
|
|
87
|
-
${a}`}]}}case"test_trpc_endpoint":{let{method:r,params:
|
|
88
|
+
${a}`}]}}case"test_trpc_endpoint":{let{method:r,params:s}=n;try{let a=s?JSON.parse(s):{},c=await this.api.testTrpcEndpoint(r,a);return{content:[{type:"text",text:`Result of ${r} with params ${JSON.stringify(a)}:
|
|
88
89
|
|
|
89
90
|
${JSON.stringify(c,null,2)}`}]}}catch(a){return{content:[{type:"text",text:`Error testing tRPC endpoint ${r}: ${a instanceof Error?a.message:"Unknown error"}`}]}}}case"verify_authentication":return{content:[{type:"text",text:`[INFO] Authentication Verification Report
|
|
90
91
|
|
|
@@ -98,31 +99,45 @@ Extracted cookies:
|
|
|
98
99
|
- CSRF Token: ${r.csrfToken?"present":"missing"}
|
|
99
100
|
- Callback URL: ${r.callbackUrl||"not set"}
|
|
100
101
|
|
|
101
|
-
You can now access real N Lobby data using other tools.`}]}}catch(r){return await this.browserAuth.close(),{content:[{type:"text",text:`[ERROR] Interactive login failed: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"login_help":{let{email:r}=n,
|
|
102
|
+
You can now access real N Lobby data using other tools.`}]}}catch(r){return await this.browserAuth.close(),{content:[{type:"text",text:`[ERROR] Interactive login failed: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"login_help":{let{email:r}=n,s=`[LOGIN] N Lobby Login Help
|
|
102
103
|
|
|
103
|
-
`;if(r){let c=this.credentialManager.validateEmail(r);
|
|
104
|
-
`,
|
|
105
|
-
`,
|
|
104
|
+
`;if(r){let c=this.credentialManager.validateEmail(r);s+=`[EMAIL] Email: ${r}
|
|
105
|
+
`,s+=`[USER] User Type: ${c.userType}
|
|
106
|
+
`,s+=`[SUCCESS] Valid: ${c.valid?"Yes":"No"}
|
|
106
107
|
|
|
107
|
-
`,c.valid||(
|
|
108
|
+
`,c.valid||(s+=`[ERROR] Issue: ${c.message}
|
|
108
109
|
|
|
109
|
-
`),
|
|
110
|
+
`),s+=this.credentialManager.getLoginGuidance(c.userType)}else s+=this.credentialManager.getLoginGuidance("unknown");s+=`
|
|
110
111
|
|
|
111
|
-
${this.credentialManager.getTroubleshootingTips()}`;let a=this.credentialManager.getSessionStats();return
|
|
112
|
+
${this.credentialManager.getTroubleshootingTips()}`;let a=this.credentialManager.getSessionStats();return s+=`
|
|
112
113
|
|
|
113
114
|
[STATUS] Session Stats:
|
|
114
115
|
- Active sessions: ${a.total-a.expired}
|
|
115
|
-
- Expired sessions: ${a.expired}`,{content:[{type:"text",text:
|
|
116
|
+
- Expired sessions: ${a.expired}`,{content:[{type:"text",text:s}]}}case"mark_news_as_read":try{let{ids:r}=n;if(!r||r.length===0)return{content:[{type:"text",text:"Error: No news article IDs provided."}]};let s=[],a=[];for(let l of r)try{await this.api.markNewsAsRead(l),s.push(l)}catch(u){a.push({id:l,error:u instanceof Error?u.message:"Unknown error"})}let c="";return s.length>0&&(c+=`Successfully marked ${s.length} news article(s) as read: ${s.join(", ")}
|
|
116
117
|
`),a.length>0&&(c+=`
|
|
117
118
|
Failed to mark ${a.length} news article(s) as read:
|
|
118
119
|
`,a.forEach(({id:l,error:u})=>{c+=`- ${l}: ${u}
|
|
119
|
-
`})),{content:[{type:"text",text:c.trim()}]}}catch(r){return{content:[{type:"text",text:`Error marking news as read: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"check_exam_day":try{let{date:r}=n,
|
|
120
|
-
`)}groupCoursesByGrade(e){let t={};for(let n of e){let r=n.grade||"Unknown";t[r]=(t[r]||0)+1}return t}groupCoursesByCurriculum(e){let t={};for(let n of e){let r=n.curriculumName||"Unknown";t[r]=(t[r]||0)+1}return t}}});import{Command as
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
120
|
+
`})),{content:[{type:"text",text:c.trim()}]}}catch(r){return{content:[{type:"text",text:`Error marking news as read: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"check_exam_day":try{let{date:r}=n,s=r?new Date(r):void 0,a=await this.api.isExamDay(s);return{content:[{type:"text",text:JSON.stringify({date:s?s.toISOString().split("T")[0]:new Date().toISOString().split("T")[0],isExamDay:a},null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"finish_exam_day_mode":try{let r=await this.api.finishExamDayMode();return{content:[{type:"text",text:JSON.stringify({success:r},null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_exam_otp":try{let r=await this.api.getExamOneTimePassword();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"update_last_access":try{let r=await this.api.updateLastAccess();return{content:[{type:"text",text:JSON.stringify({success:r},null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_navigation_menus":try{let r=await this.api.getMainNavigations();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_unread_news_info":try{let r=await this.api.getUnreadNewsInfo();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_notifications":try{let r=await this.api.getNotificationMessages();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_user_interests":try{let{with_icon:r=!1}=n,s=await this.api.getUserInterests(r);return{content:[{type:"text",text:JSON.stringify(s,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_interest_weights":try{let r=await this.api.getInterestWeights();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_calendar_filters":try{let r=await this.api.getLobbyCalendarFilters();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}default:throw new F(_.MethodNotFound,`Unknown tool: ${t}`)}}catch(r){throw new F(_.InternalError,`Tool execution failed: ${r instanceof Error?r.message:"Unknown error"}`)}}),this.server.setRequestHandler(hn,async()=>({prompts:[]})),this.server.setRequestHandler(fn,async e=>{let{name:t}=e.params;throw new F(_.InvalidRequest,`Unknown prompt: ${t}`)})}async start(){try{let e=new un;await this.server.connect(e),i.info("N Lobby MCP Server started successfully")}catch(e){i.error("Failed to start server:",e),process.exit(1)}}getAuthenticationRecommendations(){let e=this.api.getCookieStatus(),t=[];return e.includes("[ERROR] no cookies")&&e.includes("[ERROR] not authenticated")?(t.push("1. Run interactive_login to authenticate with N Lobby"),t.push("2. Make sure to complete the login process in the browser window"),t.push('3. Wait for the "Login successful" message before proceeding')):e.includes("[ERROR] not synchronized")?(t.push("1. Cookie synchronization issue detected"),t.push("2. Try running interactive_login again to refresh all cookies")):e.includes("[SUCCESS] authenticated")&&e.includes("[SUCCESS] synchronized")?(t.push("1. Authentication appears to be working correctly"),t.push("2. If endpoints are still failing, the issue may be server-side"),t.push("3. Try running health_check to verify connectivity")):(t.push("1. Check the authentication status above for specific issues"),t.push("2. Run health_check to verify overall system health")),t.join(`
|
|
121
|
+
`)}groupCoursesByGrade(e){let t={};for(let n of e){let r=n.grade||"Unknown";t[r]=(t[r]||0)+1}return t}groupCoursesByCurriculum(e){let t={};for(let n of e){let r=n.curriculumName||"Unknown";t[r]=(t[r]||0)+1}return t}}});import{Command as ce}from"commander";function et(o){return new ce("login").description("Authenticate with N Lobby via browser").action(async()=>{console.log("Opening browser for N Lobby authentication...");try{let t=new I;await t.initializeBrowser();let n=await t.interactiveLogin();n&&n.allCookies?(o.setCookies(n.allCookies),ne(n.allCookies),console.log("[OK] Login successful. Session saved.")):(console.error("[FAIL] Login failed or was cancelled."),process.exit(1))}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}})}function tt(){let o=new L;return new ce("login-help").description("Get help and troubleshooting tips for N Lobby login").option("--email <email>","Your email address (for personalized guidance)").action(t=>{let n=`[LOGIN] N Lobby Login Help
|
|
122
|
+
`;if(t.email){let s=o.validateEmail(t.email);n+=`
|
|
123
|
+
Email: ${t.email}`,n+=`
|
|
124
|
+
User type: ${s.userType}`,n+=`
|
|
125
|
+
Valid: ${s.valid?"Yes":"No"}`,!s.valid&&s.message&&(n+=`
|
|
126
|
+
Issue: ${s.message}`),n+=`
|
|
127
|
+
`,n+=o.getLoginGuidance(s.userType)}else n+=o.getLoginGuidance("unknown");n+=`
|
|
128
|
+
`,n+=o.getTroubleshootingTips();let r=o.getSessionStats();n+=`
|
|
129
|
+
|
|
130
|
+
[STATUS] Session stats: ${r.total-r.expired} active, ${r.expired} expired`,console.log(n)})}function nt(o){let e=new ce("cookies").description("Manage authentication cookies");return e.command("set <cookies>").description("Set cookies manually").action(t=>{o.setCookies(t),ne(t),console.log("[OK] Cookies saved.")}),e.command("check").description("Show current cookie/authentication status").action(()=>{console.log(o.getCookieStatus())}),e}var rt=g(()=>{"use strict";Y();re();oe()});function ot(o){if(o.length===0)return"No news found.";let e=[];for(let t of o){let n=new Date(t.publishedAt).toLocaleDateString("ja-JP"),r=t.isUnread?" [UNREAD]":"",s=t.isImportant?" [!]":"";e.push(`[${t.id}] ${n}${s}${r}`),e.push(` ${t.title}`),t.menuName&&e.push(` Category: ${t.menuName}`),e.push("")}return e.join(`
|
|
131
|
+
`).trimEnd()}function st(o){let e=[],t=new Date(o.publishedAt).toLocaleDateString("ja-JP");if(e.push(`Title: ${o.title}`),e.push(`Date: ${t}`),e.push(`Category: ${o.menuName.join(", ")}`),o.isImportant&&e.push("Important: Yes"),e.push(`URL: ${o.url}`),e.push(""),e.push("\u2500".repeat(50)),e.push(""),o.description)e.push(o.description);else{let n=o.content.replace(/<[^>]+>/g,"").replace(/ /g," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/\n{3,}/g,`
|
|
132
|
+
|
|
133
|
+
`).trim();e.push(n)}if(o.attachments&&o.attachments.length>0){e.push(""),e.push("Attachments:");for(let n of o.attachments)e.push(` - ${n.fileName}: ${n.href}`)}return e.join(`
|
|
134
|
+
`)}var it=g(()=>{"use strict"});import{Command as yn}from"commander";function at(o){let e=new yn("news").description("N Lobby news");return e.command("list",{isDefault:!0}).description("List news").option("--limit <n>","Number of items to show","10").option("--category <cat>","Filter by category").option("--sort <order>","Sort order: newest|oldest|title-asc|title-desc","newest").option("--unread","Show only unread items").option("--json","Output raw JSON").action(async t=>{try{let n=await o.getNews();if(t.unread&&(n=n.filter(s=>s.isUnread)),t.category){let s=t.category.toLowerCase();n=n.filter(a=>a.category.toLowerCase().includes(s)||(a.menuName??"").toLowerCase().includes(s))}switch(t.sort){case"oldest":n.sort((s,a)=>new Date(s.publishedAt).getTime()-new Date(a.publishedAt).getTime());break;case"title-asc":n.sort((s,a)=>s.title.localeCompare(a.title));break;case"title-desc":n.sort((s,a)=>a.title.localeCompare(s.title));break;default:n.sort((s,a)=>new Date(a.publishedAt).getTime()-new Date(s.publishedAt).getTime())}let r=parseInt(t.limit,10);n=n.slice(0,r),t.json?console.log(JSON.stringify(n,null,2)):console.log(ot(n))}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e.command("show <id>").description("Show news detail").option("--json","Output raw JSON").action(async(t,n)=>{try{let r=await o.getNewsDetail(t);n.json?console.log(JSON.stringify(r,null,2)):console.log(st(r))}catch(r){console.error("[FAIL]",r instanceof Error?r.message:r),process.exit(1)}}),e.command("read <ids...>").description("Mark one or more news articles as read").action(async t=>{let n=[],r=[];for(let s of t)try{await o.markNewsAsRead(s),r.push(s)}catch(a){n.push({id:s,error:a instanceof Error?a.message:String(a)})}if(r.length>0&&console.log(`[OK] Marked as read: ${r.join(", ")}`),n.length>0){for(let s of n)console.error(`[FAIL] ${s.id}: ${s.error}`);process.exit(1)}}),e.command("unread-info").description("Show unread news count and flags").option("--json","Output raw JSON").action(async t=>{try{let n=await o.getUnreadNewsInfo();t.json?console.log(JSON.stringify(n,null,2)):console.log(`Unread: ${n.totalCount} (important: ${n.hasImportantNews}, mentor: ${n.byMentorNewsCount})`)}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e}var ct=g(()=>{"use strict";it()});function W(o){return o.toLocaleTimeString("ja-JP",{hour:"2-digit",minute:"2-digit"})}function lt(o){return o.toLocaleDateString("ja-JP",{year:"numeric",month:"2-digit",day:"2-digit",weekday:"short"})}function ut(o){if(o.length===0)return"No schedule items found.";let e=new Map;for(let n of o){let r=lt(new Date(n.startTime)),s=e.get(r)??[];s.push(n),e.set(r,s)}let t=[];for(let[n,r]of e){t.push(`\u2500\u2500 ${n} \u2500\u2500`);for(let s of r){let a=W(new Date(s.startTime)),c=W(new Date(s.endTime));t.push(` ${a}\u2013${c} ${s.title}`),s.location&&t.push(` Location: ${s.location}`),s.description&&t.push(` ${s.description}`)}t.push("")}return t.join(`
|
|
135
|
+
`).trimEnd()}function dt(o){if(o.length===0)return"No calendar events found.";let e=[];for(let t of o){let n=t.start.dateTime??t.start.date??"",r=t.end.dateTime??t.end.date??"",s=!t.start.dateTime,a;if(s)a=n;else{let c=new Date(n),l=new Date(r);a=`${lt(c)} ${W(c)}\u2013${W(l)}`}if(e.push(`[${t.id}] ${t.summary}`),e.push(` ${a}`),t.location&&e.push(` Location: ${t.location}`),t.description){let c=t.description.replace(/<[^>]+>/g,"").trim();c&&e.push(` ${c}`)}e.push("")}return e.join(`
|
|
136
|
+
`).trimEnd()}var pt=g(()=>{"use strict"});import{Command as gt}from"commander";function mt(o){return new gt("schedule").description("Show schedule for a date (default: today)").argument("[date]","Date in YYYY-MM-DD format (default: today)").option("--json","Output raw JSON").action(async(t,n)=>{try{let r=await o.getScheduleByDate(t);n.json?console.log(JSON.stringify(r,null,2)):console.log(ut(r))}catch(r){console.error("[FAIL]",r instanceof Error?r.message:r),process.exit(1)}})}function ht(o){let e=new gt("calendar").description("Show calendar events").option("--from <date>","Start date (YYYY-MM-DD)").option("--to <date>","End date (YYYY-MM-DD)").option("--type <type>","Calendar type: personal|school (default: personal)","personal").option("--json","Output raw JSON").action(async t=>{try{let n=t.type==="school"?"school":"personal",r=t.from&&t.to?o.createDateRange(t.from,t.to):o.createWeekDateRange(),s=await o.getGoogleCalendarEvents(n,r);t.json?console.log(JSON.stringify(s,null,2)):console.log(dt(s))}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}});return e.command("test").description("Test both personal and school calendar endpoints").option("--from <date>","Start date (YYYY-MM-DD)").option("--to <date>","End date (YYYY-MM-DD)").option("--json","Output raw JSON").action(async t=>{try{let n=t.from&&t.to?o.createDateRange(t.from,t.to):t.from?o.createSingleDayRange(t.from):void 0,r=await o.testCalendarEndpoints(n);t.json?console.log(JSON.stringify(r,null,2)):(console.log(`Personal: ${r.personal.success?"[OK]":"[FAIL]"} ${r.personal.count} events${r.personal.error?` (${r.personal.error})`:""}`),console.log(`School: ${r.school.success?"[OK]":"[FAIL]"} ${r.school.count} events${r.school.error?` (${r.school.error})`:""}`))}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e.command("filters").description("Show lobby calendar filter list").option("--json","Output raw JSON").action(async t=>{try{let n=await o.getLobbyCalendarFilters();if(t.json)console.log(JSON.stringify(n,null,2));else if(n.length===0)console.log("No calendar filters found.");else for(let r of n)console.log(`[${r.id}] ${r.label} (${r.color})`)}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e}var ft=g(()=>{"use strict";v();pt()});function wn(o){switch(o){case 0:return"Not Started";case 1:return"In Progress";case 2:return"Completed";default:return`Status ${o}`}}function yt(o){if(o.length===0)return"No courses found.";let e=[],t=new Map;for(let n of o){let r=n.grade?`Grade ${n.grade}${n.term!=null?` / Term ${n.term}`:""}`:"Courses",s=t.get(r)??[];s.push(n),t.set(r,s)}for(let[n,r]of t){e.push(`\u2500\u2500 ${n} \u2500\u2500`);for(let s of r){let a=wn(s.subjectStatus),c=s.progressPercentage!=null?` (${s.progressPercentage.toFixed(0)}%)`:"";e.push(` [${s.subjectCode}] ${s.subjectName}`),e.push(` Curriculum: ${s.curriculumName}`),e.push(` Status: ${a}${c}`),e.push(` Reports: ${s.report.count}/${s.report.allCount}`),s.schooling.necessaryCount>0&&e.push(` Attendance: ${s.schooling.attendanceCount}/${s.schooling.necessaryCount}`),s.averageScore!=null&&e.push(` Avg Score: ${s.averageScore.toFixed(1)}`);let l=s.acquired.approvedCredit;l>0&&e.push(` Credits: ${l}`),e.push("")}}return e.join(`
|
|
137
|
+
`).trimEnd()}var wt=g(()=>{"use strict"});import{Command as bn}from"commander";function bt(o){return new bn("courses").description("Show required courses").option("--grade <n>","Filter by grade").option("--semester <n>","Filter by semester/term").option("--json","Output raw JSON").action(async t=>{try{let n=await o.getRequiredCourses();t.grade&&(n=n.filter(r=>String(r.grade)===t.grade)),t.semester&&(n=n.filter(r=>String(r.term)===t.semester)),t.json?console.log(JSON.stringify(n,null,2)):console.log(yt(n))}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}})}var Ct=g(()=>{"use strict";wt()});function St(o){let e=[];return e.push("\u2500\u2500 Account Information \u2500\u2500"),e.push(`Name: ${o.name??"(unknown)"}`),e.push(`Email: ${o.email??"(unknown)"}`),e.push(`Role: ${o.role??"(unknown)"}`),o.studentNo&&e.push(`Student No: ${o.studentNo}`),o.userId&&e.push(`User ID: ${o.userId}`),o.grade!=null&&e.push(`Grade: ${o.grade}`),o.term!=null&&e.push(`Term: ${o.term}`),o.isLobbyAdmin&&e.push("Admin: Yes"),typeof o.kmsLoginSuccess=="boolean"&&e.push(`KMS Login: ${o.kmsLoginSuccess?"OK":"Failed"}`),Array.isArray(o.studentOrganizations)&&o.studentOrganizations.length>0&&e.push(`Organizations: ${o.studentOrganizations.length}`),Array.isArray(o.staffDepartments)&&o.staffDepartments.length>0&&e.push(`Departments: ${o.staffDepartments.length}`),e.join(`
|
|
138
|
+
`)}var kt=g(()=>{"use strict"});import{Command as Cn}from"commander";function Nt(o){let e=new Cn("profile").description("User profile and account information");return e.command("show",{isDefault:!0}).description("Show user profile (default)").option("--json","Output raw JSON").action(async t=>{try{let n=await o.getAccountInfoFromScript("/");t.json?console.log(JSON.stringify(n,null,2)):console.log(St(n))}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e.command("card").description("Capture student ID card screenshot").option("--json","Output raw JSON (metadata only, no image)").action(async t=>{try{console.log("Capturing student card screenshot...");let n=await o.getStudentCardScreenshot();t.json?console.log(JSON.stringify({filePath:n.path,studentNo:n.studentNo,secureHost:n.secureHost,callbackUrl:n.callbackUrl,finalUrl:n.finalUrl,elementSize:n.elementSize},null,2)):(console.log(`[OK] Student card saved: ${n.path}`),console.log(` Student No: ${n.studentNo}`),n.elementSize&&console.log(` Size: ${n.elementSize.width}x${n.elementSize.height}`))}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e.command("update-access").description("Update last access timestamp").option("--json","Output raw JSON").action(async t=>{try{let n=await o.updateLastAccess();t.json?console.log(JSON.stringify({success:n},null,2)):console.log(n?"[OK] Last access updated.":"[FAIL] Update failed."),n||process.exit(1)}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e}var Rt=g(()=>{"use strict";kt()});function Et(o){return o?"[OK] N Lobby API is reachable and authenticated.":"[FAIL] N Lobby API health check failed. Run `nlobby login` or `nlobby cookies set <cookies>` to authenticate."}var xt=g(()=>{"use strict"});import{Command as Sn}from"commander";function At(o){let e=new Sn("health").description("API connectivity and debugging tools");return e.command("check",{isDefault:!0}).description("Check N Lobby API connectivity and authentication (default)").option("--json","Output raw JSON").action(async t=>{try{let n=await o.healthCheck();t.json?console.log(JSON.stringify({ok:n},null,2)):console.log(Et(n)),n||process.exit(1)}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e.command("debug").description("Debug N Lobby connection with detailed information").option("--endpoint <path>","Endpoint to test","/news").action(async t=>{try{let n=await o.debugConnection(t.endpoint);console.log(n)}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e.command("page").description("Test page content retrieval and show sample content").option("--endpoint <path>","Endpoint to test","/news").option("--length <n>","Number of characters to show","1000").action(async t=>{try{let n=await o.testPageContent(t.endpoint,parseInt(t.length,10));console.log(`Sample content from ${t.endpoint}:
|
|
139
|
+
|
|
140
|
+
${n}`)}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e.command("trpc <method>").description("Test a specific tRPC endpoint (e.g. news.getUnreadNewsCount)").option("--params <json>","JSON string of parameters").option("--json","Output raw JSON result").action(async(t,n)=>{try{let r=n.params?JSON.parse(n.params):{},s=await o.testTrpcEndpoint(t,r);n.json?console.log(JSON.stringify(s,null,2)):console.log(`Result of ${t} with params ${JSON.stringify(r)}:
|
|
141
|
+
|
|
142
|
+
${JSON.stringify(s,null,2)}`)}catch(r){console.error("[FAIL]",r instanceof Error?r.message:r),process.exit(1)}}),e.command("verify").description("Verify authentication status and cookie synchronization across all clients").action(async()=>{try{let t=o.getCookieStatus();console.log(t)}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e}var Tt=g(()=>{"use strict";xt()});import{Command as kn}from"commander";function vt(){return new kn("serve").alias("mcp").description("Start the MCP server (stdio transport)").action(async()=>{let{logger:e}=await Promise.resolve().then(()=>(S(),de));e.forceProductionMode();let{NLobbyMCPServer:t}=await Promise.resolve().then(()=>(ae(),ie));await new t().start()})}var Dt=g(()=>{"use strict"});import{Command as Nn}from"commander";function It(o){let e=new Nn("exam").description("Exam day utilities");return e.command("check").description("Check if a date is an exam day (default: today)").argument("[date]","Date in YYYY-MM-DD format").option("--json","Output raw JSON").action(async(t,n)=>{try{let r=t?new Date(t):void 0,s=await o.isExamDay(r),a=(r??new Date).toISOString().split("T")[0];n.json?console.log(JSON.stringify({date:a,isExamDay:s},null,2)):console.log(s?`[EXAM] ${a} is an exam day.`:`[OK] ${a} is not an exam day.`)}catch(r){console.error("[FAIL]",r instanceof Error?r.message:r),process.exit(1)}}),e.command("finish").description("Finish exam day mode").option("--json","Output raw JSON").action(async t=>{try{let n=await o.finishExamDayMode();t.json?console.log(JSON.stringify({success:n},null,2)):console.log(n?"[OK] Exam day mode finished.":"[FAIL] Failed to finish exam day mode."),n||process.exit(1)}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e.command("otp").description("Get one-time password for exam").option("--json","Output raw JSON").action(async t=>{try{let n=await o.getExamOneTimePassword();t.json,console.log(JSON.stringify(n,null,2))}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e}var Lt=g(()=>{"use strict"});import{Command as Rn}from"commander";function Ot(o){let e=new Rn("nav").description("Navigation, notifications, and user interests");return e.command("menus").description("Show main navigation menu list").option("--json","Output raw JSON").action(async t=>{try{let n=await o.getMainNavigations();if(t.json)console.log(JSON.stringify(n,null,2));else if(n.length===0)console.log("No navigation menus found.");else for(let r of n){r.categoryName&&console.log(`
|
|
143
|
+
\u2500\u2500 ${r.categoryName} \u2500\u2500`);for(let{menu:s}of r.items)console.log(` ${s.label}${s.badgeContent?` (${s.badgeContent})`:""}`)}}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e.command("notifications").description("Show notification messages").option("--json","Output raw JSON").action(async t=>{try{let n=await o.getNotificationMessages();if(t.json)console.log(JSON.stringify(n,null,2));else if(n.length===0)console.log("No notifications.");else for(let r of n)console.log(`[${r.id}] ${r.title??""}`),r.body&&console.log(` ${r.body}`)}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e.command("interests").description("Show user interest tags").option("--with-icon","Include icon information").option("--json","Output raw JSON").action(async t=>{try{let n=await o.getUserInterests(t.withIcon??!1);if(t.json)console.log(JSON.stringify(n,null,2));else if(n.length===0)console.log("No interests found.");else for(let r of n){let s=t.withIcon&&r.iconName?` [${r.iconName}]`:"";console.log(` ${r.name}${s} (weight: ${r.weightId})`)}}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e.command("weights").description("Show interest weight scale definitions").option("--json","Output raw JSON").action(async t=>{try{let n=await o.getInterestWeights();if(t.json)console.log(JSON.stringify(n,null,2));else if(n.length===0)console.log("No weight definitions found.");else for(let r of n)console.log(` [${r.id}] ${r.label} (value: ${r.value})`)}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e}var $t=g(()=>{"use strict"});var Pt={};j(Pt,{buildProgram:()=>Ut,runCli:()=>xn});import{Command as En}from"commander";function Ut(){let o=new D,e=new En().name("nlobby").description("N Lobby CLI \u2014 access N Lobby from the command line").version("1.4.3");return e.addCommand(et(o)),e.addCommand(nt(o)),e.addCommand(tt()),e.addCommand(at(o)),e.addCommand(mt(o)),e.addCommand(ht(o)),e.addCommand(bt(o)),e.addCommand(Nt(o)),e.addCommand(At(o)),e.addCommand(It(o)),e.addCommand(Ot(o)),e.addCommand(vt()),e}async function xn(){await Ut().parseAsync(process.argv)}var _t=g(()=>{"use strict";Y();rt();ct();ft();Ct();Rt();Tt();Dt();Lt();$t()});var le=process.argv.slice(2),An=le[0]==="serve"||le[0]==="mcp",Tn=le.length===0&&!process.stdin.isTTY;async function vn(){if(An||Tn){let{NLobbyMCPServer:o}=await Promise.resolve().then(()=>(ae(),ie));await new o().start()}else{let{runCli:o}=await Promise.resolve().then(()=>(_t(),Pt));await o()}}vn().catch(o=>{console.error("Fatal error:",o instanceof Error?o.message:o),process.exit(1)});
|