@milaboratories/pframes-rs-serv 1.1.18 → 1.1.20

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.
Files changed (82) hide show
  1. package/dist/export.cjs +16 -17
  2. package/dist/export.cjs.map +1 -1
  3. package/dist/export.d.ts +6 -2
  4. package/dist/export.d.ts.map +1 -1
  5. package/dist/export.js +16 -15
  6. package/dist/export.js.map +1 -1
  7. package/dist/fs-store.cjs +83 -87
  8. package/dist/fs-store.cjs.map +1 -1
  9. package/dist/fs-store.d.ts +14 -10
  10. package/dist/fs-store.d.ts.map +1 -1
  11. package/dist/fs-store.js +83 -85
  12. package/dist/fs-store.js.map +1 -1
  13. package/dist/handler.cjs +132 -157
  14. package/dist/handler.cjs.map +1 -1
  15. package/dist/handler.d.ts +8 -4
  16. package/dist/handler.d.ts.map +1 -1
  17. package/dist/handler.js +132 -155
  18. package/dist/handler.js.map +1 -1
  19. package/dist/index.cjs +13 -18
  20. package/dist/index.d.ts +6 -6
  21. package/dist/index.js +6 -6
  22. package/dist/parquet-server.cjs +95 -101
  23. package/dist/parquet-server.cjs.map +1 -1
  24. package/dist/parquet-server.d.ts +16 -12
  25. package/dist/parquet-server.d.ts.map +1 -1
  26. package/dist/parquet-server.js +95 -98
  27. package/dist/parquet-server.js.map +1 -1
  28. package/dist/serve.cjs +98 -94
  29. package/dist/serve.cjs.map +1 -1
  30. package/dist/serve.d.ts +11 -2
  31. package/dist/serve.d.ts.map +1 -1
  32. package/dist/serve.js +98 -92
  33. package/dist/serve.js.map +1 -1
  34. package/dist/utils/etag.cjs +5 -7
  35. package/dist/utils/etag.cjs.map +1 -1
  36. package/dist/utils/etag.js +5 -5
  37. package/dist/utils/etag.js.map +1 -1
  38. package/dist/utils/filename.cjs +9 -11
  39. package/dist/utils/filename.cjs.map +1 -1
  40. package/dist/utils/filename.js +9 -9
  41. package/dist/utils/filename.js.map +1 -1
  42. package/dist/utils/headers.cjs +28 -21
  43. package/dist/utils/headers.cjs.map +1 -1
  44. package/dist/utils/headers.js +28 -19
  45. package/dist/utils/headers.js.map +1 -1
  46. package/dist/utils/method.cjs +7 -7
  47. package/dist/utils/method.cjs.map +1 -1
  48. package/dist/utils/method.js +7 -5
  49. package/dist/utils/method.js.map +1 -1
  50. package/dist/utils/options.cjs +111 -134
  51. package/dist/utils/options.cjs.map +1 -1
  52. package/dist/utils/options.js +111 -132
  53. package/dist/utils/options.js.map +1 -1
  54. package/dist/utils/range.cjs +26 -31
  55. package/dist/utils/range.cjs.map +1 -1
  56. package/dist/utils/range.js +26 -29
  57. package/dist/utils/range.js.map +1 -1
  58. package/dist/utils/status.cjs +17 -17
  59. package/dist/utils/status.cjs.map +1 -1
  60. package/dist/utils/status.js +17 -15
  61. package/dist/utils/status.js.map +1 -1
  62. package/package.json +4 -4
  63. package/src/parquet-server.ts +16 -2
  64. package/dist/index.cjs.map +0 -1
  65. package/dist/index.d.ts.map +0 -1
  66. package/dist/index.js.map +0 -1
  67. package/dist/utils/etag.d.ts +0 -15
  68. package/dist/utils/etag.d.ts.map +0 -1
  69. package/dist/utils/filename.d.ts +0 -4
  70. package/dist/utils/filename.d.ts.map +0 -1
  71. package/dist/utils/headers.d.ts +0 -31
  72. package/dist/utils/headers.d.ts.map +0 -1
  73. package/dist/utils/index.d.ts +0 -8
  74. package/dist/utils/index.d.ts.map +0 -1
  75. package/dist/utils/method.d.ts +0 -6
  76. package/dist/utils/method.d.ts.map +0 -1
  77. package/dist/utils/options.d.ts +0 -64
  78. package/dist/utils/options.d.ts.map +0 -1
  79. package/dist/utils/range.d.ts +0 -4
  80. package/dist/utils/range.d.ts.map +0 -1
  81. package/dist/utils/status.d.ts +0 -17
  82. package/dist/utils/status.d.ts.map +0 -1
@@ -1,109 +1,103 @@
1
- 'use strict';
2
-
3
- var node_child_process = require('node:child_process');
4
- var promises = require('node:readline/promises');
5
- var node_path = require('node:path');
6
- var node_url = require('node:url');
7
- var commander = require('commander');
8
- var _export = require('./export.cjs');
9
- var plModelCommon = require('@milaboratories/pl-model-common');
10
-
11
- var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
1
+ const require_export = require("./export.cjs");
2
+ let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
3
+ let node_path = require("node:path");
4
+ let node_child_process = require("node:child_process");
5
+ let node_readline_promises = require("node:readline/promises");
6
+ let node_url = require("node:url");
7
+ let commander = require("commander");
8
+ //#region src/parquet-server.ts
12
9
  const Options = {
13
- NoHttps: "--no-https",
14
- NoAuth: "--no-auth",
15
- Port: "--port",
10
+ NoHttps: "--no-https",
11
+ NoAuth: "--no-auth",
12
+ Port: "--port"
16
13
  };
