{
  "name": "Middleman supplier starter clients",
  "version": "0.1.0",
  "files": [
    {
      "path": "middleman.ts",
      "sha256": "ab60aee349b005441d88454c0eb9131314133b67f529cf7794b8ca4ca28553a8",
      "content": "/** Middleman supplier client, preview 0.1.0. Server-side only. No dependencies. */\nexport type SupplierRecord = {\n  sourceRecordId: string;\n  sourceVersion: string;\n  kind: \"product\" | \"capacity\" | \"service\";\n  title: string;\n  manufacturer: string | null;\n  manufacturerPartNumber: string | null;\n  unit: string;\n  condition: \"new\" | \"used\" | \"refurbished\" | \"unknown\";\n  availability: { quantity: string | null; window: { start: string; end: string } | null; location: string | null; leadTimeDays: number | null };\n  pricing: { currency: string; country: string; audience: \"public\"; taxBasis: \"net\" | \"gross\" | \"unknown\"; taxRate: string | null; minimumOrderQuantity: string; orderMultiple: string; tiers: { minimumQuantity: string; unitPrice: string }[] } | null;\n  sourceUpdatedAt: string | null;\n  observedAt: string;\n  expiresAt: string;\n  status: \"active\" | \"withdrawn\";\n};\nexport type SupplierBatch = { schemaVersion: \"0.1.0\"; source: { id: string; system: string; mode: \"api\" | \"sdk\" }; records: SupplierRecord[] };\nexport type SupplierAccess = { data: { keyId: string; supplierId: string; scopes: string[]; schemaVersion: string; stage: string; capabilities: { validate: boolean; ingest: boolean; publish: boolean; quote: boolean; reserve: boolean; order: boolean } } };\nexport type ValidationResult = { valid: true; schemaVersion: string; recordsValidated: number; persisted: false; admitted: false } | { valid: false; schemaVersion: string; errors: { path: string; message: string }[] };\n\nexport class MiddlemanApiError extends Error {\n  status: number;\n  code: string;\n  retryAfter: string | null;\n  constructor(status: number, code: string, retryAfter: string | null = null) {\n    super(`Middleman API returned ${status}: ${code}`);\n    this.name = \"MiddlemanApiError\"; this.status = status; this.code = code; this.retryAfter = retryAfter;\n  }\n}\n\nexport class MiddlemanSupplier {\n  #apiKey: string;\n  #origin: string;\n  constructor({ apiKey, baseUrl = \"https://middlemantechnologies.com\" }: { apiKey: string; baseUrl?: string }) {\n    if (!apiKey || /\\s/.test(apiKey)) throw new Error(\"Load a supplier API key from your secret store.\");\n    const url = new URL(baseUrl);\n    const loopback = [\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(url.hostname);\n    if ((url.protocol !== \"https:\" && !(url.protocol === \"http:\" && loopback)) || url.username || url.password || url.search || url.hash || url.pathname !== \"/\") throw new Error(\"Use a trusted HTTPS Middleman origin, or loopback HTTP for development.\");\n    this.#apiKey = apiKey; this.#origin = url.origin;\n  }\n  async #request(path: string, batch?: SupplierBatch): Promise<unknown> {\n    const response = await fetch(`${this.#origin}${path}`, {\n      method: batch === undefined ? \"GET\" : \"POST\",\n      headers: { authorization: `Bearer ${this.#apiKey}`, ...(batch === undefined ? {} : { \"content-type\": \"application/json\" }) },\n      ...(batch === undefined ? {} : { body: JSON.stringify(batch) }),\n      redirect: \"error\", signal: AbortSignal.timeout(15_000), cache: \"no-store\",\n    });\n    let payload: unknown;\n    try { payload = await response.json(); } catch { throw new MiddlemanApiError(response.status, \"invalid_response\"); }\n    if (!response.ok && !(batch !== undefined && response.status === 422)) {\n      const code = (payload as { error?: { code?: unknown } })?.error?.code;\n      throw new MiddlemanApiError(response.status, typeof code === \"string\" && /^[a-z_]{1,80}$/.test(code) ? code : \"request_failed\", response.headers.get(\"retry-after\"));\n    }\n    return payload;\n  }\n  async me(): Promise<SupplierAccess> { return await this.#request(\"/api/v1/supplier/me\") as SupplierAccess; }\n  async validate(batch: SupplierBatch): Promise<ValidationResult> { return await this.#request(\"/api/v1/supplier/validate\", batch) as ValidationResult; }\n}\n"
    },
    {
      "path": "middleman.py",
      "sha256": "1a50f5439de0f57bec1d0a6a2b6ddb7d02f860038e590c59af41d7e9ff289023",
      "content": "\"\"\"Middleman supplier client, preview 0.1.0. Python 3.10+, no dependencies.\"\"\"\nimport json\nfrom urllib.error import HTTPError\nfrom urllib.parse import urlsplit\nfrom urllib.request import HTTPRedirectHandler, Request, build_opener\n\n\nclass MiddlemanApiError(Exception):\n    def __init__(self, status, code, retry_after=None):\n        super().__init__(f\"Middleman API returned {status}: {code}\")\n        self.status = status\n        self.code = code\n        self.retry_after = retry_after\n\n\nclass _NoRedirect(HTTPRedirectHandler):\n    def redirect_request(self, req, fp, code, msg, headers, newurl):\n        return None\n\n\nclass MiddlemanSupplier:\n    def __init__(self, *, api_key: str, base_url: str = \"https://middlemantechnologies.com\"):\n        if not api_key or any(char.isspace() for char in api_key):\n            raise ValueError(\"Load a supplier API key from your secret store.\")\n        url = urlsplit(base_url)\n        loopback = url.hostname in (\"localhost\", \"127.0.0.1\", \"::1\")\n        if (url.scheme != \"https\" and not (url.scheme == \"http\" and loopback)) or not url.hostname or url.username or url.password or url.query or url.fragment or url.path not in (\"\", \"/\"):\n            raise ValueError(\"Use a trusted HTTPS Middleman origin, or loopback HTTP for development.\")\n        self._api_key = api_key\n        self._origin = f\"{url.scheme}://{url.netloc}\"\n        self._opener = build_opener(_NoRedirect())\n\n    def _request(self, path: str, batch=None):\n        headers = {\"Authorization\": f\"Bearer {self._api_key}\"}\n        data = None\n        if batch is not None:\n            headers[\"Content-Type\"] = \"application/json\"\n            data = json.dumps(batch, allow_nan=False).encode(\"utf-8\")\n        request = Request(self._origin + path, data=data, headers=headers, method=\"GET\" if batch is None else \"POST\")\n        try:\n            response = self._opener.open(request, timeout=15)\n        except HTTPError as error:\n            response = error\n        with response:\n            status = response.code\n            retry_after = response.headers.get(\"Retry-After\")\n            try:\n                payload = json.loads(response.read(1_048_577))\n            except (ValueError, UnicodeDecodeError):\n                raise MiddlemanApiError(status, \"invalid_response\") from None\n            if not 200 <= status < 300 and not (batch is not None and status == 422):\n                code = payload.get(\"error\", {}).get(\"code\") if isinstance(payload, dict) and isinstance(payload.get(\"error\"), dict) else None\n                if not isinstance(code, str) or len(code) > 80 or not all(char in \"abcdefghijklmnopqrstuvwxyz_\" for char in code):\n                    code = \"request_failed\"\n                raise MiddlemanApiError(status, code, retry_after)\n            return payload\n\n    def me(self):\n        return self._request(\"/api/v1/supplier/me\")\n\n    def validate(self, batch):\n        return self._request(\"/api/v1/supplier/validate\", batch)\n"
    }
  ]
}
