@milaboratories/pframes-rs-serv 1.1.3 → 1.1.5

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 (81) hide show
  1. package/bin/parquet-server.mjs +2 -2
  2. package/dist/export.cjs +1 -1
  3. package/dist/export.cjs.map +1 -1
  4. package/dist/export.d.ts +1 -1
  5. package/dist/export.d.ts.map +1 -1
  6. package/dist/export.js +1 -1
  7. package/dist/export.js.map +1 -1
  8. package/dist/fs-store.cjs +18 -20
  9. package/dist/fs-store.cjs.map +1 -1
  10. package/dist/fs-store.d.ts +1 -1
  11. package/dist/fs-store.d.ts.map +1 -1
  12. package/dist/fs-store.js +18 -20
  13. package/dist/fs-store.js.map +1 -1
  14. package/dist/handler.cjs +5 -5
  15. package/dist/handler.cjs.map +1 -1
  16. package/dist/handler.d.ts +2 -2
  17. package/dist/handler.d.ts.map +1 -1
  18. package/dist/handler.js +5 -5
  19. package/dist/handler.js.map +1 -1
  20. package/dist/index.d.ts +5 -5
  21. package/dist/parquet-server.cjs +19 -19
  22. package/dist/parquet-server.cjs.map +1 -1
  23. package/dist/parquet-server.d.ts +1 -1
  24. package/dist/parquet-server.d.ts.map +1 -1
  25. package/dist/parquet-server.js +19 -19
  26. package/dist/parquet-server.js.map +1 -1
  27. package/dist/serve.cjs +20 -20
  28. package/dist/serve.cjs.map +1 -1
  29. package/dist/serve.d.ts +2 -2
  30. package/dist/serve.d.ts.map +1 -1
  31. package/dist/serve.js +20 -20
  32. package/dist/serve.js.map +1 -1
  33. package/dist/utils/etag.cjs +1 -1
  34. package/dist/utils/etag.cjs.map +1 -1
  35. package/dist/utils/etag.d.ts +3 -3
  36. package/dist/utils/etag.js +1 -1
  37. package/dist/utils/etag.js.map +1 -1
  38. package/dist/utils/filename.cjs.map +1 -1
  39. package/dist/utils/filename.d.ts +2 -2
  40. package/dist/utils/filename.js.map +1 -1
  41. package/dist/utils/headers.cjs +17 -17
  42. package/dist/utils/headers.cjs.map +1 -1
  43. package/dist/utils/headers.js +17 -17
  44. package/dist/utils/headers.js.map +1 -1
  45. package/dist/utils/index.d.ts +7 -7
  46. package/dist/utils/method.cjs +3 -3
  47. package/dist/utils/method.cjs.map +1 -1
  48. package/dist/utils/method.d.ts +5 -5
  49. package/dist/utils/method.js +3 -3
  50. package/dist/utils/method.js.map +1 -1
  51. package/dist/utils/options.cjs +10 -10
  52. package/dist/utils/options.cjs.map +1 -1
  53. package/dist/utils/options.d.ts +2 -2
  54. package/dist/utils/options.d.ts.map +1 -1
  55. package/dist/utils/options.js +10 -10
  56. package/dist/utils/options.js.map +1 -1
  57. package/dist/utils/range.cjs +4 -4
  58. package/dist/utils/range.cjs.map +1 -1
  59. package/dist/utils/range.d.ts +2 -2
  60. package/dist/utils/range.d.ts.map +1 -1
  61. package/dist/utils/range.js +4 -4
  62. package/dist/utils/range.js.map +1 -1
  63. package/dist/utils/status.cjs +1 -1
  64. package/dist/utils/status.cjs.map +1 -1
  65. package/dist/utils/status.js +1 -1
  66. package/dist/utils/status.js.map +1 -1
  67. package/package.json +25 -26
  68. package/src/export.ts +9 -11
  69. package/src/fs-store.ts +32 -43
  70. package/src/handler.ts +20 -28
  71. package/src/index.ts +5 -5
  72. package/src/parquet-server.ts +33 -37
  73. package/src/serve.ts +33 -49
  74. package/src/utils/etag.ts +4 -4
  75. package/src/utils/filename.ts +3 -3
  76. package/src/utils/headers.ts +24 -24
  77. package/src/utils/index.ts +7 -7
  78. package/src/utils/method.ts +10 -10
  79. package/src/utils/options.ts +14 -18
  80. package/src/utils/range.ts +7 -9
  81. package/src/utils/status.ts +1 -1