17
14
  /**
18
- * Serves parquet files from the given root directory.
19
- * Manages the server lifecycle with graceful shutdown.
20
- */
15
+ * Serves parquet files from the given root directory.
16
+ * Manages the server lifecycle with graceful shutdown.
17
+ */
21
18
  async function runParquetServer() {
22
- const program = new commander.Command();
23
- program
24
- .name("parquet-server")
25
- .description("Serve parquet files from a directory over HTTP(S)")
26
- .argument("<root-directory>", "Root directory containing parquet files")
27
- .option(Options.NoHttps, "Downgrade HTTPS to HTTP")
28
- .option(Options.NoAuth, "Disable authorization")
29
- .option(`${Options.Port} <number>`, "Port to listen on", (value) => {
30
- const port = parseInt(value, 10);
31
- if (isNaN(port) || port < 0 || port > 65535) {
32
- throw new commander.InvalidArgumentError("valid port numbers are 0-65535");
33
- }
34
- return port;
35
- }, 0)
36
- .action(async (rootDir, options) => {
37
- const abortController = new AbortController();
38
- process
39
- .on("SIGINT", () => abortController.abort())
40
- .on("SIGTERM", () => abortController.abort());
41
- abortController.signal.throwIfAborted();
42
- const store = await _export.HttpHelpers.createFsStore({
43
- rootDir,
44
- logger: (level, message) => {
45
- const timestamp = new Date(Date.now()).toISOString();
46
- console.log(`[${timestamp}] [${level}] ${message}`);
47
- },
48
- });
49
- abortController.signal.throwIfAborted();
50
- const handler = _export.HttpHelpers.createRequestHandler({ store });
51
- const server = await _export.HttpHelpers.createHttpServer({
52
- handler,
53
- ...(!options.https && { noHttps: true }),
54
- ...(!options.auth && { noAuth: true }),
55
- port: options.port,
56
- });
57
- abortController.signal.onabort = () => server.stop();
58
- abortController.signal.throwIfAborted();
59
- const serverInfo = plModelCommon.stringifyJson(server.info);
60
- console.log(serverInfo);
61
- await server.stopped;
62
- });
63
- await program.parseAsync();
19
+ const program = new commander.Command();
20
+ program.name("parquet-server").description("Serve parquet files from a directory over HTTP(S)").argument("<root-directory>", "Root directory containing parquet files").option(Options.NoHttps, "Downgrade HTTPS to HTTP").option(Options.NoAuth, "Disable authorization").option(`${Options.Port} <number>`, "Port to listen on", (value) => {
21
+ const port = parseInt(value, 10);
22
+ if (isNaN(port) || port < 0 || port > 65535) throw new commander.InvalidArgumentError("valid port numbers are 0-65535");
23
+ return port;
24
+ }, 0).action(async (rootDir, options) => {
25
+ const abortController = new AbortController();
26
+ process.on("SIGINT", () => abortController.abort()).on("SIGTERM", () => abortController.abort());
27
+ abortController.signal.throwIfAborted();
28
+ const store = await require_export.HttpHelpers.createFsStore({
29
+ rootDir,
30
+ logger: (level, message) => {
31
+ const timestamp = new Date(Date.now()).toISOString();
32
+ console.log(`[${timestamp}] [${level}] ${message}`);
33
+ }
34
+ });
35
+ abortController.signal.throwIfAborted();
36
+ const handler = require_export.HttpHelpers.createRequestHandler({ store });
37
+ const server = await require_export.HttpHelpers.createHttpServer({
38
+ handler,
39
+ ...!options.https && { noHttps: true },
40
+ ...!options.auth && { noAuth: true },
41
+ port: options.port
42
+ });
43
+ abortController.signal.onabort = () => server.stop();
44
+ abortController.signal.throwIfAborted();
45
+ const serverInfo = (0, _milaboratories_pl_model_common.stringifyJson)(server.info);
46
+ console.log(serverInfo);
47
+ await server.stopped;
48
+ });
49
+ await program.parseAsync();
64
50
  }
