{"_id":"@darksquarebishop/rets-client-ts","name":"@darksquarebishop/rets-client-ts","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@darksquarebishop/rets-client-ts","version":"0.1.0","description":"Modern TypeScript RETS (Real Estate Transaction Standard) client","keywords":["mls","real-estate","rets"],"homepage":"https://github.com/DarkSquareBishop/rets-client-ts#readme","bugs":{"url":"https://github.com/DarkSquareBishop/rets-client-ts/issues"},"license":"MIT","author":{"name":"Matt Cassara","email":"cassaram09@gmail.com"},"repository":{"type":"git","url":"git+https://github.com/DarkSquareBishop/rets-client-ts.git"},"type":"module","sideEffects":false,"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"publishConfig":{"access":"public","provenance":true},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","lint":"oxlint .","fmt":"oxfmt .","fmt:check":"oxfmt --check .","check:package":"publint --strict && attw --pack","changeset":"changeset","changeset:version":"changeset version","changeset:publish":"changeset publish","prepublishOnly":"npm run build","verify":"npm run typecheck && npm run lint && npm run fmt:check && npm run build && npm run check:package && npm run test"},"dependencies":{"busboy":"^1.6.0","got":"^15.0.5","pino":"^10.3.1","saxes":"^6.0.0","tough-cookie":"^6.0.1"},"devDependencies":{"@arethetypeswrong/cli":"^0.18.2","@changesets/changelog-github":"^0.5.2","@changesets/cli":"^2.29.8","@types/busboy":"^1.5.4","@types/node":"^25.9.1","nock":"^14.0.15","oxfmt":"^0.52.0","oxlint":"^1.67.0","pino-pretty":"^13.0.0","publint":"^0.3.17","tsup":"^8.5.1","typescript":"^6.0.3","vitest":"^4.1.7"},"engines":{"node":">=20"},"_id":"@darksquarebishop/rets-client-ts@0.1.0","gitHead":"e9fe9d9ee4c03365fb92f38006d99a546ce2d8f5","_nodeVersion":"22.18.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-0qvypGOkyVnLqO/OttdyZfpR2D6w9l5dXg1onK3kGxmaCpHBRpp5VtApTu3PT5WdekX5U/gDB74Qy7UjPx+K7A==","shasum":"c1171eecccd364c85fdffe84c3804793f6ac5c95","tarball":"https://registry.npmjs.org/@darksquarebishop/rets-client-ts/-/rets-client-ts-0.1.0.tgz","fileCount":6,"unpackedSize":161785,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCBrxE/W1/OiaCTKSfrXvs1iHf6RVpcxnBHjHiCn8gKNAIgdoWVrcsV2/6WxDf7dsZJGrL//8hUoA2nDZ7PIF73vmI="}]},"_npmUser":{"name":"mattc-darksquarebishop","email":"matt@darksquarebishop.com"},"directories":{},"maintainers":[{"name":"mattc-darksquarebishop","email":"matt@darksquarebishop.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/rets-client-ts_0.1.0_1780286459178_0.5994613185254449"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-01T04:00:58.933Z","0.1.0":"2026-06-01T04:00:59.320Z","modified":"2026-06-01T04:00:59.669Z"},"maintainers":[{"name":"mattc-darksquarebishop","email":"matt@darksquarebishop.com"}],"description":"Modern TypeScript RETS (Real Estate Transaction Standard) client","homepage":"https://github.com/DarkSquareBishop/rets-client-ts#readme","keywords":["mls","real-estate","rets"],"repository":{"type":"git","url":"git+https://github.com/DarkSquareBishop/rets-client-ts.git"},"author":{"name":"Matt Cassara","email":"cassaram09@gmail.com"},"bugs":{"url":"https://github.com/DarkSquareBishop/rets-client-ts/issues"},"license":"MIT","readme":"# rets-client-ts\n\n[![npm version](https://img.shields.io/npm/v/@darksquarebishop/rets-client-ts.svg)](https://www.npmjs.com/package/@darksquarebishop/rets-client-ts)\n[![CI](https://github.com/DarkSquareBishop/rets-client-ts/actions/workflows/ci.yml/badge.svg)](https://github.com/DarkSquareBishop/rets-client-ts/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nModern TypeScript client for **RETS** (Real Estate Transaction Standard) — the legacy XML-over-HTTP protocol used by MLS systems to expose listing, roster, and media data.\n\n> RETS is being superseded by [RESO Web APIs](https://sparkplatform.com/docs/rets/overview). This client targets existing RETS endpoints (Spark/flexmls, GSMLS, BMLS, and similar).\n\n**Requirements:** Node.js 20+, ESM only.\n\n## Install\n\n```bash\nnpm install @darksquarebishop/rets-client-ts\n```\n\n## Quick start\n\n```typescript\nimport { createClient } from \"@darksquarebishop/rets-client-ts\";\n\nconst client = await createClient({\n  loginUrl: \"https://rets.example.com/login\",\n  username: \"user\",\n  password: \"pass\",\n  userAgent: \"my-app/1.0\",\n});\n\nawait client.login();\n\nconst { rows, count, maxRowsExceeded } = await client.search(\n  \"Property\",\n  \"Listing\",\n  \"(ModificationTimestamp=2024-01-01+)\",\n  { limit: 100, offset: 1, format: \"COMPACT-DECODED\" },\n);\n\nconsole.log(`Found ${rows.length} listings (total: ${count})`);\n\nawait client.logout();\n```\n\n### Auto-logout with `await using`\n\n```typescript\nimport { createClient } from \"@darksquarebishop/rets-client-ts\";\n\nconst client = await createClient({\n  /* ... */\n});\nawait client.login();\n\nawait using _session = client;\n// client[Symbol.asyncDispose]() runs logout() when scope exits\n\nconst resources = await client.metadata.getResources();\n```\n\n## Provider profiles\n\nBuilt-in presets for MLS-specific transport behavior (RETS version, session mode, retry):\n\n```typescript\nimport { createClient, providers } from \"@darksquarebishop/rets-client-ts\";\n\n// Garden State MLS — RETS/1.8, UA auth, per-request sessions\nconst gsmls = await createClient({\n  ...providers.gsmls,\n  loginUrl: process.env.GSMLS_URL!,\n  username: process.env.GSMLS_USER!,\n  password: process.env.GSMLS_PASSWORD!,\n  userAgent: process.env.GSMLS_USER_AGENT!,\n  userAgentPassword: process.env.GSMLS_USER_AGENT_PASSWORD!,\n});\n\n// Brooklyn MLS — RETS/1.7.2, persistent session, no UA auth\nconst bmls = await createClient({\n  ...providers.bmls,\n  loginUrl: process.env.BROOKLYNMLS_URL!,\n  username: process.env.BROOKLYNMLS_USER!,\n  password: process.env.BROOKLYNMLS_PASSWORD!,\n});\n```\n\nProfiles set transport/session defaults only. Resource names, class tags, DMQL strings, and pagination limits are caller concerns.\n\n## Search\n\nBoth `COMPACT` and `COMPACT-DECODED` formats are supported (default: `COMPACT-DECODED`).\n\n```typescript\n// Buffered — returns all rows in memory\nconst result = await client.search(\"Property\", \"RES\", \"(LSTNGSYSID=123+)\", {\n  limit: 200,\n  offset: 1,\n  select: \"LSTNGSYSID,LISTPRICE\",\n});\n\n// Streaming — yields rows one at a time\nfor await (const row of await client.searchStream(\"Property\", \"RES\", query)) {\n  await db.upsert(row);\n}\n\n// Auto-pagination — advances offset on maxRowsExceeded\nfor await (const row of client.searchAll(\"Property\", \"RES\", query, { limit: 200 })) {\n  await db.upsert(row);\n}\n```\n\n## Metadata\n\n```typescript\nconst resources = await client.metadata.getResources();\nconst classes = await client.metadata.getClass(\"Property\");\nconst tables = await client.metadata.getTable(\"Property\", \"RES\");\nconst system = await client.metadata.getSystem();\n```\n\n## Objects (photos / media)\n\nReturns an async iterator of parts (binary data, URL location, or error):\n\n```typescript\n// Specific objects\nfor await (const obj of client.getObjects(\"Property\", \"Photo\", { \"123\": \"*\" })) {\n  if (obj.data) await fs.writeFile(`${obj.headerInfo.contentId}.jpg`, obj.data);\n  if (obj.location) console.log(obj.location);\n  if (obj.error) console.warn(obj.error);\n}\n\n// All photos for a listing\nfor await (const obj of client.getAllObjects(\"Property\", \"LargePhoto\", \"12345\")) {\n  /* ... */\n}\n\n// Preferred photo only\nfor await (const obj of client.getPreferredObjects(\"Property\", \"LargePhoto\", \"12345\")) {\n  /* ... */\n}\n```\n\nSome MLSs deliver photos as CDN URLs via search (`Media/IMG` rows with an `IMAGEURL` field) rather than binary `getObject` — use `client.search()` for those.\n\n## Authentication\n\nTwo independent layers:\n\n1. **HTTP auth** — Basic or Digest (`qop=auth`, MD5). Handled automatically via challenge/response.\n2. **`RETS-UA-Authorization`** — application-level MD5 header required by some MLSs (e.g. GSMLS). Set `userAgent` + `userAgentPassword` in config; computed per request from the session cookie.\n\n## Logging\n\nStructured logging via [pino](https://github.com/pinojs/pino). Pass a custom logger or silence:\n\n```typescript\nimport pino from \"pino\";\n\nconst client = await createClient({\n  // ...\n  logger: pino({ level: \"debug\" }),\n  // or: logger: false\n});\n```\n\nCredentials are redacted automatically (`authorization`, `password`, `RETS-UA-Authorization`, cookies).\n\nSet `RETS_LOG_LEVEL=debug` in the environment to use the default logger at that level.\n\n## Errors\n\n| Class                 | When                                  |\n| --------------------- | ------------------------------------- |\n| `RetsServerError`     | Non-200 HTTP response                 |\n| `RetsReplyError`      | RETS `ReplyCode != 0`                 |\n| `RetsParseError`      | XML/multipart parsing failure         |\n| `RetsParamError`      | Invalid arguments or unsupported auth |\n| `RetsPermissionError` | Login OK but missing capability URLs  |\n\nAll extend `RetsError` with `cause`, `retsMethod`, and `requestId` context.\n\n## Configuration\n\n```typescript\ninterface ClientConfig {\n  loginUrl: string;\n  username: string;\n  password: string;\n  userAgent?: string;\n  userAgentPassword?: string; // GSMLS UA auth\n  version?: string; // default \"RETS/1.7.2\"\n  method?: \"GET\" | \"POST\"; // default \"GET\"\n  timeout?: number;\n  proxyUrl?: string;\n  sessionMode?: \"persistent\" | \"per-request\"; // default \"persistent\"\n  logger?: pino.Logger | false;\n  retry?: GotRetryOptions; // default off\n  truncatedXmlRetry?: {\n    // default off; GSMLS profile sets attempts: 6\n    attempts: number;\n    backoffMs: number;\n  };\n}\n```\n\n## Exports\n\n```typescript\n// Client\ncreateClient, RetsClient\n\n// Provider presets\nproviders, gsmls, bmls\n\n// Errors\nRetsError, RetsServerError, RetsReplyError, RetsParseError,\nRetsParamError, RetsPermissionError, ensureRetsError, isTruncatedXmlError\n\n// Utilities\napplyDefaults, computeUaAuth, deriveCredentialKey, normalizeUrl\ngetReplyTag, isSuccessReplyCode, REPLY_TAG_MAP\n\n// Types\nClientConfig, SearchOptions, SearchResult, SearchFormat, ObjectPart,\nMetadataResult, SystemMetadata, SessionMode, ProviderProfile, /* ... */\n```\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md). PRs welcome; please add a changeset for user-facing changes.\n\n## License\n\n[MIT](LICENSE) &copy; Matt Cassara\n","readmeFilename":"README.md","_rev":"1-394d350d5dba45c6253d84c81fed4b60"}