xrootd 1.0.0-beta.2 → 1.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -393,6 +393,47 @@ declare class File {
393
393
  truncate(size: number): Promise<void>;
394
394
  }
395
395
  //#endregion
396
+ //#region src/config/sec-env.d.ts
397
+ interface SecEnvOptions {
398
+ /** Environment variable source. Defaults to process.env. */
399
+ env?: Record<string, string | undefined>;
400
+ /** Protocol whitelist (equivalent to XrdSecPROTOCOL). */
401
+ protocolFilter?: string[];
402
+ /** Whether to read GSI variables (X509_*, XrdSecGSI*). Defaults to true. */
403
+ gsi?: boolean;
404
+ /** Whether to read SSS variables (XrdSecSSSKT). Defaults to true. */
405
+ sss?: boolean;
406
+ /** Whether to read KRB5 variables (XrdSecKRB5INITTKN). Defaults to true. */
407
+ krb5?: boolean;
408
+ /** Whether to read PWD variables (XrdSecPWDSRVPUK etc). Defaults to true. */
409
+ pwd?: boolean;
410
+ }
411
+ /**
412
+ * xrootd security environment variable configuration.
413
+ *
414
+ * Maps C++ xrootd's XrdSec* / X509_* environment variables to a structured
415
+ * config object. Does NOT read process.env directly — the caller provides
416
+ * the env source via constructor options.
417
+ */
418
+ declare class SecEnv {
419
+ readonly protocolFilter: string[];
420
+ readonly proxyMode: boolean;
421
+ readonly proxyCreds: boolean;
422
+ readonly sssKeytab: string | undefined;
423
+ readonly krb5InitToken: boolean;
424
+ readonly gsiCaDir: string;
425
+ readonly gsiCrlDir: string;
426
+ readonly gsiUserCert: string;
427
+ readonly gsiUserKey: string;
428
+ readonly gsiUserProxy: string;
429
+ readonly pwdServerPubkey: string | undefined;
430
+ readonly username: string | undefined;
431
+ readonly password: string | undefined;
432
+ constructor(options?: SecEnvOptions);
433
+ static fromEnv(env?: Record<string, string | undefined>, options?: Omit<SecEnvOptions, "env">): SecEnv;
434
+ private parseProtocolFilter;
435
+ }
436
+ //#endregion
396
437
  //#region src/client.d.ts
