@izak0s/spacebring-api 1.8.0 → 1.10.0

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/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![CI](https://github.com/izak0s/spacebring-api/actions/workflows/ci.yml/badge.svg)](https://github.com/izak0s/spacebring-api/actions/workflows/ci.yml)
4
4
  [![npm](https://img.shields.io/npm/v/%40izak0s%2Fspacebring-api)](https://www.npmjs.com/package/@izak0s/spacebring-api)
5
+ [![docs](https://img.shields.io/badge/docs-API%20reference-blue)](https://izak0s.github.io/spacebring-api/)
5
6
  [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
6
7
 
7
8
  A fully-typed TypeScript client for the [Spacebring](https://www.spacebring.com) coworking space management API, auto-generated from the official OpenAPI spec.
@@ -10,6 +11,8 @@ A fully-typed TypeScript client for the [Spacebring](https://www.spacebring.com)
10
11
 
11
12
  ---
12
13
 
14
+ 📖 **[Full API reference](https://izak0s.github.io/spacebring-api/)** — every resource, method, and type, generated from the source.
15
+
13
16
  ## Features
14
17
 
15
18
  - **<!-- coverage -->162 operations across 20 resource groups<!-- /coverage -->** — the full Spacebring API surface
@@ -38,40 +41,46 @@ No runtime dependencies — HTTP uses the built-in `fetch`.
38
41
  ## Quick Start
39
42
 
40
43
  ```ts
41
- import { Spacebring } from "@izak0s/spacebring-api";
44
+ import { Spacebring, SpacebringError } from "@izak0s/spacebring-api";
42
45
 
43
46
  const sb = new Spacebring({
44
47
  clientId: process.env.SPACEBRING_CLIENT_ID!,
45
48
  clientSecret: process.env.SPACEBRING_CLIENT_SECRET!,
46
- networkId: "your-network-id", // optional, sent as spacebring-network-id header
47
- // baseUrl: "https://api.spacebring.com", // default
48
- // fetch: customFetch, // inject your own fetch (tests, proxies)
49
+ networkId: process.env.SPACEBRING_NETWORK_ID, // optional — sent as the spacebring-network-id header
49
50
  });
50
51
 
51
- async function main() {
52
- // Single-property envelopes are unwrapped: entities and plain arrays come back directly
53
- const invoice = await sb.billing.invoices.get(invoiceId);
54
- const locations = await sb.locations.list();
55
- await sb.visitors.visits.checkIn({ locationRef, visitRef });
52
+ // Single-property envelopes are unwrapped — list() gives you Location[] directly.
53
+ const locations = await sb.locations.list();
54
+ const locationRef = locations[0].id;
56
55
 
57
- // Paginated lists return the page envelope, so nextPageToken stays available
58
- const { benefits, nextPageToken } = await sb.benefits.list({ locationRef });
56
+ // Paginated lists return the page envelope, so nextPageToken stays available…
57
+ const { benefits, nextPageToken } = await sb.benefits.list({ locationRef });
59
58
 
60
- // ...or let iterate() walk nextPageToken for you; breaking early stops fetching
61
- for await (const booking of sb.resources.bookings.iterate({ locationRef })) {
62
- console.log(booking.id);
63
- }
59
+ // …or hand it to iterate(), which follows nextPageToken across pages.
60
+ // Break out early and it simply stops fetching — no wasted requests.
61
+ for await (const booking of sb.resources.bookings.iterate({ locationRef })) {
62
+ console.log(`${booking.startDate} → ${booking.endDate}`);
63
+ }
64
64
 
65
- // Endpoints returning multiple payloads keep the envelope
66
- const { invoice: paid, payment } = await sb.billing.invoices.pay(invoiceId, {
67
- paymentMethod: { type: "stripe" },
68
- });
65
+ // Non-2xx responses throw a typed SpacebringError.
66
+ try {
67
+ await sb.billing.invoices.get("does-not-exist");
68
+ } catch (error) {
69
+ if (error instanceof SpacebringError) {
70
+ console.error(`${error.status} on ${error.operation}: ${error.body?.message}`);
71
+ }
69
72
  }
73
+ ```
74
+
75
+ Writes read the same, and endpoints that return more than one payload keep the envelope intact:
70
76
 
71
- main().catch(console.error);
77
+ ```ts
78
+ const { invoice, payment } = await sb.billing.invoices.pay(invoiceId, {
79
+ paymentMethod: { type: "stripe" },
80
+ });
72
81
  ```
73
82
 
74
- Entity types are exported by name — `import type { Booking, Invoice, Membership } from "@izak0s/spacebring-api"` — matching what the methods return (`get`/`create`/`update` resolve to the entity, `iterate()` yields it). Query parameters get named interfaces too (`GetBookingsQuery`, `GetInvoicesQuery`), with per-field docs from the spec and enum filters as literal unions. Lower-level helpers too: `SpacebringConfig`, `SpacebringResources`, and the raw spec types `paths` / `components` / `operations`.
83
+ Entity types are exported by name — `import type { Booking, Invoice, Membership } from "@izak0s/spacebring-api"` — matching what the methods return (`get`/`create`/`update` resolve to the entity, `iterate()` yields it). Query parameters get named interfaces too (`GetBookingsQuery`, `GetInvoicesQuery`), with per-field docs from the spec and enum filters as literal unions, and request bodies get named types (`CreateBookingBody`, `UpdateInvoiceBody`). Lower-level helpers too: `SpacebringConfig`, `SpacebringResources`, and the raw spec types `paths` / `components` / `operations`.
75
84
 
76
85
  ### Data formats
77
86
 
@@ -87,6 +96,8 @@ Values are passed through exactly as the API sends them — no runtime conversio
87
96
 
88
97
  HTTP Basic with your **Client ID** and **Client Secret** from **Spacebring → [Network] → Network Settings → Developers**. The client builds the `Authorization: Basic …` header for you. The API's OAuth2 flow is not currently supported.
89
98
 
99
+ Because those credentials ride on every request, the client rejects a non-`https` `baseUrl` at construction — `http` is allowed only for loopback hosts (local proxies or mock servers). The default `baseUrl` is `https://api.spacebring.com`.
100
+
90
101
  For development without touching live data, Spacebring offers a [test environment](https://www.spacebring.com/docs/administration/test-environment) (Network settings → Billing add-on) with free sandbox API credentials that work with this client unchanged.
91
102
 
92
103
  ---
package/dist/index.cjs CHANGED
@@ -2107,6 +2107,8 @@ var Spacebring = class {
2107
2107
  /** Typed openapi-fetch client — escape hatch for endpoints or options the facade does not cover. */
2108
2108
  raw;
2109
2109
  constructor(config) {
2110
+ const baseUrl = config.baseUrl ?? "https://api.spacebring.com";
2111
+ assertSecureBaseUrl(baseUrl);
2110
2112
  const headers = {
2111
2113
  Authorization: `Basic ${toBase64(`${config.clientId}:${config.clientSecret}`)}`
2112
2114
  };
@@ -2114,7 +2116,7 @@ var Spacebring = class {
2114
2116
  headers["spacebring-network-id"] = config.networkId;
2115
2117
  }
2116
2118
  this.raw = createClient({
2117
- baseUrl: config.baseUrl ?? "https://api.spacebring.com",
2119
+ baseUrl,
2118
2120
  headers,
2119
2121
  fetch: withRetry(config.fetch ?? globalThis.fetch, config.maxRetries ?? 3, config.timeoutMs)
2120
2122
  });
@@ -2183,6 +2185,20 @@ function sleep(ms, signal) {
2183
2185
  signal.addEventListener("abort", onAbort, { once: true });
2184
2186
  });
2185
2187
  }
2188
+ function assertSecureBaseUrl(baseUrl) {
2189
+ let url;
2190
+ try {
2191
+ url = new URL(baseUrl);
2192
+ } catch {
2193
+ throw new Error(`Spacebring baseUrl is not a valid URL: ${baseUrl}`);
2194
+ }
2195
+ if (url.protocol === "https:") return;
2196
+ const isLoopback = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]" || url.hostname === "::1";
2197
+ if (url.protocol === "http:" && isLoopback) return;
2198
+ throw new Error(
2199
+ `Spacebring baseUrl must use https (got "${url.protocol}//"): Basic-auth credentials would otherwise be sent in cleartext. Use https, or http only for a loopback host.`
2200
+ );
2201
+ }
2186
2202
  function toBase64(value) {
2187
2203
  if (typeof Buffer !== "undefined") {
2188
2204
  return Buffer.from(value, "utf8").toString("base64");