package/src/serve.ts CHANGED
@@ -2,52 +2,42 @@ import {
2
2
  createServer as createHttpServer,
3
3
  type RequestListener,
4
4
  type Server as HttpServer,
5
- type ServerOptions
6
- } from 'node:http';
7
- import {
8
- createServer as createHttpsServer,
9
- type Server as HttpsServer
10
- } from 'node:https';
11
- import type { AddressInfo } from 'node:net';
12
- import { Deferred } from '@milaboratories/helpers';
13
- import type { PFrameInternal } from '@milaboratories/pl-model-middle-layer';
14
- import {
15
- base64Encode,
16
- Base64Encoded,
17
- ensureError
18
- } from '@milaboratories/pl-model-common';
19
- import { generate, type GenerateResult } from 'selfsigned';
20
- import { randomUUID } from 'node:crypto';
21
- import { authorizeRequestHandler } from './handler';
5
+ type ServerOptions,
6
+ } from "node:http";
7
+ import { createServer as createHttpsServer, type Server as HttpsServer } from "node:https";
8
+ import type { AddressInfo } from "node:net";
9
+ import { Deferred } from "@milaboratories/helpers";
10
+ import type { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
11
+ import { base64Encode, Base64Encoded, ensureError } from "@milaboratories/pl-model-common";
12
+ import { generate, type GenerateResult } from "selfsigned";
13
+ import { randomUUID } from "node:crypto";
14
+ import { authorizeRequestHandler } from "./handler";
22
15
 
23
16
  /** Generate a self-signed certificate for localhost */
24
17
  async function generateCertificate(): Promise<GenerateResult> {
25
- return await generate([{ name: 'commonName', value: 'localhost' }], {
18
+ return await generate([{ name: "commonName", value: "localhost" }], {
26
19
  keySize: 2048,
27
- algorithm: 'sha256',
20
+ algorithm: "sha256",
28
21
  extensions: [
29
22
  {
30
- name: 'subjectAltName',
23
+ name: "subjectAltName",
31
24
  altNames: [
32
- { type: 2, value: 'localhost' }, // DNS
33
- { type: 7, ip: '127.0.0.1' }, // IPv4
34
- { type: 7, ip: '::1' } // IPv6
35
- ]
36
- }
37
- ]
25
+ { type: 2, value: "localhost" }, // DNS
26
+ { type: 7, ip: "127.0.0.1" }, // IPv4
27
+ { type: 7, ip: "::1" }, // IPv6
28
+ ],
29
+ },
30
+ ],
38
31
  });
39
32
  }
40
33
 
41
34
  /** Create an object store URL from the server address info. */