65
51
  /**
66
- * Reference implementation of a parquet server runner for tests:
67
- * - Reads the server configuration from the spawned process stdout
68
- * - Forwards the server logs to the console
69
- * - Shuts down the server on dispose
70
- */
71
- class ParquetServer {
72
- #process;
73
- #info;
74
- #lineReader;
75
- constructor(process, info, lineReader) {
76
- this.#process = process;
77
- this.#info = info;
78
- this.#lineReader = lineReader;
79
- }
80
- get info() {
81
- return this.#info;
82
- }
83
- static async serve(rootDir, options) {
84
- const nodeDirname = node_path.dirname(node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('parquet-server.cjs', document.baseURI).href))));
85
- const binPath = node_path.join(nodeDirname, "..", "bin", "parquet-server.mjs");
86
- const serverProcess = node_child_process.spawn("node", [
87
- binPath,
88
- rootDir,
89
- ...(options?.noHttps ? [Options.NoHttps] : []),
90
- ...(options?.noAuth ? [Options.NoAuth] : []),
91
- ...(options?.port ? [Options.Port, options.port.toString()] : []),
92
- ], {
93
- stdio: ["ignore", "pipe", "ignore"],
94
- });
95
- const lineReader = promises.createInterface({ input: serverProcess.stdout });
96
- const firstLine = await lineReader[Symbol.asyncIterator]().next();
97
- const serverInfo = plModelCommon.parseJson(firstLine.value);
98
- lineReader.on("line", console.log);
99
- return new ParquetServer(serverProcess, serverInfo, lineReader);
100
- }
101
- [Symbol.dispose]() {
102
- this.#lineReader.close();
103
- this.#process.kill();
104
- }
105
- }
106
-
52
+ * Reference implementation of a parquet server runner for tests:
53
+ * - Reads the server configuration from the spawned process stdout
54
+ * - Forwards the server logs to the console
55
+ * - Shuts down the server on dispose
56
+ */
57
+ var ParquetServer = class ParquetServer {
58
+ #process;
59
+ #info;
60
+ #lineReader;
61
+ constructor(process, info, lineReader) {
62
+ this.#process = process;
63
+ this.#info = info;
64
+ this.#lineReader = lineReader;
65
+ }
66
+ get info() {
67
+ return this.#info;
68
+ }
69
+ static async serve(rootDir, options) {
70
+ const serverProcess = (0, node_child_process.spawn)("node", [
71
+ (0, node_path.join)((0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href)), "..", "bin", "parquet-server.mjs"),
72
+ rootDir,
73
+ ...options?.noHttps ? [Options.NoHttps] : [],
74
+ ...options?.noAuth ? [Options.NoAuth] : [],
75
+ ...options?.port ? [Options.Port, options.port.toString()] : []
76
+ ], { stdio: [
77
+ "ignore",
78
+ "pipe",
79
+ "inherit"
80
+ ] });
81
+ const lineReader = (0, node_readline_promises.createInterface)({ input: serverProcess.stdout });
82
+ const exitPromise = new Promise((_, reject) => {
83
+ serverProcess.once("exit", (code, signal) => {
84
+ reject(/* @__PURE__ */ new Error(`parquet-server exited before emitting server info (code=${code}, signal=${signal})`));
85
+ });
86
+ serverProcess.once("error", reject);
87
+ });
88
+ const firstLine = await Promise.race([lineReader[Symbol.asyncIterator]().next(), exitPromise]);
89
+ if (firstLine.value === void 0) throw new Error("parquet-server stdout closed without emitting server info");
90
+ const serverInfo = (0, _milaboratories_pl_model_common.parseJson)(firstLine.value);
91
+ lineReader.on("line", console.log);
92
+ return new ParquetServer(serverProcess, serverInfo, lineReader);
93
+ }
94
+ [Symbol.dispose]() {
95
+ this.#lineReader.close();
96
+ this.#process.kill();
97
+ }
98
+ };
99
+ //#endregion
107
100
  exports.ParquetServer = ParquetServer;
108
101
  exports.runParquetServer = runParquetServer;
