@agimon-ai/foundation-port-registry 0.29.0 → 0.29.2
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.
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`node:crypto`),l=require(`node:fs/promises`);l=s(l,1);let u=require(`node:net`);u=s(u,1);let d=require(`node:os`);d=s(d,1);let f=require(`node:path`);f=s(f,1);let p=require(
|
|
1
|
+
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`node:crypto`),l=require(`node:fs/promises`);l=s(l,1);let u=require(`node:net`);u=s(u,1);let d=require(`node:os`);d=s(d,1);let f=require(`node:path`);f=s(f,1);let p=require(`zod`);const m=p.z.enum([`service`,`tool`]),h=p.z.record(p.z.string(),p.z.unknown()),g=p.z.object({repositoryPath:p.z.string().trim().min(1,`repositoryPath is required`),serviceName:p.z.string().trim().min(1,`serviceName is required`),serviceType:m,environment:p.z.string().trim().min(1).optional(),pid:p.z.number().int().min(1).optional(),port:p.z.number().int().min(1).max(65535),host:p.z.string().trim().min(1).default(`127.0.0.1`),metadata:h.optional(),createdAt:p.z.string().trim().min(1),updatedAt:p.z.string().trim().min(1)}),_=p.z.object({version:p.z.literal(1),updatedAt:p.z.string().trim().min(1),entries:p.z.array(g)}),v=p.z.object({min:p.z.number().int().min(1).max(65535),max:p.z.number().int().min(1).max(65535)}).refine(e=>e.min<=e.max,{message:`Port range min must be less than or equal to max`,path:[`min`]}),y=p.z.object({repositoryPath:p.z.string().trim().min(1),serviceName:p.z.string().trim().min(1),serviceType:m.default(`service`),environment:p.z.string().trim().min(1).optional(),pid:p.z.number().int().min(1).optional(),portRange:v.optional(),preferredPort:p.z.number().int().min(1).max(65535).optional(),host:p.z.string().trim().min(1).optional(),metadata:h.optional(),force:p.z.boolean().optional()}),b=`__claim`,x=45e3,S=p.z.object({token:p.z.string().min(1),ownerPid:p.z.number().int().min(1),expiresAt:p.z.string().trim().min(1)}),C=y.omit({force:!0}).extend({claimTtlMs:p.z.number().int().min(1e3).max(6e5).default(x)}),w=p.z.object({success:p.z.boolean(),outcome:p.z.enum([`claimed`,`existing`]).optional(),port:p.z.number().int().min(1).max(65535).optional(),record:g.optional(),claimToken:p.z.string().optional(),claimPending:p.z.boolean().optional(),error:p.z.string().optional()}),T=p.z.object({repositoryPath:p.z.string().trim().min(1),serviceName:p.z.string().trim().min(1),serviceType:m.default(`service`),environment:p.z.string().trim().min(1).optional(),claimToken:p.z.string().min(1),pid:p.z.number().int().min(1),metadata:h.optional()}),E=p.z.object({repositoryPath:p.z.string().trim().min(1),serviceName:p.z.string().trim().min(1),serviceType:m.default(`service`),environment:p.z.string().trim().min(1).optional(),claimToken:p.z.string().min(1)}),D=p.z.object({repositoryPath:p.z.string().trim().min(1),serviceName:p.z.string().trim().min(1),serviceType:m.optional(),pid:p.z.number().int().min(1).optional(),environment:p.z.string().trim().min(1).optional(),force:p.z.boolean().optional()}),O=p.z.object({repositoryPath:p.z.string().trim().min(1),serviceName:p.z.string().trim().min(1),serviceType:m.optional(),environment:p.z.string().trim().min(1).optional()}),k=p.z.object({repositoryPath:p.z.string().trim().min(1),serviceName:p.z.string().trim().min(1),serviceType:m.optional(),environment:p.z.string().trim().min(1).optional(),portRange:v.optional(),preferredPort:p.z.number().int().min(1).max(65535).optional(),host:p.z.string().trim().min(1).default(`127.0.0.1`)}),A=p.z.object({success:p.z.boolean(),port:p.z.number().int().min(1).max(65535).optional(),record:g.optional(),error:p.z.string().optional()}),j=p.z.object({repositoryPath:p.z.string().trim().min(1).optional(),serviceType:m.optional(),serviceName:p.z.string().trim().min(1).optional(),environment:p.z.string().trim().min(1).optional()}),M=j.extend({pid:p.z.number().int().min(1).optional(),force:p.z.boolean().optional()}),N=p.z.object({success:p.z.boolean(),scanned:p.z.number().int().min(0),removed:p.z.number().int().min(0),error:p.z.string().optional()}),P=p.z.object({success:p.z.boolean(),released:p.z.number().int().min(0),error:p.z.string().optional()});var F=class extends Error{code;constructor(e,t,n){super(e,n),this.name=`PortRegistryError`,this.code=t}};const I=f.default.join(d.default.homedir(),`.port-registry`,`ports.turso.sqlite`),L=`${I}.lock`,R={min:3e3,max:4999},z=e=>f.default.resolve(e),B=(e,t)=>e>=t.min&&e<=t.max,V=`port_allocations`,H=`registry_metadata`,U=`legacy_json_import_v1`,W=6e3,G=new Map;var K=class e{registryPath;legacyRegistryPath;sqlite=null;initialization=null;constructor(t=I,n){this.registryPath=e.resolveRegistryPath(t),this.legacyRegistryPath=e.resolveLegacyRegistryPath(t)}static resolveRegistryPath(t){let n=e.resolveInputPath(t??I),r=f.default.extname(n);return r===`.json`?n.slice(0,-r.length)+`.sqlite`:r===`.sqlite`||r===`.db`?n:f.default.join(n,`ports.sqlite`)}async getPort(e){let t=O.parse(e),n=await this.getDb(),r=this.normalizeListFilters(t),i=this.buildWhereClause(r),a=n.prepare(`SELECT * FROM ${V}${i.sql} ORDER BY id LIMIT 1`).get(...i.params);if(!a)return this.createFailureResponse(`No allocation found for ${t.serviceName} in requested scope`);let o=this.toRecord(a);return this.createSuccessResponse(o.port,o)}async findAvailablePort(e){let t=k.parse(e),n=await this.getDb(),r=t.portRange??R,i=this.getReservedPorts(n),a=await this.findAvailablePortInternal(r,t.preferredPort,i,t.host);return a===null?this.createFailureResponse(`No available port found in range ${r.min}-${r.max}`):this.createSuccessResponse(a)}async reservePort(e){let t=y.parse(e),n=await this.getDb(),r=z(t.repositoryPath),i=t.serviceType??`service`,a=t.environment??process.env.NODE_ENV??`development`,o=t.host??`127.0.0.1`,s=t.portRange??R,c=t.force??!1;return this.withImmediateTransaction(n,async()=>{let e=n.prepare(`SELECT * FROM ${V}
|
|
2
2
|
WHERE repository_path = ? AND service_name = ? AND service_type = ? AND environment = ?
|
|
3
|
-
LIMIT 1`).get(r,t.serviceName,i,a);if(e&&!c&&
|
|
3
|
+
LIMIT 1`).get(r,t.serviceName,i,a);if(e&&!c&&B(e.port,s)&&await this.isPortAvailable(e.port,o)){let t=new Date().toISOString();n.prepare(`UPDATE ${V} SET updated_at = ? WHERE id = ?`).run(t,e.id);let r=this.toRecord({...e,updated_at:t});return this.createSuccessResponse(r.port,r)}e&&n.prepare(`DELETE FROM ${V} WHERE id = ?`).run(e.id);let l=this.getReservedPorts(n),u=await this.findAvailablePortInternal(s,t.preferredPort,l,o);if(u===null)return this.createFailureResponse(`No available port found in range ${s.min}-${s.max}`);let d=new Date().toISOString(),f=n.prepare(`INSERT INTO ${V} (
|
|
4
4
|
repository_path, service_name, service_type, environment, pid, port, host,
|
|
5
5
|
metadata_json, created_at, updated_at
|
|
6
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(r,t.serviceName,i,a,t.pid??null,u,o,t.metadata?JSON.stringify(t.metadata):null,d,d),p=n.prepare(`SELECT * FROM ${
|
|
6
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(r,t.serviceName,i,a,t.pid??null,u,o,t.metadata?JSON.stringify(t.metadata):null,d,d),p=n.prepare(`SELECT * FROM ${V} WHERE id = ?`).get(Number(f.lastInsertRowid)),m=this.toRecord(p);return this.createSuccessResponse(m.port,m)})}async claimPort(e){let t=C.parse(e),n=await this.getDb(),r=z(t.repositoryPath),i=t.serviceType??`service`,a=t.environment??process.env.NODE_ENV??`development`,o=t.host??`127.0.0.1`,s=t.portRange??R,l=t.pid??process.pid;return this.withImmediateTransaction(n,async()=>{let e=this.selectScopeRow(n,r,t.serviceName,i,a);if(e){let t=this.readClaim(e);if(!t)return this.createClaimResponse({outcome:`existing`,record:this.toRecord(e)});if(this.isClaimActive(t))return this.createClaimResponse({outcome:`existing`,claimPending:!0,record:this.toRecord(e)});n.prepare(`DELETE FROM ${V} WHERE id = ?`).run(e.id)}let u=new Set;for(let e=0;e<3;e+=1){let e=this.getReservedPorts(n);for(let t of u)e.add(t);let d=await this.findAvailablePortInternal(s,t.preferredPort,e,o);if(d===null)return this.createClaimFailure(`No available port found in range ${s.min}-${s.max}`);let f={token:(0,c.randomUUID)(),ownerPid:l,expiresAt:new Date(Date.now()+t.claimTtlMs).toISOString()},p=new Date().toISOString();try{let e=n.prepare(`INSERT INTO ${V} (
|
|
7
7
|
repository_path, service_name, service_type, environment, pid, port, host,
|
|
8
8
|
metadata_json, created_at, updated_at
|
|
9
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(r,t.serviceName,i,a,l,d,o,JSON.stringify({...t.metadata??{},[
|
|
10
|
-
CREATE TABLE IF NOT EXISTS ${
|
|
9
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(r,t.serviceName,i,a,l,d,o,JSON.stringify({...t.metadata??{},[b]:f}),p,p),s=this.selectRowById(n,Number(e.lastInsertRowid));return this.createClaimResponse({outcome:`claimed`,record:this.toRecord(s),claimToken:f.token})}catch(e){if(!this.isUniqueConstraintError(e))throw e;u.add(d)}}return this.createClaimFailure(`Failed to claim a port after 3 attempts`)})}async confirmPort(e){let t=T.parse(e),n=await this.getDb(),r=z(t.repositoryPath),i=t.serviceType??`service`,a=t.environment??process.env.NODE_ENV??`development`;return this.withImmediateTransaction(n,async()=>{let e=this.selectScopeRow(n,r,t.serviceName,i,a),o=e?this.readClaim(e):void 0;if(!e||!o||o.token!==t.claimToken)return this.createFailureResponse(`Claim not found or expired for ${t.serviceName}`);let s={...this.readMetadata(e),...t.metadata??{}};delete s[b];let c=new Date().toISOString();n.prepare(`UPDATE ${V} SET pid = ?, metadata_json = ?, updated_at = ? WHERE id = ?`).run(t.pid,Object.keys(s).length>0?JSON.stringify(s):null,c,e.id);let l=this.toRecord(this.selectRowById(n,e.id));return this.createSuccessResponse(l.port,l)})}async releaseClaim(e){let t=E.parse(e),n=await this.getDb(),r=z(t.repositoryPath),i=t.serviceType??`service`,a=t.environment??process.env.NODE_ENV??`development`;return this.withImmediateTransaction(n,async()=>{let e=this.selectScopeRow(n,r,t.serviceName,i,a),o=e?this.readClaim(e):void 0;return e&&o?.token===t.claimToken&&n.prepare(`DELETE FROM ${V} WHERE id = ?`).run(e.id),this.createSuccessResponse()})}async releasePort(e){let t=D.parse(e);return(await this.releasePorts(t)).success?this.createSuccessResponse():this.createFailureResponse(`No matching registry entry for ${t.serviceName}`)}async releasePorts(e){let t=M.parse(e),n=await this.getDb(),r=this.normalizeReleaseFilters(t),i=this.buildWhereClause(r,!0),a=n.prepare(`DELETE FROM ${V}${i.sql}`).run(...i.params);return a.changes===0?P.parse({success:!1,released:0,error:`No matching registry entries`}):P.parse({success:!0,released:a.changes})}async listAllocations(e={}){let t=j.parse(e),n=await this.getDb(),r=this.buildWhereClause(this.normalizeListFilters(t));return n.prepare(`SELECT * FROM ${V}${r.sql} ORDER BY id`).all(...r.params).map(e=>this.toRecord(e))}async cleanupStaleAllocations(e={}){let t=j.parse(e),n=await this.getDb(),r=this.buildWhereClause(this.normalizeListFilters(t)),i=n.prepare(`SELECT * FROM ${V}${r.sql}`).all(...r.params),a=[];return await Promise.all(i.map(async e=>{let t=this.readClaim(e);if(t){this.isClaimActive(t)||a.push(e.id);return}let n=await this.pathExists(e.repository_path),r=typeof e.pid==`number`&&!this.isProcessRunning(e.pid);(!n||r)&&a.push(e.id)})),a.length>0&&n.transaction(e=>{let t=n.prepare(`DELETE FROM ${V} WHERE id = ?`);for(let n of e)t.run(n)})(a),N.parse({success:!0,scanned:i.length,removed:a.length})}close(){this.sqlite?.close(),this.sqlite=null,this.initialization=null}static resolveInputPath(e){return f.default.isAbsolute(e)?e:f.default.join(process.cwd(),e)}static resolveLegacyRegistryPath(t){let n=e.resolveInputPath(t),r=f.default.extname(n);return r===`.json`?n:r===`.sqlite`||r===`.db`?n.slice(0,-r.length)+`.json`:f.default.join(n,`ports.json`)}async getDb(){return this.sqlite?this.sqlite:(this.initialization||=this.initializeDatabase(),this.initialization)}async initializeDatabase(){await l.default.mkdir(f.default.dirname(this.registryPath),{recursive:!0});let{Database:e}=await import(`@tursodatabase/database/compat`);for(let t=1;t<=8;t+=1){let n=null;try{return n=new e(this.registryPath,{experimental:[`multiprocess_wal`],timeout:W}),n.pragma(`busy_timeout = ${W}`,{}),n.pragma(`journal_mode = WAL`,{}),n.pragma(`synchronous = NORMAL`,{}),n.exec(`
|
|
10
|
+
CREATE TABLE IF NOT EXISTS ${H} (
|
|
11
11
|
key TEXT PRIMARY KEY,
|
|
12
12
|
value TEXT NOT NULL
|
|
13
13
|
);
|
|
14
|
-
CREATE TABLE IF NOT EXISTS ${
|
|
14
|
+
CREATE TABLE IF NOT EXISTS ${V} (
|
|
15
15
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
16
16
|
repository_path TEXT NOT NULL,
|
|
17
17
|
service_name TEXT NOT NULL,
|
|
@@ -26,13 +26,13 @@ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=
|
|
|
26
26
|
UNIQUE (repository_path, service_name, service_type, environment)
|
|
27
27
|
);
|
|
28
28
|
CREATE INDEX IF NOT EXISTS port_allocations_scope_idx
|
|
29
|
-
ON ${
|
|
29
|
+
ON ${V} (repository_path, service_name, service_type, environment);
|
|
30
30
|
CREATE INDEX IF NOT EXISTS port_allocations_environment_idx
|
|
31
|
-
ON ${
|
|
32
|
-
`),this.sqlite=
|
|
31
|
+
ON ${V} (environment, service_type);
|
|
32
|
+
`),this.sqlite=n,await this.importLegacyJson(n),n}catch(e){if(n?.close(),this.sqlite=null,!this.isDatabaseBusyError(e)||t===8)throw this.initialization=null,new F(`Failed to initialize registry database: ${e instanceof Error?e.message:String(e)}`,`REGISTRY_READ_FAILED`,{cause:e});await new Promise(e=>setTimeout(e,25*2**(t-1)))}}throw Error(`Unreachable database initialization state`)}isDatabaseBusyError(e){let t=e?.code;return t===`SQLITE_BUSY`||t===`SQLITE_LOCKED`}async importLegacyJson(e){if(e.prepare(`SELECT value FROM ${H} WHERE key = ?`).get(U))return;let t=null;try{let e=await l.default.readFile(this.legacyRegistryPath,`utf-8`);t=_.parse(JSON.parse(e))}catch(e){if(e.code!==`ENOENT`)throw e}e.transaction(t=>{let n=e.prepare(`INSERT OR IGNORE INTO ${V} (
|
|
33
33
|
repository_path, service_name, service_type, environment, pid, port, host,
|
|
34
34
|
metadata_json, created_at, updated_at
|
|
35
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);for(let e of t?.entries??[])n.run(
|
|
35
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);for(let e of t?.entries??[])n.run(z(e.repositoryPath),e.serviceName,e.serviceType,e.environment??``,e.pid??null,e.port,e.host,e.metadata?JSON.stringify(e.metadata):null,e.createdAt,e.updatedAt);e.prepare(`INSERT OR REPLACE INTO ${H} (key, value) VALUES (?, ?)`).run(U,this.legacyRegistryPath)})(t)}async withImmediateTransaction(e,t){let n=G.get(this.registryPath)??Promise.resolve(),r=()=>void 0,i=new Promise(e=>{r=e}),a=n.catch(()=>void 0).then(()=>i);G.set(this.registryPath,a),await n.catch(()=>void 0);try{e.exec(`BEGIN IMMEDIATE`);try{let n=await t();return e.exec(`COMMIT`),n}catch(t){throw e.inTransaction&&e.exec(`ROLLBACK`),t}}finally{r(),G.get(this.registryPath)===a&&G.delete(this.registryPath)}}normalizeListFilters(e){return{...e.repositoryPath?{repositoryPath:z(e.repositoryPath)}:{},...e.serviceName?{serviceName:e.serviceName}:{},...e.serviceType?{serviceType:e.serviceType}:{},...e.environment?{environment:e.environment}:{}}}normalizeReleaseFilters(e){return{...this.normalizeListFilters(e),...typeof e.pid==`number`?{pid:e.pid}:{},...typeof e.force==`boolean`?{force:e.force}:{}}}buildWhereClause(e,t=!1){let n=[],r=[],i=(e,t)=>{t!==void 0&&(n.push(`${e} = ?`),r.push(t))};return i(`repository_path`,e.repositoryPath),i(`service_name`,e.serviceName),i(`service_type`,e.serviceType),i(`environment`,e.environment),t&&typeof e.pid==`number`&&!e.force&&i(`pid`,e.pid),{sql:n.length>0?` WHERE ${n.join(` AND `)}`:``,params:r}}selectScopeRow(e,t,n,r,i){return e.prepare(`SELECT * FROM ${V}
|
|
36
36
|
WHERE repository_path = ? AND service_name = ? AND service_type = ? AND environment = ?
|
|
37
|
-
LIMIT 1`).get(t,n,r,i)}selectRowById(e,t){return e.prepare(`SELECT * FROM ${
|
|
37
|
+
LIMIT 1`).get(t,n,r,i)}selectRowById(e,t){return e.prepare(`SELECT * FROM ${V} WHERE id = ?`).get(t)}readMetadata(e){if(!e.metadata_json)return{};let t=JSON.parse(e.metadata_json);if(!t||typeof t!=`object`||Array.isArray(t))throw new F(`Stored port metadata is invalid`,`REGISTRY_READ_FAILED`);return t}readClaim(e){let t=this.readMetadata(e)[b];if(!t)return;let n=S.safeParse(t);return n.success?n.data:void 0}isClaimActive(e){return Date.parse(e.expiresAt)>Date.now()&&this.isProcessRunning(e.ownerPid)}isUniqueConstraintError(e){return e?.code===`SQLITE_CONSTRAINT_UNIQUE`}createClaimResponse(e){return w.parse({success:!0,...e,...e.record?{port:e.record.port}:{}})}createClaimFailure(e){return w.parse({success:!1,error:e})}getReservedPorts(e){let t=e.prepare(`SELECT port FROM ${V}`).all();return new Set(t.map(e=>e.port))}toRecord(e){let t=this.readMetadata(e),n=Object.keys(t).length>0?t:void 0;return g.parse({repositoryPath:e.repository_path,serviceName:e.service_name,serviceType:e.service_type,...e.environment?{environment:e.environment}:{},...e.pid?{pid:e.pid}:{},port:e.port,host:e.host,...n?{metadata:n}:{},createdAt:e.created_at,updatedAt:e.updated_at})}async findAvailablePortInternal(e,t,n,r){if(t!==void 0&&B(t,e)&&!n.has(t)&&await this.isPortAvailable(t,r))return t;for(let i=e.min;i<=e.max;i+=1)if(!(i===t||n.has(i))&&await this.isPortAvailable(i,r))return i;return null}async isPortAvailable(e,t){let n=d.default.platform()===`win32`?`127.0.0.1`:t,r=Array.from(new Set([n,`127.0.0.1`,`0.0.0.0`,void 0,`::1`]));for(let t of r)if(!await this.isPortAvailableOnHost(e,t))return!1;return!0}async isPortAvailableOnHost(e,t){return new Promise(n=>{let r=u.default.createServer();r.once(`error`,()=>n(!1)),r.once(`listening`,()=>r.close(()=>n(!0))),t?r.listen(e,t):r.listen(e)})}isProcessRunning(e){try{return process.kill(e,0),!0}catch{return!1}}async pathExists(e){try{return await l.default.access(e),!0}catch{return!1}}createSuccessResponse(e,t){return A.parse({success:!0,...e===void 0?{}:{port:e},...t?{record:t}:{}})}createFailureResponse(e){return A.parse({success:!1,error:e})}};Object.defineProperty(exports,`A`,{enumerable:!0,get:function(){return M}}),Object.defineProperty(exports,`C`,{enumerable:!0,get:function(){return F}}),Object.defineProperty(exports,`D`,{enumerable:!0,get:function(){return 1}}),Object.defineProperty(exports,`E`,{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,`M`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`N`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`O`,{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,`P`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`S`,{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,`T`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return I}}),Object.defineProperty(exports,`b`,{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return 5e3}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return L}}),Object.defineProperty(exports,`j`,{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,`k`,{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return B}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return`127.0.0.1`}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return 80}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return R}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return 75}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return K}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return z}}),Object.defineProperty(exports,`v`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`w`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`x`,{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,`y`,{enumerable:!0,get:function(){return A}});
|
|
38
38
|
//# sourceMappingURL=PortRegistryService.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PortRegistryService.cjs","names":["z","path","os","path","fs","Database","os","net"],"sources":["../src/types/index.ts","../src/utils/index.ts","../src/services/PortRegistryService.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport const REGISTRY_VERSION = 1 as const;\n\nexport const ServiceCategorySchema = z.enum(['service', 'tool']);\n\nexport const ServiceMetadataSchema = z.record(z.string(), z.unknown());\n\nexport const PortRegistryRecordSchema = z.object({\n repositoryPath: z.string().trim().min(1, 'repositoryPath is required'),\n serviceName: z.string().trim().min(1, 'serviceName is required'),\n serviceType: ServiceCategorySchema,\n environment: z.string().trim().min(1).optional(),\n pid: z.number().int().min(1).optional(),\n port: z.number().int().min(1).max(65535),\n host: z.string().trim().min(1).default('127.0.0.1'),\n metadata: ServiceMetadataSchema.optional(),\n createdAt: z.string().trim().min(1),\n updatedAt: z.string().trim().min(1),\n});\n\nexport const PortRegistryStateSchema = z.object({\n version: z.literal(REGISTRY_VERSION),\n updatedAt: z.string().trim().min(1),\n entries: z.array(PortRegistryRecordSchema),\n});\n\nexport const PortAllocationRangeSchema = z\n .object({\n min: z.number().int().min(1).max(65535),\n max: z.number().int().min(1).max(65535),\n })\n .refine((range) => range.min <= range.max, {\n message: 'Port range min must be less than or equal to max',\n path: ['min'],\n });\n\nexport const ReservePortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.default('service'),\n environment: z.string().trim().min(1).optional(),\n pid: z.number().int().min(1).optional(),\n portRange: PortAllocationRangeSchema.optional(),\n preferredPort: z.number().int().min(1).max(65535).optional(),\n host: z.string().trim().min(1).optional(),\n metadata: ServiceMetadataSchema.optional(),\n force: z.boolean().optional(),\n});\n\n/**\n * Reserved metadata key holding bootstrap-claim state.\n *\n * A claim turns the scope row into a cross-process mutex: the row is inserted by\n * the process that intends to spawn a service, and is only converted into a\n * normal allocation once that service confirms it is listening. Storing the\n * state in metadata avoids a schema migration for registry files already on disk.\n */\nexport const CLAIM_METADATA_KEY = '__claim' as const;\n\nexport const DEFAULT_CLAIM_TTL_MS = 45_000;\n\nexport const PortClaimSchema = z.object({\n token: z.string().min(1),\n ownerPid: z.number().int().min(1),\n expiresAt: z.string().trim().min(1),\n});\n\nexport const ClaimPortRequestSchema = ReservePortRequestSchema.omit({ force: true }).extend({\n claimTtlMs: z.number().int().min(1000).max(600_000).default(DEFAULT_CLAIM_TTL_MS),\n});\n\nexport const ClaimPortResponseSchema = z.object({\n success: z.boolean(),\n outcome: z.enum(['claimed', 'existing']).optional(),\n port: z.number().int().min(1).max(65535).optional(),\n record: PortRegistryRecordSchema.optional(),\n /** Present only when outcome is 'claimed'. Required to confirm or release the claim. */\n claimToken: z.string().optional(),\n /** True when the existing row is another process's in-flight claim rather than a live service. */\n claimPending: z.boolean().optional(),\n error: z.string().optional(),\n});\n\nexport const ConfirmPortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.default('service'),\n environment: z.string().trim().min(1).optional(),\n claimToken: z.string().min(1),\n pid: z.number().int().min(1),\n metadata: ServiceMetadataSchema.optional(),\n});\n\nexport const ReleaseClaimRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.default('service'),\n environment: z.string().trim().min(1).optional(),\n claimToken: z.string().min(1),\n});\n\nexport const ReleasePortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.optional(),\n pid: z.number().int().min(1).optional(),\n environment: z.string().trim().min(1).optional(),\n force: z.boolean().optional(),\n});\n\nexport const GetPortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.optional(),\n environment: z.string().trim().min(1).optional(),\n});\n\nexport const FindAvailablePortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.optional(),\n environment: z.string().trim().min(1).optional(),\n portRange: PortAllocationRangeSchema.optional(),\n preferredPort: z.number().int().min(1).max(65535).optional(),\n host: z.string().trim().min(1).default('127.0.0.1'),\n});\n\nexport const PortAllocationResponseSchema = z.object({\n success: z.boolean(),\n port: z.number().int().min(1).max(65535).optional(),\n record: PortRegistryRecordSchema.optional(),\n error: z.string().optional(),\n});\n\nexport const PortUsageListFiltersSchema = z.object({\n repositoryPath: z.string().trim().min(1).optional(),\n serviceType: ServiceCategorySchema.optional(),\n serviceName: z.string().trim().min(1).optional(),\n environment: z.string().trim().min(1).optional(),\n});\n\nexport const ReleasePortsRequestSchema = PortUsageListFiltersSchema.extend({\n pid: z.number().int().min(1).optional(),\n force: z.boolean().optional(),\n});\n\nexport const PortRegistryCleanupResponseSchema = z.object({\n success: z.boolean(),\n scanned: z.number().int().min(0),\n removed: z.number().int().min(0),\n error: z.string().optional(),\n});\n\nexport const PortRegistryBulkReleaseResponseSchema = z.object({\n success: z.boolean(),\n released: z.number().int().min(0),\n error: z.string().optional(),\n});\n\nexport type ServiceCategory = z.infer<typeof ServiceCategorySchema>;\nexport type ServiceMetadata = z.infer<typeof ServiceMetadataSchema>;\nexport type PortRegistryRecord = z.infer<typeof PortRegistryRecordSchema>;\nexport type PortRegistryState = z.infer<typeof PortRegistryStateSchema>;\nexport type PortAllocationRange = z.infer<typeof PortAllocationRangeSchema>;\nexport type ReservePortRequest = z.infer<typeof ReservePortRequestSchema>;\nexport type PortClaim = z.infer<typeof PortClaimSchema>;\nexport type ClaimPortRequest = z.input<typeof ClaimPortRequestSchema>;\nexport type ClaimPortResponse = z.infer<typeof ClaimPortResponseSchema>;\nexport type ConfirmPortRequest = z.input<typeof ConfirmPortRequestSchema>;\nexport type ReleaseClaimRequest = z.input<typeof ReleaseClaimRequestSchema>;\nexport type ReleasePortRequest = z.infer<typeof ReleasePortRequestSchema>;\nexport type GetPortRequest = z.infer<typeof GetPortRequestSchema>;\nexport type FindAvailablePortRequest = z.infer<typeof FindAvailablePortRequestSchema>;\nexport type PortAllocationResponse = z.infer<typeof PortAllocationResponseSchema>;\nexport type PortUsageListFilters = z.infer<typeof PortUsageListFiltersSchema>;\nexport type ReleasePortsRequest = z.infer<typeof ReleasePortsRequestSchema>;\nexport type PortRegistryCleanupResponse = z.infer<typeof PortRegistryCleanupResponseSchema>;\nexport type PortRegistryBulkReleaseResponse = z.infer<typeof PortRegistryBulkReleaseResponseSchema>;\n\nexport type PortRegistryErrorCode =\n | 'INVALID_REQUEST'\n | 'REGISTRY_READ_FAILED'\n | 'REGISTRY_WRITE_FAILED'\n | 'REGISTRY_LOCK_FAILED'\n | 'PORT_NOT_AVAILABLE'\n | 'NO_PORT_FOUND';\n\nexport class PortRegistryError extends Error {\n readonly code: PortRegistryErrorCode;\n\n constructor(message: string, code: PortRegistryErrorCode, options?: ErrorOptions) {\n super(message, options);\n this.name = 'PortRegistryError';\n this.code = code;\n }\n}\n","import os from 'node:os';\nimport path from 'node:path';\n\nexport const DEFAULT_REGISTRY_PATH = path.join(os.homedir(), '.port-registry', 'ports.turso.sqlite');\nexport const DEFAULT_REGISTRY_LOCK_PATH = `${DEFAULT_REGISTRY_PATH}.lock`;\nexport const LOCK_RETRY_DELAY_MS = 75;\nexport const LOCK_MAX_RETRIES = 80;\nexport const LOCK_STALE_AFTER_MS = 5_000;\nexport const DEFAULT_PORT_RANGE = { min: 3000, max: 4999 };\nexport const DEFAULT_HOST = '127.0.0.1';\n\nexport const normalizeRepositoryPath = (value: string): string => path.resolve(value);\n\nexport const isPortInRange = (port: number, range: { min: number; max: number }): boolean =>\n port >= range.min && port <= range.max;\n","import { randomUUID } from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport net from 'node:net';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { Database } from '@tursodatabase/database/compat';\nimport {\n CLAIM_METADATA_KEY,\n type ClaimPortRequest,\n ClaimPortRequestSchema,\n type ClaimPortResponse,\n ClaimPortResponseSchema,\n type ConfirmPortRequest,\n ConfirmPortRequestSchema,\n type FindAvailablePortRequest,\n FindAvailablePortRequestSchema,\n type GetPortRequest,\n GetPortRequestSchema,\n type PortAllocationRange,\n type PortAllocationResponse,\n PortAllocationResponseSchema,\n type PortClaim,\n PortClaimSchema,\n type PortRegistryBulkReleaseResponse,\n PortRegistryBulkReleaseResponseSchema,\n type PortRegistryCleanupResponse,\n PortRegistryCleanupResponseSchema,\n PortRegistryError,\n type PortRegistryRecord,\n PortRegistryRecordSchema,\n type PortRegistryState,\n PortRegistryStateSchema,\n type PortUsageListFilters,\n PortUsageListFiltersSchema,\n type ReleaseClaimRequest,\n ReleaseClaimRequestSchema,\n type ReleasePortRequest,\n ReleasePortRequestSchema,\n type ReleasePortsRequest,\n ReleasePortsRequestSchema,\n type ReservePortRequest,\n ReservePortRequestSchema,\n} from '../types';\nimport {\n DEFAULT_HOST,\n DEFAULT_PORT_RANGE,\n DEFAULT_REGISTRY_PATH,\n isPortInRange,\n normalizeRepositoryPath,\n} from '../utils';\n\nconst PORT_TABLE = 'port_allocations';\nconst METADATA_TABLE = 'registry_metadata';\nconst LEGACY_IMPORT_KEY = 'legacy_json_import_v1';\nconst SQLITE_BUSY_TIMEOUT_MS = 6_000;\nconst SQLITE_INIT_MAX_ATTEMPTS = 8;\nconst SQLITE_INIT_RETRY_DELAY_MS = 25;\nconst MAX_CLAIM_INSERT_ATTEMPTS = 3;\nconst writeQueues = new Map<string, Promise<void>>();\n\ntype SqlValue = string | number | null;\n\ninterface PortRow {\n id: number;\n repository_path: string;\n service_name: string;\n service_type: 'service' | 'tool';\n environment: string;\n pid: number | null;\n port: number;\n host: string;\n metadata_json: string | null;\n created_at: string;\n updated_at: string;\n}\n\ninterface NormalizedListFilters {\n repositoryPath?: string;\n serviceName?: string;\n serviceType?: 'service' | 'tool';\n environment?: string;\n}\n\ninterface NormalizedReleaseFilters extends NormalizedListFilters {\n pid?: number;\n force?: boolean;\n}\n\ninterface WhereClause {\n sql: string;\n params: SqlValue[];\n}\n\n/**\n * Service for managing shared port allocations in a cross-process SQLite database.\n */\nexport class PortRegistryService {\n private readonly registryPath: string;\n private readonly legacyRegistryPath: string;\n private sqlite: Database | null = null;\n private initialization: Promise<Database> | null = null;\n\n constructor(registryPath: string = DEFAULT_REGISTRY_PATH, _legacyLockPath?: string) {\n this.registryPath = PortRegistryService.resolveRegistryPath(registryPath);\n this.legacyRegistryPath = PortRegistryService.resolveLegacyRegistryPath(registryPath);\n }\n\n /**\n * Resolve a directory, SQLite path, or legacy JSON path to the SQLite database path.\n */\n static resolveRegistryPath(inputPath?: string): string {\n const resolvedPath = PortRegistryService.resolveInputPath(inputPath ?? DEFAULT_REGISTRY_PATH);\n const extension = path.extname(resolvedPath);\n\n if (extension === '.json') {\n return resolvedPath.slice(0, -extension.length) + '.sqlite';\n }\n\n if (extension === '.sqlite' || extension === '.db') {\n return resolvedPath;\n }\n\n return path.join(resolvedPath, 'ports.sqlite');\n }\n\n async getPort(rawRequest: GetPortRequest): Promise<PortAllocationResponse> {\n const request = GetPortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const filters = this.normalizeListFilters(request);\n const where = this.buildWhereClause(filters);\n const row = db.prepare(`SELECT * FROM ${PORT_TABLE}${where.sql} ORDER BY id LIMIT 1`).get(...where.params) as\n | PortRow\n | undefined;\n\n if (!row) {\n return this.createFailureResponse(`No allocation found for ${request.serviceName} in requested scope`);\n }\n\n const record = this.toRecord(row);\n return this.createSuccessResponse(record.port, record);\n }\n\n async findAvailablePort(rawRequest: FindAvailablePortRequest): Promise<PortAllocationResponse> {\n const request = FindAvailablePortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const range = request.portRange ?? DEFAULT_PORT_RANGE;\n const reserved = this.getReservedPorts(db);\n const availablePort = await this.findAvailablePortInternal(range, request.preferredPort, reserved, request.host);\n\n if (availablePort === null) {\n return this.createFailureResponse(`No available port found in range ${range.min}-${range.max}`);\n }\n\n return this.createSuccessResponse(availablePort);\n }\n\n async reservePort(rawRequest: ReservePortRequest): Promise<PortAllocationResponse> {\n const request = ReservePortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n const host = request.host ?? DEFAULT_HOST;\n const range = request.portRange ?? DEFAULT_PORT_RANGE;\n const force = request.force ?? false;\n\n return this.withImmediateTransaction(db, async () => {\n const existingRow = db\n .prepare(\n `SELECT * FROM ${PORT_TABLE}\n WHERE repository_path = ? AND service_name = ? AND service_type = ? AND environment = ?\n LIMIT 1`,\n )\n .get(repositoryPath, request.serviceName, serviceType, environment) as PortRow | undefined;\n\n if (existingRow && !force && isPortInRange(existingRow.port, range)) {\n const available = await this.isPortAvailable(existingRow.port, host);\n if (available) {\n const updatedAt = new Date().toISOString();\n db.prepare(`UPDATE ${PORT_TABLE} SET updated_at = ? WHERE id = ?`).run(updatedAt, existingRow.id);\n const record = this.toRecord({ ...existingRow, updated_at: updatedAt });\n return this.createSuccessResponse(record.port, record);\n }\n }\n\n if (existingRow) {\n db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`).run(existingRow.id);\n }\n\n const reserved = this.getReservedPorts(db);\n const availablePort = await this.findAvailablePortInternal(range, request.preferredPort, reserved, host);\n if (availablePort === null) {\n return this.createFailureResponse(`No available port found in range ${range.min}-${range.max}`);\n }\n\n const now = new Date().toISOString();\n const insert = db\n .prepare(\n `INSERT INTO ${PORT_TABLE} (\n repository_path, service_name, service_type, environment, pid, port, host,\n metadata_json, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n repositoryPath,\n request.serviceName,\n serviceType,\n environment,\n request.pid ?? null,\n availablePort,\n host,\n request.metadata ? JSON.stringify(request.metadata) : null,\n now,\n now,\n );\n\n const row = db.prepare(`SELECT * FROM ${PORT_TABLE} WHERE id = ?`).get(Number(insert.lastInsertRowid)) as PortRow;\n const record = this.toRecord(row);\n return this.createSuccessResponse(record.port, record);\n });\n }\n\n /**\n * Atomically claim a port for a service that is about to be started.\n *\n * Unlike {@link reservePort}, a claim never deletes a live allocation: callers\n * that find an `existing` row decide for themselves whether to reuse or replace\n * it. Exactly one concurrent caller receives `outcome: 'claimed'` — the rest see\n * the winner's row, so a claim doubles as a cross-process bootstrap mutex.\n *\n * A claim must be finalized with {@link confirmPort} or dropped with\n * {@link releaseClaim}. An abandoned claim is reaped once it expires, or\n * immediately if its owning process is gone.\n */\n async claimPort(rawRequest: ClaimPortRequest): Promise<ClaimPortResponse> {\n const request = ClaimPortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n const host = request.host ?? DEFAULT_HOST;\n const range = request.portRange ?? DEFAULT_PORT_RANGE;\n const ownerPid = request.pid ?? process.pid;\n\n return this.withImmediateTransaction(db, async () => {\n const existingRow = this.selectScopeRow(db, repositoryPath, request.serviceName, serviceType, environment);\n\n if (existingRow) {\n const claim = this.readClaim(existingRow);\n\n if (!claim) {\n return this.createClaimResponse({ outcome: 'existing', record: this.toRecord(existingRow) });\n }\n\n if (this.isClaimActive(claim)) {\n return this.createClaimResponse({\n outcome: 'existing',\n claimPending: true,\n record: this.toRecord(existingRow),\n });\n }\n\n db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`).run(existingRow.id);\n }\n\n const excluded = new Set<number>();\n for (let attempt = 0; attempt < MAX_CLAIM_INSERT_ATTEMPTS; attempt += 1) {\n const reserved = this.getReservedPorts(db);\n for (const port of excluded) {\n reserved.add(port);\n }\n\n const availablePort = await this.findAvailablePortInternal(range, request.preferredPort, reserved, host);\n if (availablePort === null) {\n return this.createClaimFailure(`No available port found in range ${range.min}-${range.max}`);\n }\n\n const claim: PortClaim = {\n token: randomUUID(),\n ownerPid,\n expiresAt: new Date(Date.now() + request.claimTtlMs).toISOString(),\n };\n const now = new Date().toISOString();\n\n try {\n const insert = db\n .prepare(\n `INSERT INTO ${PORT_TABLE} (\n repository_path, service_name, service_type, environment, pid, port, host,\n metadata_json, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n repositoryPath,\n request.serviceName,\n serviceType,\n environment,\n ownerPid,\n availablePort,\n host,\n JSON.stringify({ ...(request.metadata ?? {}), [CLAIM_METADATA_KEY]: claim }),\n now,\n now,\n );\n\n const row = this.selectRowById(db, Number(insert.lastInsertRowid));\n return this.createClaimResponse({\n outcome: 'claimed',\n record: this.toRecord(row),\n claimToken: claim.token,\n });\n } catch (error) {\n // Another scope took this port between the availability scan and the\n // insert; retry with it excluded rather than failing the bootstrap.\n if (!this.isUniqueConstraintError(error)) {\n throw error;\n }\n excluded.add(availablePort);\n }\n }\n\n return this.createClaimFailure(`Failed to claim a port after ${MAX_CLAIM_INSERT_ATTEMPTS} attempts`);\n });\n }\n\n /**\n * Convert a claim into a normal allocation owned by the now-running service.\n *\n * Fails when the claim has been reaped or taken over, which tells the caller it\n * lost the lease and must exit instead of registering over the new owner.\n */\n async confirmPort(rawRequest: ConfirmPortRequest): Promise<PortAllocationResponse> {\n const request = ConfirmPortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n\n return this.withImmediateTransaction(db, async () => {\n const row = this.selectScopeRow(db, repositoryPath, request.serviceName, serviceType, environment);\n const claim = row ? this.readClaim(row) : undefined;\n\n if (!row || !claim || claim.token !== request.claimToken) {\n return this.createFailureResponse(`Claim not found or expired for ${request.serviceName}`);\n }\n\n const metadata = { ...this.readMetadata(row), ...(request.metadata ?? {}) };\n delete metadata[CLAIM_METADATA_KEY];\n const updatedAt = new Date().toISOString();\n\n db.prepare(`UPDATE ${PORT_TABLE} SET pid = ?, metadata_json = ?, updated_at = ? WHERE id = ?`).run(\n request.pid,\n Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : null,\n updatedAt,\n row.id,\n );\n\n const record = this.toRecord(this.selectRowById(db, row.id));\n return this.createSuccessResponse(record.port, record);\n });\n }\n\n /**\n * Drop an unconfirmed claim, e.g. after the spawned service failed to start.\n * Idempotent: a claim already reaped or confirmed reports success.\n */\n async releaseClaim(rawRequest: ReleaseClaimRequest): Promise<PortAllocationResponse> {\n const request = ReleaseClaimRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n\n return this.withImmediateTransaction(db, async () => {\n const row = this.selectScopeRow(db, repositoryPath, request.serviceName, serviceType, environment);\n const claim = row ? this.readClaim(row) : undefined;\n\n if (row && claim?.token === request.claimToken) {\n db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`).run(row.id);\n }\n\n return this.createSuccessResponse();\n });\n }\n\n async releasePort(rawRequest: ReleasePortRequest): Promise<PortAllocationResponse> {\n const request = ReleasePortRequestSchema.parse(rawRequest);\n const result = await this.releasePorts(request);\n\n if (!result.success) {\n return this.createFailureResponse(`No matching registry entry for ${request.serviceName}`);\n }\n\n return this.createSuccessResponse();\n }\n\n async releasePorts(rawRequest: ReleasePortsRequest): Promise<PortRegistryBulkReleaseResponse> {\n const request = ReleasePortsRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const filters = this.normalizeReleaseFilters(request);\n const where = this.buildWhereClause(filters, true);\n const result = db.prepare(`DELETE FROM ${PORT_TABLE}${where.sql}`).run(...where.params);\n\n if (result.changes === 0) {\n return PortRegistryBulkReleaseResponseSchema.parse({\n success: false,\n released: 0,\n error: 'No matching registry entries',\n });\n }\n\n return PortRegistryBulkReleaseResponseSchema.parse({ success: true, released: result.changes });\n }\n\n async listAllocations(filters: PortUsageListFilters = {}): Promise<PortRegistryRecord[]> {\n const request = PortUsageListFiltersSchema.parse(filters);\n const db = await this.getDb();\n const where = this.buildWhereClause(this.normalizeListFilters(request));\n const rows = db.prepare(`SELECT * FROM ${PORT_TABLE}${where.sql} ORDER BY id`).all(...where.params) as PortRow[];\n return rows.map((row) => this.toRecord(row));\n }\n\n async cleanupStaleAllocations(filters: PortUsageListFilters = {}): Promise<PortRegistryCleanupResponse> {\n const request = PortUsageListFiltersSchema.parse(filters);\n const db = await this.getDb();\n const where = this.buildWhereClause(this.normalizeListFilters(request));\n const rows = db.prepare(`SELECT * FROM ${PORT_TABLE}${where.sql}`).all(...where.params) as PortRow[];\n const staleIds: number[] = [];\n\n await Promise.all(\n rows.map(async (row) => {\n const claim = this.readClaim(row);\n if (claim) {\n // A bootstrap row lives and dies by its claim, not by the pid column:\n // that pid belongs to the spawning parent, which may exit as soon as\n // the service confirms. Only an expired or orphaned claim is stale.\n if (!this.isClaimActive(claim)) {\n staleIds.push(row.id);\n }\n return;\n }\n\n const repositoryExists = await this.pathExists(row.repository_path);\n const deadPid = typeof row.pid === 'number' && !this.isProcessRunning(row.pid);\n if (!repositoryExists || deadPid) {\n staleIds.push(row.id);\n }\n }),\n );\n\n if (staleIds.length > 0) {\n const remove = db.transaction((ids: number[]) => {\n const statement = db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`);\n for (const id of ids) {\n statement.run(id);\n }\n });\n remove(staleIds);\n }\n\n return PortRegistryCleanupResponseSchema.parse({\n success: true,\n scanned: rows.length,\n removed: staleIds.length,\n });\n }\n\n close(): void {\n this.sqlite?.close();\n this.sqlite = null;\n this.initialization = null;\n }\n\n private static resolveInputPath(inputPath: string): string {\n return path.isAbsolute(inputPath) ? inputPath : path.join(process.cwd(), inputPath);\n }\n\n private static resolveLegacyRegistryPath(inputPath: string): string {\n const resolvedPath = PortRegistryService.resolveInputPath(inputPath);\n const extension = path.extname(resolvedPath);\n\n if (extension === '.json') {\n return resolvedPath;\n }\n\n if (extension === '.sqlite' || extension === '.db') {\n return resolvedPath.slice(0, -extension.length) + '.json';\n }\n\n return path.join(resolvedPath, 'ports.json');\n }\n\n private async getDb(): Promise<Database> {\n if (this.sqlite) {\n return this.sqlite;\n }\n\n if (!this.initialization) {\n this.initialization = this.initializeDatabase();\n }\n\n return this.initialization;\n }\n\n private async initializeDatabase(): Promise<Database> {\n await fs.mkdir(path.dirname(this.registryPath), { recursive: true });\n\n for (let attempt = 1; attempt <= SQLITE_INIT_MAX_ATTEMPTS; attempt += 1) {\n let db: Database | null = null;\n\n try {\n db = new Database(this.registryPath, {\n experimental: ['multiprocess_wal'],\n timeout: SQLITE_BUSY_TIMEOUT_MS,\n });\n db.pragma(`busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`, {});\n db.pragma('journal_mode = WAL', {});\n db.pragma('synchronous = NORMAL', {});\n db.exec(`\n CREATE TABLE IF NOT EXISTS ${METADATA_TABLE} (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS ${PORT_TABLE} (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n repository_path TEXT NOT NULL,\n service_name TEXT NOT NULL,\n service_type TEXT NOT NULL,\n environment TEXT NOT NULL,\n pid INTEGER,\n port INTEGER NOT NULL UNIQUE,\n host TEXT NOT NULL,\n metadata_json TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n UNIQUE (repository_path, service_name, service_type, environment)\n );\n CREATE INDEX IF NOT EXISTS port_allocations_scope_idx\n ON ${PORT_TABLE} (repository_path, service_name, service_type, environment);\n CREATE INDEX IF NOT EXISTS port_allocations_environment_idx\n ON ${PORT_TABLE} (environment, service_type);\n `);\n this.sqlite = db;\n await this.importLegacyJson(db);\n return db;\n } catch (error) {\n db?.close();\n this.sqlite = null;\n\n if (!this.isDatabaseBusyError(error) || attempt === SQLITE_INIT_MAX_ATTEMPTS) {\n this.initialization = null;\n throw new PortRegistryError(\n `Failed to initialize registry database: ${error instanceof Error ? error.message : String(error)}`,\n 'REGISTRY_READ_FAILED',\n { cause: error },\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, SQLITE_INIT_RETRY_DELAY_MS * 2 ** (attempt - 1)));\n }\n }\n\n throw new Error('Unreachable database initialization state');\n }\n\n private isDatabaseBusyError(error: unknown): boolean {\n const code = (error as { code?: unknown })?.code;\n return code === 'SQLITE_BUSY' || code === 'SQLITE_LOCKED';\n }\n\n private async importLegacyJson(db: Database): Promise<void> {\n const imported = db.prepare(`SELECT value FROM ${METADATA_TABLE} WHERE key = ?`).get(LEGACY_IMPORT_KEY);\n if (imported) {\n return;\n }\n\n let legacyState: PortRegistryState | null = null;\n try {\n const content = await fs.readFile(this.legacyRegistryPath, 'utf-8');\n legacyState = PortRegistryStateSchema.parse(JSON.parse(content));\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT') {\n throw error;\n }\n }\n\n const migrate = db.transaction((state: PortRegistryState | null) => {\n const insert = db.prepare(\n `INSERT OR IGNORE INTO ${PORT_TABLE} (\n repository_path, service_name, service_type, environment, pid, port, host,\n metadata_json, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n );\n\n for (const record of state?.entries ?? []) {\n insert.run(\n normalizeRepositoryPath(record.repositoryPath),\n record.serviceName,\n record.serviceType,\n record.environment ?? '',\n record.pid ?? null,\n record.port,\n record.host,\n record.metadata ? JSON.stringify(record.metadata) : null,\n record.createdAt,\n record.updatedAt,\n );\n }\n\n db.prepare(`INSERT OR REPLACE INTO ${METADATA_TABLE} (key, value) VALUES (?, ?)`).run(\n LEGACY_IMPORT_KEY,\n this.legacyRegistryPath,\n );\n });\n\n migrate(legacyState);\n }\n\n private async withImmediateTransaction<T>(db: Database, run: () => Promise<T>): Promise<T> {\n const previous = writeQueues.get(this.registryPath) ?? Promise.resolve();\n let releaseQueue: () => void = () => undefined;\n const current = new Promise<void>((resolve) => {\n releaseQueue = resolve;\n });\n const tail = previous.catch(() => undefined).then(() => current);\n writeQueues.set(this.registryPath, tail);\n await previous.catch(() => undefined);\n\n try {\n db.exec('BEGIN IMMEDIATE');\n try {\n const result = await run();\n db.exec('COMMIT');\n return result;\n } catch (error) {\n if (db.inTransaction) {\n db.exec('ROLLBACK');\n }\n throw error;\n }\n } finally {\n releaseQueue();\n if (writeQueues.get(this.registryPath) === tail) {\n writeQueues.delete(this.registryPath);\n }\n }\n }\n\n private normalizeListFilters(filters: PortUsageListFilters): NormalizedListFilters {\n return {\n ...(filters.repositoryPath ? { repositoryPath: normalizeRepositoryPath(filters.repositoryPath) } : {}),\n ...(filters.serviceName ? { serviceName: filters.serviceName } : {}),\n ...(filters.serviceType ? { serviceType: filters.serviceType } : {}),\n ...(filters.environment ? { environment: filters.environment } : {}),\n };\n }\n\n private normalizeReleaseFilters(filters: ReleasePortsRequest): NormalizedReleaseFilters {\n return {\n ...this.normalizeListFilters(filters),\n ...(typeof filters.pid === 'number' ? { pid: filters.pid } : {}),\n ...(typeof filters.force === 'boolean' ? { force: filters.force } : {}),\n };\n }\n\n private buildWhereClause(filters: NormalizedReleaseFilters, includePid = false): WhereClause {\n const clauses: string[] = [];\n const params: SqlValue[] = [];\n const add = (column: string, value: SqlValue | undefined): void => {\n if (value !== undefined) {\n clauses.push(`${column} = ?`);\n params.push(value);\n }\n };\n\n add('repository_path', filters.repositoryPath);\n add('service_name', filters.serviceName);\n add('service_type', filters.serviceType);\n add('environment', filters.environment);\n if (includePid && typeof filters.pid === 'number' && !filters.force) {\n add('pid', filters.pid);\n }\n\n return {\n sql: clauses.length > 0 ? ` WHERE ${clauses.join(' AND ')}` : '',\n params,\n };\n }\n\n private selectScopeRow(\n db: Database,\n repositoryPath: string,\n serviceName: string,\n serviceType: 'service' | 'tool',\n environment: string,\n ): PortRow | undefined {\n return db\n .prepare(\n `SELECT * FROM ${PORT_TABLE}\n WHERE repository_path = ? AND service_name = ? AND service_type = ? AND environment = ?\n LIMIT 1`,\n )\n .get(repositoryPath, serviceName, serviceType, environment) as PortRow | undefined;\n }\n\n private selectRowById(db: Database, id: number): PortRow {\n return db.prepare(`SELECT * FROM ${PORT_TABLE} WHERE id = ?`).get(id) as PortRow;\n }\n\n private readMetadata(row: PortRow): Record<string, unknown> {\n if (!row.metadata_json) {\n return {};\n }\n\n const parsed = JSON.parse(row.metadata_json) as unknown;\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new PortRegistryError('Stored port metadata is invalid', 'REGISTRY_READ_FAILED');\n }\n\n return parsed as Record<string, unknown>;\n }\n\n private readClaim(row: PortRow): PortClaim | undefined {\n const candidate = this.readMetadata(row)[CLAIM_METADATA_KEY];\n if (!candidate) {\n return undefined;\n }\n\n const parsed = PortClaimSchema.safeParse(candidate);\n return parsed.success ? parsed.data : undefined;\n }\n\n /** A claim holds the scope only while unexpired and its owner is still alive. */\n private isClaimActive(claim: PortClaim): boolean {\n return Date.parse(claim.expiresAt) > Date.now() && this.isProcessRunning(claim.ownerPid);\n }\n\n private isUniqueConstraintError(error: unknown): boolean {\n return (error as { code?: string } | undefined)?.code === 'SQLITE_CONSTRAINT_UNIQUE';\n }\n\n private createClaimResponse(response: Omit<ClaimPortResponse, 'success' | 'port'>): ClaimPortResponse {\n return ClaimPortResponseSchema.parse({\n success: true,\n ...response,\n ...(response.record ? { port: response.record.port } : {}),\n });\n }\n\n private createClaimFailure(error: string): ClaimPortResponse {\n return ClaimPortResponseSchema.parse({ success: false, error });\n }\n\n private getReservedPorts(db: Database): Set<number> {\n const rows = db.prepare(`SELECT port FROM ${PORT_TABLE}`).all() as Array<{ port: number }>;\n return new Set(rows.map((row) => row.port));\n }\n\n private toRecord(row: PortRow): PortRegistryRecord {\n const parsedMetadata = this.readMetadata(row);\n const metadata = Object.keys(parsedMetadata).length > 0 ? parsedMetadata : undefined;\n\n return PortRegistryRecordSchema.parse({\n repositoryPath: row.repository_path,\n serviceName: row.service_name,\n serviceType: row.service_type,\n ...(row.environment ? { environment: row.environment } : {}),\n ...(row.pid ? { pid: row.pid } : {}),\n port: row.port,\n host: row.host,\n ...(metadata ? { metadata } : {}),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n });\n }\n\n private async findAvailablePortInternal(\n portRange: PortAllocationRange,\n preferredPort: number | undefined,\n reservedPorts: Set<number>,\n host: string,\n ): Promise<number | null> {\n if (preferredPort !== undefined && isPortInRange(preferredPort, portRange)) {\n if (!reservedPorts.has(preferredPort) && (await this.isPortAvailable(preferredPort, host))) {\n return preferredPort;\n }\n }\n\n for (let port = portRange.min; port <= portRange.max; port += 1) {\n if (port === preferredPort || reservedPorts.has(port)) {\n continue;\n }\n\n if (await this.isPortAvailable(port, host)) {\n return port;\n }\n }\n\n return null;\n }\n\n private async isPortAvailable(port: number, host: string): Promise<boolean> {\n const normalizedHost = os.platform() === 'win32' ? '127.0.0.1' : host;\n const candidateHosts = Array.from(\n new Set<string | undefined>([normalizedHost, '127.0.0.1', '0.0.0.0', undefined, '::1']),\n );\n\n for (const candidateHost of candidateHosts) {\n if (!(await this.isPortAvailableOnHost(port, candidateHost))) {\n return false;\n }\n }\n\n return true;\n }\n\n private async isPortAvailableOnHost(port: number, host?: string): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer();\n server.once('error', () => resolve(false));\n server.once('listening', () => server.close(() => resolve(true)));\n if (host) {\n server.listen(port, host);\n } else {\n server.listen(port);\n }\n });\n }\n\n private isProcessRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n }\n\n private async pathExists(candidate: string): Promise<boolean> {\n try {\n await fs.access(candidate);\n return true;\n } catch {\n return false;\n }\n }\n\n private createSuccessResponse(port?: number, record?: PortRegistryRecord): PortAllocationResponse {\n return PortAllocationResponseSchema.parse({\n success: true,\n ...(port !== undefined ? { port } : {}),\n ...(record ? { record } : {}),\n });\n }\n\n private createFailureResponse(error: string): PortAllocationResponse {\n return PortAllocationResponseSchema.parse({ success: false, error });\n }\n}\n"],"mappings":"4sBAEA,MAEa,EAAwBA,EAAAA,EAAE,KAAK,CAAC,UAAW,OAAO,CAAC,CAEnD,EAAwBA,EAAAA,EAAE,OAAOA,EAAAA,EAAE,QAAQ,CAAEA,EAAAA,EAAE,SAAS,CAAC,CAEzD,EAA2BA,EAAAA,EAAE,OAAO,CAC/C,eAAgBA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAG,6BAA6B,CACtE,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAG,0BAA0B,CAChE,YAAa,EACb,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,UAAU,CAChD,IAAKA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CACvC,KAAMA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,MAAM,CACxC,KAAMA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,QAAQ,YAAY,CACnD,SAAU,EAAsB,UAAU,CAC1C,UAAWA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACnC,UAAWA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACpC,CAAC,CAEW,EAA0BA,EAAAA,EAAE,OAAO,CAC9C,QAASA,EAAAA,EAAE,QAAA,EAAyB,CACpC,UAAWA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACnC,QAASA,EAAAA,EAAE,MAAM,EAAyB,CAC3C,CAAC,CAEW,EAA4BA,EAAAA,EACtC,OAAO,CACN,IAAKA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,MAAM,CACvC,IAAKA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,MAAM,CACxC,CAAC,CACD,OAAQ,GAAU,EAAM,KAAO,EAAM,IAAK,CACzC,QAAS,mDACT,KAAM,CAAC,MAAM,CACd,CAAC,CAES,EAA2BA,EAAAA,EAAE,OAAO,CAC/C,eAAgBA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACxC,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACrC,YAAa,EAAsB,QAAQ,UAAU,CACrD,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,UAAU,CAChD,IAAKA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CACvC,UAAW,EAA0B,UAAU,CAC/C,cAAeA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,MAAM,CAAC,UAAU,CAC5D,KAAMA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,UAAU,CACzC,SAAU,EAAsB,UAAU,CAC1C,MAAOA,EAAAA,EAAE,SAAS,CAAC,UAAU,CAC9B,CAAC,CAUW,EAAqB,UAErB,EAAuB,KAEvB,EAAkBA,EAAAA,EAAE,OAAO,CACtC,MAAOA,EAAAA,EAAE,QAAQ,CAAC,IAAI,EAAE,CACxB,SAAUA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CACjC,UAAWA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACpC,CAAC,CAEW,EAAyB,EAAyB,KAAK,CAAE,MAAO,GAAM,CAAC,CAAC,OAAO,CAC1F,WAAYA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAK,CAAC,IAAI,IAAQ,CAAC,QAAQ,EAAqB,CAClF,CAAC,CAEW,EAA0BA,EAAAA,EAAE,OAAO,CAC9C,QAASA,EAAAA,EAAE,SAAS,CACpB,QAASA,EAAAA,EAAE,KAAK,CAAC,UAAW,WAAW,CAAC,CAAC,UAAU,CACnD,KAAMA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,MAAM,CAAC,UAAU,CACnD,OAAQ,EAAyB,UAAU,CAE3C,WAAYA,EAAAA,EAAE,QAAQ,CAAC,UAAU,CAEjC,aAAcA,EAAAA,EAAE,SAAS,CAAC,UAAU,CACpC,MAAOA,EAAAA,EAAE,QAAQ,CAAC,UAAU,CAC7B,CAAC,CAEW,EAA2BA,EAAAA,EAAE,OAAO,CAC/C,eAAgBA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACxC,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACrC,YAAa,EAAsB,QAAQ,UAAU,CACrD,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,UAAU,CAChD,WAAYA,EAAAA,EAAE,QAAQ,CAAC,IAAI,EAAE,CAC7B,IAAKA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAC5B,SAAU,EAAsB,UAAU,CAC3C,CAAC,CAEW,EAA4BA,EAAAA,EAAE,OAAO,CAChD,eAAgBA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACxC,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACrC,YAAa,EAAsB,QAAQ,UAAU,CACrD,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,UAAU,CAChD,WAAYA,EAAAA,EAAE,QAAQ,CAAC,IAAI,EAAE,CAC9B,CAAC,CAEW,EAA2BA,EAAAA,EAAE,OAAO,CAC/C,eAAgBA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACxC,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACrC,YAAa,EAAsB,UAAU,CAC7C,IAAKA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CACvC,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,UAAU,CAChD,MAAOA,EAAAA,EAAE,SAAS,CAAC,UAAU,CAC9B,CAAC,CAEW,EAAuBA,EAAAA,EAAE,OAAO,CAC3C,eAAgBA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACxC,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACrC,YAAa,EAAsB,UAAU,CAC7C,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,UAAU,CACjD,CAAC,CAEW,EAAiCA,EAAAA,EAAE,OAAO,CACrD,eAAgBA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACxC,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CACrC,YAAa,EAAsB,UAAU,CAC7C,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,UAAU,CAChD,UAAW,EAA0B,UAAU,CAC/C,cAAeA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,MAAM,CAAC,UAAU,CAC5D,KAAMA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,QAAQ,YAAY,CACpD,CAAC,CAEW,EAA+BA,EAAAA,EAAE,OAAO,CACnD,QAASA,EAAAA,EAAE,SAAS,CACpB,KAAMA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,MAAM,CAAC,UAAU,CACnD,OAAQ,EAAyB,UAAU,CAC3C,MAAOA,EAAAA,EAAE,QAAQ,CAAC,UAAU,CAC7B,CAAC,CAEW,EAA6BA,EAAAA,EAAE,OAAO,CACjD,eAAgBA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,UAAU,CACnD,YAAa,EAAsB,UAAU,CAC7C,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,UAAU,CAChD,YAAaA,EAAAA,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,UAAU,CACjD,CAAC,CAEW,EAA4B,EAA2B,OAAO,CACzE,IAAKA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,CACvC,MAAOA,EAAAA,EAAE,SAAS,CAAC,UAAU,CAC9B,CAAC,CAEW,EAAoCA,EAAAA,EAAE,OAAO,CACxD,QAASA,EAAAA,EAAE,SAAS,CACpB,QAASA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAChC,QAASA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAChC,MAAOA,EAAAA,EAAE,QAAQ,CAAC,UAAU,CAC7B,CAAC,CAEW,EAAwCA,EAAAA,EAAE,OAAO,CAC5D,QAASA,EAAAA,EAAE,SAAS,CACpB,SAAUA,EAAAA,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CACjC,MAAOA,EAAAA,EAAE,QAAQ,CAAC,UAAU,CAC7B,CAAC,CA8BF,IAAa,EAAb,cAAuC,KAAM,CAC3C,KAEA,YAAY,EAAiB,EAA6B,EAAwB,CAChF,MAAM,EAAS,EAAQ,CACvB,KAAK,KAAO,oBACZ,KAAK,KAAO,IC/LhB,MAAa,EAAwBC,EAAAA,QAAK,KAAKC,EAAAA,QAAG,SAAS,CAAE,iBAAkB,qBAAqB,CACvF,EAA6B,GAAG,EAAsB,OAItD,EAAqB,CAAE,IAAK,IAAM,IAAK,KAAM,CAG7C,EAA2B,GAA0BD,EAAAA,QAAK,QAAQ,EAAM,CAExE,GAAiB,EAAc,IAC1C,GAAQ,EAAM,KAAO,GAAQ,EAAM,ICqC/B,EAAa,mBACb,EAAiB,oBACjB,EAAoB,wBACpB,EAAyB,IAIzB,EAAc,IAAI,IAsCxB,IAAa,EAAb,MAAa,CAAoB,CAC/B,aACA,mBACA,OAAkC,KAClC,eAAmD,KAEnD,YAAY,EAAuB,EAAuB,EAA0B,CAClF,KAAK,aAAe,EAAoB,oBAAoB,EAAa,CACzE,KAAK,mBAAqB,EAAoB,0BAA0B,EAAa,CAMvF,OAAO,oBAAoB,EAA4B,CACrD,IAAM,EAAe,EAAoB,iBAAiB,GAAa,EAAsB,CACvF,EAAYE,EAAAA,QAAK,QAAQ,EAAa,CAU5C,OARI,IAAc,QACT,EAAa,MAAM,EAAG,CAAC,EAAU,OAAO,CAAG,UAGhD,IAAc,WAAa,IAAc,MACpC,EAGFA,EAAAA,QAAK,KAAK,EAAc,eAAe,CAGhD,MAAM,QAAQ,EAA6D,CACzE,IAAM,EAAU,EAAqB,MAAM,EAAW,CAChD,EAAK,MAAM,KAAK,OAAO,CACvB,EAAU,KAAK,qBAAqB,EAAQ,CAC5C,EAAQ,KAAK,iBAAiB,EAAQ,CACtC,EAAM,EAAG,QAAQ,iBAAiB,IAAa,EAAM,IAAI,sBAAsB,CAAC,IAAI,GAAG,EAAM,OAAO,CAI1G,GAAI,CAAC,EACH,OAAO,KAAK,sBAAsB,2BAA2B,EAAQ,YAAY,qBAAqB,CAGxG,IAAM,EAAS,KAAK,SAAS,EAAI,CACjC,OAAO,KAAK,sBAAsB,EAAO,KAAM,EAAO,CAGxD,MAAM,kBAAkB,EAAuE,CAC7F,IAAM,EAAU,EAA+B,MAAM,EAAW,CAC1D,EAAK,MAAM,KAAK,OAAO,CACvB,EAAQ,EAAQ,WAAa,EAC7B,EAAW,KAAK,iBAAiB,EAAG,CACpC,EAAgB,MAAM,KAAK,0BAA0B,EAAO,EAAQ,cAAe,EAAU,EAAQ,KAAK,CAMhH,OAJI,IAAkB,KACb,KAAK,sBAAsB,oCAAoC,EAAM,IAAI,GAAG,EAAM,MAAM,CAG1F,KAAK,sBAAsB,EAAc,CAGlD,MAAM,YAAY,EAAiE,CACjF,IAAM,EAAU,EAAyB,MAAM,EAAW,CACpD,EAAK,MAAM,KAAK,OAAO,CACvB,EAAiB,EAAwB,EAAQ,eAAe,CAChE,EAAc,EAAQ,aAAe,UACrC,EAAc,EAAQ,aAAe,QAAQ,IAAI,UAAY,cAC7D,EAAO,EAAQ,MAAA,YACf,EAAQ,EAAQ,WAAa,EAC7B,EAAQ,EAAQ,OAAS,GAE/B,OAAO,KAAK,yBAAyB,EAAI,SAAY,CACnD,IAAM,EAAc,EACjB,QACC,iBAAiB,EAAW;;oBAG7B,CACA,IAAI,EAAgB,EAAQ,YAAa,EAAa,EAAY,CAErE,GAAI,GAAe,CAAC,GAAS,EAAc,EAAY,KAAM,EAAM,EAE7D,MADoB,KAAK,gBAAgB,EAAY,KAAM,EAAK,CACrD,CACb,IAAM,EAAY,IAAI,MAAM,CAAC,aAAa,CAC1C,EAAG,QAAQ,UAAU,EAAW,kCAAkC,CAAC,IAAI,EAAW,EAAY,GAAG,CACjG,IAAM,EAAS,KAAK,SAAS,CAAE,GAAG,EAAa,WAAY,EAAW,CAAC,CACvE,OAAO,KAAK,sBAAsB,EAAO,KAAM,EAAO,CAItD,GACF,EAAG,QAAQ,eAAe,EAAW,eAAe,CAAC,IAAI,EAAY,GAAG,CAG1E,IAAM,EAAW,KAAK,iBAAiB,EAAG,CACpC,EAAgB,MAAM,KAAK,0BAA0B,EAAO,EAAQ,cAAe,EAAU,EAAK,CACxG,GAAI,IAAkB,KACpB,OAAO,KAAK,sBAAsB,oCAAoC,EAAM,IAAI,GAAG,EAAM,MAAM,CAGjG,IAAM,EAAM,IAAI,MAAM,CAAC,aAAa,CAC9B,EAAS,EACZ,QACC,eAAe,EAAW;;;oDAI3B,CACA,IACC,EACA,EAAQ,YACR,EACA,EACA,EAAQ,KAAO,KACf,EACA,EACA,EAAQ,SAAW,KAAK,UAAU,EAAQ,SAAS,CAAG,KACtD,EACA,EACD,CAEG,EAAM,EAAG,QAAQ,iBAAiB,EAAW,eAAe,CAAC,IAAI,OAAO,EAAO,gBAAgB,CAAC,CAChG,EAAS,KAAK,SAAS,EAAI,CACjC,OAAO,KAAK,sBAAsB,EAAO,KAAM,EAAO,EACtD,CAeJ,MAAM,UAAU,EAA0D,CACxE,IAAM,EAAU,EAAuB,MAAM,EAAW,CAClD,EAAK,MAAM,KAAK,OAAO,CACvB,EAAiB,EAAwB,EAAQ,eAAe,CAChE,EAAc,EAAQ,aAAe,UACrC,EAAc,EAAQ,aAAe,QAAQ,IAAI,UAAY,cAC7D,EAAO,EAAQ,MAAA,YACf,EAAQ,EAAQ,WAAa,EAC7B,EAAW,EAAQ,KAAO,QAAQ,IAExC,OAAO,KAAK,yBAAyB,EAAI,SAAY,CACnD,IAAM,EAAc,KAAK,eAAe,EAAI,EAAgB,EAAQ,YAAa,EAAa,EAAY,CAE1G,GAAI,EAAa,CACf,IAAM,EAAQ,KAAK,UAAU,EAAY,CAEzC,GAAI,CAAC,EACH,OAAO,KAAK,oBAAoB,CAAE,QAAS,WAAY,OAAQ,KAAK,SAAS,EAAY,CAAE,CAAC,CAG9F,GAAI,KAAK,cAAc,EAAM,CAC3B,OAAO,KAAK,oBAAoB,CAC9B,QAAS,WACT,aAAc,GACd,OAAQ,KAAK,SAAS,EAAY,CACnC,CAAC,CAGJ,EAAG,QAAQ,eAAe,EAAW,eAAe,CAAC,IAAI,EAAY,GAAG,CAG1E,IAAM,EAAW,IAAI,IACrB,IAAK,IAAI,EAAU,EAAG,EAAU,EAA2B,GAAW,EAAG,CACvE,IAAM,EAAW,KAAK,iBAAiB,EAAG,CAC1C,IAAK,IAAM,KAAQ,EACjB,EAAS,IAAI,EAAK,CAGpB,IAAM,EAAgB,MAAM,KAAK,0BAA0B,EAAO,EAAQ,cAAe,EAAU,EAAK,CACxG,GAAI,IAAkB,KACpB,OAAO,KAAK,mBAAmB,oCAAoC,EAAM,IAAI,GAAG,EAAM,MAAM,CAG9F,IAAM,EAAmB,CACvB,OAAA,EAAA,EAAA,aAAmB,CACnB,WACA,UAAW,IAAI,KAAK,KAAK,KAAK,CAAG,EAAQ,WAAW,CAAC,aAAa,CACnE,CACK,EAAM,IAAI,MAAM,CAAC,aAAa,CAEpC,GAAI,CACF,IAAM,EAAS,EACZ,QACC,eAAe,EAAW;;;wDAI3B,CACA,IACC,EACA,EAAQ,YACR,EACA,EACA,EACA,EACA,EACA,KAAK,UAAU,CAAE,GAAI,EAAQ,UAAY,EAAE,EAAI,GAAqB,EAAO,CAAC,CAC5E,EACA,EACD,CAEG,EAAM,KAAK,cAAc,EAAI,OAAO,EAAO,gBAAgB,CAAC,CAClE,OAAO,KAAK,oBAAoB,CAC9B,QAAS,UACT,OAAQ,KAAK,SAAS,EAAI,CAC1B,WAAY,EAAM,MACnB,CAAC,OACK,EAAO,CAGd,GAAI,CAAC,KAAK,wBAAwB,EAAM,CACtC,MAAM,EAER,EAAS,IAAI,EAAc,EAI/B,OAAO,KAAK,mBAAmB,0CAAqE,EACpG,CASJ,MAAM,YAAY,EAAiE,CACjF,IAAM,EAAU,EAAyB,MAAM,EAAW,CACpD,EAAK,MAAM,KAAK,OAAO,CACvB,EAAiB,EAAwB,EAAQ,eAAe,CAChE,EAAc,EAAQ,aAAe,UACrC,EAAc,EAAQ,aAAe,QAAQ,IAAI,UAAY,cAEnE,OAAO,KAAK,yBAAyB,EAAI,SAAY,CACnD,IAAM,EAAM,KAAK,eAAe,EAAI,EAAgB,EAAQ,YAAa,EAAa,EAAY,CAC5F,EAAQ,EAAM,KAAK,UAAU,EAAI,CAAG,IAAA,GAE1C,GAAI,CAAC,GAAO,CAAC,GAAS,EAAM,QAAU,EAAQ,WAC5C,OAAO,KAAK,sBAAsB,kCAAkC,EAAQ,cAAc,CAG5F,IAAM,EAAW,CAAE,GAAG,KAAK,aAAa,EAAI,CAAE,GAAI,EAAQ,UAAY,EAAE,CAAG,CAC3E,OAAO,EAAS,GAChB,IAAM,EAAY,IAAI,MAAM,CAAC,aAAa,CAE1C,EAAG,QAAQ,UAAU,EAAW,8DAA8D,CAAC,IAC7F,EAAQ,IACR,OAAO,KAAK,EAAS,CAAC,OAAS,EAAI,KAAK,UAAU,EAAS,CAAG,KAC9D,EACA,EAAI,GACL,CAED,IAAM,EAAS,KAAK,SAAS,KAAK,cAAc,EAAI,EAAI,GAAG,CAAC,CAC5D,OAAO,KAAK,sBAAsB,EAAO,KAAM,EAAO,EACtD,CAOJ,MAAM,aAAa,EAAkE,CACnF,IAAM,EAAU,EAA0B,MAAM,EAAW,CACrD,EAAK,MAAM,KAAK,OAAO,CACvB,EAAiB,EAAwB,EAAQ,eAAe,CAChE,EAAc,EAAQ,aAAe,UACrC,EAAc,EAAQ,aAAe,QAAQ,IAAI,UAAY,cAEnE,OAAO,KAAK,yBAAyB,EAAI,SAAY,CACnD,IAAM,EAAM,KAAK,eAAe,EAAI,EAAgB,EAAQ,YAAa,EAAa,EAAY,CAC5F,EAAQ,EAAM,KAAK,UAAU,EAAI,CAAG,IAAA,GAM1C,OAJI,GAAO,GAAO,QAAU,EAAQ,YAClC,EAAG,QAAQ,eAAe,EAAW,eAAe,CAAC,IAAI,EAAI,GAAG,CAG3D,KAAK,uBAAuB,EACnC,CAGJ,MAAM,YAAY,EAAiE,CACjF,IAAM,EAAU,EAAyB,MAAM,EAAW,CAO1D,OAJK,MAFgB,KAAK,aAAa,EAAQ,EAEnC,QAIL,KAAK,uBAAuB,CAH1B,KAAK,sBAAsB,kCAAkC,EAAQ,cAAc,CAM9F,MAAM,aAAa,EAA2E,CAC5F,IAAM,EAAU,EAA0B,MAAM,EAAW,CACrD,EAAK,MAAM,KAAK,OAAO,CACvB,EAAU,KAAK,wBAAwB,EAAQ,CAC/C,EAAQ,KAAK,iBAAiB,EAAS,GAAK,CAC5C,EAAS,EAAG,QAAQ,eAAe,IAAa,EAAM,MAAM,CAAC,IAAI,GAAG,EAAM,OAAO,CAUvF,OARI,EAAO,UAAY,EACd,EAAsC,MAAM,CACjD,QAAS,GACT,SAAU,EACV,MAAO,+BACR,CAAC,CAGG,EAAsC,MAAM,CAAE,QAAS,GAAM,SAAU,EAAO,QAAS,CAAC,CAGjG,MAAM,gBAAgB,EAAgC,EAAE,CAAiC,CACvF,IAAM,EAAU,EAA2B,MAAM,EAAQ,CACnD,EAAK,MAAM,KAAK,OAAO,CACvB,EAAQ,KAAK,iBAAiB,KAAK,qBAAqB,EAAQ,CAAC,CAEvE,OADa,EAAG,QAAQ,iBAAiB,IAAa,EAAM,IAAI,cAAc,CAAC,IAAI,GAAG,EAAM,OACjF,CAAC,IAAK,GAAQ,KAAK,SAAS,EAAI,CAAC,CAG9C,MAAM,wBAAwB,EAAgC,EAAE,CAAwC,CACtG,IAAM,EAAU,EAA2B,MAAM,EAAQ,CACnD,EAAK,MAAM,KAAK,OAAO,CACvB,EAAQ,KAAK,iBAAiB,KAAK,qBAAqB,EAAQ,CAAC,CACjE,EAAO,EAAG,QAAQ,iBAAiB,IAAa,EAAM,MAAM,CAAC,IAAI,GAAG,EAAM,OAAO,CACjF,EAAqB,EAAE,CAiC7B,OA/BA,MAAM,QAAQ,IACZ,EAAK,IAAI,KAAO,IAAQ,CACtB,IAAM,EAAQ,KAAK,UAAU,EAAI,CACjC,GAAI,EAAO,CAIJ,KAAK,cAAc,EAAM,EAC5B,EAAS,KAAK,EAAI,GAAG,CAEvB,OAGF,IAAM,EAAmB,MAAM,KAAK,WAAW,EAAI,gBAAgB,CAC7D,EAAU,OAAO,EAAI,KAAQ,UAAY,CAAC,KAAK,iBAAiB,EAAI,IAAI,EAC1E,CAAC,GAAoB,IACvB,EAAS,KAAK,EAAI,GAAG,EAEvB,CACH,CAEG,EAAS,OAAS,GACL,EAAG,YAAa,GAAkB,CAC/C,IAAM,EAAY,EAAG,QAAQ,eAAe,EAAW,eAAe,CACtE,IAAK,IAAM,KAAM,EACf,EAAU,IAAI,EAAG,EAGf,CAAC,EAAS,CAGX,EAAkC,MAAM,CAC7C,QAAS,GACT,QAAS,EAAK,OACd,QAAS,EAAS,OACnB,CAAC,CAGJ,OAAc,CACZ,KAAK,QAAQ,OAAO,CACpB,KAAK,OAAS,KACd,KAAK,eAAiB,KAGxB,OAAe,iBAAiB,EAA2B,CACzD,OAAOA,EAAAA,QAAK,WAAW,EAAU,CAAG,EAAYA,EAAAA,QAAK,KAAK,QAAQ,KAAK,CAAE,EAAU,CAGrF,OAAe,0BAA0B,EAA2B,CAClE,IAAM,EAAe,EAAoB,iBAAiB,EAAU,CAC9D,EAAYA,EAAAA,QAAK,QAAQ,EAAa,CAU5C,OARI,IAAc,QACT,EAGL,IAAc,WAAa,IAAc,MACpC,EAAa,MAAM,EAAG,CAAC,EAAU,OAAO,CAAG,QAG7CA,EAAAA,QAAK,KAAK,EAAc,aAAa,CAG9C,MAAc,OAA2B,CASvC,OARI,KAAK,OACA,KAAK,QAGd,AACE,KAAK,iBAAiB,KAAK,oBAAoB,CAG1C,KAAK,gBAGd,MAAc,oBAAwC,CACpD,MAAMC,EAAAA,QAAG,MAAMD,EAAAA,QAAK,QAAQ,KAAK,aAAa,CAAE,CAAE,UAAW,GAAM,CAAC,CAEpE,IAAK,IAAI,EAAU,EAAG,GAAW,EAA0B,GAAW,EAAG,CACvE,IAAI,EAAsB,KAE1B,GAAI,CAkCF,MAjCA,GAAK,IAAIE,EAAAA,SAAS,KAAK,aAAc,CACnC,aAAc,CAAC,mBAAmB,CAClC,QAAS,EACV,CAAC,CACF,EAAG,OAAO,kBAAkB,IAA0B,EAAE,CAAC,CACzD,EAAG,OAAO,qBAAsB,EAAE,CAAC,CACnC,EAAG,OAAO,uBAAwB,EAAE,CAAC,CACrC,EAAG,KAAK;uCACuB,EAAe;;;;uCAIf,EAAW;;;;;;;;;;;;;;;iBAejC,EAAW;;iBAEX,EAAW;UAClB,CACF,KAAK,OAAS,EACd,MAAM,KAAK,iBAAiB,EAAG,CACxB,QACA,EAAO,CAId,GAHA,GAAI,OAAO,CACX,KAAK,OAAS,KAEV,CAAC,KAAK,oBAAoB,EAAM,EAAI,IAAY,EAElD,KADA,MAAK,eAAiB,KAChB,IAAI,EACR,2CAA2C,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GACjG,uBACA,CAAE,MAAO,EAAO,CACjB,CAGH,MAAM,IAAI,QAAS,GAAY,WAAW,EAAS,GAA6B,IAAM,EAAU,GAAG,CAAC,EAIxG,MAAU,MAAM,4CAA4C,CAG9D,oBAA4B,EAAyB,CACnD,IAAM,EAAQ,GAA8B,KAC5C,OAAO,IAAS,eAAiB,IAAS,gBAG5C,MAAc,iBAAiB,EAA6B,CAE1D,GADiB,EAAG,QAAQ,qBAAqB,EAAe,gBAAgB,CAAC,IAAI,EACzE,CACV,OAGF,IAAI,EAAwC,KAC5C,GAAI,CACF,IAAM,EAAU,MAAMD,EAAAA,QAAG,SAAS,KAAK,mBAAoB,QAAQ,CACnE,EAAc,EAAwB,MAAM,KAAK,MAAM,EAAQ,CAAC,OACzD,EAAO,CAEd,GADc,EAAgC,OACjC,SACX,MAAM,EAIM,EAAG,YAAa,GAAoC,CAClE,IAAM,EAAS,EAAG,QAChB,yBAAyB,EAAW;;;kDAIrC,CAED,IAAK,IAAM,KAAU,GAAO,SAAW,EAAE,CACvC,EAAO,IACL,EAAwB,EAAO,eAAe,CAC9C,EAAO,YACP,EAAO,YACP,EAAO,aAAe,GACtB,EAAO,KAAO,KACd,EAAO,KACP,EAAO,KACP,EAAO,SAAW,KAAK,UAAU,EAAO,SAAS,CAAG,KACpD,EAAO,UACP,EAAO,UACR,CAGH,EAAG,QAAQ,0BAA0B,EAAe,6BAA6B,CAAC,IAChF,EACA,KAAK,mBACN,EAGI,CAAC,EAAY,CAGtB,MAAc,yBAA4B,EAAc,EAAmC,CACzF,IAAM,EAAW,EAAY,IAAI,KAAK,aAAa,EAAI,QAAQ,SAAS,CACpE,MAAiC,IAAA,GAC/B,EAAU,IAAI,QAAe,GAAY,CAC7C,EAAe,GACf,CACI,EAAO,EAAS,UAAY,IAAA,GAAU,CAAC,SAAW,EAAQ,CAChE,EAAY,IAAI,KAAK,aAAc,EAAK,CACxC,MAAM,EAAS,UAAY,IAAA,GAAU,CAErC,GAAI,CACF,EAAG,KAAK,kBAAkB,CAC1B,GAAI,CACF,IAAM,EAAS,MAAM,GAAK,CAE1B,OADA,EAAG,KAAK,SAAS,CACV,QACA,EAAO,CAId,MAHI,EAAG,eACL,EAAG,KAAK,WAAW,CAEf,UAEA,CACR,GAAc,CACV,EAAY,IAAI,KAAK,aAAa,GAAK,GACzC,EAAY,OAAO,KAAK,aAAa,EAK3C,qBAA6B,EAAsD,CACjF,MAAO,CACL,GAAI,EAAQ,eAAiB,CAAE,eAAgB,EAAwB,EAAQ,eAAe,CAAE,CAAG,EAAE,CACrG,GAAI,EAAQ,YAAc,CAAE,YAAa,EAAQ,YAAa,CAAG,EAAE,CACnE,GAAI,EAAQ,YAAc,CAAE,YAAa,EAAQ,YAAa,CAAG,EAAE,CACnE,GAAI,EAAQ,YAAc,CAAE,YAAa,EAAQ,YAAa,CAAG,EAAE,CACpE,CAGH,wBAAgC,EAAwD,CACtF,MAAO,CACL,GAAG,KAAK,qBAAqB,EAAQ,CACrC,GAAI,OAAO,EAAQ,KAAQ,SAAW,CAAE,IAAK,EAAQ,IAAK,CAAG,EAAE,CAC/D,GAAI,OAAO,EAAQ,OAAU,UAAY,CAAE,MAAO,EAAQ,MAAO,CAAG,EAAE,CACvE,CAGH,iBAAyB,EAAmC,EAAa,GAAoB,CAC3F,IAAM,EAAoB,EAAE,CACtB,EAAqB,EAAE,CACvB,GAAO,EAAgB,IAAsC,CAC7D,IAAU,IAAA,KACZ,EAAQ,KAAK,GAAG,EAAO,MAAM,CAC7B,EAAO,KAAK,EAAM,GAYtB,OARA,EAAI,kBAAmB,EAAQ,eAAe,CAC9C,EAAI,eAAgB,EAAQ,YAAY,CACxC,EAAI,eAAgB,EAAQ,YAAY,CACxC,EAAI,cAAe,EAAQ,YAAY,CACnC,GAAc,OAAO,EAAQ,KAAQ,UAAY,CAAC,EAAQ,OAC5D,EAAI,MAAO,EAAQ,IAAI,CAGlB,CACL,IAAK,EAAQ,OAAS,EAAI,UAAU,EAAQ,KAAK,QAAQ,GAAK,GAC9D,SACD,CAGH,eACE,EACA,EACA,EACA,EACA,EACqB,CACrB,OAAO,EACJ,QACC,iBAAiB,EAAW;;kBAG7B,CACA,IAAI,EAAgB,EAAa,EAAa,EAAY,CAG/D,cAAsB,EAAc,EAAqB,CACvD,OAAO,EAAG,QAAQ,iBAAiB,EAAW,eAAe,CAAC,IAAI,EAAG,CAGvE,aAAqB,EAAuC,CAC1D,GAAI,CAAC,EAAI,cACP,MAAO,EAAE,CAGX,IAAM,EAAS,KAAK,MAAM,EAAI,cAAc,CAC5C,GAAI,CAAC,GAAU,OAAO,GAAW,UAAY,MAAM,QAAQ,EAAO,CAChE,MAAM,IAAI,EAAkB,kCAAmC,uBAAuB,CAGxF,OAAO,EAGT,UAAkB,EAAqC,CACrD,IAAM,EAAY,KAAK,aAAa,EAAI,CAAC,GACzC,GAAI,CAAC,EACH,OAGF,IAAM,EAAS,EAAgB,UAAU,EAAU,CACnD,OAAO,EAAO,QAAU,EAAO,KAAO,IAAA,GAIxC,cAAsB,EAA2B,CAC/C,OAAO,KAAK,MAAM,EAAM,UAAU,CAAG,KAAK,KAAK,EAAI,KAAK,iBAAiB,EAAM,SAAS,CAG1F,wBAAgC,EAAyB,CACvD,OAAQ,GAAyC,OAAS,2BAG5D,oBAA4B,EAA0E,CACpG,OAAO,EAAwB,MAAM,CACnC,QAAS,GACT,GAAG,EACH,GAAI,EAAS,OAAS,CAAE,KAAM,EAAS,OAAO,KAAM,CAAG,EAAE,CAC1D,CAAC,CAGJ,mBAA2B,EAAkC,CAC3D,OAAO,EAAwB,MAAM,CAAE,QAAS,GAAO,QAAO,CAAC,CAGjE,iBAAyB,EAA2B,CAClD,IAAM,EAAO,EAAG,QAAQ,oBAAoB,IAAa,CAAC,KAAK,CAC/D,OAAO,IAAI,IAAI,EAAK,IAAK,GAAQ,EAAI,KAAK,CAAC,CAG7C,SAAiB,EAAkC,CACjD,IAAM,EAAiB,KAAK,aAAa,EAAI,CACvC,EAAW,OAAO,KAAK,EAAe,CAAC,OAAS,EAAI,EAAiB,IAAA,GAE3E,OAAO,EAAyB,MAAM,CACpC,eAAgB,EAAI,gBACpB,YAAa,EAAI,aACjB,YAAa,EAAI,aACjB,GAAI,EAAI,YAAc,CAAE,YAAa,EAAI,YAAa,CAAG,EAAE,CAC3D,GAAI,EAAI,IAAM,CAAE,IAAK,EAAI,IAAK,CAAG,EAAE,CACnC,KAAM,EAAI,KACV,KAAM,EAAI,KACV,GAAI,EAAW,CAAE,WAAU,CAAG,EAAE,CAChC,UAAW,EAAI,WACf,UAAW,EAAI,WAChB,CAAC,CAGJ,MAAc,0BACZ,EACA,EACA,EACA,EACwB,CACxB,GAAI,IAAkB,IAAA,IAAa,EAAc,EAAe,EAAU,EACpE,CAAC,EAAc,IAAI,EAAc,EAAK,MAAM,KAAK,gBAAgB,EAAe,EAAK,CACvF,OAAO,EAIX,IAAK,IAAI,EAAO,EAAU,IAAK,GAAQ,EAAU,IAAK,GAAQ,EACxD,SAAS,GAAiB,EAAc,IAAI,EAAK,GAIjD,MAAM,KAAK,gBAAgB,EAAM,EAAK,CACxC,OAAO,EAIX,OAAO,KAGT,MAAc,gBAAgB,EAAc,EAAgC,CAC1E,IAAM,EAAiBE,EAAAA,QAAG,UAAU,GAAK,QAAU,YAAc,EAC3D,EAAiB,MAAM,KAC3B,IAAI,IAAwB,CAAC,EAAgB,YAAa,UAAW,IAAA,GAAW,MAAM,CAAC,CACxF,CAED,IAAK,IAAM,KAAiB,EAC1B,GAAI,CAAE,MAAM,KAAK,sBAAsB,EAAM,EAAc,CACzD,MAAO,GAIX,MAAO,GAGT,MAAc,sBAAsB,EAAc,EAAiC,CACjF,OAAO,IAAI,QAAS,GAAY,CAC9B,IAAM,EAASC,EAAAA,QAAI,cAAc,CACjC,EAAO,KAAK,YAAe,EAAQ,GAAM,CAAC,CAC1C,EAAO,KAAK,gBAAmB,EAAO,UAAY,EAAQ,GAAK,CAAC,CAAC,CAC7D,EACF,EAAO,OAAO,EAAM,EAAK,CAEzB,EAAO,OAAO,EAAK,EAErB,CAGJ,iBAAyB,EAAsB,CAC7C,GAAI,CAEF,OADA,QAAQ,KAAK,EAAK,EAAE,CACb,QACD,CACN,MAAO,IAIX,MAAc,WAAW,EAAqC,CAC5D,GAAI,CAEF,OADA,MAAMH,EAAAA,QAAG,OAAO,EAAU,CACnB,QACD,CACN,MAAO,IAIX,sBAA8B,EAAe,EAAqD,CAChG,OAAO,EAA6B,MAAM,CACxC,QAAS,GACT,GAAI,IAAS,IAAA,GAAuB,EAAE,CAAb,CAAE,OAAM,CACjC,GAAI,EAAS,CAAE,SAAQ,CAAG,EAAE,CAC7B,CAAC,CAGJ,sBAA8B,EAAuC,CACnE,OAAO,EAA6B,MAAM,CAAE,QAAS,GAAO,QAAO,CAAC"}
|
|
1
|
+
{"version":3,"file":"PortRegistryService.cjs","names":["z","path","os","path","fs","os","net"],"sources":["../src/types/index.ts","../src/utils/index.ts","../src/services/PortRegistryService.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport const REGISTRY_VERSION = 1 as const;\n\nexport const ServiceCategorySchema = z.enum(['service', 'tool']);\n\nexport const ServiceMetadataSchema = z.record(z.string(), z.unknown());\n\nexport const PortRegistryRecordSchema = z.object({\n repositoryPath: z.string().trim().min(1, 'repositoryPath is required'),\n serviceName: z.string().trim().min(1, 'serviceName is required'),\n serviceType: ServiceCategorySchema,\n environment: z.string().trim().min(1).optional(),\n pid: z.number().int().min(1).optional(),\n port: z.number().int().min(1).max(65535),\n host: z.string().trim().min(1).default('127.0.0.1'),\n metadata: ServiceMetadataSchema.optional(),\n createdAt: z.string().trim().min(1),\n updatedAt: z.string().trim().min(1),\n});\n\nexport const PortRegistryStateSchema = z.object({\n version: z.literal(REGISTRY_VERSION),\n updatedAt: z.string().trim().min(1),\n entries: z.array(PortRegistryRecordSchema),\n});\n\nexport const PortAllocationRangeSchema = z\n .object({\n min: z.number().int().min(1).max(65535),\n max: z.number().int().min(1).max(65535),\n })\n .refine((range) => range.min <= range.max, {\n message: 'Port range min must be less than or equal to max',\n path: ['min'],\n });\n\nexport const ReservePortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.default('service'),\n environment: z.string().trim().min(1).optional(),\n pid: z.number().int().min(1).optional(),\n portRange: PortAllocationRangeSchema.optional(),\n preferredPort: z.number().int().min(1).max(65535).optional(),\n host: z.string().trim().min(1).optional(),\n metadata: ServiceMetadataSchema.optional(),\n force: z.boolean().optional(),\n});\n\n/**\n * Reserved metadata key holding bootstrap-claim state.\n *\n * A claim turns the scope row into a cross-process mutex: the row is inserted by\n * the process that intends to spawn a service, and is only converted into a\n * normal allocation once that service confirms it is listening. Storing the\n * state in metadata avoids a schema migration for registry files already on disk.\n */\nexport const CLAIM_METADATA_KEY = '__claim' as const;\n\nexport const DEFAULT_CLAIM_TTL_MS = 45_000;\n\nexport const PortClaimSchema = z.object({\n token: z.string().min(1),\n ownerPid: z.number().int().min(1),\n expiresAt: z.string().trim().min(1),\n});\n\nexport const ClaimPortRequestSchema = ReservePortRequestSchema.omit({ force: true }).extend({\n claimTtlMs: z.number().int().min(1000).max(600_000).default(DEFAULT_CLAIM_TTL_MS),\n});\n\nexport const ClaimPortResponseSchema = z.object({\n success: z.boolean(),\n outcome: z.enum(['claimed', 'existing']).optional(),\n port: z.number().int().min(1).max(65535).optional(),\n record: PortRegistryRecordSchema.optional(),\n /** Present only when outcome is 'claimed'. Required to confirm or release the claim. */\n claimToken: z.string().optional(),\n /** True when the existing row is another process's in-flight claim rather than a live service. */\n claimPending: z.boolean().optional(),\n error: z.string().optional(),\n});\n\nexport const ConfirmPortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.default('service'),\n environment: z.string().trim().min(1).optional(),\n claimToken: z.string().min(1),\n pid: z.number().int().min(1),\n metadata: ServiceMetadataSchema.optional(),\n});\n\nexport const ReleaseClaimRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.default('service'),\n environment: z.string().trim().min(1).optional(),\n claimToken: z.string().min(1),\n});\n\nexport const ReleasePortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.optional(),\n pid: z.number().int().min(1).optional(),\n environment: z.string().trim().min(1).optional(),\n force: z.boolean().optional(),\n});\n\nexport const GetPortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.optional(),\n environment: z.string().trim().min(1).optional(),\n});\n\nexport const FindAvailablePortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.optional(),\n environment: z.string().trim().min(1).optional(),\n portRange: PortAllocationRangeSchema.optional(),\n preferredPort: z.number().int().min(1).max(65535).optional(),\n host: z.string().trim().min(1).default('127.0.0.1'),\n});\n\nexport const PortAllocationResponseSchema = z.object({\n success: z.boolean(),\n port: z.number().int().min(1).max(65535).optional(),\n record: PortRegistryRecordSchema.optional(),\n error: z.string().optional(),\n});\n\nexport const PortUsageListFiltersSchema = z.object({\n repositoryPath: z.string().trim().min(1).optional(),\n serviceType: ServiceCategorySchema.optional(),\n serviceName: z.string().trim().min(1).optional(),\n environment: z.string().trim().min(1).optional(),\n});\n\nexport const ReleasePortsRequestSchema = PortUsageListFiltersSchema.extend({\n pid: z.number().int().min(1).optional(),\n force: z.boolean().optional(),\n});\n\nexport const PortRegistryCleanupResponseSchema = z.object({\n success: z.boolean(),\n scanned: z.number().int().min(0),\n removed: z.number().int().min(0),\n error: z.string().optional(),\n});\n\nexport const PortRegistryBulkReleaseResponseSchema = z.object({\n success: z.boolean(),\n released: z.number().int().min(0),\n error: z.string().optional(),\n});\n\nexport type ServiceCategory = z.infer<typeof ServiceCategorySchema>;\nexport type ServiceMetadata = z.infer<typeof ServiceMetadataSchema>;\nexport type PortRegistryRecord = z.infer<typeof PortRegistryRecordSchema>;\nexport type PortRegistryState = z.infer<typeof PortRegistryStateSchema>;\nexport type PortAllocationRange = z.infer<typeof PortAllocationRangeSchema>;\nexport type ReservePortRequest = z.infer<typeof ReservePortRequestSchema>;\nexport type PortClaim = z.infer<typeof PortClaimSchema>;\nexport type ClaimPortRequest = z.input<typeof ClaimPortRequestSchema>;\nexport type ClaimPortResponse = z.infer<typeof ClaimPortResponseSchema>;\nexport type ConfirmPortRequest = z.input<typeof ConfirmPortRequestSchema>;\nexport type ReleaseClaimRequest = z.input<typeof ReleaseClaimRequestSchema>;\nexport type ReleasePortRequest = z.infer<typeof ReleasePortRequestSchema>;\nexport type GetPortRequest = z.infer<typeof GetPortRequestSchema>;\nexport type FindAvailablePortRequest = z.infer<typeof FindAvailablePortRequestSchema>;\nexport type PortAllocationResponse = z.infer<typeof PortAllocationResponseSchema>;\nexport type PortUsageListFilters = z.infer<typeof PortUsageListFiltersSchema>;\nexport type ReleasePortsRequest = z.infer<typeof ReleasePortsRequestSchema>;\nexport type PortRegistryCleanupResponse = z.infer<typeof PortRegistryCleanupResponseSchema>;\nexport type PortRegistryBulkReleaseResponse = z.infer<typeof PortRegistryBulkReleaseResponseSchema>;\n\nexport type PortRegistryErrorCode =\n | 'INVALID_REQUEST'\n | 'REGISTRY_READ_FAILED'\n | 'REGISTRY_WRITE_FAILED'\n | 'REGISTRY_LOCK_FAILED'\n | 'PORT_NOT_AVAILABLE'\n | 'NO_PORT_FOUND';\n\nexport class PortRegistryError extends Error {\n readonly code: PortRegistryErrorCode;\n\n constructor(message: string, code: PortRegistryErrorCode, options?: ErrorOptions) {\n super(message, options);\n this.name = 'PortRegistryError';\n this.code = code;\n }\n}\n","import os from 'node:os';\nimport path from 'node:path';\n\nexport const DEFAULT_REGISTRY_PATH = path.join(os.homedir(), '.port-registry', 'ports.turso.sqlite');\nexport const DEFAULT_REGISTRY_LOCK_PATH = `${DEFAULT_REGISTRY_PATH}.lock`;\nexport const LOCK_RETRY_DELAY_MS = 75;\nexport const LOCK_MAX_RETRIES = 80;\nexport const LOCK_STALE_AFTER_MS = 5_000;\nexport const DEFAULT_PORT_RANGE = { min: 3000, max: 4999 };\nexport const DEFAULT_HOST = '127.0.0.1';\n\nexport const normalizeRepositoryPath = (value: string): string => path.resolve(value);\n\nexport const isPortInRange = (port: number, range: { min: number; max: number }): boolean =>\n port >= range.min && port <= range.max;\n","import { randomUUID } from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport net from 'node:net';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { Database } from '@tursodatabase/database/compat';\nimport {\n CLAIM_METADATA_KEY,\n type ClaimPortRequest,\n ClaimPortRequestSchema,\n type ClaimPortResponse,\n ClaimPortResponseSchema,\n type ConfirmPortRequest,\n ConfirmPortRequestSchema,\n type FindAvailablePortRequest,\n FindAvailablePortRequestSchema,\n type GetPortRequest,\n GetPortRequestSchema,\n type PortAllocationRange,\n type PortAllocationResponse,\n PortAllocationResponseSchema,\n type PortClaim,\n PortClaimSchema,\n type PortRegistryBulkReleaseResponse,\n PortRegistryBulkReleaseResponseSchema,\n type PortRegistryCleanupResponse,\n PortRegistryCleanupResponseSchema,\n PortRegistryError,\n type PortRegistryRecord,\n PortRegistryRecordSchema,\n type PortRegistryState,\n PortRegistryStateSchema,\n type PortUsageListFilters,\n PortUsageListFiltersSchema,\n type ReleaseClaimRequest,\n ReleaseClaimRequestSchema,\n type ReleasePortRequest,\n ReleasePortRequestSchema,\n type ReleasePortsRequest,\n ReleasePortsRequestSchema,\n type ReservePortRequest,\n ReservePortRequestSchema,\n} from '../types';\nimport {\n DEFAULT_HOST,\n DEFAULT_PORT_RANGE,\n DEFAULT_REGISTRY_PATH,\n isPortInRange,\n normalizeRepositoryPath,\n} from '../utils';\n\nconst PORT_TABLE = 'port_allocations';\nconst METADATA_TABLE = 'registry_metadata';\nconst LEGACY_IMPORT_KEY = 'legacy_json_import_v1';\nconst SQLITE_BUSY_TIMEOUT_MS = 6_000;\nconst SQLITE_INIT_MAX_ATTEMPTS = 8;\nconst SQLITE_INIT_RETRY_DELAY_MS = 25;\nconst MAX_CLAIM_INSERT_ATTEMPTS = 3;\nconst writeQueues = new Map<string, Promise<void>>();\n\ntype SqlValue = string | number | null;\n\ninterface PortRow {\n id: number;\n repository_path: string;\n service_name: string;\n service_type: 'service' | 'tool';\n environment: string;\n pid: number | null;\n port: number;\n host: string;\n metadata_json: string | null;\n created_at: string;\n updated_at: string;\n}\n\ninterface NormalizedListFilters {\n repositoryPath?: string;\n serviceName?: string;\n serviceType?: 'service' | 'tool';\n environment?: string;\n}\n\ninterface NormalizedReleaseFilters extends NormalizedListFilters {\n pid?: number;\n force?: boolean;\n}\n\ninterface WhereClause {\n sql: string;\n params: SqlValue[];\n}\n\n/**\n * Service for managing shared port allocations in a cross-process SQLite database.\n */\nexport class PortRegistryService {\n private readonly registryPath: string;\n private readonly legacyRegistryPath: string;\n private sqlite: Database | null = null;\n private initialization: Promise<Database> | null = null;\n\n constructor(registryPath: string = DEFAULT_REGISTRY_PATH, _legacyLockPath?: string) {\n this.registryPath = PortRegistryService.resolveRegistryPath(registryPath);\n this.legacyRegistryPath = PortRegistryService.resolveLegacyRegistryPath(registryPath);\n }\n\n /**\n * Resolve a directory, SQLite path, or legacy JSON path to the SQLite database path.\n */\n static resolveRegistryPath(inputPath?: string): string {\n const resolvedPath = PortRegistryService.resolveInputPath(inputPath ?? DEFAULT_REGISTRY_PATH);\n const extension = path.extname(resolvedPath);\n\n if (extension === '.json') {\n return resolvedPath.slice(0, -extension.length) + '.sqlite';\n }\n\n if (extension === '.sqlite' || extension === '.db') {\n return resolvedPath;\n }\n\n return path.join(resolvedPath, 'ports.sqlite');\n }\n\n async getPort(rawRequest: GetPortRequest): Promise<PortAllocationResponse> {\n const request = GetPortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const filters = this.normalizeListFilters(request);\n const where = this.buildWhereClause(filters);\n const row = db.prepare(`SELECT * FROM ${PORT_TABLE}${where.sql} ORDER BY id LIMIT 1`).get(...where.params) as\n | PortRow\n | undefined;\n\n if (!row) {\n return this.createFailureResponse(`No allocation found for ${request.serviceName} in requested scope`);\n }\n\n const record = this.toRecord(row);\n return this.createSuccessResponse(record.port, record);\n }\n\n async findAvailablePort(rawRequest: FindAvailablePortRequest): Promise<PortAllocationResponse> {\n const request = FindAvailablePortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const range = request.portRange ?? DEFAULT_PORT_RANGE;\n const reserved = this.getReservedPorts(db);\n const availablePort = await this.findAvailablePortInternal(range, request.preferredPort, reserved, request.host);\n\n if (availablePort === null) {\n return this.createFailureResponse(`No available port found in range ${range.min}-${range.max}`);\n }\n\n return this.createSuccessResponse(availablePort);\n }\n\n async reservePort(rawRequest: ReservePortRequest): Promise<PortAllocationResponse> {\n const request = ReservePortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n const host = request.host ?? DEFAULT_HOST;\n const range = request.portRange ?? DEFAULT_PORT_RANGE;\n const force = request.force ?? false;\n\n return this.withImmediateTransaction(db, async () => {\n const existingRow = db\n .prepare(\n `SELECT * FROM ${PORT_TABLE}\n WHERE repository_path = ? AND service_name = ? AND service_type = ? AND environment = ?\n LIMIT 1`,\n )\n .get(repositoryPath, request.serviceName, serviceType, environment) as PortRow | undefined;\n\n if (existingRow && !force && isPortInRange(existingRow.port, range)) {\n const available = await this.isPortAvailable(existingRow.port, host);\n if (available) {\n const updatedAt = new Date().toISOString();\n db.prepare(`UPDATE ${PORT_TABLE} SET updated_at = ? WHERE id = ?`).run(updatedAt, existingRow.id);\n const record = this.toRecord({ ...existingRow, updated_at: updatedAt });\n return this.createSuccessResponse(record.port, record);\n }\n }\n\n if (existingRow) {\n db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`).run(existingRow.id);\n }\n\n const reserved = this.getReservedPorts(db);\n const availablePort = await this.findAvailablePortInternal(range, request.preferredPort, reserved, host);\n if (availablePort === null) {\n return this.createFailureResponse(`No available port found in range ${range.min}-${range.max}`);\n }\n\n const now = new Date().toISOString();\n const insert = db\n .prepare(\n `INSERT INTO ${PORT_TABLE} (\n repository_path, service_name, service_type, environment, pid, port, host,\n metadata_json, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n repositoryPath,\n request.serviceName,\n serviceType,\n environment,\n request.pid ?? null,\n availablePort,\n host,\n request.metadata ? JSON.stringify(request.metadata) : null,\n now,\n now,\n );\n\n const row = db.prepare(`SELECT * FROM ${PORT_TABLE} WHERE id = ?`).get(Number(insert.lastInsertRowid)) as PortRow;\n const record = this.toRecord(row);\n return this.createSuccessResponse(record.port, record);\n });\n }\n\n /**\n * Atomically claim a port for a service that is about to be started.\n *\n * Unlike {@link reservePort}, a claim never deletes a live allocation: callers\n * that find an `existing` row decide for themselves whether to reuse or replace\n * it. Exactly one concurrent caller receives `outcome: 'claimed'` — the rest see\n * the winner's row, so a claim doubles as a cross-process bootstrap mutex.\n *\n * A claim must be finalized with {@link confirmPort} or dropped with\n * {@link releaseClaim}. An abandoned claim is reaped once it expires, or\n * immediately if its owning process is gone.\n */\n async claimPort(rawRequest: ClaimPortRequest): Promise<ClaimPortResponse> {\n const request = ClaimPortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n const host = request.host ?? DEFAULT_HOST;\n const range = request.portRange ?? DEFAULT_PORT_RANGE;\n const ownerPid = request.pid ?? process.pid;\n\n return this.withImmediateTransaction(db, async () => {\n const existingRow = this.selectScopeRow(db, repositoryPath, request.serviceName, serviceType, environment);\n\n if (existingRow) {\n const claim = this.readClaim(existingRow);\n\n if (!claim) {\n return this.createClaimResponse({ outcome: 'existing', record: this.toRecord(existingRow) });\n }\n\n if (this.isClaimActive(claim)) {\n return this.createClaimResponse({\n outcome: 'existing',\n claimPending: true,\n record: this.toRecord(existingRow),\n });\n }\n\n db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`).run(existingRow.id);\n }\n\n const excluded = new Set<number>();\n for (let attempt = 0; attempt < MAX_CLAIM_INSERT_ATTEMPTS; attempt += 1) {\n const reserved = this.getReservedPorts(db);\n for (const port of excluded) {\n reserved.add(port);\n }\n\n const availablePort = await this.findAvailablePortInternal(range, request.preferredPort, reserved, host);\n if (availablePort === null) {\n return this.createClaimFailure(`No available port found in range ${range.min}-${range.max}`);\n }\n\n const claim: PortClaim = {\n token: randomUUID(),\n ownerPid,\n expiresAt: new Date(Date.now() + request.claimTtlMs).toISOString(),\n };\n const now = new Date().toISOString();\n\n try {\n const insert = db\n .prepare(\n `INSERT INTO ${PORT_TABLE} (\n repository_path, service_name, service_type, environment, pid, port, host,\n metadata_json, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n repositoryPath,\n request.serviceName,\n serviceType,\n environment,\n ownerPid,\n availablePort,\n host,\n JSON.stringify({ ...(request.metadata ?? {}), [CLAIM_METADATA_KEY]: claim }),\n now,\n now,\n );\n\n const row = this.selectRowById(db, Number(insert.lastInsertRowid));\n return this.createClaimResponse({\n outcome: 'claimed',\n record: this.toRecord(row),\n claimToken: claim.token,\n });\n } catch (error) {\n // Another scope took this port between the availability scan and the\n // insert; retry with it excluded rather than failing the bootstrap.\n if (!this.isUniqueConstraintError(error)) {\n throw error;\n }\n excluded.add(availablePort);\n }\n }\n\n return this.createClaimFailure(`Failed to claim a port after ${MAX_CLAIM_INSERT_ATTEMPTS} attempts`);\n });\n }\n\n /**\n * Convert a claim into a normal allocation owned by the now-running service.\n *\n * Fails when the claim has been reaped or taken over, which tells the caller it\n * lost the lease and must exit instead of registering over the new owner.\n */\n async confirmPort(rawRequest: ConfirmPortRequest): Promise<PortAllocationResponse> {\n const request = ConfirmPortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n\n return this.withImmediateTransaction(db, async () => {\n const row = this.selectScopeRow(db, repositoryPath, request.serviceName, serviceType, environment);\n const claim = row ? this.readClaim(row) : undefined;\n\n if (!row || !claim || claim.token !== request.claimToken) {\n return this.createFailureResponse(`Claim not found or expired for ${request.serviceName}`);\n }\n\n const metadata = { ...this.readMetadata(row), ...(request.metadata ?? {}) };\n delete metadata[CLAIM_METADATA_KEY];\n const updatedAt = new Date().toISOString();\n\n db.prepare(`UPDATE ${PORT_TABLE} SET pid = ?, metadata_json = ?, updated_at = ? WHERE id = ?`).run(\n request.pid,\n Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : null,\n updatedAt,\n row.id,\n );\n\n const record = this.toRecord(this.selectRowById(db, row.id));\n return this.createSuccessResponse(record.port, record);\n });\n }\n\n /**\n * Drop an unconfirmed claim, e.g. after the spawned service failed to start.\n * Idempotent: a claim already reaped or confirmed reports success.\n */\n async releaseClaim(rawRequest: ReleaseClaimRequest): Promise<PortAllocationResponse> {\n const request = ReleaseClaimRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n\n return this.withImmediateTransaction(db, async () => {\n const row = this.selectScopeRow(db, repositoryPath, request.serviceName, serviceType, environment);\n const claim = row ? this.readClaim(row) : undefined;\n\n if (row && claim?.token === request.claimToken) {\n db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`).run(row.id);\n }\n\n return this.createSuccessResponse();\n });\n }\n\n async releasePort(rawRequest: ReleasePortRequest): Promise<PortAllocationResponse> {\n const request = ReleasePortRequestSchema.parse(rawRequest);\n const result = await this.releasePorts(request);\n\n if (!result.success) {\n return this.createFailureResponse(`No matching registry entry for ${request.serviceName}`);\n }\n\n return this.createSuccessResponse();\n }\n\n async releasePorts(rawRequest: ReleasePortsRequest): Promise<PortRegistryBulkReleaseResponse> {\n const request = ReleasePortsRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const filters = this.normalizeReleaseFilters(request);\n const where = this.buildWhereClause(filters, true);\n const result = db.prepare(`DELETE FROM ${PORT_TABLE}${where.sql}`).run(...where.params);\n\n if (result.changes === 0) {\n return PortRegistryBulkReleaseResponseSchema.parse({\n success: false,\n released: 0,\n error: 'No matching registry entries',\n });\n }\n\n return PortRegistryBulkReleaseResponseSchema.parse({ success: true, released: result.changes });\n }\n\n async listAllocations(filters: PortUsageListFilters = {}): Promise<PortRegistryRecord[]> {\n const request = PortUsageListFiltersSchema.parse(filters);\n const db = await this.getDb();\n const where = this.buildWhereClause(this.normalizeListFilters(request));\n const rows = db.prepare(`SELECT * FROM ${PORT_TABLE}${where.sql} ORDER BY id`).all(...where.params) as PortRow[];\n return rows.map((row) => this.toRecord(row));\n }\n\n async cleanupStaleAllocations(filters: PortUsageListFilters = {}): Promise<PortRegistryCleanupResponse> {\n const request = PortUsageListFiltersSchema.parse(filters);\n const db = await this.getDb();\n const where = this.buildWhereClause(this.normalizeListFilters(request));\n const rows = db.prepare(`SELECT * FROM ${PORT_TABLE}${where.sql}`).all(...where.params) as PortRow[];\n const staleIds: number[] = [];\n\n await Promise.all(\n rows.map(async (row) => {\n const claim = this.readClaim(row);\n if (claim) {\n // A bootstrap row lives and dies by its claim, not by the pid column:\n // that pid belongs to the spawning parent, which may exit as soon as\n // the service confirms. Only an expired or orphaned claim is stale.\n if (!this.isClaimActive(claim)) {\n staleIds.push(row.id);\n }\n return;\n }\n\n const repositoryExists = await this.pathExists(row.repository_path);\n const deadPid = typeof row.pid === 'number' && !this.isProcessRunning(row.pid);\n if (!repositoryExists || deadPid) {\n staleIds.push(row.id);\n }\n }),\n );\n\n if (staleIds.length > 0) {\n const remove = db.transaction((ids: number[]) => {\n const statement = db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`);\n for (const id of ids) {\n statement.run(id);\n }\n });\n remove(staleIds);\n }\n\n return PortRegistryCleanupResponseSchema.parse({\n success: true,\n scanned: rows.length,\n removed: staleIds.length,\n });\n }\n\n close(): void {\n this.sqlite?.close();\n this.sqlite = null;\n this.initialization = null;\n }\n\n private static resolveInputPath(inputPath: string): string {\n return path.isAbsolute(inputPath) ? inputPath : path.join(process.cwd(), inputPath);\n }\n\n private static resolveLegacyRegistryPath(inputPath: string): string {\n const resolvedPath = PortRegistryService.resolveInputPath(inputPath);\n const extension = path.extname(resolvedPath);\n\n if (extension === '.json') {\n return resolvedPath;\n }\n\n if (extension === '.sqlite' || extension === '.db') {\n return resolvedPath.slice(0, -extension.length) + '.json';\n }\n\n return path.join(resolvedPath, 'ports.json');\n }\n\n private async getDb(): Promise<Database> {\n if (this.sqlite) {\n return this.sqlite;\n }\n\n if (!this.initialization) {\n this.initialization = this.initializeDatabase();\n }\n\n return this.initialization;\n }\n\n private async initializeDatabase(): Promise<Database> {\n await fs.mkdir(path.dirname(this.registryPath), { recursive: true });\n const { Database } = await import('@tursodatabase/database/compat');\n\n for (let attempt = 1; attempt <= SQLITE_INIT_MAX_ATTEMPTS; attempt += 1) {\n let db: Database | null = null;\n\n try {\n db = new Database(this.registryPath, {\n experimental: ['multiprocess_wal'],\n timeout: SQLITE_BUSY_TIMEOUT_MS,\n });\n db.pragma(`busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`, {});\n db.pragma('journal_mode = WAL', {});\n db.pragma('synchronous = NORMAL', {});\n db.exec(`\n CREATE TABLE IF NOT EXISTS ${METADATA_TABLE} (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS ${PORT_TABLE} (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n repository_path TEXT NOT NULL,\n service_name TEXT NOT NULL,\n service_type TEXT NOT NULL,\n environment TEXT NOT NULL,\n pid INTEGER,\n port INTEGER NOT NULL UNIQUE,\n host TEXT NOT NULL,\n metadata_json TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n UNIQUE (repository_path, service_name, service_type, environment)\n );\n CREATE INDEX IF NOT EXISTS port_allocations_scope_idx\n ON ${PORT_TABLE} (repository_path, service_name, service_type, environment);\n CREATE INDEX IF NOT EXISTS port_allocations_environment_idx\n ON ${PORT_TABLE} (environment, service_type);\n `);\n this.sqlite = db;\n await this.importLegacyJson(db);\n return db;\n } catch (error) {\n db?.close();\n this.sqlite = null;\n\n if (!this.isDatabaseBusyError(error) || attempt === SQLITE_INIT_MAX_ATTEMPTS) {\n this.initialization = null;\n throw new PortRegistryError(\n `Failed to initialize registry database: ${error instanceof Error ? error.message : String(error)}`,\n 'REGISTRY_READ_FAILED',\n { cause: error },\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, SQLITE_INIT_RETRY_DELAY_MS * 2 ** (attempt - 1)));\n }\n }\n\n throw new Error('Unreachable database initialization state');\n }\n\n private isDatabaseBusyError(error: unknown): boolean {\n const code = (error as { code?: unknown })?.code;\n return code === 'SQLITE_BUSY' || code === 'SQLITE_LOCKED';\n }\n\n private async importLegacyJson(db: Database): Promise<void> {\n const imported = db.prepare(`SELECT value FROM ${METADATA_TABLE} WHERE key = ?`).get(LEGACY_IMPORT_KEY);\n if (imported) {\n return;\n }\n\n let legacyState: PortRegistryState | null = null;\n try {\n const content = await fs.readFile(this.legacyRegistryPath, 'utf-8');\n legacyState = PortRegistryStateSchema.parse(JSON.parse(content));\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT') {\n throw error;\n }\n }\n\n const migrate = db.transaction((state: PortRegistryState | null) => {\n const insert = db.prepare(\n `INSERT OR IGNORE INTO ${PORT_TABLE} (\n repository_path, service_name, service_type, environment, pid, port, host,\n metadata_json, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n );\n\n for (const record of state?.entries ?? []) {\n insert.run(\n normalizeRepositoryPath(record.repositoryPath),\n record.serviceName,\n record.serviceType,\n record.environment ?? '',\n record.pid ?? null,\n record.port,\n record.host,\n record.metadata ? JSON.stringify(record.metadata) : null,\n record.createdAt,\n record.updatedAt,\n );\n }\n\n db.prepare(`INSERT OR REPLACE INTO ${METADATA_TABLE} (key, value) VALUES (?, ?)`).run(\n LEGACY_IMPORT_KEY,\n this.legacyRegistryPath,\n );\n });\n\n migrate(legacyState);\n }\n\n private async withImmediateTransaction<T>(db: Database, run: () => Promise<T>): Promise<T> {\n const previous = writeQueues.get(this.registryPath) ?? Promise.resolve();\n let releaseQueue: () => void = () => undefined;\n const current = new Promise<void>((resolve) => {\n releaseQueue = resolve;\n });\n const tail = previous.catch(() => undefined).then(() => current);\n writeQueues.set(this.registryPath, tail);\n await previous.catch(() => undefined);\n\n try {\n db.exec('BEGIN IMMEDIATE');\n try {\n const result = await run();\n db.exec('COMMIT');\n return result;\n } catch (error) {\n if (db.inTransaction) {\n db.exec('ROLLBACK');\n }\n throw error;\n }\n } finally {\n releaseQueue();\n if (writeQueues.get(this.registryPath) === tail) {\n writeQueues.delete(this.registryPath);\n }\n }\n }\n\n private normalizeListFilters(filters: PortUsageListFilters): NormalizedListFilters {\n return {\n ...(filters.repositoryPath ? { repositoryPath: normalizeRepositoryPath(filters.repositoryPath) } : {}),\n ...(filters.serviceName ? { serviceName: filters.serviceName } : {}),\n ...(filters.serviceType ? { serviceType: filters.serviceType } : {}),\n ...(filters.environment ? { environment: filters.environment } : {}),\n };\n }\n\n private normalizeReleaseFilters(filters: ReleasePortsRequest): NormalizedReleaseFilters {\n return {\n ...this.normalizeListFilters(filters),\n ...(typeof filters.pid === 'number' ? { pid: filters.pid } : {}),\n ...(typeof filters.force === 'boolean' ? { force: filters.force } : {}),\n };\n }\n\n private buildWhereClause(filters: NormalizedReleaseFilters, includePid = false): WhereClause {\n const clauses: string[] = [];\n const params: SqlValue[] = [];\n const add = (column: string, value: SqlValue | undefined): void => {\n if (value !== undefined) {\n clauses.push(`${column} = ?`);\n params.push(value);\n }\n };\n\n add('repository_path', filters.repositoryPath);\n add('service_name', filters.serviceName);\n add('service_type', filters.serviceType);\n add('environment', filters.environment);\n if (includePid && typeof filters.pid === 'number' && !filters.force) {\n add('pid', filters.pid);\n }\n\n return {\n sql: clauses.length > 0 ? ` WHERE ${clauses.join(' AND ')}` : '',\n params,\n };\n }\n\n private selectScopeRow(\n db: Database,\n repositoryPath: string,\n serviceName: string,\n serviceType: 'service' | 'tool',\n environment: string,\n ): PortRow | undefined {\n return db\n .prepare(\n `SELECT * FROM ${PORT_TABLE}\n WHERE repository_path = ? AND service_name = ? AND service_type = ? AND environment = ?\n LIMIT 1`,\n )\n .get(repositoryPath, serviceName, serviceType, environment) as PortRow | undefined;\n }\n\n private selectRowById(db: Database, id: number): PortRow {\n return db.prepare(`SELECT * FROM ${PORT_TABLE} WHERE id = ?`).get(id) as PortRow;\n }\n\n private readMetadata(row: PortRow): Record<string, unknown> {\n if (!row.metadata_json) {\n return {};\n }\n\n const parsed = JSON.parse(row.metadata_json) as unknown;\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new PortRegistryError('Stored port metadata is invalid', 'REGISTRY_READ_FAILED');\n }\n\n return parsed as Record<string, unknown>;\n }\n\n private readClaim(row: PortRow): PortClaim | undefined {\n const candidate = this.readMetadata(row)[CLAIM_METADATA_KEY];\n if (!candidate) {\n return undefined;\n }\n\n const parsed = PortClaimSchema.safeParse(candidate);\n return parsed.success ? parsed.data : undefined;\n }\n\n /** A claim holds the scope only while unexpired and its owner is still alive. */\n private isClaimActive(claim: PortClaim): boolean {\n return Date.parse(claim.expiresAt) > Date.now() && this.isProcessRunning(claim.ownerPid);\n }\n\n private isUniqueConstraintError(error: unknown): boolean {\n return (error as { code?: string } | undefined)?.code === 'SQLITE_CONSTRAINT_UNIQUE';\n }\n\n private createClaimResponse(response: Omit<ClaimPortResponse, 'success' | 'port'>): ClaimPortResponse {\n return ClaimPortResponseSchema.parse({\n success: true,\n ...response,\n ...(response.record ? { port: response.record.port } : {}),\n });\n }\n\n private createClaimFailure(error: string): ClaimPortResponse {\n return ClaimPortResponseSchema.parse({ success: false, error });\n }\n\n private getReservedPorts(db: Database): Set<number> {\n const rows = db.prepare(`SELECT port FROM ${PORT_TABLE}`).all() as Array<{ port: number }>;\n return new Set(rows.map((row) => row.port));\n }\n\n private toRecord(row: PortRow): PortRegistryRecord {\n const parsedMetadata = this.readMetadata(row);\n const metadata = Object.keys(parsedMetadata).length > 0 ? parsedMetadata : undefined;\n\n return PortRegistryRecordSchema.parse({\n repositoryPath: row.repository_path,\n serviceName: row.service_name,\n serviceType: row.service_type,\n ...(row.environment ? { environment: row.environment } : {}),\n ...(row.pid ? { pid: row.pid } : {}),\n port: row.port,\n host: row.host,\n ...(metadata ? { metadata } : {}),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n });\n }\n\n private async findAvailablePortInternal(\n portRange: PortAllocationRange,\n preferredPort: number | undefined,\n reservedPorts: Set<number>,\n host: string,\n ): Promise<number | null> {\n if (preferredPort !== undefined && isPortInRange(preferredPort, portRange)) {\n if (!reservedPorts.has(preferredPort) && (await this.isPortAvailable(preferredPort, host))) {\n return preferredPort;\n }\n }\n\n for (let port = portRange.min; port <= portRange.max; port += 1) {\n if (port === preferredPort || reservedPorts.has(port)) {\n continue;\n }\n\n if (await this.isPortAvailable(port, host)) {\n return port;\n }\n }\n\n return null;\n }\n\n private async isPortAvailable(port: number, host: string): Promise<boolean> {\n const normalizedHost = os.platform() === 'win32' ? '127.0.0.1' : host;\n const candidateHosts = Array.from(\n new Set<string | undefined>([normalizedHost, '127.0.0.1', '0.0.0.0', undefined, '::1']),\n );\n\n for (const candidateHost of candidateHosts) {\n if (!(await this.isPortAvailableOnHost(port, candidateHost))) {\n return false;\n }\n }\n\n return true;\n }\n\n private async isPortAvailableOnHost(port: number, host?: string): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer();\n server.once('error', () => resolve(false));\n server.once('listening', () => server.close(() => resolve(true)));\n if (host) {\n server.listen(port, host);\n } else {\n server.listen(port);\n }\n });\n }\n\n private isProcessRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n }\n\n private async pathExists(candidate: string): Promise<boolean> {\n try {\n await fs.access(candidate);\n return true;\n } catch {\n return false;\n }\n }\n\n private createSuccessResponse(port?: number, record?: PortRegistryRecord): PortAllocationResponse {\n return PortAllocationResponseSchema.parse({\n success: true,\n ...(port !== undefined ? { port } : {}),\n ...(record ? { record } : {}),\n });\n }\n\n private createFailureResponse(error: string): PortAllocationResponse {\n return PortAllocationResponseSchema.parse({ success: false, error });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import{randomUUID as e}from"node:crypto";import t from"node:fs/promises";import n from"node:net";import r from"node:os";import i from"node:path";import{
|
|
1
|
+
import{randomUUID as e}from"node:crypto";import t from"node:fs/promises";import n from"node:net";import r from"node:os";import i from"node:path";import{z as a}from"zod";const o=1,s=a.enum([`service`,`tool`]),c=a.record(a.string(),a.unknown()),l=a.object({repositoryPath:a.string().trim().min(1,`repositoryPath is required`),serviceName:a.string().trim().min(1,`serviceName is required`),serviceType:s,environment:a.string().trim().min(1).optional(),pid:a.number().int().min(1).optional(),port:a.number().int().min(1).max(65535),host:a.string().trim().min(1).default(`127.0.0.1`),metadata:c.optional(),createdAt:a.string().trim().min(1),updatedAt:a.string().trim().min(1)}),u=a.object({version:a.literal(1),updatedAt:a.string().trim().min(1),entries:a.array(l)}),d=a.object({min:a.number().int().min(1).max(65535),max:a.number().int().min(1).max(65535)}).refine(e=>e.min<=e.max,{message:`Port range min must be less than or equal to max`,path:[`min`]}),f=a.object({repositoryPath:a.string().trim().min(1),serviceName:a.string().trim().min(1),serviceType:s.default(`service`),environment:a.string().trim().min(1).optional(),pid:a.number().int().min(1).optional(),portRange:d.optional(),preferredPort:a.number().int().min(1).max(65535).optional(),host:a.string().trim().min(1).optional(),metadata:c.optional(),force:a.boolean().optional()}),p=`__claim`,m=45e3,h=a.object({token:a.string().min(1),ownerPid:a.number().int().min(1),expiresAt:a.string().trim().min(1)}),g=f.omit({force:!0}).extend({claimTtlMs:a.number().int().min(1e3).max(6e5).default(m)}),_=a.object({success:a.boolean(),outcome:a.enum([`claimed`,`existing`]).optional(),port:a.number().int().min(1).max(65535).optional(),record:l.optional(),claimToken:a.string().optional(),claimPending:a.boolean().optional(),error:a.string().optional()}),v=a.object({repositoryPath:a.string().trim().min(1),serviceName:a.string().trim().min(1),serviceType:s.default(`service`),environment:a.string().trim().min(1).optional(),claimToken:a.string().min(1),pid:a.number().int().min(1),metadata:c.optional()}),y=a.object({repositoryPath:a.string().trim().min(1),serviceName:a.string().trim().min(1),serviceType:s.default(`service`),environment:a.string().trim().min(1).optional(),claimToken:a.string().min(1)}),b=a.object({repositoryPath:a.string().trim().min(1),serviceName:a.string().trim().min(1),serviceType:s.optional(),pid:a.number().int().min(1).optional(),environment:a.string().trim().min(1).optional(),force:a.boolean().optional()}),x=a.object({repositoryPath:a.string().trim().min(1),serviceName:a.string().trim().min(1),serviceType:s.optional(),environment:a.string().trim().min(1).optional()}),S=a.object({repositoryPath:a.string().trim().min(1),serviceName:a.string().trim().min(1),serviceType:s.optional(),environment:a.string().trim().min(1).optional(),portRange:d.optional(),preferredPort:a.number().int().min(1).max(65535).optional(),host:a.string().trim().min(1).default(`127.0.0.1`)}),C=a.object({success:a.boolean(),port:a.number().int().min(1).max(65535).optional(),record:l.optional(),error:a.string().optional()}),w=a.object({repositoryPath:a.string().trim().min(1).optional(),serviceType:s.optional(),serviceName:a.string().trim().min(1).optional(),environment:a.string().trim().min(1).optional()}),T=w.extend({pid:a.number().int().min(1).optional(),force:a.boolean().optional()}),E=a.object({success:a.boolean(),scanned:a.number().int().min(0),removed:a.number().int().min(0),error:a.string().optional()}),D=a.object({success:a.boolean(),released:a.number().int().min(0),error:a.string().optional()});var O=class extends Error{code;constructor(e,t,n){super(e,n),this.name=`PortRegistryError`,this.code=t}};const k=i.join(r.homedir(),`.port-registry`,`ports.turso.sqlite`),A=`${k}.lock`,j=75,M=80,N=5e3,P={min:3e3,max:4999},F=`127.0.0.1`,I=e=>i.resolve(e),L=(e,t)=>e>=t.min&&e<=t.max,R=`port_allocations`,z=`registry_metadata`,B=`legacy_json_import_v1`,V=6e3,H=new Map;var U=class a{registryPath;legacyRegistryPath;sqlite=null;initialization=null;constructor(e=k,t){this.registryPath=a.resolveRegistryPath(e),this.legacyRegistryPath=a.resolveLegacyRegistryPath(e)}static resolveRegistryPath(e){let t=a.resolveInputPath(e??k),n=i.extname(t);return n===`.json`?t.slice(0,-n.length)+`.sqlite`:n===`.sqlite`||n===`.db`?t:i.join(t,`ports.sqlite`)}async getPort(e){let t=x.parse(e),n=await this.getDb(),r=this.normalizeListFilters(t),i=this.buildWhereClause(r),a=n.prepare(`SELECT * FROM ${R}${i.sql} ORDER BY id LIMIT 1`).get(...i.params);if(!a)return this.createFailureResponse(`No allocation found for ${t.serviceName} in requested scope`);let o=this.toRecord(a);return this.createSuccessResponse(o.port,o)}async findAvailablePort(e){let t=S.parse(e),n=await this.getDb(),r=t.portRange??P,i=this.getReservedPorts(n),a=await this.findAvailablePortInternal(r,t.preferredPort,i,t.host);return a===null?this.createFailureResponse(`No available port found in range ${r.min}-${r.max}`):this.createSuccessResponse(a)}async reservePort(e){let t=f.parse(e),n=await this.getDb(),r=I(t.repositoryPath),i=t.serviceType??`service`,a=t.environment??process.env.NODE_ENV??`development`,o=t.host??`127.0.0.1`,s=t.portRange??P,c=t.force??!1;return this.withImmediateTransaction(n,async()=>{let e=n.prepare(`SELECT * FROM ${R}
|
|
2
2
|
WHERE repository_path = ? AND service_name = ? AND service_type = ? AND environment = ?
|
|
3
|
-
LIMIT 1`).get(r,t.serviceName,i,a);if(e&&!c&&
|
|
3
|
+
LIMIT 1`).get(r,t.serviceName,i,a);if(e&&!c&&L(e.port,s)&&await this.isPortAvailable(e.port,o)){let t=new Date().toISOString();n.prepare(`UPDATE ${R} SET updated_at = ? WHERE id = ?`).run(t,e.id);let r=this.toRecord({...e,updated_at:t});return this.createSuccessResponse(r.port,r)}e&&n.prepare(`DELETE FROM ${R} WHERE id = ?`).run(e.id);let l=this.getReservedPorts(n),u=await this.findAvailablePortInternal(s,t.preferredPort,l,o);if(u===null)return this.createFailureResponse(`No available port found in range ${s.min}-${s.max}`);let d=new Date().toISOString(),f=n.prepare(`INSERT INTO ${R} (
|
|
4
4
|
repository_path, service_name, service_type, environment, pid, port, host,
|
|
5
5
|
metadata_json, created_at, updated_at
|
|
6
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(r,t.serviceName,i,a,t.pid??null,u,o,t.metadata?JSON.stringify(t.metadata):null,d,d),p=n.prepare(`SELECT * FROM ${
|
|
6
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(r,t.serviceName,i,a,t.pid??null,u,o,t.metadata?JSON.stringify(t.metadata):null,d,d),p=n.prepare(`SELECT * FROM ${R} WHERE id = ?`).get(Number(f.lastInsertRowid)),m=this.toRecord(p);return this.createSuccessResponse(m.port,m)})}async claimPort(t){let n=g.parse(t),r=await this.getDb(),i=I(n.repositoryPath),a=n.serviceType??`service`,o=n.environment??process.env.NODE_ENV??`development`,s=n.host??`127.0.0.1`,c=n.portRange??P,l=n.pid??process.pid;return this.withImmediateTransaction(r,async()=>{let t=this.selectScopeRow(r,i,n.serviceName,a,o);if(t){let e=this.readClaim(t);if(!e)return this.createClaimResponse({outcome:`existing`,record:this.toRecord(t)});if(this.isClaimActive(e))return this.createClaimResponse({outcome:`existing`,claimPending:!0,record:this.toRecord(t)});r.prepare(`DELETE FROM ${R} WHERE id = ?`).run(t.id)}let u=new Set;for(let t=0;t<3;t+=1){let t=this.getReservedPorts(r);for(let e of u)t.add(e);let d=await this.findAvailablePortInternal(c,n.preferredPort,t,s);if(d===null)return this.createClaimFailure(`No available port found in range ${c.min}-${c.max}`);let f={token:e(),ownerPid:l,expiresAt:new Date(Date.now()+n.claimTtlMs).toISOString()},m=new Date().toISOString();try{let e=r.prepare(`INSERT INTO ${R} (
|
|
7
7
|
repository_path, service_name, service_type, environment, pid, port, host,
|
|
8
8
|
metadata_json, created_at, updated_at
|
|
9
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(i,n.serviceName,a,o,l,d,s,JSON.stringify({...n.metadata??{},[
|
|
10
|
-
CREATE TABLE IF NOT EXISTS ${
|
|
9
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(i,n.serviceName,a,o,l,d,s,JSON.stringify({...n.metadata??{},[p]:f}),m,m),t=this.selectRowById(r,Number(e.lastInsertRowid));return this.createClaimResponse({outcome:`claimed`,record:this.toRecord(t),claimToken:f.token})}catch(e){if(!this.isUniqueConstraintError(e))throw e;u.add(d)}}return this.createClaimFailure(`Failed to claim a port after 3 attempts`)})}async confirmPort(e){let t=v.parse(e),n=await this.getDb(),r=I(t.repositoryPath),i=t.serviceType??`service`,a=t.environment??process.env.NODE_ENV??`development`;return this.withImmediateTransaction(n,async()=>{let e=this.selectScopeRow(n,r,t.serviceName,i,a),o=e?this.readClaim(e):void 0;if(!e||!o||o.token!==t.claimToken)return this.createFailureResponse(`Claim not found or expired for ${t.serviceName}`);let s={...this.readMetadata(e),...t.metadata??{}};delete s[p];let c=new Date().toISOString();n.prepare(`UPDATE ${R} SET pid = ?, metadata_json = ?, updated_at = ? WHERE id = ?`).run(t.pid,Object.keys(s).length>0?JSON.stringify(s):null,c,e.id);let l=this.toRecord(this.selectRowById(n,e.id));return this.createSuccessResponse(l.port,l)})}async releaseClaim(e){let t=y.parse(e),n=await this.getDb(),r=I(t.repositoryPath),i=t.serviceType??`service`,a=t.environment??process.env.NODE_ENV??`development`;return this.withImmediateTransaction(n,async()=>{let e=this.selectScopeRow(n,r,t.serviceName,i,a),o=e?this.readClaim(e):void 0;return e&&o?.token===t.claimToken&&n.prepare(`DELETE FROM ${R} WHERE id = ?`).run(e.id),this.createSuccessResponse()})}async releasePort(e){let t=b.parse(e);return(await this.releasePorts(t)).success?this.createSuccessResponse():this.createFailureResponse(`No matching registry entry for ${t.serviceName}`)}async releasePorts(e){let t=T.parse(e),n=await this.getDb(),r=this.normalizeReleaseFilters(t),i=this.buildWhereClause(r,!0),a=n.prepare(`DELETE FROM ${R}${i.sql}`).run(...i.params);return a.changes===0?D.parse({success:!1,released:0,error:`No matching registry entries`}):D.parse({success:!0,released:a.changes})}async listAllocations(e={}){let t=w.parse(e),n=await this.getDb(),r=this.buildWhereClause(this.normalizeListFilters(t));return n.prepare(`SELECT * FROM ${R}${r.sql} ORDER BY id`).all(...r.params).map(e=>this.toRecord(e))}async cleanupStaleAllocations(e={}){let t=w.parse(e),n=await this.getDb(),r=this.buildWhereClause(this.normalizeListFilters(t)),i=n.prepare(`SELECT * FROM ${R}${r.sql}`).all(...r.params),a=[];return await Promise.all(i.map(async e=>{let t=this.readClaim(e);if(t){this.isClaimActive(t)||a.push(e.id);return}let n=await this.pathExists(e.repository_path),r=typeof e.pid==`number`&&!this.isProcessRunning(e.pid);(!n||r)&&a.push(e.id)})),a.length>0&&n.transaction(e=>{let t=n.prepare(`DELETE FROM ${R} WHERE id = ?`);for(let n of e)t.run(n)})(a),E.parse({success:!0,scanned:i.length,removed:a.length})}close(){this.sqlite?.close(),this.sqlite=null,this.initialization=null}static resolveInputPath(e){return i.isAbsolute(e)?e:i.join(process.cwd(),e)}static resolveLegacyRegistryPath(e){let t=a.resolveInputPath(e),n=i.extname(t);return n===`.json`?t:n===`.sqlite`||n===`.db`?t.slice(0,-n.length)+`.json`:i.join(t,`ports.json`)}async getDb(){return this.sqlite?this.sqlite:(this.initialization||=this.initializeDatabase(),this.initialization)}async initializeDatabase(){await t.mkdir(i.dirname(this.registryPath),{recursive:!0});let{Database:e}=await import(`@tursodatabase/database/compat`);for(let t=1;t<=8;t+=1){let n=null;try{return n=new e(this.registryPath,{experimental:[`multiprocess_wal`],timeout:V}),n.pragma(`busy_timeout = ${V}`,{}),n.pragma(`journal_mode = WAL`,{}),n.pragma(`synchronous = NORMAL`,{}),n.exec(`
|
|
10
|
+
CREATE TABLE IF NOT EXISTS ${z} (
|
|
11
11
|
key TEXT PRIMARY KEY,
|
|
12
12
|
value TEXT NOT NULL
|
|
13
13
|
);
|
|
14
|
-
CREATE TABLE IF NOT EXISTS ${
|
|
14
|
+
CREATE TABLE IF NOT EXISTS ${R} (
|
|
15
15
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
16
16
|
repository_path TEXT NOT NULL,
|
|
17
17
|
service_name TEXT NOT NULL,
|
|
@@ -26,13 +26,13 @@ import{randomUUID as e}from"node:crypto";import t from"node:fs/promises";import
|
|
|
26
26
|
UNIQUE (repository_path, service_name, service_type, environment)
|
|
27
27
|
);
|
|
28
28
|
CREATE INDEX IF NOT EXISTS port_allocations_scope_idx
|
|
29
|
-
ON ${
|
|
29
|
+
ON ${R} (repository_path, service_name, service_type, environment);
|
|
30
30
|
CREATE INDEX IF NOT EXISTS port_allocations_environment_idx
|
|
31
|
-
ON ${
|
|
32
|
-
`),this.sqlite=
|
|
31
|
+
ON ${R} (environment, service_type);
|
|
32
|
+
`),this.sqlite=n,await this.importLegacyJson(n),n}catch(e){if(n?.close(),this.sqlite=null,!this.isDatabaseBusyError(e)||t===8)throw this.initialization=null,new O(`Failed to initialize registry database: ${e instanceof Error?e.message:String(e)}`,`REGISTRY_READ_FAILED`,{cause:e});await new Promise(e=>setTimeout(e,25*2**(t-1)))}}throw Error(`Unreachable database initialization state`)}isDatabaseBusyError(e){let t=e?.code;return t===`SQLITE_BUSY`||t===`SQLITE_LOCKED`}async importLegacyJson(e){if(e.prepare(`SELECT value FROM ${z} WHERE key = ?`).get(B))return;let n=null;try{let e=await t.readFile(this.legacyRegistryPath,`utf-8`);n=u.parse(JSON.parse(e))}catch(e){if(e.code!==`ENOENT`)throw e}e.transaction(t=>{let n=e.prepare(`INSERT OR IGNORE INTO ${R} (
|
|
33
33
|
repository_path, service_name, service_type, environment, pid, port, host,
|
|
34
34
|
metadata_json, created_at, updated_at
|
|
35
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);for(let e of t?.entries??[])n.run(
|
|
35
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);for(let e of t?.entries??[])n.run(I(e.repositoryPath),e.serviceName,e.serviceType,e.environment??``,e.pid??null,e.port,e.host,e.metadata?JSON.stringify(e.metadata):null,e.createdAt,e.updatedAt);e.prepare(`INSERT OR REPLACE INTO ${z} (key, value) VALUES (?, ?)`).run(B,this.legacyRegistryPath)})(n)}async withImmediateTransaction(e,t){let n=H.get(this.registryPath)??Promise.resolve(),r=()=>void 0,i=new Promise(e=>{r=e}),a=n.catch(()=>void 0).then(()=>i);H.set(this.registryPath,a),await n.catch(()=>void 0);try{e.exec(`BEGIN IMMEDIATE`);try{let n=await t();return e.exec(`COMMIT`),n}catch(t){throw e.inTransaction&&e.exec(`ROLLBACK`),t}}finally{r(),H.get(this.registryPath)===a&&H.delete(this.registryPath)}}normalizeListFilters(e){return{...e.repositoryPath?{repositoryPath:I(e.repositoryPath)}:{},...e.serviceName?{serviceName:e.serviceName}:{},...e.serviceType?{serviceType:e.serviceType}:{},...e.environment?{environment:e.environment}:{}}}normalizeReleaseFilters(e){return{...this.normalizeListFilters(e),...typeof e.pid==`number`?{pid:e.pid}:{},...typeof e.force==`boolean`?{force:e.force}:{}}}buildWhereClause(e,t=!1){let n=[],r=[],i=(e,t)=>{t!==void 0&&(n.push(`${e} = ?`),r.push(t))};return i(`repository_path`,e.repositoryPath),i(`service_name`,e.serviceName),i(`service_type`,e.serviceType),i(`environment`,e.environment),t&&typeof e.pid==`number`&&!e.force&&i(`pid`,e.pid),{sql:n.length>0?` WHERE ${n.join(` AND `)}`:``,params:r}}selectScopeRow(e,t,n,r,i){return e.prepare(`SELECT * FROM ${R}
|
|
36
36
|
WHERE repository_path = ? AND service_name = ? AND service_type = ? AND environment = ?
|
|
37
|
-
LIMIT 1`).get(t,n,r,i)}selectRowById(e,t){return e.prepare(`SELECT * FROM ${
|
|
37
|
+
LIMIT 1`).get(t,n,r,i)}selectRowById(e,t){return e.prepare(`SELECT * FROM ${R} WHERE id = ?`).get(t)}readMetadata(e){if(!e.metadata_json)return{};let t=JSON.parse(e.metadata_json);if(!t||typeof t!=`object`||Array.isArray(t))throw new O(`Stored port metadata is invalid`,`REGISTRY_READ_FAILED`);return t}readClaim(e){let t=this.readMetadata(e)[p];if(!t)return;let n=h.safeParse(t);return n.success?n.data:void 0}isClaimActive(e){return Date.parse(e.expiresAt)>Date.now()&&this.isProcessRunning(e.ownerPid)}isUniqueConstraintError(e){return e?.code===`SQLITE_CONSTRAINT_UNIQUE`}createClaimResponse(e){return _.parse({success:!0,...e,...e.record?{port:e.record.port}:{}})}createClaimFailure(e){return _.parse({success:!1,error:e})}getReservedPorts(e){let t=e.prepare(`SELECT port FROM ${R}`).all();return new Set(t.map(e=>e.port))}toRecord(e){let t=this.readMetadata(e),n=Object.keys(t).length>0?t:void 0;return l.parse({repositoryPath:e.repository_path,serviceName:e.service_name,serviceType:e.service_type,...e.environment?{environment:e.environment}:{},...e.pid?{pid:e.pid}:{},port:e.port,host:e.host,...n?{metadata:n}:{},createdAt:e.created_at,updatedAt:e.updated_at})}async findAvailablePortInternal(e,t,n,r){if(t!==void 0&&L(t,e)&&!n.has(t)&&await this.isPortAvailable(t,r))return t;for(let i=e.min;i<=e.max;i+=1)if(!(i===t||n.has(i))&&await this.isPortAvailable(i,r))return i;return null}async isPortAvailable(e,t){let n=r.platform()===`win32`?`127.0.0.1`:t,i=Array.from(new Set([n,`127.0.0.1`,`0.0.0.0`,void 0,`::1`]));for(let t of i)if(!await this.isPortAvailableOnHost(e,t))return!1;return!0}async isPortAvailableOnHost(e,t){return new Promise(r=>{let i=n.createServer();i.once(`error`,()=>r(!1)),i.once(`listening`,()=>i.close(()=>r(!0))),t?i.listen(e,t):i.listen(e)})}isProcessRunning(e){try{return process.kill(e,0),!0}catch{return!1}}async pathExists(e){try{return await t.access(e),!0}catch{return!1}}createSuccessResponse(e,t){return C.parse({success:!0,...e===void 0?{}:{port:e},...t?{record:t}:{}})}createFailureResponse(e){return C.parse({success:!1,error:e})}};export{T as A,O as C,o as D,w as E,s as M,c as N,y as O,E as S,u as T,x as _,k as a,h as b,N as c,p as d,g as f,S as g,m as h,A as i,f as j,b as k,L as l,v as m,F as n,M as o,_ as p,P as r,j as s,U as t,I as u,d as v,l as w,D as x,C as y};
|
|
38
38
|
//# sourceMappingURL=PortRegistryService.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PortRegistryService.mjs","names":[],"sources":["../src/types/index.ts","../src/utils/index.ts","../src/services/PortRegistryService.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport const REGISTRY_VERSION = 1 as const;\n\nexport const ServiceCategorySchema = z.enum(['service', 'tool']);\n\nexport const ServiceMetadataSchema = z.record(z.string(), z.unknown());\n\nexport const PortRegistryRecordSchema = z.object({\n repositoryPath: z.string().trim().min(1, 'repositoryPath is required'),\n serviceName: z.string().trim().min(1, 'serviceName is required'),\n serviceType: ServiceCategorySchema,\n environment: z.string().trim().min(1).optional(),\n pid: z.number().int().min(1).optional(),\n port: z.number().int().min(1).max(65535),\n host: z.string().trim().min(1).default('127.0.0.1'),\n metadata: ServiceMetadataSchema.optional(),\n createdAt: z.string().trim().min(1),\n updatedAt: z.string().trim().min(1),\n});\n\nexport const PortRegistryStateSchema = z.object({\n version: z.literal(REGISTRY_VERSION),\n updatedAt: z.string().trim().min(1),\n entries: z.array(PortRegistryRecordSchema),\n});\n\nexport const PortAllocationRangeSchema = z\n .object({\n min: z.number().int().min(1).max(65535),\n max: z.number().int().min(1).max(65535),\n })\n .refine((range) => range.min <= range.max, {\n message: 'Port range min must be less than or equal to max',\n path: ['min'],\n });\n\nexport const ReservePortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.default('service'),\n environment: z.string().trim().min(1).optional(),\n pid: z.number().int().min(1).optional(),\n portRange: PortAllocationRangeSchema.optional(),\n preferredPort: z.number().int().min(1).max(65535).optional(),\n host: z.string().trim().min(1).optional(),\n metadata: ServiceMetadataSchema.optional(),\n force: z.boolean().optional(),\n});\n\n/**\n * Reserved metadata key holding bootstrap-claim state.\n *\n * A claim turns the scope row into a cross-process mutex: the row is inserted by\n * the process that intends to spawn a service, and is only converted into a\n * normal allocation once that service confirms it is listening. Storing the\n * state in metadata avoids a schema migration for registry files already on disk.\n */\nexport const CLAIM_METADATA_KEY = '__claim' as const;\n\nexport const DEFAULT_CLAIM_TTL_MS = 45_000;\n\nexport const PortClaimSchema = z.object({\n token: z.string().min(1),\n ownerPid: z.number().int().min(1),\n expiresAt: z.string().trim().min(1),\n});\n\nexport const ClaimPortRequestSchema = ReservePortRequestSchema.omit({ force: true }).extend({\n claimTtlMs: z.number().int().min(1000).max(600_000).default(DEFAULT_CLAIM_TTL_MS),\n});\n\nexport const ClaimPortResponseSchema = z.object({\n success: z.boolean(),\n outcome: z.enum(['claimed', 'existing']).optional(),\n port: z.number().int().min(1).max(65535).optional(),\n record: PortRegistryRecordSchema.optional(),\n /** Present only when outcome is 'claimed'. Required to confirm or release the claim. */\n claimToken: z.string().optional(),\n /** True when the existing row is another process's in-flight claim rather than a live service. */\n claimPending: z.boolean().optional(),\n error: z.string().optional(),\n});\n\nexport const ConfirmPortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.default('service'),\n environment: z.string().trim().min(1).optional(),\n claimToken: z.string().min(1),\n pid: z.number().int().min(1),\n metadata: ServiceMetadataSchema.optional(),\n});\n\nexport const ReleaseClaimRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.default('service'),\n environment: z.string().trim().min(1).optional(),\n claimToken: z.string().min(1),\n});\n\nexport const ReleasePortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.optional(),\n pid: z.number().int().min(1).optional(),\n environment: z.string().trim().min(1).optional(),\n force: z.boolean().optional(),\n});\n\nexport const GetPortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.optional(),\n environment: z.string().trim().min(1).optional(),\n});\n\nexport const FindAvailablePortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.optional(),\n environment: z.string().trim().min(1).optional(),\n portRange: PortAllocationRangeSchema.optional(),\n preferredPort: z.number().int().min(1).max(65535).optional(),\n host: z.string().trim().min(1).default('127.0.0.1'),\n});\n\nexport const PortAllocationResponseSchema = z.object({\n success: z.boolean(),\n port: z.number().int().min(1).max(65535).optional(),\n record: PortRegistryRecordSchema.optional(),\n error: z.string().optional(),\n});\n\nexport const PortUsageListFiltersSchema = z.object({\n repositoryPath: z.string().trim().min(1).optional(),\n serviceType: ServiceCategorySchema.optional(),\n serviceName: z.string().trim().min(1).optional(),\n environment: z.string().trim().min(1).optional(),\n});\n\nexport const ReleasePortsRequestSchema = PortUsageListFiltersSchema.extend({\n pid: z.number().int().min(1).optional(),\n force: z.boolean().optional(),\n});\n\nexport const PortRegistryCleanupResponseSchema = z.object({\n success: z.boolean(),\n scanned: z.number().int().min(0),\n removed: z.number().int().min(0),\n error: z.string().optional(),\n});\n\nexport const PortRegistryBulkReleaseResponseSchema = z.object({\n success: z.boolean(),\n released: z.number().int().min(0),\n error: z.string().optional(),\n});\n\nexport type ServiceCategory = z.infer<typeof ServiceCategorySchema>;\nexport type ServiceMetadata = z.infer<typeof ServiceMetadataSchema>;\nexport type PortRegistryRecord = z.infer<typeof PortRegistryRecordSchema>;\nexport type PortRegistryState = z.infer<typeof PortRegistryStateSchema>;\nexport type PortAllocationRange = z.infer<typeof PortAllocationRangeSchema>;\nexport type ReservePortRequest = z.infer<typeof ReservePortRequestSchema>;\nexport type PortClaim = z.infer<typeof PortClaimSchema>;\nexport type ClaimPortRequest = z.input<typeof ClaimPortRequestSchema>;\nexport type ClaimPortResponse = z.infer<typeof ClaimPortResponseSchema>;\nexport type ConfirmPortRequest = z.input<typeof ConfirmPortRequestSchema>;\nexport type ReleaseClaimRequest = z.input<typeof ReleaseClaimRequestSchema>;\nexport type ReleasePortRequest = z.infer<typeof ReleasePortRequestSchema>;\nexport type GetPortRequest = z.infer<typeof GetPortRequestSchema>;\nexport type FindAvailablePortRequest = z.infer<typeof FindAvailablePortRequestSchema>;\nexport type PortAllocationResponse = z.infer<typeof PortAllocationResponseSchema>;\nexport type PortUsageListFilters = z.infer<typeof PortUsageListFiltersSchema>;\nexport type ReleasePortsRequest = z.infer<typeof ReleasePortsRequestSchema>;\nexport type PortRegistryCleanupResponse = z.infer<typeof PortRegistryCleanupResponseSchema>;\nexport type PortRegistryBulkReleaseResponse = z.infer<typeof PortRegistryBulkReleaseResponseSchema>;\n\nexport type PortRegistryErrorCode =\n | 'INVALID_REQUEST'\n | 'REGISTRY_READ_FAILED'\n | 'REGISTRY_WRITE_FAILED'\n | 'REGISTRY_LOCK_FAILED'\n | 'PORT_NOT_AVAILABLE'\n | 'NO_PORT_FOUND';\n\nexport class PortRegistryError extends Error {\n readonly code: PortRegistryErrorCode;\n\n constructor(message: string, code: PortRegistryErrorCode, options?: ErrorOptions) {\n super(message, options);\n this.name = 'PortRegistryError';\n this.code = code;\n }\n}\n","import os from 'node:os';\nimport path from 'node:path';\n\nexport const DEFAULT_REGISTRY_PATH = path.join(os.homedir(), '.port-registry', 'ports.turso.sqlite');\nexport const DEFAULT_REGISTRY_LOCK_PATH = `${DEFAULT_REGISTRY_PATH}.lock`;\nexport const LOCK_RETRY_DELAY_MS = 75;\nexport const LOCK_MAX_RETRIES = 80;\nexport const LOCK_STALE_AFTER_MS = 5_000;\nexport const DEFAULT_PORT_RANGE = { min: 3000, max: 4999 };\nexport const DEFAULT_HOST = '127.0.0.1';\n\nexport const normalizeRepositoryPath = (value: string): string => path.resolve(value);\n\nexport const isPortInRange = (port: number, range: { min: number; max: number }): boolean =>\n port >= range.min && port <= range.max;\n","import { randomUUID } from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport net from 'node:net';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { Database } from '@tursodatabase/database/compat';\nimport {\n CLAIM_METADATA_KEY,\n type ClaimPortRequest,\n ClaimPortRequestSchema,\n type ClaimPortResponse,\n ClaimPortResponseSchema,\n type ConfirmPortRequest,\n ConfirmPortRequestSchema,\n type FindAvailablePortRequest,\n FindAvailablePortRequestSchema,\n type GetPortRequest,\n GetPortRequestSchema,\n type PortAllocationRange,\n type PortAllocationResponse,\n PortAllocationResponseSchema,\n type PortClaim,\n PortClaimSchema,\n type PortRegistryBulkReleaseResponse,\n PortRegistryBulkReleaseResponseSchema,\n type PortRegistryCleanupResponse,\n PortRegistryCleanupResponseSchema,\n PortRegistryError,\n type PortRegistryRecord,\n PortRegistryRecordSchema,\n type PortRegistryState,\n PortRegistryStateSchema,\n type PortUsageListFilters,\n PortUsageListFiltersSchema,\n type ReleaseClaimRequest,\n ReleaseClaimRequestSchema,\n type ReleasePortRequest,\n ReleasePortRequestSchema,\n type ReleasePortsRequest,\n ReleasePortsRequestSchema,\n type ReservePortRequest,\n ReservePortRequestSchema,\n} from '../types';\nimport {\n DEFAULT_HOST,\n DEFAULT_PORT_RANGE,\n DEFAULT_REGISTRY_PATH,\n isPortInRange,\n normalizeRepositoryPath,\n} from '../utils';\n\nconst PORT_TABLE = 'port_allocations';\nconst METADATA_TABLE = 'registry_metadata';\nconst LEGACY_IMPORT_KEY = 'legacy_json_import_v1';\nconst SQLITE_BUSY_TIMEOUT_MS = 6_000;\nconst SQLITE_INIT_MAX_ATTEMPTS = 8;\nconst SQLITE_INIT_RETRY_DELAY_MS = 25;\nconst MAX_CLAIM_INSERT_ATTEMPTS = 3;\nconst writeQueues = new Map<string, Promise<void>>();\n\ntype SqlValue = string | number | null;\n\ninterface PortRow {\n id: number;\n repository_path: string;\n service_name: string;\n service_type: 'service' | 'tool';\n environment: string;\n pid: number | null;\n port: number;\n host: string;\n metadata_json: string | null;\n created_at: string;\n updated_at: string;\n}\n\ninterface NormalizedListFilters {\n repositoryPath?: string;\n serviceName?: string;\n serviceType?: 'service' | 'tool';\n environment?: string;\n}\n\ninterface NormalizedReleaseFilters extends NormalizedListFilters {\n pid?: number;\n force?: boolean;\n}\n\ninterface WhereClause {\n sql: string;\n params: SqlValue[];\n}\n\n/**\n * Service for managing shared port allocations in a cross-process SQLite database.\n */\nexport class PortRegistryService {\n private readonly registryPath: string;\n private readonly legacyRegistryPath: string;\n private sqlite: Database | null = null;\n private initialization: Promise<Database> | null = null;\n\n constructor(registryPath: string = DEFAULT_REGISTRY_PATH, _legacyLockPath?: string) {\n this.registryPath = PortRegistryService.resolveRegistryPath(registryPath);\n this.legacyRegistryPath = PortRegistryService.resolveLegacyRegistryPath(registryPath);\n }\n\n /**\n * Resolve a directory, SQLite path, or legacy JSON path to the SQLite database path.\n */\n static resolveRegistryPath(inputPath?: string): string {\n const resolvedPath = PortRegistryService.resolveInputPath(inputPath ?? DEFAULT_REGISTRY_PATH);\n const extension = path.extname(resolvedPath);\n\n if (extension === '.json') {\n return resolvedPath.slice(0, -extension.length) + '.sqlite';\n }\n\n if (extension === '.sqlite' || extension === '.db') {\n return resolvedPath;\n }\n\n return path.join(resolvedPath, 'ports.sqlite');\n }\n\n async getPort(rawRequest: GetPortRequest): Promise<PortAllocationResponse> {\n const request = GetPortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const filters = this.normalizeListFilters(request);\n const where = this.buildWhereClause(filters);\n const row = db.prepare(`SELECT * FROM ${PORT_TABLE}${where.sql} ORDER BY id LIMIT 1`).get(...where.params) as\n | PortRow\n | undefined;\n\n if (!row) {\n return this.createFailureResponse(`No allocation found for ${request.serviceName} in requested scope`);\n }\n\n const record = this.toRecord(row);\n return this.createSuccessResponse(record.port, record);\n }\n\n async findAvailablePort(rawRequest: FindAvailablePortRequest): Promise<PortAllocationResponse> {\n const request = FindAvailablePortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const range = request.portRange ?? DEFAULT_PORT_RANGE;\n const reserved = this.getReservedPorts(db);\n const availablePort = await this.findAvailablePortInternal(range, request.preferredPort, reserved, request.host);\n\n if (availablePort === null) {\n return this.createFailureResponse(`No available port found in range ${range.min}-${range.max}`);\n }\n\n return this.createSuccessResponse(availablePort);\n }\n\n async reservePort(rawRequest: ReservePortRequest): Promise<PortAllocationResponse> {\n const request = ReservePortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n const host = request.host ?? DEFAULT_HOST;\n const range = request.portRange ?? DEFAULT_PORT_RANGE;\n const force = request.force ?? false;\n\n return this.withImmediateTransaction(db, async () => {\n const existingRow = db\n .prepare(\n `SELECT * FROM ${PORT_TABLE}\n WHERE repository_path = ? AND service_name = ? AND service_type = ? AND environment = ?\n LIMIT 1`,\n )\n .get(repositoryPath, request.serviceName, serviceType, environment) as PortRow | undefined;\n\n if (existingRow && !force && isPortInRange(existingRow.port, range)) {\n const available = await this.isPortAvailable(existingRow.port, host);\n if (available) {\n const updatedAt = new Date().toISOString();\n db.prepare(`UPDATE ${PORT_TABLE} SET updated_at = ? WHERE id = ?`).run(updatedAt, existingRow.id);\n const record = this.toRecord({ ...existingRow, updated_at: updatedAt });\n return this.createSuccessResponse(record.port, record);\n }\n }\n\n if (existingRow) {\n db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`).run(existingRow.id);\n }\n\n const reserved = this.getReservedPorts(db);\n const availablePort = await this.findAvailablePortInternal(range, request.preferredPort, reserved, host);\n if (availablePort === null) {\n return this.createFailureResponse(`No available port found in range ${range.min}-${range.max}`);\n }\n\n const now = new Date().toISOString();\n const insert = db\n .prepare(\n `INSERT INTO ${PORT_TABLE} (\n repository_path, service_name, service_type, environment, pid, port, host,\n metadata_json, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n repositoryPath,\n request.serviceName,\n serviceType,\n environment,\n request.pid ?? null,\n availablePort,\n host,\n request.metadata ? JSON.stringify(request.metadata) : null,\n now,\n now,\n );\n\n const row = db.prepare(`SELECT * FROM ${PORT_TABLE} WHERE id = ?`).get(Number(insert.lastInsertRowid)) as PortRow;\n const record = this.toRecord(row);\n return this.createSuccessResponse(record.port, record);\n });\n }\n\n /**\n * Atomically claim a port for a service that is about to be started.\n *\n * Unlike {@link reservePort}, a claim never deletes a live allocation: callers\n * that find an `existing` row decide for themselves whether to reuse or replace\n * it. Exactly one concurrent caller receives `outcome: 'claimed'` — the rest see\n * the winner's row, so a claim doubles as a cross-process bootstrap mutex.\n *\n * A claim must be finalized with {@link confirmPort} or dropped with\n * {@link releaseClaim}. An abandoned claim is reaped once it expires, or\n * immediately if its owning process is gone.\n */\n async claimPort(rawRequest: ClaimPortRequest): Promise<ClaimPortResponse> {\n const request = ClaimPortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n const host = request.host ?? DEFAULT_HOST;\n const range = request.portRange ?? DEFAULT_PORT_RANGE;\n const ownerPid = request.pid ?? process.pid;\n\n return this.withImmediateTransaction(db, async () => {\n const existingRow = this.selectScopeRow(db, repositoryPath, request.serviceName, serviceType, environment);\n\n if (existingRow) {\n const claim = this.readClaim(existingRow);\n\n if (!claim) {\n return this.createClaimResponse({ outcome: 'existing', record: this.toRecord(existingRow) });\n }\n\n if (this.isClaimActive(claim)) {\n return this.createClaimResponse({\n outcome: 'existing',\n claimPending: true,\n record: this.toRecord(existingRow),\n });\n }\n\n db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`).run(existingRow.id);\n }\n\n const excluded = new Set<number>();\n for (let attempt = 0; attempt < MAX_CLAIM_INSERT_ATTEMPTS; attempt += 1) {\n const reserved = this.getReservedPorts(db);\n for (const port of excluded) {\n reserved.add(port);\n }\n\n const availablePort = await this.findAvailablePortInternal(range, request.preferredPort, reserved, host);\n if (availablePort === null) {\n return this.createClaimFailure(`No available port found in range ${range.min}-${range.max}`);\n }\n\n const claim: PortClaim = {\n token: randomUUID(),\n ownerPid,\n expiresAt: new Date(Date.now() + request.claimTtlMs).toISOString(),\n };\n const now = new Date().toISOString();\n\n try {\n const insert = db\n .prepare(\n `INSERT INTO ${PORT_TABLE} (\n repository_path, service_name, service_type, environment, pid, port, host,\n metadata_json, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n repositoryPath,\n request.serviceName,\n serviceType,\n environment,\n ownerPid,\n availablePort,\n host,\n JSON.stringify({ ...(request.metadata ?? {}), [CLAIM_METADATA_KEY]: claim }),\n now,\n now,\n );\n\n const row = this.selectRowById(db, Number(insert.lastInsertRowid));\n return this.createClaimResponse({\n outcome: 'claimed',\n record: this.toRecord(row),\n claimToken: claim.token,\n });\n } catch (error) {\n // Another scope took this port between the availability scan and the\n // insert; retry with it excluded rather than failing the bootstrap.\n if (!this.isUniqueConstraintError(error)) {\n throw error;\n }\n excluded.add(availablePort);\n }\n }\n\n return this.createClaimFailure(`Failed to claim a port after ${MAX_CLAIM_INSERT_ATTEMPTS} attempts`);\n });\n }\n\n /**\n * Convert a claim into a normal allocation owned by the now-running service.\n *\n * Fails when the claim has been reaped or taken over, which tells the caller it\n * lost the lease and must exit instead of registering over the new owner.\n */\n async confirmPort(rawRequest: ConfirmPortRequest): Promise<PortAllocationResponse> {\n const request = ConfirmPortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n\n return this.withImmediateTransaction(db, async () => {\n const row = this.selectScopeRow(db, repositoryPath, request.serviceName, serviceType, environment);\n const claim = row ? this.readClaim(row) : undefined;\n\n if (!row || !claim || claim.token !== request.claimToken) {\n return this.createFailureResponse(`Claim not found or expired for ${request.serviceName}`);\n }\n\n const metadata = { ...this.readMetadata(row), ...(request.metadata ?? {}) };\n delete metadata[CLAIM_METADATA_KEY];\n const updatedAt = new Date().toISOString();\n\n db.prepare(`UPDATE ${PORT_TABLE} SET pid = ?, metadata_json = ?, updated_at = ? WHERE id = ?`).run(\n request.pid,\n Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : null,\n updatedAt,\n row.id,\n );\n\n const record = this.toRecord(this.selectRowById(db, row.id));\n return this.createSuccessResponse(record.port, record);\n });\n }\n\n /**\n * Drop an unconfirmed claim, e.g. after the spawned service failed to start.\n * Idempotent: a claim already reaped or confirmed reports success.\n */\n async releaseClaim(rawRequest: ReleaseClaimRequest): Promise<PortAllocationResponse> {\n const request = ReleaseClaimRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n\n return this.withImmediateTransaction(db, async () => {\n const row = this.selectScopeRow(db, repositoryPath, request.serviceName, serviceType, environment);\n const claim = row ? this.readClaim(row) : undefined;\n\n if (row && claim?.token === request.claimToken) {\n db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`).run(row.id);\n }\n\n return this.createSuccessResponse();\n });\n }\n\n async releasePort(rawRequest: ReleasePortRequest): Promise<PortAllocationResponse> {\n const request = ReleasePortRequestSchema.parse(rawRequest);\n const result = await this.releasePorts(request);\n\n if (!result.success) {\n return this.createFailureResponse(`No matching registry entry for ${request.serviceName}`);\n }\n\n return this.createSuccessResponse();\n }\n\n async releasePorts(rawRequest: ReleasePortsRequest): Promise<PortRegistryBulkReleaseResponse> {\n const request = ReleasePortsRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const filters = this.normalizeReleaseFilters(request);\n const where = this.buildWhereClause(filters, true);\n const result = db.prepare(`DELETE FROM ${PORT_TABLE}${where.sql}`).run(...where.params);\n\n if (result.changes === 0) {\n return PortRegistryBulkReleaseResponseSchema.parse({\n success: false,\n released: 0,\n error: 'No matching registry entries',\n });\n }\n\n return PortRegistryBulkReleaseResponseSchema.parse({ success: true, released: result.changes });\n }\n\n async listAllocations(filters: PortUsageListFilters = {}): Promise<PortRegistryRecord[]> {\n const request = PortUsageListFiltersSchema.parse(filters);\n const db = await this.getDb();\n const where = this.buildWhereClause(this.normalizeListFilters(request));\n const rows = db.prepare(`SELECT * FROM ${PORT_TABLE}${where.sql} ORDER BY id`).all(...where.params) as PortRow[];\n return rows.map((row) => this.toRecord(row));\n }\n\n async cleanupStaleAllocations(filters: PortUsageListFilters = {}): Promise<PortRegistryCleanupResponse> {\n const request = PortUsageListFiltersSchema.parse(filters);\n const db = await this.getDb();\n const where = this.buildWhereClause(this.normalizeListFilters(request));\n const rows = db.prepare(`SELECT * FROM ${PORT_TABLE}${where.sql}`).all(...where.params) as PortRow[];\n const staleIds: number[] = [];\n\n await Promise.all(\n rows.map(async (row) => {\n const claim = this.readClaim(row);\n if (claim) {\n // A bootstrap row lives and dies by its claim, not by the pid column:\n // that pid belongs to the spawning parent, which may exit as soon as\n // the service confirms. Only an expired or orphaned claim is stale.\n if (!this.isClaimActive(claim)) {\n staleIds.push(row.id);\n }\n return;\n }\n\n const repositoryExists = await this.pathExists(row.repository_path);\n const deadPid = typeof row.pid === 'number' && !this.isProcessRunning(row.pid);\n if (!repositoryExists || deadPid) {\n staleIds.push(row.id);\n }\n }),\n );\n\n if (staleIds.length > 0) {\n const remove = db.transaction((ids: number[]) => {\n const statement = db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`);\n for (const id of ids) {\n statement.run(id);\n }\n });\n remove(staleIds);\n }\n\n return PortRegistryCleanupResponseSchema.parse({\n success: true,\n scanned: rows.length,\n removed: staleIds.length,\n });\n }\n\n close(): void {\n this.sqlite?.close();\n this.sqlite = null;\n this.initialization = null;\n }\n\n private static resolveInputPath(inputPath: string): string {\n return path.isAbsolute(inputPath) ? inputPath : path.join(process.cwd(), inputPath);\n }\n\n private static resolveLegacyRegistryPath(inputPath: string): string {\n const resolvedPath = PortRegistryService.resolveInputPath(inputPath);\n const extension = path.extname(resolvedPath);\n\n if (extension === '.json') {\n return resolvedPath;\n }\n\n if (extension === '.sqlite' || extension === '.db') {\n return resolvedPath.slice(0, -extension.length) + '.json';\n }\n\n return path.join(resolvedPath, 'ports.json');\n }\n\n private async getDb(): Promise<Database> {\n if (this.sqlite) {\n return this.sqlite;\n }\n\n if (!this.initialization) {\n this.initialization = this.initializeDatabase();\n }\n\n return this.initialization;\n }\n\n private async initializeDatabase(): Promise<Database> {\n await fs.mkdir(path.dirname(this.registryPath), { recursive: true });\n\n for (let attempt = 1; attempt <= SQLITE_INIT_MAX_ATTEMPTS; attempt += 1) {\n let db: Database | null = null;\n\n try {\n db = new Database(this.registryPath, {\n experimental: ['multiprocess_wal'],\n timeout: SQLITE_BUSY_TIMEOUT_MS,\n });\n db.pragma(`busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`, {});\n db.pragma('journal_mode = WAL', {});\n db.pragma('synchronous = NORMAL', {});\n db.exec(`\n CREATE TABLE IF NOT EXISTS ${METADATA_TABLE} (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS ${PORT_TABLE} (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n repository_path TEXT NOT NULL,\n service_name TEXT NOT NULL,\n service_type TEXT NOT NULL,\n environment TEXT NOT NULL,\n pid INTEGER,\n port INTEGER NOT NULL UNIQUE,\n host TEXT NOT NULL,\n metadata_json TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n UNIQUE (repository_path, service_name, service_type, environment)\n );\n CREATE INDEX IF NOT EXISTS port_allocations_scope_idx\n ON ${PORT_TABLE} (repository_path, service_name, service_type, environment);\n CREATE INDEX IF NOT EXISTS port_allocations_environment_idx\n ON ${PORT_TABLE} (environment, service_type);\n `);\n this.sqlite = db;\n await this.importLegacyJson(db);\n return db;\n } catch (error) {\n db?.close();\n this.sqlite = null;\n\n if (!this.isDatabaseBusyError(error) || attempt === SQLITE_INIT_MAX_ATTEMPTS) {\n this.initialization = null;\n throw new PortRegistryError(\n `Failed to initialize registry database: ${error instanceof Error ? error.message : String(error)}`,\n 'REGISTRY_READ_FAILED',\n { cause: error },\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, SQLITE_INIT_RETRY_DELAY_MS * 2 ** (attempt - 1)));\n }\n }\n\n throw new Error('Unreachable database initialization state');\n }\n\n private isDatabaseBusyError(error: unknown): boolean {\n const code = (error as { code?: unknown })?.code;\n return code === 'SQLITE_BUSY' || code === 'SQLITE_LOCKED';\n }\n\n private async importLegacyJson(db: Database): Promise<void> {\n const imported = db.prepare(`SELECT value FROM ${METADATA_TABLE} WHERE key = ?`).get(LEGACY_IMPORT_KEY);\n if (imported) {\n return;\n }\n\n let legacyState: PortRegistryState | null = null;\n try {\n const content = await fs.readFile(this.legacyRegistryPath, 'utf-8');\n legacyState = PortRegistryStateSchema.parse(JSON.parse(content));\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT') {\n throw error;\n }\n }\n\n const migrate = db.transaction((state: PortRegistryState | null) => {\n const insert = db.prepare(\n `INSERT OR IGNORE INTO ${PORT_TABLE} (\n repository_path, service_name, service_type, environment, pid, port, host,\n metadata_json, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n );\n\n for (const record of state?.entries ?? []) {\n insert.run(\n normalizeRepositoryPath(record.repositoryPath),\n record.serviceName,\n record.serviceType,\n record.environment ?? '',\n record.pid ?? null,\n record.port,\n record.host,\n record.metadata ? JSON.stringify(record.metadata) : null,\n record.createdAt,\n record.updatedAt,\n );\n }\n\n db.prepare(`INSERT OR REPLACE INTO ${METADATA_TABLE} (key, value) VALUES (?, ?)`).run(\n LEGACY_IMPORT_KEY,\n this.legacyRegistryPath,\n );\n });\n\n migrate(legacyState);\n }\n\n private async withImmediateTransaction<T>(db: Database, run: () => Promise<T>): Promise<T> {\n const previous = writeQueues.get(this.registryPath) ?? Promise.resolve();\n let releaseQueue: () => void = () => undefined;\n const current = new Promise<void>((resolve) => {\n releaseQueue = resolve;\n });\n const tail = previous.catch(() => undefined).then(() => current);\n writeQueues.set(this.registryPath, tail);\n await previous.catch(() => undefined);\n\n try {\n db.exec('BEGIN IMMEDIATE');\n try {\n const result = await run();\n db.exec('COMMIT');\n return result;\n } catch (error) {\n if (db.inTransaction) {\n db.exec('ROLLBACK');\n }\n throw error;\n }\n } finally {\n releaseQueue();\n if (writeQueues.get(this.registryPath) === tail) {\n writeQueues.delete(this.registryPath);\n }\n }\n }\n\n private normalizeListFilters(filters: PortUsageListFilters): NormalizedListFilters {\n return {\n ...(filters.repositoryPath ? { repositoryPath: normalizeRepositoryPath(filters.repositoryPath) } : {}),\n ...(filters.serviceName ? { serviceName: filters.serviceName } : {}),\n ...(filters.serviceType ? { serviceType: filters.serviceType } : {}),\n ...(filters.environment ? { environment: filters.environment } : {}),\n };\n }\n\n private normalizeReleaseFilters(filters: ReleasePortsRequest): NormalizedReleaseFilters {\n return {\n ...this.normalizeListFilters(filters),\n ...(typeof filters.pid === 'number' ? { pid: filters.pid } : {}),\n ...(typeof filters.force === 'boolean' ? { force: filters.force } : {}),\n };\n }\n\n private buildWhereClause(filters: NormalizedReleaseFilters, includePid = false): WhereClause {\n const clauses: string[] = [];\n const params: SqlValue[] = [];\n const add = (column: string, value: SqlValue | undefined): void => {\n if (value !== undefined) {\n clauses.push(`${column} = ?`);\n params.push(value);\n }\n };\n\n add('repository_path', filters.repositoryPath);\n add('service_name', filters.serviceName);\n add('service_type', filters.serviceType);\n add('environment', filters.environment);\n if (includePid && typeof filters.pid === 'number' && !filters.force) {\n add('pid', filters.pid);\n }\n\n return {\n sql: clauses.length > 0 ? ` WHERE ${clauses.join(' AND ')}` : '',\n params,\n };\n }\n\n private selectScopeRow(\n db: Database,\n repositoryPath: string,\n serviceName: string,\n serviceType: 'service' | 'tool',\n environment: string,\n ): PortRow | undefined {\n return db\n .prepare(\n `SELECT * FROM ${PORT_TABLE}\n WHERE repository_path = ? AND service_name = ? AND service_type = ? AND environment = ?\n LIMIT 1`,\n )\n .get(repositoryPath, serviceName, serviceType, environment) as PortRow | undefined;\n }\n\n private selectRowById(db: Database, id: number): PortRow {\n return db.prepare(`SELECT * FROM ${PORT_TABLE} WHERE id = ?`).get(id) as PortRow;\n }\n\n private readMetadata(row: PortRow): Record<string, unknown> {\n if (!row.metadata_json) {\n return {};\n }\n\n const parsed = JSON.parse(row.metadata_json) as unknown;\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new PortRegistryError('Stored port metadata is invalid', 'REGISTRY_READ_FAILED');\n }\n\n return parsed as Record<string, unknown>;\n }\n\n private readClaim(row: PortRow): PortClaim | undefined {\n const candidate = this.readMetadata(row)[CLAIM_METADATA_KEY];\n if (!candidate) {\n return undefined;\n }\n\n const parsed = PortClaimSchema.safeParse(candidate);\n return parsed.success ? parsed.data : undefined;\n }\n\n /** A claim holds the scope only while unexpired and its owner is still alive. */\n private isClaimActive(claim: PortClaim): boolean {\n return Date.parse(claim.expiresAt) > Date.now() && this.isProcessRunning(claim.ownerPid);\n }\n\n private isUniqueConstraintError(error: unknown): boolean {\n return (error as { code?: string } | undefined)?.code === 'SQLITE_CONSTRAINT_UNIQUE';\n }\n\n private createClaimResponse(response: Omit<ClaimPortResponse, 'success' | 'port'>): ClaimPortResponse {\n return ClaimPortResponseSchema.parse({\n success: true,\n ...response,\n ...(response.record ? { port: response.record.port } : {}),\n });\n }\n\n private createClaimFailure(error: string): ClaimPortResponse {\n return ClaimPortResponseSchema.parse({ success: false, error });\n }\n\n private getReservedPorts(db: Database): Set<number> {\n const rows = db.prepare(`SELECT port FROM ${PORT_TABLE}`).all() as Array<{ port: number }>;\n return new Set(rows.map((row) => row.port));\n }\n\n private toRecord(row: PortRow): PortRegistryRecord {\n const parsedMetadata = this.readMetadata(row);\n const metadata = Object.keys(parsedMetadata).length > 0 ? parsedMetadata : undefined;\n\n return PortRegistryRecordSchema.parse({\n repositoryPath: row.repository_path,\n serviceName: row.service_name,\n serviceType: row.service_type,\n ...(row.environment ? { environment: row.environment } : {}),\n ...(row.pid ? { pid: row.pid } : {}),\n port: row.port,\n host: row.host,\n ...(metadata ? { metadata } : {}),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n });\n }\n\n private async findAvailablePortInternal(\n portRange: PortAllocationRange,\n preferredPort: number | undefined,\n reservedPorts: Set<number>,\n host: string,\n ): Promise<number | null> {\n if (preferredPort !== undefined && isPortInRange(preferredPort, portRange)) {\n if (!reservedPorts.has(preferredPort) && (await this.isPortAvailable(preferredPort, host))) {\n return preferredPort;\n }\n }\n\n for (let port = portRange.min; port <= portRange.max; port += 1) {\n if (port === preferredPort || reservedPorts.has(port)) {\n continue;\n }\n\n if (await this.isPortAvailable(port, host)) {\n return port;\n }\n }\n\n return null;\n }\n\n private async isPortAvailable(port: number, host: string): Promise<boolean> {\n const normalizedHost = os.platform() === 'win32' ? '127.0.0.1' : host;\n const candidateHosts = Array.from(\n new Set<string | undefined>([normalizedHost, '127.0.0.1', '0.0.0.0', undefined, '::1']),\n );\n\n for (const candidateHost of candidateHosts) {\n if (!(await this.isPortAvailableOnHost(port, candidateHost))) {\n return false;\n }\n }\n\n return true;\n }\n\n private async isPortAvailableOnHost(port: number, host?: string): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer();\n server.once('error', () => resolve(false));\n server.once('listening', () => server.close(() => resolve(true)));\n if (host) {\n server.listen(port, host);\n } else {\n server.listen(port);\n }\n });\n }\n\n private isProcessRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n }\n\n private async pathExists(candidate: string): Promise<boolean> {\n try {\n await fs.access(candidate);\n return true;\n } catch {\n return false;\n }\n }\n\n private createSuccessResponse(port?: number, record?: PortRegistryRecord): PortAllocationResponse {\n return PortAllocationResponseSchema.parse({\n success: true,\n ...(port !== undefined ? { port } : {}),\n ...(record ? { record } : {}),\n });\n }\n\n private createFailureResponse(error: string): PortAllocationResponse {\n return PortAllocationResponseSchema.parse({ success: false, error });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PortRegistryService.mjs","names":[],"sources":["../src/types/index.ts","../src/utils/index.ts","../src/services/PortRegistryService.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport const REGISTRY_VERSION = 1 as const;\n\nexport const ServiceCategorySchema = z.enum(['service', 'tool']);\n\nexport const ServiceMetadataSchema = z.record(z.string(), z.unknown());\n\nexport const PortRegistryRecordSchema = z.object({\n repositoryPath: z.string().trim().min(1, 'repositoryPath is required'),\n serviceName: z.string().trim().min(1, 'serviceName is required'),\n serviceType: ServiceCategorySchema,\n environment: z.string().trim().min(1).optional(),\n pid: z.number().int().min(1).optional(),\n port: z.number().int().min(1).max(65535),\n host: z.string().trim().min(1).default('127.0.0.1'),\n metadata: ServiceMetadataSchema.optional(),\n createdAt: z.string().trim().min(1),\n updatedAt: z.string().trim().min(1),\n});\n\nexport const PortRegistryStateSchema = z.object({\n version: z.literal(REGISTRY_VERSION),\n updatedAt: z.string().trim().min(1),\n entries: z.array(PortRegistryRecordSchema),\n});\n\nexport const PortAllocationRangeSchema = z\n .object({\n min: z.number().int().min(1).max(65535),\n max: z.number().int().min(1).max(65535),\n })\n .refine((range) => range.min <= range.max, {\n message: 'Port range min must be less than or equal to max',\n path: ['min'],\n });\n\nexport const ReservePortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.default('service'),\n environment: z.string().trim().min(1).optional(),\n pid: z.number().int().min(1).optional(),\n portRange: PortAllocationRangeSchema.optional(),\n preferredPort: z.number().int().min(1).max(65535).optional(),\n host: z.string().trim().min(1).optional(),\n metadata: ServiceMetadataSchema.optional(),\n force: z.boolean().optional(),\n});\n\n/**\n * Reserved metadata key holding bootstrap-claim state.\n *\n * A claim turns the scope row into a cross-process mutex: the row is inserted by\n * the process that intends to spawn a service, and is only converted into a\n * normal allocation once that service confirms it is listening. Storing the\n * state in metadata avoids a schema migration for registry files already on disk.\n */\nexport const CLAIM_METADATA_KEY = '__claim' as const;\n\nexport const DEFAULT_CLAIM_TTL_MS = 45_000;\n\nexport const PortClaimSchema = z.object({\n token: z.string().min(1),\n ownerPid: z.number().int().min(1),\n expiresAt: z.string().trim().min(1),\n});\n\nexport const ClaimPortRequestSchema = ReservePortRequestSchema.omit({ force: true }).extend({\n claimTtlMs: z.number().int().min(1000).max(600_000).default(DEFAULT_CLAIM_TTL_MS),\n});\n\nexport const ClaimPortResponseSchema = z.object({\n success: z.boolean(),\n outcome: z.enum(['claimed', 'existing']).optional(),\n port: z.number().int().min(1).max(65535).optional(),\n record: PortRegistryRecordSchema.optional(),\n /** Present only when outcome is 'claimed'. Required to confirm or release the claim. */\n claimToken: z.string().optional(),\n /** True when the existing row is another process's in-flight claim rather than a live service. */\n claimPending: z.boolean().optional(),\n error: z.string().optional(),\n});\n\nexport const ConfirmPortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.default('service'),\n environment: z.string().trim().min(1).optional(),\n claimToken: z.string().min(1),\n pid: z.number().int().min(1),\n metadata: ServiceMetadataSchema.optional(),\n});\n\nexport const ReleaseClaimRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.default('service'),\n environment: z.string().trim().min(1).optional(),\n claimToken: z.string().min(1),\n});\n\nexport const ReleasePortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.optional(),\n pid: z.number().int().min(1).optional(),\n environment: z.string().trim().min(1).optional(),\n force: z.boolean().optional(),\n});\n\nexport const GetPortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.optional(),\n environment: z.string().trim().min(1).optional(),\n});\n\nexport const FindAvailablePortRequestSchema = z.object({\n repositoryPath: z.string().trim().min(1),\n serviceName: z.string().trim().min(1),\n serviceType: ServiceCategorySchema.optional(),\n environment: z.string().trim().min(1).optional(),\n portRange: PortAllocationRangeSchema.optional(),\n preferredPort: z.number().int().min(1).max(65535).optional(),\n host: z.string().trim().min(1).default('127.0.0.1'),\n});\n\nexport const PortAllocationResponseSchema = z.object({\n success: z.boolean(),\n port: z.number().int().min(1).max(65535).optional(),\n record: PortRegistryRecordSchema.optional(),\n error: z.string().optional(),\n});\n\nexport const PortUsageListFiltersSchema = z.object({\n repositoryPath: z.string().trim().min(1).optional(),\n serviceType: ServiceCategorySchema.optional(),\n serviceName: z.string().trim().min(1).optional(),\n environment: z.string().trim().min(1).optional(),\n});\n\nexport const ReleasePortsRequestSchema = PortUsageListFiltersSchema.extend({\n pid: z.number().int().min(1).optional(),\n force: z.boolean().optional(),\n});\n\nexport const PortRegistryCleanupResponseSchema = z.object({\n success: z.boolean(),\n scanned: z.number().int().min(0),\n removed: z.number().int().min(0),\n error: z.string().optional(),\n});\n\nexport const PortRegistryBulkReleaseResponseSchema = z.object({\n success: z.boolean(),\n released: z.number().int().min(0),\n error: z.string().optional(),\n});\n\nexport type ServiceCategory = z.infer<typeof ServiceCategorySchema>;\nexport type ServiceMetadata = z.infer<typeof ServiceMetadataSchema>;\nexport type PortRegistryRecord = z.infer<typeof PortRegistryRecordSchema>;\nexport type PortRegistryState = z.infer<typeof PortRegistryStateSchema>;\nexport type PortAllocationRange = z.infer<typeof PortAllocationRangeSchema>;\nexport type ReservePortRequest = z.infer<typeof ReservePortRequestSchema>;\nexport type PortClaim = z.infer<typeof PortClaimSchema>;\nexport type ClaimPortRequest = z.input<typeof ClaimPortRequestSchema>;\nexport type ClaimPortResponse = z.infer<typeof ClaimPortResponseSchema>;\nexport type ConfirmPortRequest = z.input<typeof ConfirmPortRequestSchema>;\nexport type ReleaseClaimRequest = z.input<typeof ReleaseClaimRequestSchema>;\nexport type ReleasePortRequest = z.infer<typeof ReleasePortRequestSchema>;\nexport type GetPortRequest = z.infer<typeof GetPortRequestSchema>;\nexport type FindAvailablePortRequest = z.infer<typeof FindAvailablePortRequestSchema>;\nexport type PortAllocationResponse = z.infer<typeof PortAllocationResponseSchema>;\nexport type PortUsageListFilters = z.infer<typeof PortUsageListFiltersSchema>;\nexport type ReleasePortsRequest = z.infer<typeof ReleasePortsRequestSchema>;\nexport type PortRegistryCleanupResponse = z.infer<typeof PortRegistryCleanupResponseSchema>;\nexport type PortRegistryBulkReleaseResponse = z.infer<typeof PortRegistryBulkReleaseResponseSchema>;\n\nexport type PortRegistryErrorCode =\n | 'INVALID_REQUEST'\n | 'REGISTRY_READ_FAILED'\n | 'REGISTRY_WRITE_FAILED'\n | 'REGISTRY_LOCK_FAILED'\n | 'PORT_NOT_AVAILABLE'\n | 'NO_PORT_FOUND';\n\nexport class PortRegistryError extends Error {\n readonly code: PortRegistryErrorCode;\n\n constructor(message: string, code: PortRegistryErrorCode, options?: ErrorOptions) {\n super(message, options);\n this.name = 'PortRegistryError';\n this.code = code;\n }\n}\n","import os from 'node:os';\nimport path from 'node:path';\n\nexport const DEFAULT_REGISTRY_PATH = path.join(os.homedir(), '.port-registry', 'ports.turso.sqlite');\nexport const DEFAULT_REGISTRY_LOCK_PATH = `${DEFAULT_REGISTRY_PATH}.lock`;\nexport const LOCK_RETRY_DELAY_MS = 75;\nexport const LOCK_MAX_RETRIES = 80;\nexport const LOCK_STALE_AFTER_MS = 5_000;\nexport const DEFAULT_PORT_RANGE = { min: 3000, max: 4999 };\nexport const DEFAULT_HOST = '127.0.0.1';\n\nexport const normalizeRepositoryPath = (value: string): string => path.resolve(value);\n\nexport const isPortInRange = (port: number, range: { min: number; max: number }): boolean =>\n port >= range.min && port <= range.max;\n","import { randomUUID } from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport net from 'node:net';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { Database } from '@tursodatabase/database/compat';\nimport {\n CLAIM_METADATA_KEY,\n type ClaimPortRequest,\n ClaimPortRequestSchema,\n type ClaimPortResponse,\n ClaimPortResponseSchema,\n type ConfirmPortRequest,\n ConfirmPortRequestSchema,\n type FindAvailablePortRequest,\n FindAvailablePortRequestSchema,\n type GetPortRequest,\n GetPortRequestSchema,\n type PortAllocationRange,\n type PortAllocationResponse,\n PortAllocationResponseSchema,\n type PortClaim,\n PortClaimSchema,\n type PortRegistryBulkReleaseResponse,\n PortRegistryBulkReleaseResponseSchema,\n type PortRegistryCleanupResponse,\n PortRegistryCleanupResponseSchema,\n PortRegistryError,\n type PortRegistryRecord,\n PortRegistryRecordSchema,\n type PortRegistryState,\n PortRegistryStateSchema,\n type PortUsageListFilters,\n PortUsageListFiltersSchema,\n type ReleaseClaimRequest,\n ReleaseClaimRequestSchema,\n type ReleasePortRequest,\n ReleasePortRequestSchema,\n type ReleasePortsRequest,\n ReleasePortsRequestSchema,\n type ReservePortRequest,\n ReservePortRequestSchema,\n} from '../types';\nimport {\n DEFAULT_HOST,\n DEFAULT_PORT_RANGE,\n DEFAULT_REGISTRY_PATH,\n isPortInRange,\n normalizeRepositoryPath,\n} from '../utils';\n\nconst PORT_TABLE = 'port_allocations';\nconst METADATA_TABLE = 'registry_metadata';\nconst LEGACY_IMPORT_KEY = 'legacy_json_import_v1';\nconst SQLITE_BUSY_TIMEOUT_MS = 6_000;\nconst SQLITE_INIT_MAX_ATTEMPTS = 8;\nconst SQLITE_INIT_RETRY_DELAY_MS = 25;\nconst MAX_CLAIM_INSERT_ATTEMPTS = 3;\nconst writeQueues = new Map<string, Promise<void>>();\n\ntype SqlValue = string | number | null;\n\ninterface PortRow {\n id: number;\n repository_path: string;\n service_name: string;\n service_type: 'service' | 'tool';\n environment: string;\n pid: number | null;\n port: number;\n host: string;\n metadata_json: string | null;\n created_at: string;\n updated_at: string;\n}\n\ninterface NormalizedListFilters {\n repositoryPath?: string;\n serviceName?: string;\n serviceType?: 'service' | 'tool';\n environment?: string;\n}\n\ninterface NormalizedReleaseFilters extends NormalizedListFilters {\n pid?: number;\n force?: boolean;\n}\n\ninterface WhereClause {\n sql: string;\n params: SqlValue[];\n}\n\n/**\n * Service for managing shared port allocations in a cross-process SQLite database.\n */\nexport class PortRegistryService {\n private readonly registryPath: string;\n private readonly legacyRegistryPath: string;\n private sqlite: Database | null = null;\n private initialization: Promise<Database> | null = null;\n\n constructor(registryPath: string = DEFAULT_REGISTRY_PATH, _legacyLockPath?: string) {\n this.registryPath = PortRegistryService.resolveRegistryPath(registryPath);\n this.legacyRegistryPath = PortRegistryService.resolveLegacyRegistryPath(registryPath);\n }\n\n /**\n * Resolve a directory, SQLite path, or legacy JSON path to the SQLite database path.\n */\n static resolveRegistryPath(inputPath?: string): string {\n const resolvedPath = PortRegistryService.resolveInputPath(inputPath ?? DEFAULT_REGISTRY_PATH);\n const extension = path.extname(resolvedPath);\n\n if (extension === '.json') {\n return resolvedPath.slice(0, -extension.length) + '.sqlite';\n }\n\n if (extension === '.sqlite' || extension === '.db') {\n return resolvedPath;\n }\n\n return path.join(resolvedPath, 'ports.sqlite');\n }\n\n async getPort(rawRequest: GetPortRequest): Promise<PortAllocationResponse> {\n const request = GetPortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const filters = this.normalizeListFilters(request);\n const where = this.buildWhereClause(filters);\n const row = db.prepare(`SELECT * FROM ${PORT_TABLE}${where.sql} ORDER BY id LIMIT 1`).get(...where.params) as\n | PortRow\n | undefined;\n\n if (!row) {\n return this.createFailureResponse(`No allocation found for ${request.serviceName} in requested scope`);\n }\n\n const record = this.toRecord(row);\n return this.createSuccessResponse(record.port, record);\n }\n\n async findAvailablePort(rawRequest: FindAvailablePortRequest): Promise<PortAllocationResponse> {\n const request = FindAvailablePortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const range = request.portRange ?? DEFAULT_PORT_RANGE;\n const reserved = this.getReservedPorts(db);\n const availablePort = await this.findAvailablePortInternal(range, request.preferredPort, reserved, request.host);\n\n if (availablePort === null) {\n return this.createFailureResponse(`No available port found in range ${range.min}-${range.max}`);\n }\n\n return this.createSuccessResponse(availablePort);\n }\n\n async reservePort(rawRequest: ReservePortRequest): Promise<PortAllocationResponse> {\n const request = ReservePortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n const host = request.host ?? DEFAULT_HOST;\n const range = request.portRange ?? DEFAULT_PORT_RANGE;\n const force = request.force ?? false;\n\n return this.withImmediateTransaction(db, async () => {\n const existingRow = db\n .prepare(\n `SELECT * FROM ${PORT_TABLE}\n WHERE repository_path = ? AND service_name = ? AND service_type = ? AND environment = ?\n LIMIT 1`,\n )\n .get(repositoryPath, request.serviceName, serviceType, environment) as PortRow | undefined;\n\n if (existingRow && !force && isPortInRange(existingRow.port, range)) {\n const available = await this.isPortAvailable(existingRow.port, host);\n if (available) {\n const updatedAt = new Date().toISOString();\n db.prepare(`UPDATE ${PORT_TABLE} SET updated_at = ? WHERE id = ?`).run(updatedAt, existingRow.id);\n const record = this.toRecord({ ...existingRow, updated_at: updatedAt });\n return this.createSuccessResponse(record.port, record);\n }\n }\n\n if (existingRow) {\n db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`).run(existingRow.id);\n }\n\n const reserved = this.getReservedPorts(db);\n const availablePort = await this.findAvailablePortInternal(range, request.preferredPort, reserved, host);\n if (availablePort === null) {\n return this.createFailureResponse(`No available port found in range ${range.min}-${range.max}`);\n }\n\n const now = new Date().toISOString();\n const insert = db\n .prepare(\n `INSERT INTO ${PORT_TABLE} (\n repository_path, service_name, service_type, environment, pid, port, host,\n metadata_json, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n repositoryPath,\n request.serviceName,\n serviceType,\n environment,\n request.pid ?? null,\n availablePort,\n host,\n request.metadata ? JSON.stringify(request.metadata) : null,\n now,\n now,\n );\n\n const row = db.prepare(`SELECT * FROM ${PORT_TABLE} WHERE id = ?`).get(Number(insert.lastInsertRowid)) as PortRow;\n const record = this.toRecord(row);\n return this.createSuccessResponse(record.port, record);\n });\n }\n\n /**\n * Atomically claim a port for a service that is about to be started.\n *\n * Unlike {@link reservePort}, a claim never deletes a live allocation: callers\n * that find an `existing` row decide for themselves whether to reuse or replace\n * it. Exactly one concurrent caller receives `outcome: 'claimed'` — the rest see\n * the winner's row, so a claim doubles as a cross-process bootstrap mutex.\n *\n * A claim must be finalized with {@link confirmPort} or dropped with\n * {@link releaseClaim}. An abandoned claim is reaped once it expires, or\n * immediately if its owning process is gone.\n */\n async claimPort(rawRequest: ClaimPortRequest): Promise<ClaimPortResponse> {\n const request = ClaimPortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n const host = request.host ?? DEFAULT_HOST;\n const range = request.portRange ?? DEFAULT_PORT_RANGE;\n const ownerPid = request.pid ?? process.pid;\n\n return this.withImmediateTransaction(db, async () => {\n const existingRow = this.selectScopeRow(db, repositoryPath, request.serviceName, serviceType, environment);\n\n if (existingRow) {\n const claim = this.readClaim(existingRow);\n\n if (!claim) {\n return this.createClaimResponse({ outcome: 'existing', record: this.toRecord(existingRow) });\n }\n\n if (this.isClaimActive(claim)) {\n return this.createClaimResponse({\n outcome: 'existing',\n claimPending: true,\n record: this.toRecord(existingRow),\n });\n }\n\n db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`).run(existingRow.id);\n }\n\n const excluded = new Set<number>();\n for (let attempt = 0; attempt < MAX_CLAIM_INSERT_ATTEMPTS; attempt += 1) {\n const reserved = this.getReservedPorts(db);\n for (const port of excluded) {\n reserved.add(port);\n }\n\n const availablePort = await this.findAvailablePortInternal(range, request.preferredPort, reserved, host);\n if (availablePort === null) {\n return this.createClaimFailure(`No available port found in range ${range.min}-${range.max}`);\n }\n\n const claim: PortClaim = {\n token: randomUUID(),\n ownerPid,\n expiresAt: new Date(Date.now() + request.claimTtlMs).toISOString(),\n };\n const now = new Date().toISOString();\n\n try {\n const insert = db\n .prepare(\n `INSERT INTO ${PORT_TABLE} (\n repository_path, service_name, service_type, environment, pid, port, host,\n metadata_json, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n repositoryPath,\n request.serviceName,\n serviceType,\n environment,\n ownerPid,\n availablePort,\n host,\n JSON.stringify({ ...(request.metadata ?? {}), [CLAIM_METADATA_KEY]: claim }),\n now,\n now,\n );\n\n const row = this.selectRowById(db, Number(insert.lastInsertRowid));\n return this.createClaimResponse({\n outcome: 'claimed',\n record: this.toRecord(row),\n claimToken: claim.token,\n });\n } catch (error) {\n // Another scope took this port between the availability scan and the\n // insert; retry with it excluded rather than failing the bootstrap.\n if (!this.isUniqueConstraintError(error)) {\n throw error;\n }\n excluded.add(availablePort);\n }\n }\n\n return this.createClaimFailure(`Failed to claim a port after ${MAX_CLAIM_INSERT_ATTEMPTS} attempts`);\n });\n }\n\n /**\n * Convert a claim into a normal allocation owned by the now-running service.\n *\n * Fails when the claim has been reaped or taken over, which tells the caller it\n * lost the lease and must exit instead of registering over the new owner.\n */\n async confirmPort(rawRequest: ConfirmPortRequest): Promise<PortAllocationResponse> {\n const request = ConfirmPortRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n\n return this.withImmediateTransaction(db, async () => {\n const row = this.selectScopeRow(db, repositoryPath, request.serviceName, serviceType, environment);\n const claim = row ? this.readClaim(row) : undefined;\n\n if (!row || !claim || claim.token !== request.claimToken) {\n return this.createFailureResponse(`Claim not found or expired for ${request.serviceName}`);\n }\n\n const metadata = { ...this.readMetadata(row), ...(request.metadata ?? {}) };\n delete metadata[CLAIM_METADATA_KEY];\n const updatedAt = new Date().toISOString();\n\n db.prepare(`UPDATE ${PORT_TABLE} SET pid = ?, metadata_json = ?, updated_at = ? WHERE id = ?`).run(\n request.pid,\n Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : null,\n updatedAt,\n row.id,\n );\n\n const record = this.toRecord(this.selectRowById(db, row.id));\n return this.createSuccessResponse(record.port, record);\n });\n }\n\n /**\n * Drop an unconfirmed claim, e.g. after the spawned service failed to start.\n * Idempotent: a claim already reaped or confirmed reports success.\n */\n async releaseClaim(rawRequest: ReleaseClaimRequest): Promise<PortAllocationResponse> {\n const request = ReleaseClaimRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const repositoryPath = normalizeRepositoryPath(request.repositoryPath);\n const serviceType = request.serviceType ?? 'service';\n const environment = request.environment ?? process.env.NODE_ENV ?? 'development';\n\n return this.withImmediateTransaction(db, async () => {\n const row = this.selectScopeRow(db, repositoryPath, request.serviceName, serviceType, environment);\n const claim = row ? this.readClaim(row) : undefined;\n\n if (row && claim?.token === request.claimToken) {\n db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`).run(row.id);\n }\n\n return this.createSuccessResponse();\n });\n }\n\n async releasePort(rawRequest: ReleasePortRequest): Promise<PortAllocationResponse> {\n const request = ReleasePortRequestSchema.parse(rawRequest);\n const result = await this.releasePorts(request);\n\n if (!result.success) {\n return this.createFailureResponse(`No matching registry entry for ${request.serviceName}`);\n }\n\n return this.createSuccessResponse();\n }\n\n async releasePorts(rawRequest: ReleasePortsRequest): Promise<PortRegistryBulkReleaseResponse> {\n const request = ReleasePortsRequestSchema.parse(rawRequest);\n const db = await this.getDb();\n const filters = this.normalizeReleaseFilters(request);\n const where = this.buildWhereClause(filters, true);\n const result = db.prepare(`DELETE FROM ${PORT_TABLE}${where.sql}`).run(...where.params);\n\n if (result.changes === 0) {\n return PortRegistryBulkReleaseResponseSchema.parse({\n success: false,\n released: 0,\n error: 'No matching registry entries',\n });\n }\n\n return PortRegistryBulkReleaseResponseSchema.parse({ success: true, released: result.changes });\n }\n\n async listAllocations(filters: PortUsageListFilters = {}): Promise<PortRegistryRecord[]> {\n const request = PortUsageListFiltersSchema.parse(filters);\n const db = await this.getDb();\n const where = this.buildWhereClause(this.normalizeListFilters(request));\n const rows = db.prepare(`SELECT * FROM ${PORT_TABLE}${where.sql} ORDER BY id`).all(...where.params) as PortRow[];\n return rows.map((row) => this.toRecord(row));\n }\n\n async cleanupStaleAllocations(filters: PortUsageListFilters = {}): Promise<PortRegistryCleanupResponse> {\n const request = PortUsageListFiltersSchema.parse(filters);\n const db = await this.getDb();\n const where = this.buildWhereClause(this.normalizeListFilters(request));\n const rows = db.prepare(`SELECT * FROM ${PORT_TABLE}${where.sql}`).all(...where.params) as PortRow[];\n const staleIds: number[] = [];\n\n await Promise.all(\n rows.map(async (row) => {\n const claim = this.readClaim(row);\n if (claim) {\n // A bootstrap row lives and dies by its claim, not by the pid column:\n // that pid belongs to the spawning parent, which may exit as soon as\n // the service confirms. Only an expired or orphaned claim is stale.\n if (!this.isClaimActive(claim)) {\n staleIds.push(row.id);\n }\n return;\n }\n\n const repositoryExists = await this.pathExists(row.repository_path);\n const deadPid = typeof row.pid === 'number' && !this.isProcessRunning(row.pid);\n if (!repositoryExists || deadPid) {\n staleIds.push(row.id);\n }\n }),\n );\n\n if (staleIds.length > 0) {\n const remove = db.transaction((ids: number[]) => {\n const statement = db.prepare(`DELETE FROM ${PORT_TABLE} WHERE id = ?`);\n for (const id of ids) {\n statement.run(id);\n }\n });\n remove(staleIds);\n }\n\n return PortRegistryCleanupResponseSchema.parse({\n success: true,\n scanned: rows.length,\n removed: staleIds.length,\n });\n }\n\n close(): void {\n this.sqlite?.close();\n this.sqlite = null;\n this.initialization = null;\n }\n\n private static resolveInputPath(inputPath: string): string {\n return path.isAbsolute(inputPath) ? inputPath : path.join(process.cwd(), inputPath);\n }\n\n private static resolveLegacyRegistryPath(inputPath: string): string {\n const resolvedPath = PortRegistryService.resolveInputPath(inputPath);\n const extension = path.extname(resolvedPath);\n\n if (extension === '.json') {\n return resolvedPath;\n }\n\n if (extension === '.sqlite' || extension === '.db') {\n return resolvedPath.slice(0, -extension.length) + '.json';\n }\n\n return path.join(resolvedPath, 'ports.json');\n }\n\n private async getDb(): Promise<Database> {\n if (this.sqlite) {\n return this.sqlite;\n }\n\n if (!this.initialization) {\n this.initialization = this.initializeDatabase();\n }\n\n return this.initialization;\n }\n\n private async initializeDatabase(): Promise<Database> {\n await fs.mkdir(path.dirname(this.registryPath), { recursive: true });\n const { Database } = await import('@tursodatabase/database/compat');\n\n for (let attempt = 1; attempt <= SQLITE_INIT_MAX_ATTEMPTS; attempt += 1) {\n let db: Database | null = null;\n\n try {\n db = new Database(this.registryPath, {\n experimental: ['multiprocess_wal'],\n timeout: SQLITE_BUSY_TIMEOUT_MS,\n });\n db.pragma(`busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`, {});\n db.pragma('journal_mode = WAL', {});\n db.pragma('synchronous = NORMAL', {});\n db.exec(`\n CREATE TABLE IF NOT EXISTS ${METADATA_TABLE} (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS ${PORT_TABLE} (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n repository_path TEXT NOT NULL,\n service_name TEXT NOT NULL,\n service_type TEXT NOT NULL,\n environment TEXT NOT NULL,\n pid INTEGER,\n port INTEGER NOT NULL UNIQUE,\n host TEXT NOT NULL,\n metadata_json TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n UNIQUE (repository_path, service_name, service_type, environment)\n );\n CREATE INDEX IF NOT EXISTS port_allocations_scope_idx\n ON ${PORT_TABLE} (repository_path, service_name, service_type, environment);\n CREATE INDEX IF NOT EXISTS port_allocations_environment_idx\n ON ${PORT_TABLE} (environment, service_type);\n `);\n this.sqlite = db;\n await this.importLegacyJson(db);\n return db;\n } catch (error) {\n db?.close();\n this.sqlite = null;\n\n if (!this.isDatabaseBusyError(error) || attempt === SQLITE_INIT_MAX_ATTEMPTS) {\n this.initialization = null;\n throw new PortRegistryError(\n `Failed to initialize registry database: ${error instanceof Error ? error.message : String(error)}`,\n 'REGISTRY_READ_FAILED',\n { cause: error },\n );\n }\n\n await new Promise((resolve) => setTimeout(resolve, SQLITE_INIT_RETRY_DELAY_MS * 2 ** (attempt - 1)));\n }\n }\n\n throw new Error('Unreachable database initialization state');\n }\n\n private isDatabaseBusyError(error: unknown): boolean {\n const code = (error as { code?: unknown })?.code;\n return code === 'SQLITE_BUSY' || code === 'SQLITE_LOCKED';\n }\n\n private async importLegacyJson(db: Database): Promise<void> {\n const imported = db.prepare(`SELECT value FROM ${METADATA_TABLE} WHERE key = ?`).get(LEGACY_IMPORT_KEY);\n if (imported) {\n return;\n }\n\n let legacyState: PortRegistryState | null = null;\n try {\n const content = await fs.readFile(this.legacyRegistryPath, 'utf-8');\n legacyState = PortRegistryStateSchema.parse(JSON.parse(content));\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT') {\n throw error;\n }\n }\n\n const migrate = db.transaction((state: PortRegistryState | null) => {\n const insert = db.prepare(\n `INSERT OR IGNORE INTO ${PORT_TABLE} (\n repository_path, service_name, service_type, environment, pid, port, host,\n metadata_json, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n );\n\n for (const record of state?.entries ?? []) {\n insert.run(\n normalizeRepositoryPath(record.repositoryPath),\n record.serviceName,\n record.serviceType,\n record.environment ?? '',\n record.pid ?? null,\n record.port,\n record.host,\n record.metadata ? JSON.stringify(record.metadata) : null,\n record.createdAt,\n record.updatedAt,\n );\n }\n\n db.prepare(`INSERT OR REPLACE INTO ${METADATA_TABLE} (key, value) VALUES (?, ?)`).run(\n LEGACY_IMPORT_KEY,\n this.legacyRegistryPath,\n );\n });\n\n migrate(legacyState);\n }\n\n private async withImmediateTransaction<T>(db: Database, run: () => Promise<T>): Promise<T> {\n const previous = writeQueues.get(this.registryPath) ?? Promise.resolve();\n let releaseQueue: () => void = () => undefined;\n const current = new Promise<void>((resolve) => {\n releaseQueue = resolve;\n });\n const tail = previous.catch(() => undefined).then(() => current);\n writeQueues.set(this.registryPath, tail);\n await previous.catch(() => undefined);\n\n try {\n db.exec('BEGIN IMMEDIATE');\n try {\n const result = await run();\n db.exec('COMMIT');\n return result;\n } catch (error) {\n if (db.inTransaction) {\n db.exec('ROLLBACK');\n }\n throw error;\n }\n } finally {\n releaseQueue();\n if (writeQueues.get(this.registryPath) === tail) {\n writeQueues.delete(this.registryPath);\n }\n }\n }\n\n private normalizeListFilters(filters: PortUsageListFilters): NormalizedListFilters {\n return {\n ...(filters.repositoryPath ? { repositoryPath: normalizeRepositoryPath(filters.repositoryPath) } : {}),\n ...(filters.serviceName ? { serviceName: filters.serviceName } : {}),\n ...(filters.serviceType ? { serviceType: filters.serviceType } : {}),\n ...(filters.environment ? { environment: filters.environment } : {}),\n };\n }\n\n private normalizeReleaseFilters(filters: ReleasePortsRequest): NormalizedReleaseFilters {\n return {\n ...this.normalizeListFilters(filters),\n ...(typeof filters.pid === 'number' ? { pid: filters.pid } : {}),\n ...(typeof filters.force === 'boolean' ? { force: filters.force } : {}),\n };\n }\n\n private buildWhereClause(filters: NormalizedReleaseFilters, includePid = false): WhereClause {\n const clauses: string[] = [];\n const params: SqlValue[] = [];\n const add = (column: string, value: SqlValue | undefined): void => {\n if (value !== undefined) {\n clauses.push(`${column} = ?`);\n params.push(value);\n }\n };\n\n add('repository_path', filters.repositoryPath);\n add('service_name', filters.serviceName);\n add('service_type', filters.serviceType);\n add('environment', filters.environment);\n if (includePid && typeof filters.pid === 'number' && !filters.force) {\n add('pid', filters.pid);\n }\n\n return {\n sql: clauses.length > 0 ? ` WHERE ${clauses.join(' AND ')}` : '',\n params,\n };\n }\n\n private selectScopeRow(\n db: Database,\n repositoryPath: string,\n serviceName: string,\n serviceType: 'service' | 'tool',\n environment: string,\n ): PortRow | undefined {\n return db\n .prepare(\n `SELECT * FROM ${PORT_TABLE}\n WHERE repository_path = ? AND service_name = ? AND service_type = ? AND environment = ?\n LIMIT 1`,\n )\n .get(repositoryPath, serviceName, serviceType, environment) as PortRow | undefined;\n }\n\n private selectRowById(db: Database, id: number): PortRow {\n return db.prepare(`SELECT * FROM ${PORT_TABLE} WHERE id = ?`).get(id) as PortRow;\n }\n\n private readMetadata(row: PortRow): Record<string, unknown> {\n if (!row.metadata_json) {\n return {};\n }\n\n const parsed = JSON.parse(row.metadata_json) as unknown;\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new PortRegistryError('Stored port metadata is invalid', 'REGISTRY_READ_FAILED');\n }\n\n return parsed as Record<string, unknown>;\n }\n\n private readClaim(row: PortRow): PortClaim | undefined {\n const candidate = this.readMetadata(row)[CLAIM_METADATA_KEY];\n if (!candidate) {\n return undefined;\n }\n\n const parsed = PortClaimSchema.safeParse(candidate);\n return parsed.success ? parsed.data : undefined;\n }\n\n /** A claim holds the scope only while unexpired and its owner is still alive. */\n private isClaimActive(claim: PortClaim): boolean {\n return Date.parse(claim.expiresAt) > Date.now() && this.isProcessRunning(claim.ownerPid);\n }\n\n private isUniqueConstraintError(error: unknown): boolean {\n return (error as { code?: string } | undefined)?.code === 'SQLITE_CONSTRAINT_UNIQUE';\n }\n\n private createClaimResponse(response: Omit<ClaimPortResponse, 'success' | 'port'>): ClaimPortResponse {\n return ClaimPortResponseSchema.parse({\n success: true,\n ...response,\n ...(response.record ? { port: response.record.port } : {}),\n });\n }\n\n private createClaimFailure(error: string): ClaimPortResponse {\n return ClaimPortResponseSchema.parse({ success: false, error });\n }\n\n private getReservedPorts(db: Database): Set<number> {\n const rows = db.prepare(`SELECT port FROM ${PORT_TABLE}`).all() as Array<{ port: number }>;\n return new Set(rows.map((row) => row.port));\n }\n\n private toRecord(row: PortRow): PortRegistryRecord {\n const parsedMetadata = this.readMetadata(row);\n const metadata = Object.keys(parsedMetadata).length > 0 ? parsedMetadata : undefined;\n\n return PortRegistryRecordSchema.parse({\n repositoryPath: row.repository_path,\n serviceName: row.service_name,\n serviceType: row.service_type,\n ...(row.environment ? { environment: row.environment } : {}),\n ...(row.pid ? { pid: row.pid } : {}),\n port: row.port,\n host: row.host,\n ...(metadata ? { metadata } : {}),\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n });\n }\n\n private async findAvailablePortInternal(\n portRange: PortAllocationRange,\n preferredPort: number | undefined,\n reservedPorts: Set<number>,\n host: string,\n ): Promise<number | null> {\n if (preferredPort !== undefined && isPortInRange(preferredPort, portRange)) {\n if (!reservedPorts.has(preferredPort) && (await this.isPortAvailable(preferredPort, host))) {\n return preferredPort;\n }\n }\n\n for (let port = portRange.min; port <= portRange.max; port += 1) {\n if (port === preferredPort || reservedPorts.has(port)) {\n continue;\n }\n\n if (await this.isPortAvailable(port, host)) {\n return port;\n }\n }\n\n return null;\n }\n\n private async isPortAvailable(port: number, host: string): Promise<boolean> {\n const normalizedHost = os.platform() === 'win32' ? '127.0.0.1' : host;\n const candidateHosts = Array.from(\n new Set<string | undefined>([normalizedHost, '127.0.0.1', '0.0.0.0', undefined, '::1']),\n );\n\n for (const candidateHost of candidateHosts) {\n if (!(await this.isPortAvailableOnHost(port, candidateHost))) {\n return false;\n }\n }\n\n return true;\n }\n\n private async isPortAvailableOnHost(port: number, host?: string): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer();\n server.once('error', () => resolve(false));\n server.once('listening', () => server.close(() => resolve(true)));\n if (host) {\n server.listen(port, host);\n } else {\n server.listen(port);\n }\n });\n }\n\n private isProcessRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n }\n\n private async pathExists(candidate: string): Promise<boolean> {\n try {\n await fs.access(candidate);\n return true;\n } catch {\n return false;\n }\n }\n\n private createSuccessResponse(port?: number, record?: PortRegistryRecord): PortAllocationResponse {\n return PortAllocationResponseSchema.parse({\n success: true,\n ...(port !== undefined ? { port } : {}),\n ...(record ? { record } : {}),\n });\n }\n\n private createFailureResponse(error: string): PortAllocationResponse {\n return PortAllocationResponseSchema.parse({ success: false, error });\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/index.ts","../src/services/PortRegistryService.ts","../src/utils/index.ts"],"mappings":";;;cAEa,gBAAA;AAAA,cAEA,qBAAA,EAAqB,CAAA,CAAA,OAAA;;;;cAErB,qBAAA,EAAqB,CAAA,CAAA,SAAA,CAAA,CAAA,CAAA,SAAA,EAAA,CAAA,CAAA,UAAA;AAAA,cAErB,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;cAaxB,uBAAA,EAAuB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;cAMvB,yBAAA,EAAyB,CAAA,CAAA,SAAA;;;;cAUzB,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;cAqBxB,kBAAA;AAAA,cAEA,oBAAA;AAAA,cAEA,eAAA,EAAe,CAAA,CAAA,SAAA;;;;;cAMf,sBAAA,EAAsB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;cAItB,uBAAA,EAAuB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;cAYvB,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;;cAUxB,yBAAA,EAAyB,CAAA,CAAA,SAAA;;;;;;;;;;cAQzB,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;cASxB,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;cAOpB,8BAAA,EAA8B,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;cAU9B,4BAAA,EAA4B,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;cAO5B,0BAAA,EAA0B,CAAA,CAAA,SAAA;;;;;;;;;cAO1B,yBAAA,EAAyB,CAAA,CAAA,SAAA;;;;;;;;;;;cAKzB,iCAAA,EAAiC,CAAA,CAAA,SAAA;;;;;;cAOjC,qCAAA,EAAqC,CAAA,CAAA,SAAA;;;;;KAMtC,eAAA,GAAkB,CAAA,CAAE,KAAA,QAAa,qBAAA;AAAA,KACjC,eAAA,GAAkB,CAAA,CAAE,KAAA,QAAa,qBAAA;AAAA,KACjC,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,KACpC,iBAAA,GAAoB,CAAA,CAAE,KAAA,QAAa,uBAAA;AAAA,KACnC,mBAAA,GAAsB,CAAA,CAAE,KAAA,QAAa,yBAAA;AAAA,KACrC,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,KACpC,SAAA,GAAY,CAAA,CAAE,KAAA,QAAa,eAAA;AAAA,KAC3B,gBAAA,GAAmB,CAAA,CAAE,KAAA,QAAa,sBAAA;AAAA,KAClC,iBAAA,GAAoB,CAAA,CAAE,KAAA,QAAa,uBAAA;AAAA,KACnC,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,KACpC,mBAAA,GAAsB,CAAA,CAAE,KAAA,QAAa,yBAAA;AAAA,KACrC,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,KACpC,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,KAChC,wBAAA,GAA2B,CAAA,CAAE,KAAA,QAAa,8BAAA;AAAA,KAC1C,sBAAA,GAAyB,CAAA,CAAE,KAAA,QAAa,4BAAA;AAAA,KACxC,oBAAA,GAAuB,CAAA,CAAE,KAAA,QAAa,0BAAA;AAAA,KACtC,mBAAA,GAAsB,CAAA,CAAE,KAAA,QAAa,yBAAA;AAAA,KACrC,2BAAA,GAA8B,CAAA,CAAE,KAAA,QAAa,iCAAA;AAAA,KAC7C,+BAAA,GAAkC,CAAA,CAAE,KAAA,QAAa,qCAAA;AAAA,KAEjD,qBAAA;AAAA,cAQC,iBAAA,SAA0B,KAAA;EAAA,SAC5B,IAAA,EAAM,qBAAA;cAEH,OAAA,UAAiB,IAAA,EAAM,qBAAA,EAAuB,OAAA,GAAU,YAAA;AAAA;;;;;AA7LtE;cC8Fa,mBAAA;EAAA,iBACM,YAAA;EAAA,iBACA,kBAAA;EAAA,QACT,MAAA;EAAA,QACA,cAAA;cAEI,YAAA,WAA8C,eAAA;;;;SAQnD,mBAAA,CAAoB,SAAA;EAerB,OAAA,CAAQ,UAAA,EAAY,cAAA,GAAiB,OAAA,CAAQ,sBAAA;EAiB7C,iBAAA,CAAkB,UAAA,EAAY,wBAAA,GAA2B,OAAA,CAAQ,sBAAA;EAcjE,WAAA,CAAY,UAAA,EAAY,kBAAA,GAAqB,OAAA,CAAQ,sBAAA;;ADtJ7D;;;;;;;;;;;ECoOQ,SAAA,CAAU,UAAA,EAAY,gBAAA,GAAmB,OAAA,CAAQ,iBAAA;EDpOvB;;;;AAElC;;ECmUQ,WAAA,CAAY,UAAA,EAAY,kBAAA,GAAqB,OAAA,CAAQ,sBAAA;;;;;EAmCrD,YAAA,CAAa,UAAA,EAAY,mBAAA,GAAsB,OAAA,CAAQ,sBAAA;EAmBvD,WAAA,CAAY,UAAA,EAAY,kBAAA,GAAqB,OAAA,CAAQ,sBAAA;EAWrD,YAAA,CAAa,UAAA,EAAY,mBAAA,GAAsB,OAAA,CAAQ,+BAAA;EAkBvD,eAAA,CAAgB,OAAA,GAAS,oBAAA,GAA4B,OAAA,CAAQ,kBAAA;EAQ7D,uBAAA,CAAwB,OAAA,GAAS,oBAAA,GAA4B,OAAA,CAAQ,2BAAA;EA6C3E,KAAA,CAAA;EAAA,eAMe,gBAAA;EAAA,eAIA,yBAAA;EAAA,QAeD,KAAA;EAAA,QAYA,kBAAA;EAAA,
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types/index.ts","../src/services/PortRegistryService.ts","../src/utils/index.ts"],"mappings":"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"}
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/index.ts","../src/services/PortRegistryService.ts","../src/utils/index.ts"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/index.ts","../src/services/PortRegistryService.ts","../src/utils/index.ts"],"mappings":";;;cAEa,gBAAA;AAAA,cAEA,qBAAA,EAAqB,CAAA,CAAA,OAAA;;;;cAErB,qBAAA,EAAqB,CAAA,CAAA,SAAA,CAAA,CAAA,CAAA,SAAA,EAAA,CAAA,CAAA,UAAA;AAAA,cAErB,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;cAaxB,uBAAA,EAAuB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;cAMvB,yBAAA,EAAyB,CAAA,CAAA,SAAA;;;;cAUzB,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;cAqBxB,kBAAA;AAAA,cAEA,oBAAA;AAAA,cAEA,eAAA,EAAe,CAAA,CAAA,SAAA;;;;;cAMf,sBAAA,EAAsB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;cAItB,uBAAA,EAAuB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;cAYvB,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;;cAUxB,yBAAA,EAAyB,CAAA,CAAA,SAAA;;;;;;;;;;cAQzB,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;cASxB,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;cAOpB,8BAAA,EAA8B,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;cAU9B,4BAAA,EAA4B,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;cAO5B,0BAAA,EAA0B,CAAA,CAAA,SAAA;;;;;;;;;cAO1B,yBAAA,EAAyB,CAAA,CAAA,SAAA;;;;;;;;;;;cAKzB,iCAAA,EAAiC,CAAA,CAAA,SAAA;;;;;;cAOjC,qCAAA,EAAqC,CAAA,CAAA,SAAA;;;;;KAMtC,eAAA,GAAkB,CAAA,CAAE,KAAA,QAAa,qBAAA;AAAA,KACjC,eAAA,GAAkB,CAAA,CAAE,KAAA,QAAa,qBAAA;AAAA,KACjC,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,KACpC,iBAAA,GAAoB,CAAA,CAAE,KAAA,QAAa,uBAAA;AAAA,KACnC,mBAAA,GAAsB,CAAA,CAAE,KAAA,QAAa,yBAAA;AAAA,KACrC,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,KACpC,SAAA,GAAY,CAAA,CAAE,KAAA,QAAa,eAAA;AAAA,KAC3B,gBAAA,GAAmB,CAAA,CAAE,KAAA,QAAa,sBAAA;AAAA,KAClC,iBAAA,GAAoB,CAAA,CAAE,KAAA,QAAa,uBAAA;AAAA,KACnC,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,KACpC,mBAAA,GAAsB,CAAA,CAAE,KAAA,QAAa,yBAAA;AAAA,KACrC,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,KACpC,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;AAAA,KAChC,wBAAA,GAA2B,CAAA,CAAE,KAAA,QAAa,8BAAA;AAAA,KAC1C,sBAAA,GAAyB,CAAA,CAAE,KAAA,QAAa,4BAAA;AAAA,KACxC,oBAAA,GAAuB,CAAA,CAAE,KAAA,QAAa,0BAAA;AAAA,KACtC,mBAAA,GAAsB,CAAA,CAAE,KAAA,QAAa,yBAAA;AAAA,KACrC,2BAAA,GAA8B,CAAA,CAAE,KAAA,QAAa,iCAAA;AAAA,KAC7C,+BAAA,GAAkC,CAAA,CAAE,KAAA,QAAa,qCAAA;AAAA,KAEjD,qBAAA;AAAA,cAQC,iBAAA,SAA0B,KAAA;EAAA,SAC5B,IAAA,EAAM,qBAAA;cAEH,OAAA,UAAiB,IAAA,EAAM,qBAAA,EAAuB,OAAA,GAAU,YAAA;AAAA;;;;;AA7LtE;cC8Fa,mBAAA;EAAA,iBACM,YAAA;EAAA,iBACA,kBAAA;EAAA,QACT,MAAA;EAAA,QACA,cAAA;cAEI,YAAA,WAA8C,eAAA;;;;SAQnD,mBAAA,CAAoB,SAAA;EAerB,OAAA,CAAQ,UAAA,EAAY,cAAA,GAAiB,OAAA,CAAQ,sBAAA;EAiB7C,iBAAA,CAAkB,UAAA,EAAY,wBAAA,GAA2B,OAAA,CAAQ,sBAAA;EAcjE,WAAA,CAAY,UAAA,EAAY,kBAAA,GAAqB,OAAA,CAAQ,sBAAA;;ADtJ7D;;;;;;;;;;;ECoOQ,SAAA,CAAU,UAAA,EAAY,gBAAA,GAAmB,OAAA,CAAQ,iBAAA;EDpOvB;;;;AAElC;;ECmUQ,WAAA,CAAY,UAAA,EAAY,kBAAA,GAAqB,OAAA,CAAQ,sBAAA;;;;;EAmCrD,YAAA,CAAa,UAAA,EAAY,mBAAA,GAAsB,OAAA,CAAQ,sBAAA;EAmBvD,WAAA,CAAY,UAAA,EAAY,kBAAA,GAAqB,OAAA,CAAQ,sBAAA;EAWrD,YAAA,CAAa,UAAA,EAAY,mBAAA,GAAsB,OAAA,CAAQ,+BAAA;EAkBvD,eAAA,CAAgB,OAAA,GAAS,oBAAA,GAA4B,OAAA,CAAQ,kBAAA;EAQ7D,uBAAA,CAAwB,OAAA,GAAS,oBAAA,GAA4B,OAAA,CAAQ,2BAAA;EA6C3E,KAAA,CAAA;EAAA,eAMe,gBAAA;EAAA,eAIA,yBAAA;EAAA,QAeD,KAAA;EAAA,QAYA,kBAAA;EAAA,QA8DN,mBAAA;EAAA,QAKM,gBAAA;EAAA,QAiDA,wBAAA;EAAA,QA8BN,oBAAA;EAAA,QASA,uBAAA;EAAA,QAQA,gBAAA;EAAA,QAwBA,cAAA;EAAA,QAgBA,aAAA;EAAA,QAIA,YAAA;EAAA,QAaA,SAAA;;UAWA,aAAA;EAAA,QAIA,uBAAA;EAAA,QAIA,mBAAA;EAAA,QAQA,kBAAA;EAAA,QAIA,gBAAA;EAAA,QAKA,QAAA;EAAA,QAkBM,yBAAA;EAAA,QAyBA,eAAA;EAAA,QAeA,qBAAA;EAAA,QAaN,gBAAA;EAAA,QASM,UAAA;EAAA,QASN,qBAAA;EAAA,QAQA,qBAAA;AAAA;;;cCt1BG,qBAAA;AAAA,cACA,0BAAA;AAAA,cACA,mBAAA;AAAA,cACA,gBAAA;AAAA,cACA,mBAAA;AAAA,cACA,kBAAA;EAA6C,GAAA;EAAA,GAAA;AAAA;AAAA,cAC7C,YAAA;AAAA,cAEA,uBAAA,GAA2B,KAAA;AAAA,cAE3B,aAAA,GAAiB,IAAA,UAAc,KAAA;EAAS,GAAA;EAAa,GAAA;AAAA"}
|