42
- function createObjectStoreUrl(
43
- info: AddressInfo,
44
- noHttps?: true
45
- ): PFrameInternal.ObjectStoreUrl {
46
- const protocol = noHttps ? 'http' : 'https';
35
+ function createObjectStoreUrl(info: AddressInfo, noHttps?: true): PFrameInternal.ObjectStoreUrl {
36
+ const protocol = noHttps ? "http" : "https";
47
37
  switch (info.family) {
48
- case 'IPv4':
38
+ case "IPv4":
49
39
  return `${protocol}://${info.address}:${info.port}/` as PFrameInternal.ObjectStoreUrl;
50
- case 'IPv6':
40
+ case "IPv6":
51
41
  return `${protocol}://[${info.address}]:${info.port}/` as PFrameInternal.ObjectStoreUrl;
52
42
  default:
53
43
  return `${protocol}://localhost:${info.port}/` as PFrameInternal.ObjectStoreUrl;
@@ -62,7 +52,7 @@ export async function serve({
62
52
  handler,
63
53
  port = 0,
64
54
  noHttps,
65
- noAuth
55
+ noAuth,
66
56
  }: PFrameInternal.HttpServerOptions): Promise<PFrameInternal.HttpServer> {
67
57
  const started = new Deferred<PFrameInternal.HttpServer>();
68
58
  try {
@@ -78,7 +68,7 @@ export async function serve({
78
68
  // Create HTTP server
79
69
  let encodedCaCert: Base64Encoded<PFrameInternal.PemCertificate> | undefined;
80
70
  const defaultOptions: ServerOptions = {
81
- keepAlive: true
71
+ keepAlive: true,
82
72
  };
83
73
  let server: HttpServer | HttpsServer;
84
74
 
@@ -87,19 +77,13 @@ export async function serve({
87
77
  } else {
88
78
  const { cert, private: key, public: ca } = await generateCertificate();
89
79
  encodedCaCert = base64Encode(cert as PFrameInternal.PemCertificate);
90
- server = createHttpsServer(
91
- { ...defaultOptions, cert, key, ca },
92
- effectiveHandler
93
- );
80
+ server = createHttpsServer({ ...defaultOptions, cert, key, ca }, effectiveHandler);
94
81
  }
95
82
 
96
83
  server
97
- .on('listening', () => {
84
+ .on("listening", () => {
98
85
  // Cast is safe by specification <https://nodejs.org/api/net.html#serveraddress>
99
- const url = createObjectStoreUrl(
100
- server.address() as AddressInfo,
101
- noHttps
102
- );
86
+ const url = createObjectStoreUrl(server.address() as AddressInfo, noHttps);
103
87
  stopped = new Deferred<void>();
104
88
 
105
89
  started.resolve({
@@ -112,17 +96,17 @@ export async function serve({
112
96
  stop(): Promise<void> {
113
97
  server.close();
114
98
  return stopped!.promise;
115
- }
99
+ },
116
100
  });
117
101
  })
118
- .on('error', (err) => {
102
+ .on("error", (err) => {
119
103
  started.reject(err);
120
104
  stopped?.reject(err);
121
105
  })
122
- .on('close', () => stopped?.resolve())
106
+ .on("close", () => stopped?.resolve())
123
107
  .listen({
124
- host: 'localhost',
125
- port
108
+ host: "localhost",
109
+ port,
126
110
  });
127
111
  } catch (error: unknown) {
128
112
  started.reject(ensureError(error));
package/src/utils/etag.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { Branded } from '@milaboratories/pl-model-common';
2
- import type { PFrameInternal } from '@milaboratories/pl-model-middle-layer';
1
+ import type { Branded } from "@milaboratories/pl-model-common";
2
+ import type { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
3
3
 
4
4
  /**
5
5
  * See <https://datatracker.ietf.org/doc/html/rfc9110#section-8.8.3>
@@ -11,10 +11,10 @@ import type { PFrameInternal } from '@milaboratories/pl-model-middle-layer';
11
11
  * ETag: W/"xyzzy"
12
12
  * ```
13
13
  */
14
- export type Etag = Branded<string, 'Etag'>;
14
+ export type Etag = Branded<string, "Etag">;
15
15
 
16
16
  export function createETag(filename: PFrameInternal.ParquetFileName): Etag {
17
17
  // For immutable files, use URL-safe base64 encoded filename as ETag
18
- const filenameETag = Buffer.from(filename, 'utf8').toString('base64url');
18
+ const filenameETag = Buffer.from(filename, "utf8").toString("base64url");
19
19
  return `"${filenameETag}"` as Etag;
20
20
  }
@@ -1,10 +1,10 @@
1
- import type { PFrameInternal } from '@milaboratories/pl-model-middle-layer';
2
- import type { IncomingMessage } from 'node:http';
1
+ import type { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
2
+ import type { IncomingMessage } from "node:http";
3
3
 
4
4
  const PARQUET_FILENAME_REGEX = /^\/([\w\-.]+.parquet)$/;
5
5
 
6
6
  export function getFilenameFromUrl(
7
- request: IncomingMessage
7
+ request: IncomingMessage,
8
8
  ): PFrameInternal.ParquetFileName | null {
9
9
  const url = request.url;
10
10
  if (url === undefined) return null;
@@ -1,31 +1,31 @@
1
1
  /** HTTP header names used in the parquet server handler */
2
2
  export const HeaderName = {
3
- Accept: 'accept',
4
- AcceptRanges: 'accept-ranges',
5
- Allow: 'allow',
6
- Authorization: 'authorization',
7
- CacheControl: 'cache-control',
8
- Connection: 'connection',
9
- ContentLength: 'content-length',
10
- ContentRange: 'content-range',
11
- ContentType: 'content-type',
12
- Date: 'date',
13
- ETag: 'etag',
14
- IfMatch: 'if-match',
15
- IfModifiedSince: 'if-modified-since',
16
- IfNoneMatch: 'if-none-match',
17
- IfUnmodifiedSince: 'if-unmodified-since',
18
- LastModified: 'last-modified',
19
- Range: 'range',
20
- WWWAuthenticate: 'www-authenticate'
3
+ Accept: "accept",
4
+ AcceptRanges: "accept-ranges",
5
+ Allow: "allow",
6
+ Authorization: "authorization",
7
+ CacheControl: "cache-control",
8
+ Connection: "connection",
9
+ ContentLength: "content-length",
10
+ ContentRange: "content-range",
11
+ ContentType: "content-type",
12
+ Date: "date",
13
+ ETag: "etag",
14
+ IfMatch: "if-match",
15
+ IfModifiedSince: "if-modified-since",
16
+ IfNoneMatch: "if-none-match",
17
+ IfUnmodifiedSince: "if-unmodified-since",
18
+ LastModified: "last-modified",
19
+ Range: "range",
20
+ WWWAuthenticate: "www-authenticate",
21
21
  } as const;
22
22
 
23
23
  /** HTTP header values used in the parquet server handler */
24
24
  export const HeaderValue = {
25
- AcceptRanges: 'bytes',
26
- Allow: 'GET, HEAD',
27
- CacheControl: 'public, immutable, max-age=31536000',
28
- Connection: 'close',
29
- ContentType: 'application/octet-stream',
30
- WWWAuthenticate: 'Bearer realm="parquet-server"'
25
+ AcceptRanges: "bytes",
26
+ Allow: "GET, HEAD",
27
+ CacheControl: "public, immutable, max-age=31536000",
28
+ Connection: "close",
29
+ ContentType: "application/octet-stream",
30
+ WWWAuthenticate: 'Bearer realm="parquet-server"',
31
31
  } as const;
@@ -1,7 +1,7 @@
1
- export * from './filename';
2
- export * from './etag';
3
- export * from './headers';
4
- export * from './options';
5
- export * from './range';
6
- export * from './method';
7
- export * from './status';
1
+ export * from "./filename";
2
+ export * from "./etag";
3
+ export * from "./headers";
4
+ export * from "./options";
5
+ export * from "./range";
6
+ export * from "./method";
7
+ export * from "./status";
@@ -1,20 +1,20 @@
1
- import type { PFrameInternal } from '@milaboratories/pl-model-middle-layer';
2
- import type { IncomingHttpHeaders } from 'node:http';
1
+ import type { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
2
+ import type { IncomingHttpHeaders } from "node:http";
3
3
 
4
4
  export function isGetOrHead(
5
- method: IncomingHttpHeaders['method']
5
+ method: IncomingHttpHeaders["method"],
6
6
  ): method is PFrameInternal.HttpMethod {
7
- return method === 'GET' || method === 'HEAD';
7
+ return method === "GET" || method === "HEAD";
8
8
  }
9
9
 
10
10
  export function isGet(
11
- method: PFrameInternal.HttpMethod
12
- ): method is Extract<PFrameInternal.HttpMethod, 'GET'> {
13
- return method === 'GET';
11
+ method: PFrameInternal.HttpMethod,
12
+ ): method is Extract<PFrameInternal.HttpMethod, "GET"> {
13
+ return method === "GET";
14
14
  }
15
15
 
16
16
  export function isHead(
17
- method: PFrameInternal.HttpMethod
18
- ): method is Extract<PFrameInternal.HttpMethod, 'HEAD'> {
19
- return method === 'HEAD';
17
+ method: PFrameInternal.HttpMethod,
18
+ ): method is Extract<PFrameInternal.HttpMethod, "HEAD"> {
19
+ return method === "HEAD";
20
20
  }
@@ -1,13 +1,13 @@
1
- import type { IncomingMessage } from 'node:http';
2
- import type { Etag } from './etag';
1
+ import type { IncomingMessage } from "node:http";
2
+ import type { Etag } from "./etag";
3
3
 
4
4
  type EtagMatchType =
5
5
  | {
6
- type: 'match';
6
+ type: "match";
7
7
  value: Etag[];
8
8
  }
9
9
  | {
10
- type: 'wildcard';
10
+ type: "wildcard";
11
11
  };
12
12
 
13
13
  class EtagMatch {
@@ -15,21 +15,21 @@ class EtagMatch {
15
15
 
16
16
  static parse(etagMatch: string | undefined): EtagMatch | null {
17
17
  if (etagMatch === undefined) return null;
18
- if (etagMatch === '*') {
19
- return new EtagMatch({ type: 'wildcard' });
18
+ if (etagMatch === "*") {
19
+ return new EtagMatch({ type: "wildcard" });
20
20
  } else {
21
21
  return new EtagMatch({
22
- type: 'match',
23
- value: etagMatch.split(',').map((etag) => etag.trim() as Etag)
22
+ type: "match",
23
+ value: etagMatch.split(",").map((etag) => etag.trim() as Etag),
24
24
  });
25
25
  }
26
26
  }
27
27
 
28
28
  matches(etag: Etag): boolean {
29
29
  switch (this.etagMatch.type) {
30
- case 'match':
30
+ case "match":
31
31
  return this.etagMatch.value.includes(etag);
32
- case 'wildcard':
32
+ case "wildcard":
33
33
  return true;
34
34
  }
35
35
  }
@@ -100,14 +100,10 @@ export class Options {
100
100
  private ifUnmodifiedSince: DateMatch | null;
101
101
 
102
102
  constructor(request: IncomingMessage) {
103
- this.ifMatch = EtagMatch.parse(request.headers['if-match']);
104
- this.ifNoneMatch = EtagMatch.parse(request.headers['if-none-match']);
105
- this.ifModifiedSince = DateMatch.parse(
106
- request.headers['if-modified-since']
107
- );
108
- this.ifUnmodifiedSince = DateMatch.parse(
109
- request.headers['if-unmodified-since']
110
- );
103
+ this.ifMatch = EtagMatch.parse(request.headers["if-match"]);
104
+ this.ifNoneMatch = EtagMatch.parse(request.headers["if-none-match"]);
105
+ this.ifModifiedSince = DateMatch.parse(request.headers["if-modified-since"]);
106
+ this.ifUnmodifiedSince = DateMatch.parse(request.headers["if-unmodified-since"]);
111
107
  }
112
108
 
113
109
  /**
@@ -1,10 +1,8 @@
1
- import type { PFrameInternal } from '@milaboratories/pl-model-middle-layer';
2
- import type { IncomingMessage } from 'node:http';
1
+ import type { PFrameInternal } from "@milaboratories/pl-model-middle-layer";
2
+ import type { IncomingMessage } from "node:http";
3
3
 
4
- export function parseRange(
5
- request: IncomingMessage
6
- ): PFrameInternal.HttpRange | null | undefined {
7
- const range = request.headers['range'];
4
+ export function parseRange(request: IncomingMessage): PFrameInternal.HttpRange | null | undefined {
5
+ const range = request.headers["range"];
8
6
  if (range === undefined) return undefined;
9
7
 
10
8
  const match = range.match(/^bytes=(\d*)-(\d*)$/);
@@ -22,17 +20,17 @@ export function parseRange(
22
20
 
23
21
  // Both start and end are specified - bounded range
24
22
  if (start !== null && end !== null) {
25
- return { type: 'bounded', start, end };
23
+ return { type: "bounded", start, end };
26
24
  }
27
25
 
28
26
  // Only start is specified - offset range (e.g., bytes=500-)
29
27
  if (start !== null && end === null) {
30
- return { type: 'offset', offset: start };
28
+ return { type: "offset", offset: start };
31
29
  }
32
30
 
33
31
  // Only end is specified - suffix range (e.g., bytes=-500)
34
32
  if (start === null && end !== null) {
35
- return { type: 'suffix', suffix: end };
33
+ return { type: "suffix", suffix: end };
36
34
  }
37
35
 
38
36
  // Neither start nor end specified (bytes=-) - invalid
@@ -12,5 +12,5 @@ export const StatusCode = {
12
12
  PreconditionFailed: 412, // <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/412>
13
13
  RangeNotSatisfiable: 416, // <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/416>
14
14
  InternalServerError: 500, // <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500>
15
- GatewayTimeout: 504 // <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504>
15
+ GatewayTimeout: 504, // <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504>
16
16
  } as const;