109
- //# sourceMappingURL=parquet-server.cjs.map
102
+
103
+ //# sourceMappingURL=parquet-server.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"parquet-server.cjs","sources":["../src/parquet-server.ts"],"sourcesContent":["import { type ChildProcess, spawn } from \"node:child_process\";\nimport { createInterface, type Interface } from \"node:readline/promises\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command, InvalidArgumentError } from \"commander\";\nimport { HttpHelpers } from \"./export\";\nimport { parseJson, stringifyJson, type StringifiedJson } from \"@milaboratories/pl-model-common\";\nimport { type PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\n\nconst Options = {\n NoHttps: \"--no-https\",\n NoAuth: \"--no-auth\",\n Port: \"--port\",\n} as const;\n\ntype Info = StringifiedJson<PFrameInternal.HttpServerInfo>;\n\n/**\n * Serves parquet files from the given root directory.\n * Manages the server lifecycle with graceful shutdown.\n */\nexport async function runParquetServer(): Promise<void> {\n const program = new Command();\n\n program\n .name(\"parquet-server\")\n .description(\"Serve parquet files from a directory over HTTP(S)\")\n .argument(\"<root-directory>\", \"Root directory containing parquet files\")\n .option(Options.NoHttps, \"Downgrade HTTPS to HTTP\")\n .option(Options.NoAuth, \"Disable authorization\")\n .option(\n `${Options.Port} <number>`,\n \"Port to listen on\",\n (value) => {\n const port = parseInt(value, 10);\n if (isNaN(port) || port < 0 || port > 65535) {\n throw new InvalidArgumentError(\"valid port numbers are 0-65535\");\n }\n return port;\n },\n 0,\n )\n .action(\n async (\n rootDir: string,\n options: {\n https: boolean;\n auth: boolean;\n port: number;\n },\n ) => {\n const abortController = new AbortController();\n process\n .on(\"SIGINT\", () => abortController.abort())\n .on(\"SIGTERM\", () => abortController.abort());\n abortController.signal.throwIfAborted();\n\n const store = await HttpHelpers.createFsStore({\n rootDir,\n logger: (level, message) => {\n const timestamp = new Date(Date.now()).toISOString();\n console.log(`[${timestamp}] [${level}] ${message}`);\n },\n });\n abortController.signal.throwIfAborted();\n const handler = HttpHelpers.createRequestHandler({ store });\n\n const server = await HttpHelpers.createHttpServer({\n handler,\n ...(!options.https && { noHttps: true }),\n ...(!options.auth && { noAuth: true }),\n port: options.port,\n });\n abortController.signal.onabort = () => server.stop();\n abortController.signal.throwIfAborted();\n\n const serverInfo: Info = stringifyJson(server.info);\n console.log(serverInfo);\n\n await server.stopped;\n },\n );\n\n await program.parseAsync();\n}\n\n/**\n * Reference implementation of a parquet server runner for tests:\n * - Reads the server configuration from the spawned process stdout\n * - Forwards the server logs to the console\n * - Shuts down the server on dispose\n */\nexport class ParquetServer implements Disposable {\n readonly #process: ChildProcess;\n readonly #info: PFrameInternal.HttpServerInfo;\n readonly #lineReader: Interface;\n\n private constructor(\n process: ChildProcess,\n info: PFrameInternal.HttpServerInfo,\n lineReader: Interface,\n ) {\n this.#process = process;\n this.#info = info;\n this.#lineReader = lineReader;\n }\n\n get info(): PFrameInternal.HttpServerInfo {\n return this.#info;\n }\n\n static async serve(\n rootDir: string,\n options?: {\n noHttps?: true;\n noAuth?: true;\n port?: number;\n },\n ): Promise<ParquetServer> {\n const nodeDirname = dirname(fileURLToPath(import.meta.url));\n const binPath = join(nodeDirname, \"..\", \"bin\", \"parquet-server.mjs\");\n\n const serverProcess = spawn(\n \"node\",\n [\n binPath,\n rootDir,\n ...(options?.noHttps ? [Options.NoHttps] : []),\n ...(options?.noAuth ? [Options.NoAuth] : []),\n ...(options?.port ? [Options.Port, options.port.toString()] : []),\n ],\n {\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n },\n );\n\n const lineReader = createInterface({ input: serverProcess.stdout! });\n\n const firstLine = await lineReader[Symbol.asyncIterator]().next();\n const serverInfo = parseJson(firstLine.value as Info);\n\n lineReader.on(\"line\", console.log);\n\n return new ParquetServer(serverProcess, serverInfo, lineReader);\n }\n\n [Symbol.dispose](): void {\n this.#lineReader.close();\n this.#process.kill();\n }\n}\n"],"names":["Command","InvalidArgumentError","HttpHelpers","stringifyJson","dirname","fileURLToPath","join","spawn","createInterface","parseJson"],"mappings":"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"}
1
+ {"version":3,"file":"parquet-server.cjs","names":["Command","InvalidArgumentError","HttpHelpers","#process","#info","#lineReader"],"sources":["../src/parquet-server.ts"],"sourcesContent":["import { type ChildProcess, spawn } from \"node:child_process\";\nimport { createInterface, type Interface } from \"node:readline/promises\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command, InvalidArgumentError } from \"commander\";\nimport { HttpHelpers } from \"./export\";\nimport { parseJson, stringifyJson, type StringifiedJson } from \"@milaboratories/pl-model-common\";\nimport { type PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\n\nconst Options = {\n NoHttps: \"--no-https\",\n NoAuth: \"--no-auth\",\n Port: \"--port\",\n} as const;\n\ntype Info = StringifiedJson<PFrameInternal.HttpServerInfo>;\n\n/**\n * Serves parquet files from the given root directory.\n * Manages the server lifecycle with graceful shutdown.\n */\nexport async function runParquetServer(): Promise<void> {\n const program = new Command();\n\n program\n .name(\"parquet-server\")\n .description(\"Serve parquet files from a directory over HTTP(S)\")\n .argument(\"<root-directory>\", \"Root directory containing parquet files\")\n .option(Options.NoHttps, \"Downgrade HTTPS to HTTP\")\n .option(Options.NoAuth, \"Disable authorization\")\n .option(\n `${Options.Port} <number>`,\n \"Port to listen on\",\n (value) => {\n const port = parseInt(value, 10);\n if (isNaN(port) || port < 0 || port > 65535) {\n throw new InvalidArgumentError(\"valid port numbers are 0-65535\");\n }\n return port;\n },\n 0,\n )\n .action(\n async (\n rootDir: string,\n options: {\n https: boolean;\n auth: boolean;\n port: number;\n },\n ) => {\n const abortController = new AbortController();\n process\n .on(\"SIGINT\", () => abortController.abort())\n .on(\"SIGTERM\", () => abortController.abort());\n abortController.signal.throwIfAborted();\n\n const store = await HttpHelpers.createFsStore({\n rootDir,\n logger: (level, message) => {\n const timestamp = new Date(Date.now()).toISOString();\n console.log(`[${timestamp}] [${level}] ${message}`);\n },\n });\n abortController.signal.throwIfAborted();\n const handler = HttpHelpers.createRequestHandler({ store });\n\n const server = await HttpHelpers.createHttpServer({\n handler,\n ...(!options.https && { noHttps: true }),\n ...(!options.auth && { noAuth: true }),\n port: options.port,\n });\n abortController.signal.onabort = () => server.stop();\n abortController.signal.throwIfAborted();\n\n const serverInfo: Info = stringifyJson(server.info);\n console.log(serverInfo);\n\n await server.stopped;\n },\n );\n\n await program.parseAsync();\n}\n\n/**\n * Reference implementation of a parquet server runner for tests:\n * - Reads the server configuration from the spawned process stdout\n * - Forwards the server logs to the console\n * - Shuts down the server on dispose\n */\nexport class ParquetServer implements Disposable {\n readonly #process: ChildProcess;\n readonly #info: PFrameInternal.HttpServerInfo;\n readonly #lineReader: Interface;\n\n private constructor(\n process: ChildProcess,\n info: PFrameInternal.HttpServerInfo,\n lineReader: Interface,\n ) {\n this.#process = process;\n this.#info = info;\n this.#lineReader = lineReader;\n }\n\n get info(): PFrameInternal.HttpServerInfo {\n return this.#info;\n }\n\n static async serve(\n rootDir: string,\n options?: {\n noHttps?: true;\n noAuth?: true;\n port?: number;\n },\n ): Promise<ParquetServer> {\n const nodeDirname = dirname(fileURLToPath(import.meta.url));\n const binPath = join(nodeDirname, \"..\", \"bin\", \"parquet-server.mjs\");\n\n const serverProcess = spawn(\n \"node\",\n [\n binPath,\n rootDir,\n ...(options?.noHttps ? [Options.NoHttps] : []),\n ...(options?.noAuth ? [Options.NoAuth] : []),\n ...(options?.port ? [Options.Port, options.port.toString()] : []),\n ],\n {\n stdio: [\"ignore\", \"pipe\", \"inherit\"],\n },\n );\n\n const lineReader = createInterface({ input: serverProcess.stdout! });\n\n const exitPromise = new Promise<never>((_, reject) => {\n serverProcess.once(\"exit\", (code, signal) => {\n reject(\n new Error(\n `parquet-server exited before emitting server info (code=${code}, signal=${signal})`,\n ),\n );\n });\n serverProcess.once(\"error\", reject);\n });\n\n const firstLine = await Promise.race([lineReader[Symbol.asyncIterator]().next(), exitPromise]);\n if (firstLine.value === undefined) {\n throw new Error(\"parquet-server stdout closed without emitting server info\");\n }\n const serverInfo = parseJson(firstLine.value as Info);\n\n lineReader.on(\"line\", console.log);\n\n return new ParquetServer(serverProcess, serverInfo, lineReader);\n }\n\n [Symbol.dispose](): void {\n this.#lineReader.close();\n this.#process.kill();\n }\n}\n"],"mappings":"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"}
@@ -1,24 +1,28 @@
1
- import { type PFrameInternal } from "@milaboratories/pl-model-middle-layer";
1
+ import { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
2
+
3
+ //#region src/parquet-server.d.ts
2
4
  /**
3
5
  * Serves parquet files from the given root directory.
4
6
  * Manages the server lifecycle with graceful shutdown.
5
7
  */
6
- export declare function runParquetServer(): Promise<void>;
8
+ declare function runParquetServer(): Promise<void>;
7
9
  /**
8
10
  * Reference implementation of a parquet server runner for tests:
9
11
  * - Reads the server configuration from the spawned process stdout
10
12
  * - Forwards the server logs to the console
11
13
  * - Shuts down the server on dispose
12
14
  */
13
- export declare class ParquetServer implements Disposable {
14
- #private;
15
- private constructor();
16
- get info(): PFrameInternal.HttpServerInfo;
17
- static serve(rootDir: string, options?: {
18
- noHttps?: true;
19
- noAuth?: true;
20
- port?: number;
21
- }): Promise<ParquetServer>;
22
- [Symbol.dispose](): void;
15
+ declare class ParquetServer implements Disposable {
16
+ #private;
17
+ private constructor();
18
+ get info(): PFrameInternal.HttpServerInfo;
19
+ static serve(rootDir: string, options?: {
20
+ noHttps?: true;
21
+ noAuth?: true;
22
+ port?: number;
23
+ }): Promise<ParquetServer>;
24
+ [Symbol.dispose](): void;
23
25
  }
26
+ //#endregion
27
+ export { ParquetServer, runParquetServer };
24
28
  //# sourceMappingURL=parquet-server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parquet-server.d.ts","sourceRoot":"","sources":["../src/parquet-server.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAU5E;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CA+DtD;AAED;;;;;GAKG;AACH,qBAAa,aAAc,YAAW,UAAU;;IAK9C,OAAO;IAUP,IAAI,IAAI,IAAI,cAAc,CAAC,cAAc,CAExC;WAEY,KAAK,CAChB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,IAAI,CAAC;QACf,MAAM,CAAC,EAAE,IAAI,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GACA,OAAO,CAAC,aAAa,CAAC;IA4BzB,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI;CAIzB"}
1
+ {"version":3,"file":"parquet-server.d.ts","names":[],"sources":["../src/parquet-server.ts"],"mappings":";;;;;AAqBA;;iBAAsB,gBAAA,CAAA,GAAoB,OAAA;;;AAuE1C;;;;cAAa,aAAA,YAAyB,UAAA;EAAA;UAK7B,WAAA,CAAA;EAAA,IAUH,IAAA,CAAA,GAAQ,cAAA,CAAe,cAAA;EAAA,OAId,KAAA,CACX,OAAA,UACA,OAAA;IACE,OAAA;IACA,MAAA;IACA,IAAA;EAAA,IAED,OAAA,CAAQ,aAAA;EAAA,CA0CV,MAAA,CAAO,OAAA;AAAA"}
@@ -1,105 +1,102 @@
1
- import { spawn } from 'node:child_process';
2
- import { createInterface } from 'node:readline/promises';
3
- import { dirname, join } from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import { Command, InvalidArgumentError } from 'commander';
6
- import { HttpHelpers } from './export.js';
7
- import { stringifyJson, parseJson } from '@milaboratories/pl-model-common';
8
-
1
+ import { HttpHelpers } from "./export.js";
2
+ import { parseJson, stringifyJson } from "@milaboratories/pl-model-common";
3
+ import { dirname, join } from "node:path";
4
+ import { spawn } from "node:child_process";
5
+ import { createInterface } from "node:readline/promises";
6
+ import { fileURLToPath } from "node:url";
7
+ import { Command, InvalidArgumentError } from "commander";
8
+ //#region src/parquet-server.ts
9
9
  const Options = {
10
- NoHttps: "--no-https",
11
- NoAuth: "--no-auth",
12
- Port: "--port",
10
+ NoHttps: "--no-https",
11
+ NoAuth: "--no-auth",
12
+ Port: "--port"
13
13
  };
14
14
  /**
15
- * Serves parquet files from the given root directory.
16
- * Manages the server lifecycle with graceful shutdown.
17
- */
15
+ * Serves parquet files from the given root directory.
16
+ * Manages the server lifecycle with graceful shutdown.
17
+ */
18
18
  async function runParquetServer() {
19
- const program = new Command();
20
- program
21
- .name("parquet-server")
22
- .description("Serve parquet files from a directory over HTTP(S)")
23
- .argument("<root-directory>", "Root directory containing parquet files")
24
- .option(Options.NoHttps, "Downgrade HTTPS to HTTP")
25
- .option(Options.NoAuth, "Disable authorization")
26
- .option(`${Options.Port} <number>`, "Port to listen on", (value) => {
27
- const port = parseInt(value, 10);
28
- if (isNaN(port) || port < 0 || port > 65535) {
29
- throw new InvalidArgumentError("valid port numbers are 0-65535");
30
- }
31
- return port;
32
- }, 0)
33
- .action(async (rootDir, options) => {
34
- const abortController = new AbortController();
35
- process
36
- .on("SIGINT", () => abortController.abort())
37
- .on("SIGTERM", () => abortController.abort());
38
- abortController.signal.throwIfAborted();
39
- const store = await HttpHelpers.createFsStore({
40
- rootDir,
41
- logger: (level, message) => {
42
- const timestamp = new Date(Date.now()).toISOString();
43
- console.log(`[${timestamp}] [${level}] ${message}`);
44
- },
45
- });
46
- abortController.signal.throwIfAborted();
47
- const handler = HttpHelpers.createRequestHandler({ store });
48
- const server = await HttpHelpers.createHttpServer({
49
- handler,
50
- ...(!options.https && { noHttps: true }),
51
- ...(!options.auth && { noAuth: true }),
52
- port: options.port,
53
- });
54
- abortController.signal.onabort = () => server.stop();
55
- abortController.signal.throwIfAborted();
56
- const serverInfo = stringifyJson(server.info);
57
- console.log(serverInfo);
58
- await server.stopped;
59
- });
60
- await program.parseAsync();
19
+ const program = new Command();
20
+ program.name("parquet-server").description("Serve parquet files from a directory over HTTP(S)").argument("<root-directory>", "Root directory containing parquet files").option(Options.NoHttps, "Downgrade HTTPS to HTTP").option(Options.NoAuth, "Disable authorization").option(`${Options.Port} <number>`, "Port to listen on", (value) => {
21
+ const port = parseInt(value, 10);
22
+ if (isNaN(port) || port < 0 || port > 65535) throw new InvalidArgumentError("valid port numbers are 0-65535");
23
+ return port;
24
+ }, 0).action(async (rootDir, options) => {
25
+ const abortController = new AbortController();
26
+ process.on("SIGINT", () => abortController.abort()).on("SIGTERM", () => abortController.abort());
27
+ abortController.signal.throwIfAborted();
28
+ const store = await HttpHelpers.createFsStore({
29
+ rootDir,
30
+ logger: (level, message) => {
31
+ const timestamp = new Date(Date.now()).toISOString();
32
+ console.log(`[${timestamp}] [${level}] ${message}`);
33
+ }
34
+ });
35
+ abortController.signal.throwIfAborted();
36
+ const handler = HttpHelpers.createRequestHandler({ store });
37
+ const server = await HttpHelpers.createHttpServer({
38
+ handler,
39
+ ...!options.https && { noHttps: true },
40
+ ...!options.auth && { noAuth: true },
41
+ port: options.port
42
+ });
43
+ abortController.signal.onabort = () => server.stop();
44
+ abortController.signal.throwIfAborted();
45
+ const serverInfo = stringifyJson(server.info);
46
+ console.log(serverInfo);
47
+ await server.stopped;
48
+ });
49
+ await program.parseAsync();
61
50
  }
62
51
  /**
63
- * Reference implementation of a parquet server runner for tests:
64
- * - Reads the server configuration from the spawned process stdout
65
- * - Forwards the server logs to the console
66
- * - Shuts down the server on dispose
67
- */
68
- class ParquetServer {
69
- #process;
70
- #info;
71
- #lineReader;
72
- constructor(process, info, lineReader) {
73
- this.#process = process;
74
- this.#info = info;
75
- this.#lineReader = lineReader;
76
- }
77
- get info() {
78
- return this.#info;
79
- }
80
- static async serve(rootDir, options) {
81
- const nodeDirname = dirname(fileURLToPath(import.meta.url));
82
- const binPath = join(nodeDirname, "..", "bin", "parquet-server.mjs");
83
- const serverProcess = spawn("node", [
84
- binPath,
85
- rootDir,
86
- ...(options?.noHttps ? [Options.NoHttps] : []),
87
- ...(options?.noAuth ? [Options.NoAuth] : []),
88
- ...(options?.port ? [Options.Port, options.port.toString()] : []),
89
- ], {
90
- stdio: ["ignore", "pipe", "ignore"],
91
- });
92
- const lineReader = createInterface({ input: serverProcess.stdout });
93
- const firstLine = await lineReader[Symbol.asyncIterator]().next();
94
- const serverInfo = parseJson(firstLine.value);
95
- lineReader.on("line", console.log);
96
- return new ParquetServer(serverProcess, serverInfo, lineReader);
97
- }
98
- [Symbol.dispose]() {
99
- this.#lineReader.close();
100
- this.#process.kill();
101
- }
102
- }
103
-
52
+ * Reference implementation of a parquet server runner for tests:
53
+ * - Reads the server configuration from the spawned process stdout
54
+ * - Forwards the server logs to the console
55
+ * - Shuts down the server on dispose
56
+ */
57
+ var ParquetServer = class ParquetServer {
58
+ #process;
59
+ #info;
60
+ #lineReader;
61
+ constructor(process, info, lineReader) {
62
+ this.#process = process;
63
+ this.#info = info;
64
+ this.#lineReader = lineReader;
65
+ }
66
+ get info() {
67
+ return this.#info;
68
+ }
69
+ static async serve(rootDir, options) {
70
+ const serverProcess = spawn("node", [
71
+ join(dirname(fileURLToPath(import.meta.url)), "..", "bin", "parquet-server.mjs"),
72
+ rootDir,
73
+ ...options?.noHttps ? [Options.NoHttps] : [],
74
+ ...options?.noAuth ? [Options.NoAuth] : [],
75
+ ...options?.port ? [Options.Port, options.port.toString()] : []
76
+ ], { stdio: [
77
+ "ignore",
78
+ "pipe",
79
+ "inherit"
80
+ ] });
81
+ const lineReader = createInterface({ input: serverProcess.stdout });
82
+ const exitPromise = new Promise((_, reject) => {
83
+ serverProcess.once("exit", (code, signal) => {
84
+ reject(/* @__PURE__ */ new Error(`parquet-server exited before emitting server info (code=${code}, signal=${signal})`));
85
+ });
86
+ serverProcess.once("error", reject);
87
+ });
88
+ const firstLine = await Promise.race([lineReader[Symbol.asyncIterator]().next(), exitPromise]);
89
+ if (firstLine.value === void 0) throw new Error("parquet-server stdout closed without emitting server info");
90
+ const serverInfo = parseJson(firstLine.value);
91
+ lineReader.on("line", console.log);
92
+ return new ParquetServer(serverProcess, serverInfo, lineReader);
93
+ }
94
+ [Symbol.dispose]() {
95
+ this.#lineReader.close();
96
+ this.#process.kill();
97
+ }
98
+ };
99
+ //#endregion
104
100
  export { ParquetServer, runParquetServer };
105
- //# sourceMappingURL=parquet-server.js.map
101
+
102
+ //# sourceMappingURL=parquet-server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"parquet-server.js","sources":["../src/parquet-server.ts"],"sourcesContent":["import { type ChildProcess, spawn } from \"node:child_process\";\nimport { createInterface, type Interface } from \"node:readline/promises\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command, InvalidArgumentError } from \"commander\";\nimport { HttpHelpers } from \"./export\";\nimport { parseJson, stringifyJson, type StringifiedJson } from \"@milaboratories/pl-model-common\";\nimport { type PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\n\nconst Options = {\n NoHttps: \"--no-https\",\n NoAuth: \"--no-auth\",\n Port: \"--port\",\n} as const;\n\ntype Info = StringifiedJson<PFrameInternal.HttpServerInfo>;\n\n/**\n * Serves parquet files from the given root directory.\n * Manages the server lifecycle with graceful shutdown.\n */\nexport async function runParquetServer(): Promise<void> {\n const program = new Command();\n\n program\n .name(\"parquet-server\")\n .description(\"Serve parquet files from a directory over HTTP(S)\")\n .argument(\"<root-directory>\", \"Root directory containing parquet files\")\n .option(Options.NoHttps, \"Downgrade HTTPS to HTTP\")\n .option(Options.NoAuth, \"Disable authorization\")\n .option(\n `${Options.Port} <number>`,\n \"Port to listen on\",\n (value) => {\n const port = parseInt(value, 10);\n if (isNaN(port) || port < 0 || port > 65535) {\n throw new InvalidArgumentError(\"valid port numbers are 0-65535\");\n }\n return port;\n },\n 0,\n )\n .action(\n async (\n rootDir: string,\n options: {\n https: boolean;\n auth: boolean;\n port: number;\n },\n ) => {\n const abortController = new AbortController();\n process\n .on(\"SIGINT\", () => abortController.abort())\n .on(\"SIGTERM\", () => abortController.abort());\n abortController.signal.throwIfAborted();\n\n const store = await HttpHelpers.createFsStore({\n rootDir,\n logger: (level, message) => {\n const timestamp = new Date(Date.now()).toISOString();\n console.log(`[${timestamp}] [${level}] ${message}`);\n },\n });\n abortController.signal.throwIfAborted();\n const handler = HttpHelpers.createRequestHandler({ store });\n\n const server = await HttpHelpers.createHttpServer({\n handler,\n ...(!options.https && { noHttps: true }),\n ...(!options.auth && { noAuth: true }),\n port: options.port,\n });\n abortController.signal.onabort = () => server.stop();\n abortController.signal.throwIfAborted();\n\n const serverInfo: Info = stringifyJson(server.info);\n console.log(serverInfo);\n\n await server.stopped;\n },\n );\n\n await program.parseAsync();\n}\n\n/**\n * Reference implementation of a parquet server runner for tests:\n * - Reads the server configuration from the spawned process stdout\n * - Forwards the server logs to the console\n * - Shuts down the server on dispose\n */\nexport class ParquetServer implements Disposable {\n readonly #process: ChildProcess;\n readonly #info: PFrameInternal.HttpServerInfo;\n readonly #lineReader: Interface;\n\n private constructor(\n process: ChildProcess,\n info: PFrameInternal.HttpServerInfo,\n lineReader: Interface,\n ) {\n this.#process = process;\n this.#info = info;\n this.#lineReader = lineReader;\n }\n\n get info(): PFrameInternal.HttpServerInfo {\n return this.#info;\n }\n\n static async serve(\n rootDir: string,\n options?: {\n noHttps?: true;\n noAuth?: true;\n port?: number;\n },\n ): Promise<ParquetServer> {\n const nodeDirname = dirname(fileURLToPath(import.meta.url));\n const binPath = join(nodeDirname, \"..\", \"bin\", \"parquet-server.mjs\");\n\n const serverProcess = spawn(\n \"node\",\n [\n binPath,\n rootDir,\n ...(options?.noHttps ? [Options.NoHttps] : []),\n ...(options?.noAuth ? [Options.NoAuth] : []),\n ...(options?.port ? [Options.Port, options.port.toString()] : []),\n ],\n {\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n },\n );\n\n const lineReader = createInterface({ input: serverProcess.stdout! });\n\n const firstLine = await lineReader[Symbol.asyncIterator]().next();\n const serverInfo = parseJson(firstLine.value as Info);\n\n lineReader.on(\"line\", console.log);\n\n return new ParquetServer(serverProcess, serverInfo, lineReader);\n }\n\n [Symbol.dispose](): void {\n this.#lineReader.close();\n this.#process.kill();\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"parquet-server.js","names":["#process","#info","#lineReader"],"sources":["../src/parquet-server.ts"],"sourcesContent":["import { type ChildProcess, spawn } from \"node:child_process\";\nimport { createInterface, type Interface } from \"node:readline/promises\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command, InvalidArgumentError } from \"commander\";\nimport { HttpHelpers } from \"./export\";\nimport { parseJson, stringifyJson, type StringifiedJson } from \"@milaboratories/pl-model-common\";\nimport { type PFrameInternal } from \"@milaboratories/pl-model-middle-layer\";\n\nconst Options = {\n NoHttps: \"--no-https\",\n NoAuth: \"--no-auth\",\n Port: \"--port\",\n} as const;\n\ntype Info = StringifiedJson<PFrameInternal.HttpServerInfo>;\n\n/**\n * Serves parquet files from the given root directory.\n * Manages the server lifecycle with graceful shutdown.\n */\nexport async function runParquetServer(): Promise<void> {\n const program = new Command();\n\n program\n .name(\"parquet-server\")\n .description(\"Serve parquet files from a directory over HTTP(S)\")\n .argument(\"<root-directory>\", \"Root directory containing parquet files\")\n .option(Options.NoHttps, \"Downgrade HTTPS to HTTP\")\n .option(Options.NoAuth, \"Disable authorization\")\n .option(\n `${Options.Port} <number>`,\n \"Port to listen on\",\n (value) => {\n const port = parseInt(value, 10);\n if (isNaN(port) || port < 0 || port > 65535) {\n throw new InvalidArgumentError(\"valid port numbers are 0-65535\");\n }\n return port;\n },\n 0,\n )\n .action(\n async (\n rootDir: string,\n options: {\n https: boolean;\n auth: boolean;\n port: number;\n },\n ) => {\n const abortController = new AbortController();\n process\n .on(\"SIGINT\", () => abortController.abort())\n .on(\"SIGTERM\", () => abortController.abort());\n abortController.signal.throwIfAborted();\n\n const store = await HttpHelpers.createFsStore({\n rootDir,\n logger: (level, message) => {\n const timestamp = new Date(Date.now()).toISOString();\n console.log(`[${timestamp}] [${level}] ${message}`);\n },\n });\n abortController.signal.throwIfAborted();\n const handler = HttpHelpers.createRequestHandler({ store });\n\n const server = await HttpHelpers.createHttpServer({\n handler,\n ...(!options.https && { noHttps: true }),\n ...(!options.auth && { noAuth: true }),\n port: options.port,\n });\n abortController.signal.onabort = () => server.stop();\n abortController.signal.throwIfAborted();\n\n const serverInfo: Info = stringifyJson(server.info);\n console.log(serverInfo);\n\n await server.stopped;\n },\n );\n\n await program.parseAsync();\n}\n\n/**\n * Reference implementation of a parquet server runner for tests:\n * - Reads the server configuration from the spawned process stdout\n * - Forwards the server logs to the console\n * - Shuts down the server on dispose\n */\nexport class ParquetServer implements Disposable {\n readonly #process: ChildProcess;\n readonly #info: PFrameInternal.HttpServerInfo;\n readonly #lineReader: Interface;\n\n private constructor(\n process: ChildProcess,\n info: PFrameInternal.HttpServerInfo,\n lineReader: Interface,\n ) {\n this.#process = process;\n this.#info = info;\n this.#lineReader = lineReader;\n }\n\n get info(): PFrameInternal.HttpServerInfo {\n return this.#info;\n }\n\n static async serve(\n rootDir: string,\n options?: {\n noHttps?: true;\n noAuth?: true;\n port?: number;\n },\n ): Promise<ParquetServer> {\n const nodeDirname = dirname(fileURLToPath(import.meta.url));\n const binPath = join(nodeDirname, \"..\", \"bin\", \"parquet-server.mjs\");\n\n const serverProcess = spawn(\n \"node\",\n [\n binPath,\n rootDir,\n ...(options?.noHttps ? [Options.NoHttps] : []),\n ...(options?.noAuth ? [Options.NoAuth] : []),\n ...(options?.port ? [Options.Port, options.port.toString()] : []),\n ],\n {\n stdio: [\"ignore\", \"pipe\", \"inherit\"],\n },\n );\n\n const lineReader = createInterface({ input: serverProcess.stdout! });\n\n const exitPromise = new Promise<never>((_, reject) => {\n serverProcess.once(\"exit\", (code, signal) => {\n reject(\n new Error(\n `parquet-server exited before emitting server info (code=${code}, signal=${signal})`,\n ),\n );\n });\n serverProcess.once(\"error\", reject);\n });\n\n const firstLine = await Promise.race([lineReader[Symbol.asyncIterator]().next(), exitPromise]);\n if (firstLine.value === undefined) {\n throw new Error(\"parquet-server stdout closed without emitting server info\");\n }\n const serverInfo = parseJson(firstLine.value as Info);\n\n lineReader.on(\"line\", console.log);\n\n return new ParquetServer(serverProcess, serverInfo, lineReader);\n }\n\n [Symbol.dispose](): void {\n this.#lineReader.close();\n this.#process.kill();\n }\n}\n"],"mappings":"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"}