397
438
  interface XRootDClientOptions {
398
439
  credentials?: {
@@ -401,6 +442,8 @@ interface XRootDClientOptions {
401
442
  };
402
443
  timeout?: number;
403
444
  maxRedirects?: number;
445
+ /** Security environment configuration. Enables credential auto-discovery and protocol filtering. */
446
+ secEnv?: SecEnv;
404
447
  }
405
448
  declare class XRootDClient {
406
449
  private readonly url;
@@ -431,6 +474,31 @@ declare class XRootDClient {
431
474
  private ensureFileSystem;
432
475
  }
433
476
  //#endregion
477
+ //#region src/config/loader.d.ts
478
+ interface ResolvedAuthConfig {
479
+ username?: string;
480
+ password?: string;
481
+ sssKey?: Buffer;
482
+ }
483
+ /**
484
+ * Resolve authentication credentials from multiple sources.
485
+ *
486
+ * Priority (high → low):
487
+ * 1. options.credentials (explicit)
488
+ * 2. URL userinfo (root://user:pass@host)
489
+ * 3. SecEnv XrdSecUSER / XrdSecCREDS
490
+ *
491
+ * Also reads the SSS keytab file specified by SecEnv if available.
492
+ */
493
+ declare function loadAuthConfig(options: {
494
+ url?: XRootDUrl;
495
+ credentials?: {
496
+ username: string;
497
+ password?: string;
498
+ };
499
+ secEnv?: SecEnv;
500
+ }): ResolvedAuthConfig;
501
+ //#endregion
434
502
  //#region src/api/filesystem.d.ts
435
503
  declare class FileSystem {
436
504
  private mux;
@@ -659,5 +727,5 @@ declare function putBytes(buf: Buffer, offset: number, data: Uint8Array): number
659
727
  /** Slice `length` bytes from `buf` at `offset`, return `[slice, newOffset]`. */
660
728
  declare function getBytes(buf: Buffer, offset: number, length: number): [Buffer, number];
661
729
  //#endregion
662
- export { type AuthConfig, BODY_SIZE, CRED_TYPE, type ChunkInfo, ClientError, DEFAULT_PORT, type DirectoryEntry, type DirectoryList, DirlistOptions, type ErrorResponse, FHANDLE_SIZE, File, FileSystem, type Frame, Framer, HANDSHAKE_FIFTH, HANDSHAKE_FIRST, HANDSHAKE_FOURTH, HANDSHAKE_SECOND, HANDSHAKE_THIRD, type ITransport, type Location, type LocationInfo, type LoginResponse, Message, Multiplexer, OpenFlags, type OpenOptions, type OpenResponse, PROTOCOL_VERSION, type ProtocolInfo, type ProtocolResponse, REQUEST_HDR_SIZE, REQUEST_OFFSET_BODY, REQUEST_OFFSET_DLEN, REQUEST_OFFSET_REQUEST_ID, REQUEST_OFFSET_STREAM_ID, RESPONSE_HDR_SIZE, RESPONSE_OFFSET_BODY, RESPONSE_OFFSET_DLEN, RESPONSE_OFFSET_STATUS, RESPONSE_OFFSET_STREAM_ID, type RedirectResponse, RequestId, ResponseStatus, SESS_ID_SIZE, S_IFDIR, S_IFLNK, ServerError, type Session, StatFlags, type StatInfo, Transport, type WaitResponse, XRootDClient, type XRootDClientOptions, XRootDError, XRootDUrl, buildCloseRequest, buildHandshakeAndProtocol, buildLoginRequest, buildOpenRequest, buildReadRequest, buildStatRequest, buildWriteRequest, createStatInfo, get16, get32, getBytes, getString, handshake, kXR_ExpBind, kXR_ExpLogin, kXR_ableTLS, kXR_bifreqs, kXR_secreqs, kXR_wantTLS, parseErrorResponse, parseLoginResponse, parseOpenResponse, parseProtocolResponse, parseRedirectResponse, parseWaitResponse, put16, put32, putBytes, putString };
730
+ export { type AuthConfig, BODY_SIZE, CRED_TYPE, type ChunkInfo, ClientError, DEFAULT_PORT, type DirectoryEntry, type DirectoryList, DirlistOptions, type ErrorResponse, FHANDLE_SIZE, File, FileSystem, type Frame, Framer, HANDSHAKE_FIFTH, HANDSHAKE_FIRST, HANDSHAKE_FOURTH, HANDSHAKE_SECOND, HANDSHAKE_THIRD, type ITransport, type Location, type LocationInfo, type LoginResponse, Message, Multiplexer, OpenFlags, type OpenOptions, type OpenResponse, PROTOCOL_VERSION, type ProtocolInfo, type ProtocolResponse, REQUEST_HDR_SIZE, REQUEST_OFFSET_BODY, REQUEST_OFFSET_DLEN, REQUEST_OFFSET_REQUEST_ID, REQUEST_OFFSET_STREAM_ID, RESPONSE_HDR_SIZE, RESPONSE_OFFSET_BODY, RESPONSE_OFFSET_DLEN, RESPONSE_OFFSET_STATUS, RESPONSE_OFFSET_STREAM_ID, type RedirectResponse, RequestId, type ResolvedAuthConfig, ResponseStatus, SESS_ID_SIZE, S_IFDIR, S_IFLNK, SecEnv, type SecEnvOptions, ServerError, type Session, StatFlags, type StatInfo, Transport, type WaitResponse, XRootDClient, type XRootDClientOptions, XRootDError, XRootDUrl, buildCloseRequest, buildHandshakeAndProtocol, buildLoginRequest, buildOpenRequest, buildReadRequest, buildStatRequest, buildWriteRequest, createStatInfo, get16, get32, getBytes, getString, handshake, kXR_ExpBind, kXR_ExpLogin, kXR_ableTLS, kXR_bifreqs, kXR_secreqs, kXR_wantTLS, loadAuthConfig, parseErrorResponse, parseLoginResponse, parseOpenResponse, parseProtocolResponse, parseRedirectResponse, parseWaitResponse, put16, put32, putBytes, putString };
663
731
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,5 +1,8 @@
1
1
  import net from "node:net";
2
2
  import tls from "node:tls";
3
+ import { createCipheriv } from "node:crypto";
4
+ import { readFileSync } from "node:fs";
5
+ import { homedir } from "node:os";
3
6
  //#region src/protocol/constants.ts
4
7
  const RequestId = {
5
8
  Auth: 3e3,
@@ -588,8 +591,9 @@ function buildMkdirRequest(streamId, path, mode = 493) {
588
591
  const msg = new Message(24 + pathBytes.length);
589
592
  msg.writeBytes(streamIdToBytes(streamId));
590
593
  msg.writeInt16BE(RequestId.Mkdir);
594
+ msg.writeUInt8(0);
595
+ msg.writeBytes(/* @__PURE__ */ new Uint8Array(13));
591
596
  msg.writeInt16BE(mode & 65535);
592
- msg.writeBytes(/* @__PURE__ */ new Uint8Array(14));
593
597
  msg.writeInt32BE(pathBytes.length);
594
598
  msg.writeBytes(pathBytes);
595
599
  return msg.getBuffer();
@@ -637,13 +641,15 @@ function buildRmRequest(streamId, path) {
637
641
  function buildMvRequest(streamId, source, target) {
638
642
  const srcBytes = strToBytes(source);
639
643
  const tgtBytes = strToBytes(target);
640
- const msg = new Message(24 + srcBytes.length + tgtBytes.length);
644
+ const spaceSep = new Uint8Array([32]);
645
+ const msg = new Message(24 + srcBytes.length + 1 + tgtBytes.length);
641
646
  msg.writeBytes(streamIdToBytes(streamId));
642
647
  msg.writeInt16BE(RequestId.Mv);
643
648
  msg.writeBytes(/* @__PURE__ */ new Uint8Array(14));
644
649
  msg.writeInt16BE(srcBytes.length & 65535);
645
- msg.writeInt32BE(srcBytes.length + tgtBytes.length);
650
+ msg.writeInt32BE(srcBytes.length + 1 + tgtBytes.length);
646
651
  msg.writeBytes(srcBytes);
652
+ msg.writeBytes(spaceSep);
647
653
  msg.writeBytes(tgtBytes);
648
654
  return msg.getBuffer();
649
655
  }
@@ -1189,19 +1195,21 @@ const authProtocols = /* @__PURE__ */ new Map();
1189
1195
  function registerAuthProtocol(name, factory) {
1190
1196
  authProtocols.set(name, factory);
1191
1197
  }
1192
- async function doAuthentication(mux, secReqs, params) {
1198
+ async function doAuthentication(mux, secReqs, params, options) {
1193
1199
  if (!secReqs || secReqs.trim().length === 0) return {
1194
1200
  prot: "",
1195
1201
  uid: 0,
1196
1202
  gid: 0
1197
1203
  };
1198
1204
  const supportedProtocols = secReqs.split(",").map((s) => s.trim());
1199
- for (const protoName of supportedProtocols) {
1205
+ const filter = options?.protocolFilter;
1206
+ const candidates = filter?.length ? supportedProtocols.filter((p) => filter.includes(p)) : supportedProtocols;
1207
+ for (const protoName of candidates) {
1200
1208
  const factory = authProtocols.get(protoName);
1201
1209
  if (!factory) continue;
1202
1210
  return await executeAuth(mux, factory(), params);
1203
1211
  }
1204
- throw new XRootDError(ServerError.AuthFailed, `No supported authentication protocol. Server requires: ${secReqs}`);
1212
+ throw new XRootDError(ServerError.AuthFailed, `No supported authentication protocol. Server requires: ${secReqs}` + (filter ? `. Allowed: ${filter.join(",")}` : ""));
1205
1213
  }
1206
1214
  async function executeAuth(mux, protocol, params) {
1207
1215
  const creds = await protocol.getCredentials(params);
@@ -1254,6 +1262,79 @@ var HostAuth = class {
1254
1262
  }
1255
1263
  };
1256
1264
  //#endregion
1265
+ //#region src/utils/crc32.ts
1266
+ function crc32(data) {
1267
+ let crc = 4294967295;
1268
+ for (let i = 0; i < data.length; i++) {
1269
+ crc ^= data[i];
1270
+ for (let j = 0; j < 8; j++) crc = crc >>> 1 ^ (crc & 1 ? 3988292384 : 0);
1271
+ }
1272
+ return (crc ^ 4294967295) >>> 0;
1273
+ }
1274
+ //#endregion
1275
+ //#region src/security/sss.ts
1276
+ function pkcs5Pad(data, blockSize) {
1277
+ const padLen = blockSize - data.length % blockSize;
1278
+ const padded = Buffer.alloc(data.length + padLen);
1279
+ data.copy(padded);
1280
+ padded.fill(padLen, data.length);
1281
+ return padded;
1282
+ }
1283
+ /**
1284
+ * SSS (Simple Shared Secret) authentication protocol.
1285
+ *
1286
+ * Uses Blowfish-ECB encryption + CRC32 checksum.
1287
+ * Note: Requires Node.js with legacy OpenSSL provider for Blowfish support.
1288
+ * Run with: NODE_OPTIONS=--openssl-legacy-provider
1289
+ *
1290
+ * Or use the static create() method which checks if Blowfish is available.
1291
+ */
1292
+ var SSSAuth = class {
1293
+ name = "sss";
1294
+ entity = {
1295
+ prot: "sss",
1296
+ uid: 0,
1297
+ gid: 0
1298
+ };
1299
+ complete = false;
1300
+ key;
1301
+ constructor(key) {
1302
+ if (key.length !== 8) throw new Error("SSS key must be 8 bytes");
1303
+ this.key = key;
1304
+ }
1305
+ static isSupported() {
1306
+ try {
1307
+ createCipheriv("bf-ecb", Buffer.alloc(8), null).final();
1308
+ return true;
1309
+ } catch {
1310
+ return false;
1311
+ }
1312
+ }
1313
+ async getCredentials(params) {
1314
+ const password = params.password || "";
1315
+ const passwordBytes = new TextEncoder().encode(password);
1316
+ const crc = crc32(passwordBytes);
1317
+ const payload = Buffer.alloc(passwordBytes.length + 4);
1318
+ Buffer.from(passwordBytes).copy(payload, 0);
1319
+ payload.writeUInt32BE(crc, passwordBytes.length);
1320
+ const cipher = createCipheriv("bf-ecb", this.key, null);
1321
+ const padded = pkcs5Pad(payload, 8);
1322
+ const encrypted = Buffer.concat([cipher.update(padded), cipher.final()]);
1323
+ this.entity.name = params.username;
1324
+ return new Uint8Array(encrypted);
1325
+ }
1326
+ async processChallenge(_challenge) {
1327
+ this.complete = true;
1328
+ return /* @__PURE__ */ new Uint8Array(0);
1329
+ }
1330
+ isComplete() {
1331
+ return this.complete;
1332
+ }
1333
+ getEntity() {
1334
+ return this.entity;
1335
+ }
1336
+ };
1337
+ //#endregion
1257
1338
  //#region src/api/types.ts
1258
1339
  const StatFlags = {
1259
1340
  XBitSet: 1,
@@ -1301,7 +1382,7 @@ function createStatInfo(data) {
1301
1382
  owner: parts[7] ?? "",
1302
1383
  group: parts[8] ?? "",
1303
1384
  get isDirectory() {
1304
- return (mode & S_IFDIR) !== 0;
1385
+ return (serverFlags & StatFlags.IsDir) !== 0;
1305
1386
  },
1306
1387
  get isLink() {
1307
1388
  return (mode & S_IFLNK) === S_IFLNK;
@@ -1383,7 +1464,7 @@ var File = class {
1383
1464
  const { errnum, errmsg } = parseErrorResponse(frame.body);
1384
1465
  throw new XRootDError(errnum, errmsg);
1385
1466
  }
1386
- if (frame.status === ResponseStatus.Ok) return new Uint8Array(frame.body);
1467
+ if (frame.status === ResponseStatus.Ok || frame.status === ResponseStatus.Oksofar) return new Uint8Array(frame.body);
1387
1468
  throw new XRootDError(ServerError.ServerError, `Unexpected read response status: ${frame.status}`);
1388
1469
  }
1389
1470
  async write(offset, data) {
@@ -1394,7 +1475,7 @@ var File = class {
1394
1475
  const { errnum, errmsg } = parseErrorResponse(frame.body);
1395
1476
  throw new XRootDError(errnum, errmsg);
1396
1477
  }
1397
- if (frame.status === ResponseStatus.Ok) return frame.dlen;
1478
+ if (frame.status === ResponseStatus.Ok) return frame.dlen > 0 ? frame.dlen : data.length;
1398
1479
  throw new XRootDError(ServerError.ServerError, `Unexpected write response status: ${frame.status}`);
1399
1480
  }
1400
1481
  async close() {
@@ -1492,6 +1573,32 @@ var FileSystem = class {
1492
1573
  }
1493
1574
  };
1494
1575
  //#endregion
1576
+ //#region src/config/loader.ts
1577
+ /**
1578
+ * Resolve authentication credentials from multiple sources.
1579
+ *
1580
+ * Priority (high → low):
1581
+ * 1. options.credentials (explicit)
1582
+ * 2. URL userinfo (root://user:pass@host)
1583
+ * 3. SecEnv XrdSecUSER / XrdSecCREDS
1584
+ *
1585
+ * Also reads the SSS keytab file specified by SecEnv if available.
1586
+ */
1587
+ function loadAuthConfig(options) {
1588
+ const { url, credentials, secEnv } = options;
1589
+ const username = credentials?.username ?? url?.user ?? secEnv?.username;
1590
+ const password = credentials?.password ?? url?.password ?? secEnv?.password;
1591
+ let sssKey;
1592
+ if (secEnv?.sssKeytab) try {
1593
+ sssKey = readFileSync(secEnv.sssKeytab);
1594
+ } catch {}
1595
+ return {
1596
+ username,
1597
+ password,
1598
+ sssKey
1599
+ };
1600
+ }
1601
+ //#endregion
1495
1602
  //#region src/client.ts
1496
1603
  var XRootDClient = class {
1497
1604
  url;
@@ -1516,15 +1623,22 @@ var XRootDClient = class {
1516
1623
  });
1517
1624
  if (this.options.timeout) this.mux.setTimeout(this.options.timeout);
1518
1625
  this.session = await handshake(this.mux, url, { username: this.options.credentials?.username });
1626
+ const secEnv = this.options.secEnv;
1627
+ const authConfig = loadAuthConfig({
1628
+ url,
1629
+ credentials: this.options.credentials,
1630
+ secEnv
1631
+ });
1519
1632
  registerAuthProtocol("host", () => new HostAuth());
1520
- if (this.session.secReqs && this.options.credentials) {
1633
+ if (authConfig.sssKey && SSSAuth.isSupported()) registerAuthProtocol("sss", () => new SSSAuth(authConfig.sssKey));
1634
+ if (this.session.secReqs && (authConfig.username || authConfig.password)) {
1521
1635
  const secEntity = await doAuthentication(this.mux, this.session.secReqs, {
1522
1636
  host: url.host,
1523
1637
  port: url.port,
1524
- username: this.options.credentials.username,
1525
- password: this.options.credentials.password,
1638
+ username: authConfig.username,
1639
+ password: authConfig.password,
1526
1640
  sessid: this.session.sessid
1527
- });
1641
+ }, { protocolFilter: secEnv?.protocolFilter });
1528
1642
  this.session.secEntity = secEntity;
1529
1643
  }
1530
1644
  this.fs = new FileSystem(this.mux);
@@ -1611,6 +1725,69 @@ var XRootDClient = class {
1611
1725
  }
1612
1726
  };
1613
1727
  //#endregion
1614
- export { BODY_SIZE, CRED_TYPE, ClientError, DEFAULT_PORT, DirlistOptions, FHANDLE_SIZE, File, FileSystem, Framer, HANDSHAKE_FIFTH, HANDSHAKE_FIRST, HANDSHAKE_FOURTH, HANDSHAKE_SECOND, HANDSHAKE_THIRD, Message, Multiplexer, OpenFlags, PROTOCOL_VERSION, REQUEST_HDR_SIZE, REQUEST_OFFSET_BODY, REQUEST_OFFSET_DLEN, REQUEST_OFFSET_REQUEST_ID, REQUEST_OFFSET_STREAM_ID, RESPONSE_HDR_SIZE, RESPONSE_OFFSET_BODY, RESPONSE_OFFSET_DLEN, RESPONSE_OFFSET_STATUS, RESPONSE_OFFSET_STREAM_ID, RequestId, ResponseStatus, SESS_ID_SIZE, S_IFDIR, S_IFLNK, ServerError, StatFlags, Transport, XRootDClient, XRootDError, XRootDUrl, buildCloseRequest, buildHandshakeAndProtocol, buildLoginRequest, buildOpenRequest, buildReadRequest, buildStatRequest, buildWriteRequest, createStatInfo, get16, get32, getBytes, getString, handshake, kXR_ExpBind, kXR_ExpLogin, kXR_ableTLS, kXR_bifreqs, kXR_secreqs, kXR_wantTLS, parseErrorResponse, parseLoginResponse, parseOpenResponse, parseProtocolResponse, parseRedirectResponse, parseWaitResponse, put16, put32, putBytes, putString };
1728
+ //#region src/config/sec-env.ts
1729
+ /**
1730
+ * xrootd security environment variable configuration.
1731
+ *
1732
+ * Maps C++ xrootd's XrdSec* / X509_* environment variables to a structured
1733
+ * config object. Does NOT read process.env directly — the caller provides
1734
+ * the env source via constructor options.
1735
+ */
1736
+ var SecEnv = class SecEnv {
1737
+ protocolFilter;
1738
+ proxyMode;
1739
+ proxyCreds;
1740
+ sssKeytab;
1741
+ krb5InitToken;
1742
+ gsiCaDir;
1743
+ gsiCrlDir;
1744
+ gsiUserCert;
1745
+ gsiUserKey;
1746
+ gsiUserProxy;
1747
+ pwdServerPubkey;
1748
+ username;
1749
+ password;
1750
+ constructor(options = {}) {
1751
+ const env = options.env ?? process.env;
1752
+ this.protocolFilter = options.protocolFilter ?? this.parseProtocolFilter(env);
1753
+ this.proxyMode = truthy(env["XrdSecPROXY"]);
1754
+ this.proxyCreds = truthy(env["XrdSecPROXYCREDS"]);
1755
+ this.sssKeytab = options.sss !== false ? env["XrdSecSSSKT"] ?? env["XrdSecsssKT"] : void 0;
1756
+ this.krb5InitToken = options.krb5 !== false ? truthy(env["XrdSecKRB5INITTKN"]) : false;
1757
+ if (options.gsi !== false) {
1758
+ const home = homedir();
1759
+ this.gsiCaDir = env["XrdSecGSICADIR"] ?? env["X509_CERT_DIR"] ?? "/etc/grid-security/certificates";
1760
+ this.gsiCrlDir = env["XrdSecGSICRLDIR"] ?? env["X509_CERT_DIR"] ?? "/etc/grid-security/certificates";
1761
+ this.gsiUserCert = env["XrdSecGSIUSERCERT"] ?? env["X509_USER_CERT"] ?? `${home}/.globus/usercert.pem`;
1762
+ this.gsiUserKey = env["XrdSecGSIUSERKEY"] ?? env["X509_USER_KEY"] ?? `${home}/.globus/userkey.pem`;
1763
+ this.gsiUserProxy = env["XrdSecGSIUSERPROXY"] ?? env["X509_USER_PROXY"] ?? `/tmp/x509up_u${process.getuid?.() ?? 0}`;
1764
+ } else {
1765
+ this.gsiCaDir = "";
1766
+ this.gsiCrlDir = "";
1767
+ this.gsiUserCert = "";
1768
+ this.gsiUserKey = "";
1769
+ this.gsiUserProxy = "";
1770
+ }
1771
+ this.pwdServerPubkey = options.pwd !== false ? env["XrdSecPWDSRVPUK"] : void 0;
1772
+ this.username = env["XrdSecUSER"];
1773
+ this.password = env["XrdSecCREDS"];
1774
+ }
1775
+ static fromEnv(env, options) {
1776
+ return new SecEnv({
1777
+ ...options,
1778
+ env: env ?? process.env
1779
+ });
1780
+ }
1781
+ parseProtocolFilter(env) {
1782
+ const raw = env["XrdSecPROTOCOL"];
1783
+ if (!raw) return [];
1784
+ return raw.split(",").map((s) => s.trim()).filter(Boolean);
1785
+ }
1786
+ };
1787
+ function truthy(val) {
1788
+ return val !== void 0 && val !== "0" && val !== "";
1789
+ }
1790
+ //#endregion
1791
+ export { BODY_SIZE, CRED_TYPE, ClientError, DEFAULT_PORT, DirlistOptions, FHANDLE_SIZE, File, FileSystem, Framer, HANDSHAKE_FIFTH, HANDSHAKE_FIRST, HANDSHAKE_FOURTH, HANDSHAKE_SECOND, HANDSHAKE_THIRD, Message, Multiplexer, OpenFlags, PROTOCOL_VERSION, REQUEST_HDR_SIZE, REQUEST_OFFSET_BODY, REQUEST_OFFSET_DLEN, REQUEST_OFFSET_REQUEST_ID, REQUEST_OFFSET_STREAM_ID, RESPONSE_HDR_SIZE, RESPONSE_OFFSET_BODY, RESPONSE_OFFSET_DLEN, RESPONSE_OFFSET_STATUS, RESPONSE_OFFSET_STREAM_ID, RequestId, ResponseStatus, SESS_ID_SIZE, S_IFDIR, S_IFLNK, SecEnv, ServerError, StatFlags, Transport, XRootDClient, XRootDError, XRootDUrl, buildCloseRequest, buildHandshakeAndProtocol, buildLoginRequest, buildOpenRequest, buildReadRequest, buildStatRequest, buildWriteRequest, createStatInfo, get16, get32, getBytes, getString, handshake, kXR_ExpBind, kXR_ExpLogin, kXR_ableTLS, kXR_bifreqs, kXR_secreqs, kXR_wantTLS, loadAuthConfig, parseErrorResponse, parseLoginResponse, parseOpenResponse, parseProtocolResponse, parseRedirectResponse, parseWaitResponse, put16, put32, putBytes, putString };
1615
1792
 
1616
1793
  //# sourceMappingURL=index.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xrootd",
3
- "version": "1.0.0-beta.2",
3
+ "version": "1.0.0-beta.4",
4
4
  "description": "A TypeScript client library for the XRootD protocol",
5
5
  "main": "dist/index.mjs",
6
6
  "types": "dist/index.d.mts",