insite-cookie 2.3.5 → 2.5.0

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 Eugene Nesvetaev
3
+ Copyright (c) 2026 Eugene Nesvetaev
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,13 +1,134 @@
1
- # Cookie support for inSite
1
+ # insite-cookie
2
+
3
+ [![npm](https://img.shields.io/npm/v/insite-cookie)](https://www.npmjs.com/package/insite-cookie)
4
+
5
+ Cookie support for inSite — token-based handoff for setting cookies over WebSocket. Browsers do not expose `Set-Cookie` for WebSocket responses; this package uses a token handoff: server sends token via WS, client fetches HTTP endpoint with token, receives `Set-Cookie`.
6
+
7
+ Part of [inSite](../../README.md) — depends on [insite-users-server-ws](../users-server-ws/README.md), [insite-http](../http/README.md), [insite-ws](../ws/README.md), [insite-common](../common/README.md).
2
8
 
3
9
  ## Installation
4
10
 
5
11
  ```sh
6
- $ npm install insite-cookie
12
+ npm install insite-cookie
7
13
  ```
8
14
 
9
- Or
15
+ Or:
10
16
 
11
17
  ```sh
12
- $ bun add insite-cookie
18
+ bun add insite-cookie
19
+ ```
20
+
21
+ ## Overview
22
+
23
+ ```mermaid
24
+ sequenceDiagram
25
+ participant Client
26
+ participant WS as WebSocket
27
+ participant Server
28
+ participant Middleware as Cookie Middleware
29
+
30
+ Client->>WS: connect
31
+ Server->>Client: message ~setcookie token
32
+ Client->>Middleware: GET /cookie?token
33
+ Middleware->>Client: 200 Set-Cookie
34
+ Client->>Client: browser stores cookie
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ **Server**
40
+
41
+ ```ts
42
+ import { CookieSetter, CookieMiddleware } from "insite-cookie/server";
43
+ import { UsersServer } from "insite-users-server-ws";
44
+ import { HTTPServer } from "insite-http";
45
+
46
+ const usersServer = new UsersServer({ /* ... */ });
47
+ const cookieSetter = new CookieSetter({ usersServer });
48
+ const cookieMiddleware = new CookieMiddleware();
49
+
50
+ const http = new HTTPServer();
51
+ http.use(cookieMiddleware);
52
+ ```
53
+
54
+ **Client**
55
+
56
+ ```ts
57
+ import { CookieSetter } from "insite-cookie/client";
58
+ import { WS } from "insite-ws/client";
59
+
60
+ const ws = new WS({ url: "wss://example.com" });
61
+ new CookieSetter(ws, { url: "/cookie" });
62
+ ```
63
+
64
+ Or use [insite-client](../client/README.md) with `cookie: {}`.
65
+
66
+ ## API Reference
67
+
68
+ ### Exports
69
+
70
+ **Server (`insite-cookie/server`):**
71
+
72
+ | Export | Type | Description |
73
+ |--------|------|-------------|
74
+ | `CookieSetter` | class | Sets cookies via token handoff; session sync on connect/session change |
75
+ | `CookieMiddleware` | class | HTTP middleware for `/cookie?token` |
76
+ | `parseCookie` | function | Parses cookie string to `Record<string, unknown>` |
77
+ | `CookieMiddlewareOptions` | type | CookieMiddleware constructor options |
78
+
79
+ **Client (`insite-cookie/client`):**
80
+
81
+ | Export | Type | Description |
82
+ |--------|------|-------------|
83
+ | `CookieSetter` | class | Listens for `~setcookie`, XHR to set cookies |
84
+ | `Options` | type | Constructor options |
85
+
86
+ **Types:** `Cookie` — `Record<string, string>`; `CookieOptions` — maxAge, expiresAt, domain, path, secure, httpOnly, sameSite
87
+
88
+ ### CookieSetter (server)
89
+
90
+ ```ts
91
+ class CookieSetter<AS extends AbilitiesSchema>
92
+ ```
93
+
94
+ | Member | Signature | Description |
95
+ |--------|------------|-------------|
96
+ | constructor | `(options: Options<AS>)` | `usersServer` required; `domain` defaults to `process.env.INSITE_HOST`; `maxAge` defaults to session TTL |
97
+ | set | `(wssc, cookie, options) => void` | Queues cookie, sends token; client fetches URL for Set-Cookie |
98
+ | unset | `(wssc, names) => void` | Clears cookies by name |
99
+ | usersServer | `UsersServer<AS>` | Injected |
100
+ | domain | `string \| undefined` | Cookie domain |
101
+ | maxAge | `number` | Cookie max-age in seconds |
102
+ | parse | `static` | Alias for parseCookie |
103
+
104
+ ### CookieMiddleware
105
+
106
+ ```ts
107
+ class CookieMiddleware extends ClassMiddleware
13
108
  ```
109
+
110
+ | Member | Signature | Description |
111
+ |--------|------------|-------------|
112
+ | constructor | `(options?: CookieMiddlewareOptions)` | `path` defaults to `"/cookie"` |
113
+ | make | `static (arg: MakeArg) => string` | Builds Set-Cookie header |
114
+ | cookify | `static (cookie, options) => string[]` | Builds Set-Cookie array |
115
+
116
+ ### CookieSetter (client)
117
+
118
+ | Member | Signature | Description |
119
+ |--------|------------|-------------|
120
+ | constructor | `(ws: WS, options?: Options)` | Subscribes to `~setcookie`; fetches `url?token` |
121
+ | method | `"GET" \| "POST"` | Default `"GET"` |
122
+ | url | `string` | Default `"/cookie"` |
123
+
124
+ **Options:** method, url, onload, onerror
125
+
126
+ ## Related
127
+
128
+ - [insite-client](../client/README.md) — pass `cookie: {}` to enable
129
+ - [insite-users-server-ws](../users-server-ws/README.md) — server CookieSetter binds to client-connect, client-session
130
+ - [insite-http](../http/README.md), [insite-ws](../ws/README.md), [insite-common](../common/README.md)
131
+
132
+ ## License
133
+
134
+ MIT
@@ -1,2 +1,2 @@
1
- function p(){}var y=new WeakMap,h=class o extends Promise{constructor(e,t){let r,n;if(super((i,s)=>{r=i,n=s}),y.set(this,{resolve:r,reject:n}),t?.signal)if(t.signal.aborted)this.reject(new DOMException("Aborted","AbortError"));else{let i=()=>this.reject(new DOMException("Aborted","AbortError"));t.signal.addEventListener("abort",i),this.finally(()=>t.signal?.removeEventListener("abort",i))}if(typeof t?.timeout=="number"&&Number.isFinite(t.timeout)){let i=setTimeout(()=>this.reject(new DOMException("Timeout exceeded","TimeoutError")),t.timeout);this.finally(()=>clearTimeout(i))}e?.(this.resolve,this.reject)}isPending=!0;isFulfilled=!1;isRejected=!1;state="pending";result;resolve=e=>{if(this.isPending){this.isPending=!1,this.isFulfilled=!0,this.state="fulfilled",this.result=e;let t=y.get(this);t&&(t.resolve.call(this,e),y.delete(this))}};reject=e=>{if(this.isPending){this.isPending=!1,this.isRejected=!0,this.state="rejected",this.result=e;let t=y.get(this);t&&(t.reject.call(this,e),y.delete(this))}};static resolved(e){return new o(t=>t(e))}static rejected(e){return new o((t,r)=>r(e))}};function D(o,e=0,t={}){let{leading:r=!1,trailing:n=!0}=t,{maxWait:i=1/0}=t,s,l,d,x,f,g,a,S,j=async()=>{let u=Date.now();u>=d?(s=void 0,d=void 0,clearTimeout(l),l=void 0,typeof a=="function"&&await a(),c.resolve(S),g=r):(clearTimeout(s),s=setTimeout(j,d-u))},O=Number.isFinite(i)?()=>{a===m&&(a=!1),m(),l=setTimeout(O,i)}:null;async function m(){try{return S=await o.apply(x,f),S}catch(u){throw c.reject(u),u}}r&&typeof r=="boolean"&&(r=m),g=r,n&&typeof n=="boolean"&&(n=m),a=n;let c=Object.assign(function(...u){return f=u,x=this,d=Date.now()+e,a=n,c.promise.isPending||(c.promise=new h((W,N)=>{c.resolve=W,c.reject=N,typeof g=="function"&&(g(),g=!1,a===m&&(a=!1)),s||(s=setTimeout(j,e),O&&(l=setTimeout(O,i)))})),c.promise},{callback:o,promise:h.resolved(void 0),resolve:p,reject:p,run:m,clear:async u=>{clearTimeout(s),s=void 0,clearTimeout(l),l=void 0,c.resolve(u?await m():S)}});return c}D.noop=Object.assign(()=>{},{callback:p,promise:h.resolved(void 0),resolve:p,reject:p,run:p,clear:p});var w=new Map;function $(o,e){o.delete(e);let t=w.get(o);if(t){let r=t.get(e);r&&(clearTimeout(r),t.delete(e)),t.size||w.delete(o)}}function v(o,e,t){let r=setTimeout(()=>$(o,e),t);w.get(o)?.set(e,r)??w.set(o,new Map([[e,r]]))}function b(o,e){let t=o.get(e);return $(o,e),t}function T(o,e,t,r,n=!0){return Array.isArray(o)&&(o=o.length),typeof r!="string"&&(n=r??!0,r=t),(n?`${o}\xA0`:"")+T.raw(o,e,t,r)}T.raw=(o,e,t,r=t)=>{o=Math.abs(o);let n=o%10,i=o%100;return n===1&&i!==11?e:n>=2&&n<=4&&!(i>=12&&i<=15)?t:r};function E(o,e){return Math.floor(Math.random()*(e-o+1)+o)}function A(o,e,t,r){return v(o,e,r),o.set(e,t)}import{ClassMiddleware as B}from"insite-http";var k=new Map;var C=class o extends B{constructor(e={}){super();let{path:t="/cookie"}=e;this.listeners={GET:[[t,this.#e]]}}#e=(e,t)=>{let r=e.querystring;return r&&k.has(r)?t.writeHead(200,{"Content-Type":"text/plain; charset=utf-8","Set-Cookie":o.cookify(...b(k,r))}).end():!1};static make({name:e,value:t,maxAge:r,expiresAt:n,domain:i,path:s="/",secure:l=!0,httpOnly:d=!0,sameSite:x="Strict"}){let f=[`${e}=${t}`];return r!==void 0?f.push(`Max-Age=${r}`):n&&f.push(`Max-Age=${Math.round((n.getTime()-Date.now())/1e3)}`),i&&f.push(`Domain=${i}`),s&&f.push(`Path=${s}`),l&&f.push("Secure"),d&&f.push("HttpOnly"),x&&f.push(`SameSite=${x}`),f.join("; ")}static cookify(e,t){return Object.entries(e).map(([r,n])=>this.make({name:r,value:n,...t}))}};function M(o){return o?o.split(/;\s*/).reduce((e,t)=>{let[r,n]=t.split(/=/);try{e[r]=JSON.parse(n)}catch{e[r]=n}return e},{}):{}}import R from"node:crypto";var I={set:"~setcookie"};var _=2e3,P=class{constructor({usersServer:e,domain:t,maxAge:r}){this.usersServer=e,this.domain=t??process.env.INSITE_HOST,this.maxAge=r??this.usersServer.users.sessions.collection.expireAfterSeconds,this.usersServer.wss.on("client-connect",this.#t),this.usersServer.wss.on("client-session",this.#r)}#e=new WeakMap;usersServer;domain;maxAge;set(e,t,r){let n=`${Math.round(performance.now()*Number.MAX_SAFE_INTEGER).toString(36)}$${R.randomBytes(E(4,8)).toString("hex")}`;A(k,n,[t,r],_),e.sendMessage(I.set,n)}unset(e,t){this.set(e,t.reduce((r,n)=>(r[n]="",r),{}),{domain:this.domain,maxAge:0})}#t=(e,t)=>{if(this.#e.set(e,null),t.headers.cookie){let{sessionId:r=null}=M(t.headers.cookie);this.#e.set(e,r),r&&this.usersServer.setSession(e,r,!0)}};#r=e=>{this.#e.get(e)!==e.session?._id&&(this.#e.set(e,e.session?._id??null),e.isOpen&&e.session?this.set(e,{sessionId:e.session._id},{domain:this.domain,maxAge:this.maxAge}):this.unset(e,["sessionId"]))};static parse=M};export{C as CookieMiddleware,P as CookieSetter,M as parseCookie};
1
+ import{getWithTimeout as f}from"@nesvet/n";import{ClassMiddleware as l}from"insite-http";var n=new Map;var u=class r extends l{constructor(e={}){super();let{path:s="/cookie"}=e;this.listeners={GET:[[s,this.#e]]}}#e=(e,s)=>{let t=e.querystring;return t&&n.has(t)?s.writeHead(200,{"Content-Type":"text/plain; charset=utf-8","Set-Cookie":r.cookify(...f(n,t))}).end():!1};static make({name:e,value:s,maxAge:t,expiresAt:o,domain:a,path:m="/",secure:k=!0,httpOnly:c=!0,sameSite:h="Strict"}){let i=[`${e}=${s}`];return t!==void 0?i.push(`Max-Age=${t}`):o&&i.push(`Max-Age=${Math.round((o.getTime()-Date.now())/1e3)}`),a&&i.push(`Domain=${a}`),m&&i.push(`Path=${m}`),k&&i.push("Secure"),c&&i.push("HttpOnly"),h&&i.push(`SameSite=${h}`),i.join("; ")}static cookify(e,s){return Object.entries(e).map(([t,o])=>this.make({name:t,value:o,...s}))}};function p(r){return r?r.split(/;\s*/).reduce((e,s)=>{let[t,o]=s.split(/=/);try{e[t]=JSON.parse(o)}catch{e[t]=o}return e},{}):{}}import C from"node:crypto";import{random as g,setWithTimeout as y}from"@nesvet/n";var S={set:"~setcookie"};var x=2e3,d=class{constructor({usersServer:e,domain:s,maxAge:t}){this.usersServer=e,this.domain=s??process.env.INSITE_HOST,this.maxAge=t??this.usersServer.users.sessions.collection.expireAfterSeconds,this.usersServer.wss.on("client-connect",this.#t),this.usersServer.wss.on("client-session",this.#s)}#e=new WeakMap;usersServer;domain;maxAge;set(e,s,t){let o=`${Math.round(performance.now()*Number.MAX_SAFE_INTEGER).toString(36)}$${C.randomBytes(g(4,8)).toString("hex")}`;y(n,o,[s,t],x),e.sendMessage(S.set,o)}unset(e,s){this.set(e,s.reduce((t,o)=>(t[o]="",t),{}),{domain:this.domain,maxAge:0})}#t=(e,s)=>{if(this.#e.set(e,null),s.headers.cookie){let{sessionId:t=null}=p(s.headers.cookie);this.#e.set(e,t),t&&this.usersServer.setSession(e,t,!0)}};#s=e=>{this.#e.get(e)!==e.session?._id&&(this.#e.set(e,e.session?._id??null),e.isOpen&&e.session?this.set(e,{sessionId:e.session._id},{domain:this.domain,maxAge:this.maxAge}):this.unset(e,["sessionId"]))};static parse=p};export{u as CookieMiddleware,d as CookieSetter,p as parseCookie};
2
2
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../../../@nesvet/npm/n/src/noop.ts", "../../../../../@nesvet/npm/n/src/StatefulPromise.ts", "../../../../../@nesvet/npm/n/src/debounce.ts", "../../../../../@nesvet/npm/n/src/timeouts.ts", "../../../../../@nesvet/npm/n/src/getWithTimeout.ts", "../../../../../@nesvet/npm/n/src/howmuch.ts", "../../../../../@nesvet/npm/n/src/random.ts", "../../../../../@nesvet/npm/n/src/setWithTimeout.ts", "../../src/server/Middleware.ts", "../../src/server/tokenMap.ts", "../../src/server/parse.ts", "../../src/server/Setter.ts", "../../src/common.ts"],
4
- "sourcesContent": ["export function noop() { /**/ }\n", "/* eslint-disable @typescript-eslint/no-explicit-any */\n\ntype Value<T> = PromiseLike<T> | T;\ntype Resolve<T> = (value: Value<T>) => void;\ntype Reject = (reason?: any) => void;\n\ntype Options = {\n\tsignal?: AbortSignal;\n\ttimeout?: number;\n};\n\nconst nativesMap = new WeakMap<StatefulPromise<any>, { resolve: Resolve<any>; reject: Reject }>();\n\n\nexport class StatefulPromise<T> extends Promise<T> {\n\tconstructor(\n\t\texecutor?: (resolve: Resolve<T>, reject: Reject) => void,\n\t\toptions?: Options\n\t) {\n\t\tlet nativeResolve: Resolve<T>;\n\t\tlet nativeReject: Reject;\n\t\t\n\t\tsuper((resolve, reject) => {\n\t\t\tnativeResolve = resolve;\n\t\t\tnativeReject = reject;\n\t\t\t\n\t\t});\n\t\t\n\t\tnativesMap.set(this, { resolve: nativeResolve!, reject: nativeReject! });\n\t\t\n\t\tif (options?.signal)\n\t\t\tif (options.signal.aborted)\n\t\t\t\tthis.reject(new DOMException(\"Aborted\", \"AbortError\"));\n\t\t\telse {\n\t\t\t\tconst abortListener = () => this.reject(new DOMException(\"Aborted\", \"AbortError\"));\n\t\t\t\t\n\t\t\t\toptions.signal.addEventListener(\"abort\", abortListener);\n\t\t\t\t\n\t\t\t\tthis.finally(() => options.signal?.removeEventListener(\"abort\", abortListener));\n\t\t\t}\n\t\t\n\t\tif (typeof options?.timeout === \"number\" && Number.isFinite(options.timeout)) {\n\t\t\tconst timeout = setTimeout(() => this.reject(new DOMException(\"Timeout exceeded\", \"TimeoutError\")), options.timeout);\n\t\t\t\n\t\t\tthis.finally(() => clearTimeout(timeout));\n\t\t}\n\t\t\n\t\texecutor?.(this.resolve, this.reject);\n\t\t\n\t}\n\t\n\tisPending = true;\n\tisFulfilled = false;\n\tisRejected = false;\n\t\n\tstate: \"fulfilled\" | \"pending\" | \"rejected\" = \"pending\";\n\t\n\tresult?: T | unknown;\n\t\n\treadonly resolve = (value: Value<T>) => {\n\t\t\n\t\tif (this.isPending) {\n\t\t\tthis.isPending = false;\n\t\t\tthis.isFulfilled = true;\n\t\t\tthis.state = \"fulfilled\";\n\t\t\tthis.result = value;\n\t\t\t\n\t\t\tconst native = nativesMap.get(this);\n\t\t\t\n\t\t\tif (native) {\n\t\t\t\tnative.resolve.call(this, value);\n\t\t\t\tnativesMap.delete(this);\n\t\t\t}\n\t\t}\n\t\t\n\t};\n\t\n\treadonly reject = (reason?: any) => {\n\t\t\n\t\tif (this.isPending) {\n\t\t\tthis.isPending = false;\n\t\t\tthis.isRejected = true;\n\t\t\tthis.state = \"rejected\";\n\t\t\tthis.result = reason;\n\t\t\t\n\t\t\tconst native = nativesMap.get(this);\n\t\t\t\n\t\t\tif (native) {\n\t\t\t\tnative.reject.call(this, reason);\n\t\t\t\tnativesMap.delete(this);\n\t\t\t}\n\t\t}\n\t\t\n\t};\n\t\n\t\n\tstatic resolved<U>(value: U): StatefulPromise<U> {\n\t\treturn new StatefulPromise<U>(resolve => resolve(value));\n\t}\n\t\n\tstatic rejected(reason: unknown): StatefulPromise<never> {\n\t\treturn new StatefulPromise((_, reject) => reject(reason));\n\t}\n\t\n}\n", "import { noop } from \"./noop.js\";\nimport { StatefulPromise } from \"./StatefulPromise.js\";\n\n\ntype Callback = (...args: any[]) => unknown;// eslint-disable-line @typescript-eslint/no-explicit-any\ntype FunctionOrBoolean = (() => unknown) | boolean;\ntype Options = { leading?: FunctionOrBoolean; maxWait?: number; trailing?: FunctionOrBoolean };\n\ntype DebouncedFunction<C extends Callback> = {\n\t(this: ThisParameterType<C>, ...args: Parameters<C>): Promise<Awaited<ReturnType<C>>>;\n};\n\nexport type Debounced<C extends Callback, R extends ReturnType<C>> = DebouncedFunction<C> & {\n\tcallback: C;\n\tpromise: StatefulPromise<R>;\n\tresolve: (value: R) => void;\n\treject: (reason?: unknown) => void;\n\trun(): Promise<R>;\n\tclear(shouldRun?: boolean): Promise<void>;\n};\n\n\nexport function debounce<C extends Callback, R extends ReturnType<C>>(callback: C, limit = 0, options: Options = {}) {\n\tlet { leading = false, trailing = true } = options;\n\tconst { maxWait = Infinity } = options;\n\t\n\tlet timeout: ReturnType<typeof setTimeout> | undefined;\n\tlet maxWaitTimeout: ReturnType<typeof setTimeout> | undefined;\n\tlet end: number | undefined;\n\tlet context: ThisParameterType<C>;\n\tlet args: unknown[];\n\tlet initial: FunctionOrBoolean;\n\tlet final: FunctionOrBoolean;\n\tlet result: R;\n\t\n\tconst expired = async () => {\n\t\t\n\t\tconst n = Date.now();\n\t\t\n\t\tif (n >= end!) {\n\t\t\ttimeout = undefined;\n\t\t\tend = undefined;\n\t\t\t\n\t\t\tclearTimeout(maxWaitTimeout);\n\t\t\tmaxWaitTimeout = undefined;\n\t\t\t\n\t\t\tif (typeof final == \"function\")\n\t\t\t\tawait final();\n\t\t\t\n\t\t\tdebounced.resolve(result);\n\t\t\t\n\t\t\tinitial = leading;\n\t\t} else {\n\t\t\tclearTimeout(timeout);\n\t\t\ttimeout = setTimeout(expired, end! - n);\n\t\t}\n\t\t\n\t};\n\t\n\tconst maxWaitExpired = Number.isFinite(maxWait) ? () => {\n\t\t\n\t\tif (final === run)\n\t\t\tfinal = false;\n\t\t\n\t\trun();\n\t\t\n\t\tmaxWaitTimeout = setTimeout(maxWaitExpired as TimerHandler, maxWait);\n\t\t\n\t} : null;\n\t\n\tasync function run() {\n\t\ttry {\n\t\t\tresult = await callback.apply(context, args) as R;\n\t\t\t\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tdebounced.reject(error);\n\t\t\t\n\t\t\tthrow error;\n\t\t}\n\t}\n\t\n\tif (leading && typeof leading == \"boolean\")\n\t\tleading = run;\n\tinitial = leading;\n\t\n\tif (trailing && typeof trailing == \"boolean\")\n\t\ttrailing = run;\n\tfinal = trailing;\n\t\n\tconst debounced: Debounced<C, R> = Object.assign(function (..._args) {\n\t\targs = _args;\n\t\tcontext = this;// eslint-disable-line no-invalid-this\n\t\t\n\t\tend = Date.now() + limit;\n\t\tfinal = trailing;\n\t\t\n\t\tif (!debounced.promise.isPending)\n\t\t\tdebounced.promise = new StatefulPromise<R>((resolve, reject) => {\n\t\t\t\tdebounced.resolve = resolve;\n\t\t\t\tdebounced.reject = reject;\n\t\t\t\t\n\t\t\t\tif (typeof initial == \"function\") {\n\t\t\t\t\tinitial();\n\t\t\t\t\t\n\t\t\t\t\tinitial = false;\n\t\t\t\t\t\n\t\t\t\t\tif (final === run)\n\t\t\t\t\t\tfinal = false;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (!timeout) {\n\t\t\t\t\ttimeout = setTimeout(expired, limit);\n\t\t\t\t\t\n\t\t\t\t\tif (maxWaitExpired)\n\t\t\t\t\t\tmaxWaitTimeout = setTimeout(maxWaitExpired, maxWait);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t});\n\t\t\n\t\treturn debounced.promise;\n\t} as DebouncedFunction<C>, {\n\t\tcallback,\n\t\tpromise: StatefulPromise.resolved(undefined as unknown as R),\n\t\tresolve: noop,\n\t\treject: noop,\n\t\trun,\n\t\tclear: async (shouldRun?: boolean) => {\n\t\t\t\n\t\t\tclearTimeout(timeout);\n\t\t\ttimeout = undefined;\n\t\t\t\n\t\t\tclearTimeout(maxWaitTimeout);\n\t\t\tmaxWaitTimeout = undefined;\n\t\t\t\n\t\t\tdebounced.resolve(shouldRun ? await run() : result);\n\t\t\t\n\t\t}\n\t});\n\t\n\treturn debounced;\n}\n\n\ndebounce.noop = Object.assign(() => { /**/ }, {\n\tcallback: noop,\n\tpromise: StatefulPromise.resolved(undefined), // eslint-disable-line unicorn/no-useless-undefined\n\tresolve: noop,\n\treject: noop,\n\trun: noop,\n\tclear: noop\n}) as Debounced<() => void, void>;\n\n\nexport function throttle(callback: Callback, limit?: number, options?: Options) {\n\treturn debounce(callback, limit, {\n\t\tmaxWait: limit,\n\t\tleading: true,\n\t\ttrailing: true,\n\t\t...options\n\t});\n}\n", "const timeoutsMapMap: Map<Map<any, any>, Map<any, number>> = new Map();// eslint-disable-line @typescript-eslint/no-explicit-any\n\nexport function cleanup<K, V>(map: Map<K, V>, key: K) {\n\tmap.delete(key);\n\t\n\tconst timeoutsMap = timeoutsMapMap.get(map);\n\tif (timeoutsMap) {\n\t\t\n\t\tconst timeout = timeoutsMap.get(key);\n\t\tif (timeout) {\n\t\t\tclearTimeout(timeout);\n\t\t\ttimeoutsMap.delete(key);\n\t\t}\n\t\t\n\t\tif (!timeoutsMap.size)\n\t\t\ttimeoutsMapMap.delete(map);\n\t}\n\t\n}\n\nexport function setup<K, V>(map: Map<K, V>, key: K, ms: number) {\n\tconst timeout = setTimeout(() => cleanup(map, key), ms);\n\t\n\ttimeoutsMapMap.get(map)?.set(key, timeout) ??\n\ttimeoutsMapMap.set(map, new Map([ [ key, timeout ] ]));\n\t\n}\n", "import { cleanup } from \"./timeouts.js\";\n\n\nexport function getWithTimeout<K, V>(map: Map<K, V>, key: K) {\n\tconst value = map.get(key);\n\t\n\tcleanup(map, key);\n\t\n\treturn value;\n}\n", "export function howmuch(number: [] | number, one: string, two: string, five: boolean | string, shouldPrintNumber = true) {\n\tif (Array.isArray(number))\n\t\tnumber = number.length;\n\t\n\tif (typeof five != \"string\") {\n\t\tshouldPrintNumber = five ?? true;\n\t\tfive = two;\n\t}\n\t\n\t\n\treturn (shouldPrintNumber ? `${number}\u00A0` : \"\") + howmuch.raw(number, one, two, five);\n}\n\nhowmuch.raw = (number: number, one: string, two: string, five = two) => {\n\tnumber = Math.abs(number);\n\tconst u = number % 10;\n\tconst d = number % 100;\n\t\n\treturn (\n\t\t(u === 1 && d !== 11) ?\n\t\t\tone :\n\t\t\t((u >= 2 && u <= 4) && !(d >= 12 && d <= 15)) ?\n\t\t\t\ttwo :\n\t\t\t\tfive\n\t);\n};\n", "export function random(from: number, to: number) {\n\treturn Math.floor(Math.random() * (to - from + 1) + from);\n}\n", "import { setup } from \"./timeouts.js\";\n\n\nexport function setWithTimeout<K, V>(map: Map<K, V>, key: K, value: V, ms: number) {\n\tsetup(map, key, ms);\n\t\n\treturn map.set(key, value);\n}\n", "import { getWithTimeout } from \"@nesvet/n\";\nimport { ClassMiddleware, type RequestHandler } from \"insite-http\";\nimport { tokenMap } from \"./tokenMap\";\nimport type { Cookie, CookieOptions } from \"./types\";\n\n\ntype Options = {\n\tpath?: RegExp | string;\n};\n\nexport type { Options as CookieMiddlewareOptions };\n\ntype MakeArg = CookieOptions & {\n\tname: keyof Cookie;\n\tvalue: Cookie[keyof Cookie];\n};\n\n\nexport class CookieMiddleware extends ClassMiddleware {\n\tconstructor(options: Options = {}) {\n\t\tsuper();\n\t\t\n\t\tconst {\n\t\t\tpath = \"/cookie\"\n\t\t} = options;\n\t\t\n\t\tthis.listeners = {\n\t\t\tGET: [ [ path, this.#handler ] ]\n\t\t};\n\t\t\n\t}\n\t\n\t#handler: RequestHandler = (request, response) => {\n\t\tconst token = request.querystring;\n\t\t\n\t\tif (token && tokenMap.has(token))\n\t\t\treturn response.writeHead(200, {\n\t\t\t\t\"Content-Type\": \"text/plain; charset=utf-8\",\n\t\t\t\t\"Set-Cookie\": CookieMiddleware.cookify(...getWithTimeout(tokenMap, token)!)\n\t\t\t}).end();\n\t\t\n\t\treturn false;\n\t};\n\t\n\t\n\tstatic make({ name, value, maxAge, expiresAt, domain, path = \"/\", secure = true, httpOnly = true, sameSite = \"Strict\" }: MakeArg) {\n\t\tconst cookie = [ `${name}=${value}` ];\n\t\t\n\t\tif (maxAge !== undefined)\n\t\t\tcookie.push(`Max-Age=${maxAge}`);\n\t\telse if (expiresAt)\n\t\t\tcookie.push(`Max-Age=${Math.round((expiresAt.getTime() - Date.now()) / 1000)}`);\n\t\t\n\t\tif (domain)\n\t\t\tcookie.push(`Domain=${domain}`);\n\t\t\n\t\tif (path)\n\t\t\tcookie.push(`Path=${path}`);\n\t\t\n\t\tif (secure)\n\t\t\tcookie.push(\"Secure\");\n\t\t\n\t\tif (httpOnly)\n\t\t\tcookie.push(\"HttpOnly\");\n\t\t\n\t\tif (sameSite)\n\t\t\tcookie.push(`SameSite=${sameSite}`);\n\t\t\n\t\treturn cookie.join(\"; \");\n\t}\n\t\n\tstatic cookify(cookie: Cookie, options: CookieOptions) {\n\t\treturn Object.entries(cookie).map(([ name, value ]) => this.make({ name, value, ...options }));\n\t}\n\t\n}\n", "import type { Cookie, CookieOptions } from \"./types\";\n\n\nexport const tokenMap = new Map<string, [ cookie: Cookie, options: CookieOptions ]>();\n", "export function parseCookie(cookie: string) {\n\treturn cookie ? cookie.split(/;\\s*/).reduce((object, keyEqValue) => {\n\t\tconst [ key, value ] = keyEqValue.split(/=/);\n\t\t\n\t\ttry {\n\t\t\tobject[key] = JSON.parse(value);\n\t\t} catch {\n\t\t\tobject[key] = value;\n\t\t}\n\t\t\n\t\treturn object;\n\t}, {} as Record<string, unknown>) : {};\n}\n", "import crypto from \"node:crypto\";\nimport type { IncomingMessage } from \"node:http\";\nimport { random, setWithTimeout } from \"@nesvet/n\";\nimport type { AbilitiesSchema } from \"insite-common\";\nimport type { UsersServer, WSSCWithUser } from \"insite-users-server-ws\";\nimport { headers } from \"../common\";\nimport { parseCookie } from \"./parse\";\nimport { tokenMap } from \"./tokenMap\";\nimport type { Cookie, CookieOptions } from \"./types\";\n\n\nconst cookieTokenTimeout = 2000;\n\nexport type Options<AS extends AbilitiesSchema> = {\n\tusersServer: UsersServer<AS>;\n\tdomain?: string;\n\tmaxAge?: number;\n};\n\n\nexport class CookieSetter<AS extends AbilitiesSchema> {\n\tconstructor({ usersServer, domain, maxAge }: Options<AS>) {\n\t\tthis.usersServer = usersServer;\n\t\tthis.domain = domain ?? process.env.INSITE_HOST;\n\t\tthis.maxAge = maxAge ?? this.usersServer.users.sessions.collection.expireAfterSeconds;\n\t\t\n\t\tthis.usersServer.wss.on(\"client-connect\", this.#handleClientConnect);\n\t\tthis.usersServer.wss.on(\"client-session\", this.#handleClientSession);\n\t\t\n\t}\n\t\n\t#wsSessionIdMap = new WeakMap<WSSCWithUser<AS>, string | null>();\n\t\n\tusersServer;\n\tdomain;\n\tmaxAge;\n\t\n\tset(wssc: WSSCWithUser<AS>, cookie: Cookie, options: CookieOptions) {\n\t\t\n\t\tconst token = `${Math.round(performance.now() * Number.MAX_SAFE_INTEGER).toString(36)}$${crypto.randomBytes(random(4, 8)).toString(\"hex\")}`;\n\t\t\n\t\tsetWithTimeout(tokenMap, token, [ cookie, options ], cookieTokenTimeout);\n\t\t\n\t\twssc.sendMessage(headers.set, token);\n\t\t\n\t}\n\t\n\tunset(wssc: WSSCWithUser<AS>, names: string[]) {\n\t\tthis.set(wssc, names.reduce((cookie, name) => {\n\t\t\tcookie[name] = \"\";\n\t\t\t\n\t\t\treturn cookie;\n\t\t}, {} as Cookie), { domain: this.domain, maxAge: 0 });\n\t\t\n\t}\n\t\n\t#handleClientConnect = (wssc: WSSCWithUser<AS>, request: IncomingMessage) => {\n\t\tthis.#wsSessionIdMap.set(wssc, null);\n\t\t\n\t\tif (request.headers.cookie) {\n\t\t\tconst { sessionId = null } = parseCookie(request.headers.cookie) as { sessionId: string | null };\n\t\t\t\n\t\t\tthis.#wsSessionIdMap.set(wssc, sessionId);\n\t\t\t\n\t\t\tif (sessionId)\n\t\t\t\tthis.usersServer.setSession(wssc, sessionId, true);\n\t\t}\n\t\t\n\t};\n\t\n\t#handleClientSession = (wssc: WSSCWithUser<AS>) => {\n\t\tif (this.#wsSessionIdMap.get(wssc) !== wssc.session?._id) {\n\t\t\tthis.#wsSessionIdMap.set(wssc, wssc.session?._id ?? null);\n\t\t\t\n\t\t\tif (wssc.isOpen && wssc.session)\n\t\t\t\tthis.set(wssc, { sessionId: wssc.session._id }, { domain: this.domain, maxAge: this.maxAge });\n\t\t\telse\n\t\t\t\tthis.unset(wssc, [ \"sessionId\" ]);\n\t\t}\n\t\t\n\t};\n\t\n\t\n\tstatic parse = parseCookie;\n\t\n}\n", "export const headers = {\n\tset: \"~setcookie\"\n};\n\nexport type Method = \"GET\" | \"POST\";\n"],
5
- "mappings": "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",
6
- "names": ["noop", "nativesMap", "StatefulPromise", "_StatefulPromise", "executor", "options", "nativeResolve", "nativeReject", "resolve", "reject", "abortListener", "timeout", "value", "native", "reason", "_", "debounce", "callback", "limit", "options", "leading", "trailing", "maxWait", "timeout", "maxWaitTimeout", "end", "context", "args", "initial", "final", "result", "expired", "n", "debounced", "maxWaitExpired", "run", "error", "_args", "StatefulPromise", "resolve", "reject", "noop", "shouldRun", "timeoutsMapMap", "cleanup", "map", "key", "timeoutsMap", "timeout", "setup", "ms", "getWithTimeout", "map", "key", "value", "cleanup", "howmuch", "number", "one", "two", "five", "shouldPrintNumber", "u", "d", "random", "from", "to", "setWithTimeout", "map", "key", "value", "ms", "setup", "ClassMiddleware", "tokenMap", "CookieMiddleware", "_CookieMiddleware", "ClassMiddleware", "options", "path", "#handler", "request", "response", "token", "tokenMap", "getWithTimeout", "name", "value", "maxAge", "expiresAt", "domain", "secure", "httpOnly", "sameSite", "cookie", "parseCookie", "cookie", "object", "keyEqValue", "key", "value", "crypto", "headers", "cookieTokenTimeout", "CookieSetter", "usersServer", "domain", "maxAge", "#handleClientConnect", "#handleClientSession", "#wsSessionIdMap", "wssc", "cookie", "options", "token", "crypto", "random", "setWithTimeout", "tokenMap", "headers", "names", "name", "request", "sessionId", "parseCookie"]
3
+ "sources": ["../../src/server/Middleware.ts", "../../src/server/tokenMap.ts", "../../src/server/parse.ts", "../../src/server/Setter.ts", "../../src/common.ts"],
4
+ "sourcesContent": ["import { getWithTimeout } from \"@nesvet/n\";\nimport { ClassMiddleware, type RequestHandler } from \"insite-http\";\nimport { tokenMap } from \"./tokenMap\";\nimport type { Cookie, CookieOptions } from \"./types\";\n\n\ntype Options = {\n\tpath?: RegExp | string;\n};\n\nexport type { Options as CookieMiddlewareOptions };\n\ntype MakeArg = CookieOptions & {\n\tname: keyof Cookie;\n\tvalue: Cookie[keyof Cookie];\n};\n\n\nexport class CookieMiddleware extends ClassMiddleware {\n\tconstructor(options: Options = {}) {\n\t\tsuper();\n\t\t\n\t\tconst {\n\t\t\tpath = \"/cookie\"\n\t\t} = options;\n\t\t\n\t\tthis.listeners = {\n\t\t\tGET: [ [ path, this.#handler ] ]\n\t\t};\n\t\t\n\t}\n\t\n\t#handler: RequestHandler = (request, response) => {\n\t\tconst token = request.querystring;\n\t\t\n\t\tif (token && tokenMap.has(token))\n\t\t\treturn response.writeHead(200, {\n\t\t\t\t\"Content-Type\": \"text/plain; charset=utf-8\",\n\t\t\t\t\"Set-Cookie\": CookieMiddleware.cookify(...getWithTimeout(tokenMap, token)!)\n\t\t\t}).end();\n\t\t\n\t\treturn false;\n\t};\n\t\n\t\n\tstatic make({ name, value, maxAge, expiresAt, domain, path = \"/\", secure = true, httpOnly = true, sameSite = \"Strict\" }: MakeArg) {\n\t\tconst cookie = [ `${name}=${value}` ];\n\t\t\n\t\tif (maxAge !== undefined)\n\t\t\tcookie.push(`Max-Age=${maxAge}`);\n\t\telse if (expiresAt)\n\t\t\tcookie.push(`Max-Age=${Math.round((expiresAt.getTime() - Date.now()) / 1000)}`);\n\t\t\n\t\tif (domain)\n\t\t\tcookie.push(`Domain=${domain}`);\n\t\t\n\t\tif (path)\n\t\t\tcookie.push(`Path=${path}`);\n\t\t\n\t\tif (secure)\n\t\t\tcookie.push(\"Secure\");\n\t\t\n\t\tif (httpOnly)\n\t\t\tcookie.push(\"HttpOnly\");\n\t\t\n\t\tif (sameSite)\n\t\t\tcookie.push(`SameSite=${sameSite}`);\n\t\t\n\t\treturn cookie.join(\"; \");\n\t}\n\t\n\tstatic cookify(cookie: Cookie, options: CookieOptions) {\n\t\treturn Object.entries(cookie).map(([ name, value ]) => this.make({ name, value, ...options }));\n\t}\n\t\n}\n", "import type { Cookie, CookieOptions } from \"./types\";\n\n\nexport const tokenMap = new Map<string, [ cookie: Cookie, options: CookieOptions ]>();\n", "export function parseCookie(cookie: string) {\n\treturn cookie ? cookie.split(/;\\s*/).reduce((object, keyEqValue) => {\n\t\tconst [ key, value ] = keyEqValue.split(/=/);\n\t\t\n\t\ttry {\n\t\t\tobject[key] = JSON.parse(value);\n\t\t} catch {\n\t\t\tobject[key] = value;\n\t\t}\n\t\t\n\t\treturn object;\n\t}, {} as Record<string, unknown>) : {};\n}\n", "import crypto from \"node:crypto\";\nimport type { IncomingMessage } from \"node:http\";\nimport { random, setWithTimeout } from \"@nesvet/n\";\nimport type { AbilitiesSchema } from \"insite-common\";\nimport type { UsersServer, WSSCWithUser } from \"insite-users-server-ws\";\nimport { headers } from \"../common\";\nimport { parseCookie } from \"./parse\";\nimport { tokenMap } from \"./tokenMap\";\nimport type { Cookie, CookieOptions } from \"./types\";\n\n\nconst cookieTokenTimeout = 2000;\n\nexport type Options<AS extends AbilitiesSchema> = {\n\tusersServer: UsersServer<AS>;\n\tdomain?: string;\n\tmaxAge?: number;\n};\n\n\nexport class CookieSetter<AS extends AbilitiesSchema> {\n\tconstructor({ usersServer, domain, maxAge }: Options<AS>) {\n\t\tthis.usersServer = usersServer;\n\t\tthis.domain = domain ?? process.env.INSITE_HOST;\n\t\tthis.maxAge = maxAge ?? this.usersServer.users.sessions.collection.expireAfterSeconds;\n\t\t\n\t\tthis.usersServer.wss.on(\"client-connect\", this.#handleClientConnect);\n\t\tthis.usersServer.wss.on(\"client-session\", this.#handleClientSession);\n\t\t\n\t}\n\t\n\t#wsSessionIdMap = new WeakMap<WSSCWithUser<AS>, string | null>();\n\t\n\tusersServer;\n\tdomain;\n\tmaxAge;\n\t\n\tset(wssc: WSSCWithUser<AS>, cookie: Cookie, options: CookieOptions) {\n\t\t\n\t\tconst token = `${Math.round(performance.now() * Number.MAX_SAFE_INTEGER).toString(36)}$${crypto.randomBytes(random(4, 8)).toString(\"hex\")}`;\n\t\t\n\t\tsetWithTimeout(tokenMap, token, [ cookie, options ], cookieTokenTimeout);\n\t\t\n\t\twssc.sendMessage(headers.set, token);\n\t\t\n\t}\n\t\n\tunset(wssc: WSSCWithUser<AS>, names: string[]) {\n\t\tthis.set(wssc, names.reduce((cookie, name) => {\n\t\t\tcookie[name] = \"\";\n\t\t\t\n\t\t\treturn cookie;\n\t\t}, {} as Cookie), { domain: this.domain, maxAge: 0 });\n\t\t\n\t}\n\t\n\t#handleClientConnect = (wssc: WSSCWithUser<AS>, request: IncomingMessage) => {\n\t\tthis.#wsSessionIdMap.set(wssc, null);\n\t\t\n\t\tif (request.headers.cookie) {\n\t\t\tconst { sessionId = null } = parseCookie(request.headers.cookie) as { sessionId: string | null };\n\t\t\t\n\t\t\tthis.#wsSessionIdMap.set(wssc, sessionId);\n\t\t\t\n\t\t\tif (sessionId)\n\t\t\t\tthis.usersServer.setSession(wssc, sessionId, true);\n\t\t}\n\t\t\n\t};\n\t\n\t#handleClientSession = (wssc: WSSCWithUser<AS>) => {\n\t\tif (this.#wsSessionIdMap.get(wssc) !== wssc.session?._id) {\n\t\t\tthis.#wsSessionIdMap.set(wssc, wssc.session?._id ?? null);\n\t\t\t\n\t\t\tif (wssc.isOpen && wssc.session)\n\t\t\t\tthis.set(wssc, { sessionId: wssc.session._id }, { domain: this.domain, maxAge: this.maxAge });\n\t\t\telse\n\t\t\t\tthis.unset(wssc, [ \"sessionId\" ]);\n\t\t}\n\t\t\n\t};\n\t\n\t\n\tstatic parse = parseCookie;\n\t\n}\n", "export const headers = {\n\tset: \"~setcookie\"\n};\n\nexport type Method = \"GET\" | \"POST\";\n"],
5
+ "mappings": "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",
6
+ "names": ["getWithTimeout", "ClassMiddleware", "tokenMap", "CookieMiddleware", "_CookieMiddleware", "ClassMiddleware", "options", "path", "#handler", "request", "response", "token", "tokenMap", "getWithTimeout", "name", "value", "maxAge", "expiresAt", "domain", "secure", "httpOnly", "sameSite", "cookie", "parseCookie", "cookie", "object", "keyEqValue", "key", "value", "crypto", "random", "setWithTimeout", "headers", "cookieTokenTimeout", "CookieSetter", "usersServer", "domain", "maxAge", "#handleClientConnect", "#handleClientSession", "#wsSessionIdMap", "wssc", "cookie", "options", "token", "crypto", "random", "setWithTimeout", "tokenMap", "headers", "names", "name", "request", "sessionId", "parseCookie"]
7
7
  }
package/package.json CHANGED
@@ -1,44 +1,55 @@
1
1
  {
2
- "name": "insite-cookie",
3
- "version": "2.3.5",
4
- "description": "Cookie support for inSite",
5
- "type": "module",
6
- "main": "./dist/server.js",
7
- "module": "./dist/server.js",
8
- "exports": {
9
- "./server": "./dist/server/index.js",
10
- "./client": "./dist/client/index.js"
11
- },
12
- "packageManager": "bun@1.2.21",
13
- "scripts": {
14
- "test": "echo \"Error: no test specified\" && exit 1",
15
- "build": "bun .conveyer.js",
16
- "postbuild": "tsc -p ."
17
- },
18
- "repository": {
19
- "type": "git",
20
- "url": "git+https://github.com/nesvet/insite-cookie.git"
21
- },
22
- "keywords": [
23
- "insite",
24
- "cookie",
25
- "client",
26
- "server"
27
- ],
28
- "author": "Eugene Nesvetaev <dev@nesvet.dev> (https://nesvet.dev/)",
29
- "license": "MIT",
30
- "dependencies": {
31
- "@nesvet/n": "^1.2.1",
32
- "insite-common": "^2.3.5",
33
- "insite-http": "^2.3.5",
34
- "insite-users-server-ws": "^2.3.5",
35
- "insite-ws": "^2.3.5"
36
- },
37
- "devDependencies": {
38
- "@nesvet/eslint-config": "^2.1.2",
39
- "@types/node": "^24.3.1",
40
- "@types/ws": "^8.18.1",
41
- "cnvr": "^2.7.2",
42
- "typescript": "^5.9.2"
43
- }
2
+ "name": "insite-cookie",
3
+ "version": "2.5.0",
4
+ "description": "Cookie-based auth for inSite (client + server)",
5
+ "keywords": [
6
+ "insite",
7
+ "cookie",
8
+ "auth",
9
+ "session"
10
+ ],
11
+ "homepage": "https://github.com/nesvet/insite#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/nesvet/insite/issues"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/nesvet/insite.git",
18
+ "directory": "packages/cookie"
19
+ },
20
+ "funding": {
21
+ "type": "patreon",
22
+ "url": "https://www.patreon.com/nesvet"
23
+ },
24
+ "license": "MIT",
25
+ "author": "Eugene Nesvetaev <dev@nesvet.dev> (https://nesvet.dev/)",
26
+ "type": "module",
27
+ "exports": {
28
+ "./server": "./dist/server/index.js",
29
+ "./client": "./dist/client/index.js"
30
+ },
31
+ "main": "./dist/server.js",
32
+ "module": "./dist/server.js",
33
+ "files": [
34
+ "dist",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "scripts": {
39
+ "build": "bun .conveyer.js",
40
+ "postbuild": "tsc -p .",
41
+ "clean": "rm -rf dist",
42
+ "test": "echo \"Error: no test specified\" && exit 1",
43
+ "typecheck": "tsc --noEmit"
44
+ },
45
+ "dependencies": {
46
+ "@nesvet/n": "^1.2.1",
47
+ "insite-common": "^2.5.0",
48
+ "insite-http": "^2.5.0",
49
+ "insite-users-server-ws": "^2.5.0",
50
+ "insite-ws": "^2.5.0"
51
+ },
52
+ "engines": {
53
+ "node": ">=20.0.0"
54
+ }
44
55
  }