{"version":3,"file":"serve.cjs","names":["Deferred","authorizeRequestHandler"],"sources":["../src/serve.ts"],"sourcesContent":["import {\n  createServer as createHttpServer,\n  type RequestListener,\n  type Server as HttpServer,\n  type ServerOptions,\n} from \"node:http\";\nimport { createServer as createHttpsServer, type Server as HttpsServer } from \"node:https\";\nimport type { AddressInfo } from \"node:net\";\nimport { Deferred } from \"@milaboratories/helpers\";\nimport type { PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\nimport { base64Encode, Base64Encoded, ensureError } from \"@milaboratories/pl-model-common\";\nimport { generate, type GenerateResult } from \"selfsigned\";\nimport { randomUUID } from \"node:crypto\";\nimport { authorizeRequestHandler } from \"./handler\";\n\n/** Generate a self-signed certificate for localhost */\nasync function generateCertificate(): Promise<GenerateResult> {\n  return await generate([{ name: \"commonName\", value: \"localhost\" }], {\n    keySize: 2048,\n    algorithm: \"sha256\",\n    extensions: [\n      {\n        name: \"subjectAltName\",\n        altNames: [\n          { type: 2, value: \"localhost\" }, // DNS\n          { type: 7, ip: \"127.0.0.1\" }, // IPv4\n          { type: 7, ip: \"::1\" }, // IPv6\n        ],\n      },\n    ],\n  });\n}\n\n/** Create an object store URL from the server address info. */\nfunction createObjectStoreUrl(info: AddressInfo, noHttps?: true): PFrameInternal.ObjectStoreUrl {\n  const protocol = noHttps ? \"http\" : \"https\";\n  switch (info.family) {\n    case \"IPv4\":\n      return `${protocol}://${info.address}:${info.port}/` as PFrameInternal.ObjectStoreUrl;\n    case \"IPv6\":\n      return `${protocol}://[${info.address}]:${info.port}/` as PFrameInternal.ObjectStoreUrl;\n    default:\n      return `${protocol}://localhost:${info.port}/` as PFrameInternal.ObjectStoreUrl;\n  }\n}\n\n/**\n * Serve HTTP requests using the provided handler.\n * Returns a promise that resolves when the server is stopped.\n */\nexport async function serve({\n  handler,\n  port = 0,\n  noHttps,\n  noAuth,\n}: PFrameInternal.HttpServerOptions): Promise<PFrameInternal.HttpServer> {\n  const started = new Deferred<PFrameInternal.HttpServer>();\n  try {\n    let stopped: Deferred<void> | null = null;\n\n    let authToken: PFrameInternal.HttpAuthorizationToken | undefined;\n    let effectiveHandler: RequestListener = handler;\n    if (!noAuth) {\n      authToken = randomUUID() as PFrameInternal.HttpAuthorizationToken;\n      effectiveHandler = authorizeRequestHandler(effectiveHandler, authToken);\n    }\n\n    // Create HTTP server\n    let encodedCaCert: Base64Encoded<PFrameInternal.PemCertificate> | undefined;\n    const defaultOptions: ServerOptions = {\n      keepAlive: true,\n    };\n    let server: HttpServer | HttpsServer;\n\n    if (noHttps) {\n      server = createHttpServer(defaultOptions, effectiveHandler);\n    } else {\n      const { cert, private: key, public: ca } = await generateCertificate();\n      encodedCaCert = base64Encode(cert as PFrameInternal.PemCertificate);\n      server = createHttpsServer({ ...defaultOptions, cert, key, ca }, effectiveHandler);\n    }\n\n    server\n      .on(\"listening\", () => {\n        // Cast is safe by specification <https://nodejs.org/api/net.html#serveraddress>\n        const url = createObjectStoreUrl(server.address() as AddressInfo, noHttps);\n        stopped = new Deferred<void>();\n\n        started.resolve({\n          get info(): PFrameInternal.HttpServerInfo {\n            return { url, authToken, encodedCaCert };\n          },\n          get stopped(): Promise<void> {\n            return stopped!.promise;\n          },\n          stop(): Promise<void> {\n            server.close();\n            return stopped!.promise;\n          },\n        });\n      })\n      .on(\"error\", (err) => {\n        started.reject(err);\n        stopped?.reject(err);\n      })\n      .on(\"close\", () => stopped?.resolve())\n      .listen({\n        host: \"localhost\",\n        port,\n      });\n  } catch (error: unknown) {\n    started.reject(ensureError(error));\n  }\n\n  return started.promise;\n}\n"],"mappings":";;;;;;;;;AAgBA,eAAe,sBAA+C;AAC5D,QAAO,OAAA,GAAA,WAAA,UAAe,CAAC;EAAE,MAAM;EAAc,OAAO;EAAa,CAAC,EAAE;EAClE,SAAS;EACT,WAAW;EACX,YAAY,CACV;GACE,MAAM;GACN,UAAU;IACR;KAAE,MAAM;KAAG,OAAO;KAAa;IAC/B;KAAE,MAAM;KAAG,IAAI;KAAa;IAC5B;KAAE,MAAM;KAAG,IAAI;KAAO;IACvB;GACF,CACF;EACF,CAAC;;;AAIJ,SAAS,qBAAqB,MAAmB,SAA+C;CAC9F,MAAM,WAAW,UAAU,SAAS;AACpC,SAAQ,KAAK,QAAb;EACE,KAAK,OACH,QAAO,GAAG,SAAS,KAAK,KAAK,QAAQ,GAAG,KAAK,KAAK;EACpD,KAAK,OACH,QAAO,GAAG,SAAS,MAAM,KAAK,QAAQ,IAAI,KAAK,KAAK;EACtD,QACE,QAAO,GAAG,SAAS,eAAe,KAAK,KAAK;;;;;;;AAQlD,eAAsB,MAAM,EAC1B,SACA,OAAO,GACP,SACA,UACuE;CACvE,MAAM,UAAU,IAAIA,wBAAAA,UAAqC;AACzD,KAAI;EACF,IAAI,UAAiC;EAErC,IAAI;EACJ,IAAI,mBAAoC;AACxC,MAAI,CAAC,QAAQ;AACX,gBAAA,GAAA,YAAA,aAAwB;AACxB,sBAAmBC,gBAAAA,wBAAwB,kBAAkB,UAAU;;EAIzE,IAAI;EACJ,MAAM,iBAAgC,EACpC,WAAW,MACZ;EACD,IAAI;AAEJ,MAAI,QACF,WAAA,GAAA,UAAA,cAA0B,gBAAgB,iBAAiB;OACtD;GACL,MAAM,EAAE,MAAM,SAAS,KAAK,QAAQ,OAAO,MAAM,qBAAqB;AACtE,oBAAA,GAAA,gCAAA,cAA6B,KAAsC;AACnE,aAAA,GAAA,WAAA,cAA2B;IAAE,GAAG;IAAgB;IAAM;IAAK;IAAI,EAAE,iBAAiB;;AAGpF,SACG,GAAG,mBAAmB;GAErB,MAAM,MAAM,qBAAqB,OAAO,SAAS,EAAiB,QAAQ;AAC1E,aAAU,IAAID,wBAAAA,UAAgB;AAE9B,WAAQ,QAAQ;IACd,IAAI,OAAsC;AACxC,YAAO;MAAE;MAAK;MAAW;MAAe;;IAE1C,IAAI,UAAyB;AAC3B,YAAO,QAAS;;IAElB,OAAsB;AACpB,YAAO,OAAO;AACd,YAAO,QAAS;;IAEnB,CAAC;IACF,CACD,GAAG,UAAU,QAAQ;AACpB,WAAQ,OAAO,IAAI;AACnB,YAAS,OAAO,IAAI;IACpB,CACD,GAAG,eAAe,SAAS,SAAS,CAAC,CACrC,OAAO;GACN,MAAM;GACN;GACD,CAAC;UACG,OAAgB;AACvB,UAAQ,QAAA,GAAA,gCAAA,aAAmB,MAAM,CAAC;;AAGpC,QAAO,QAAQ"}