@geolonia/geonicdb-sdk 0.21.0 → 0.23.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 +26 -4
- package/geonicdb.cjs +55 -12
- package/geonicdb.cjs.map +2 -2
- package/geonicdb.d.ts +14 -2
- package/geonicdb.iife.js +55 -12
- package/geonicdb.iife.js.map +2 -2
- package/geonicdb.mjs +55 -12
- package/geonicdb.mjs.map +2 -2
- package/package.json +1 -1
- package/react/index.d.ts +14 -2
package/README.md
CHANGED
|
@@ -248,8 +248,10 @@ const entities = await db.getEntities({ type: 'GeoJSON' });
|
|
|
248
248
|
> restricts where `@context` may come from based on `Content-Type` and forbids
|
|
249
249
|
> mixing the two. Since the SDK always sends `application/ld+json`, adding a
|
|
250
250
|
> JSON-LD `Link` header to a `POST` / `PATCH` / `PUT` via the `request()` /
|
|
251
|
-
> `requestRaw()` escape hatch returns `400 BadRequestData`. Put the `@context`
|
|
252
|
-
> in the body for writes; the `Link` header remains the channel for reads
|
|
251
|
+
> `requestRaw()` escape hatch (`options.headers`) returns `400 BadRequestData`. Put the `@context`
|
|
252
|
+
> in the body for writes; the `Link` header remains the channel for reads and is
|
|
253
|
+
> passed as `options.headers`. `Authorization`, `DPoP`, `Fiware-Service`, and
|
|
254
|
+
> `NGSILD-Tenant` (any casing) are reserved and throw `TypeError`. A CR or LF in a header name or value also throws `TypeError`.
|
|
253
255
|
|
|
254
256
|
```typescript
|
|
255
257
|
// Create
|
|
@@ -644,8 +646,28 @@ handle.stop();
|
|
|
644
646
|
|
|
645
647
|
| Method | Parameters | Returns | Description |
|
|
646
648
|
|--------|-----------|---------|-------------|
|
|
647
|
-
| `request(method, path, body?)` | `string, string, unknown` | `Promise<unknown>` | Authenticated request with automatic JSON parsing |
|
|
648
|
-
| `requestRaw(method, path, body?)` | `string, string, unknown` | `Promise<Response>` | Authenticated request returning raw `Response` (for accessing headers) |
|
|
649
|
+
| `request(method, path, body?, options?)` | `string, string, unknown, RequestOptions` | `Promise<unknown>` | Authenticated request with automatic JSON parsing. `options.headers` overrides `Content-Type` / `Accept` (header names are case-insensitive) |
|
|
650
|
+
| `requestRaw(method, path, body?, options?)` | `string, string, unknown, RequestOptions` | `Promise<Response>` | Authenticated request returning raw `Response` (for accessing headers). Same `options` as `request()` |
|
|
651
|
+
|
|
652
|
+
#### Calling `POST /mcp` (#3322)
|
|
653
|
+
|
|
654
|
+
`POST /mcp` requires `Content-Type: application/json` and `Accept: application/json, text/event-stream`. The SDK defaults are `application/ld+json`, so omitting `headers` returns **406**.
|
|
655
|
+
|
|
656
|
+
```javascript
|
|
657
|
+
const rpc = await db.request('POST', '/mcp', {
|
|
658
|
+
jsonrpc: '2.0',
|
|
659
|
+
id: 1,
|
|
660
|
+
method: 'tools/call',
|
|
661
|
+
params: { name: 'config', arguments: { resource: 'rules', action: 'list' } },
|
|
662
|
+
}, {
|
|
663
|
+
headers: {
|
|
664
|
+
'Content-Type': 'application/json',
|
|
665
|
+
Accept: 'application/json, text/event-stream',
|
|
666
|
+
},
|
|
667
|
+
});
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
The body is JSON-RPC, not SSE. Tool failures are still HTTP 200 — check `result.isError`. `Authorization`, `DPoP`, `Fiware-Service`, and `NGSILD-Tenant` (any casing) throw `TypeError`, as does a CR or LF in a header name or value. A GET or HEAD that passes `headers` skips the ETag cache and in-flight dedup. After `login()`, the DPoP session calls `/mcp` as that user. `config` / `admin` need `tenant_admin`; an API-key principal gets `Admin privileges required`.
|
|
649
671
|
|
|
650
672
|
### Cache & Polling
|
|
651
673
|
|
package/geonicdb.cjs
CHANGED
|
@@ -585,6 +585,46 @@ function isCacheableMethod(method) {
|
|
|
585
585
|
}
|
|
586
586
|
|
|
587
587
|
// src/sdk/auth.ts
|
|
588
|
+
var SDK_RESERVED_REQUEST_HEADERS = /* @__PURE__ */ new Set([
|
|
589
|
+
"authorization",
|
|
590
|
+
"dpop",
|
|
591
|
+
"fiware-service",
|
|
592
|
+
"ngsild-tenant"
|
|
593
|
+
]);
|
|
594
|
+
function assertCallerHeadersAllowed(headers) {
|
|
595
|
+
if (!headers) return;
|
|
596
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
597
|
+
if (/[\r\n]/.test(name) || /[\r\n]/.test(value)) {
|
|
598
|
+
throw new TypeError("Header name or value contains CR or LF");
|
|
599
|
+
}
|
|
600
|
+
if (SDK_RESERVED_REQUEST_HEADERS.has(name.toLowerCase())) {
|
|
601
|
+
throw new TypeError(
|
|
602
|
+
`Header "${name}" is reserved; the SDK sets Authorization, DPoP, Fiware-Service, and NGSILD-Tenant`
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
function mergeCallerHeaders(defaults, extraHeaders) {
|
|
608
|
+
const merged = new Headers(defaults);
|
|
609
|
+
const callerNames = /* @__PURE__ */ new Map();
|
|
610
|
+
if (extraHeaders) {
|
|
611
|
+
for (const [name, value] of Object.entries(extraHeaders)) {
|
|
612
|
+
merged.set(name, value);
|
|
613
|
+
callerNames.set(name.toLowerCase(), name);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
const headers = {};
|
|
617
|
+
for (const name of Object.keys(defaults)) {
|
|
618
|
+
if (callerNames.has(name.toLowerCase())) continue;
|
|
619
|
+
const value = merged.get(name);
|
|
620
|
+
if (value !== null) headers[name] = value;
|
|
621
|
+
}
|
|
622
|
+
for (const [lower, name] of callerNames) {
|
|
623
|
+
const value = merged.get(lower);
|
|
624
|
+
if (value !== null) headers[name] = value;
|
|
625
|
+
}
|
|
626
|
+
return headers;
|
|
627
|
+
}
|
|
588
628
|
var _AuthManager = class _AuthManager {
|
|
589
629
|
constructor(baseUrl, apiKey, tenant, debug = false, anonymous = false) {
|
|
590
630
|
__publicField(this, "_baseUrl");
|
|
@@ -1205,11 +1245,12 @@ var _AuthManager = class _AuthManager {
|
|
|
1205
1245
|
* the cache.
|
|
1206
1246
|
* - Deduplicates concurrent in-flight requests to the same path.
|
|
1207
1247
|
*/
|
|
1208
|
-
async request(method, path, body) {
|
|
1248
|
+
async request(method, path, body, headers) {
|
|
1209
1249
|
this._log(method, path);
|
|
1210
|
-
|
|
1250
|
+
assertCallerHeadersAllowed(headers);
|
|
1251
|
+
if (!this._cache || !isCacheableMethod(method) || body !== void 0 || headers !== void 0) {
|
|
1211
1252
|
const token = this.isAnonymous() ? null : await this.ensureToken();
|
|
1212
|
-
const res = await this._doAuthenticatedRequest(method, path, body, token);
|
|
1253
|
+
const res = await this._doAuthenticatedRequest(method, path, body, token, 0, headers);
|
|
1213
1254
|
this._log(method, path, "\u2192", res.status);
|
|
1214
1255
|
return res;
|
|
1215
1256
|
}
|
|
@@ -1304,11 +1345,13 @@ var _AuthManager = class _AuthManager {
|
|
|
1304
1345
|
reqToken,
|
|
1305
1346
|
dpopNonce
|
|
1306
1347
|
) : null;
|
|
1307
|
-
const headers =
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1348
|
+
const headers = mergeCallerHeaders(
|
|
1349
|
+
{
|
|
1350
|
+
"Content-Type": "application/ld+json",
|
|
1351
|
+
Accept: "application/ld+json"
|
|
1352
|
+
},
|
|
1353
|
+
extraHeaders
|
|
1354
|
+
);
|
|
1312
1355
|
if (reqToken !== null) {
|
|
1313
1356
|
headers["Authorization"] = (reqIsDPoP ? "DPoP " : "Bearer ") + reqToken;
|
|
1314
1357
|
}
|
|
@@ -2216,8 +2259,8 @@ var GeonicDB = class extends EventEmitter {
|
|
|
2216
2259
|
* 空だが、サーバ実装が `Content-Type: application/ld+json` を付けて返す
|
|
2217
2260
|
* ケースがあり、そこで `res.json()` が SyntaxError を投げて止まっていた。
|
|
2218
2261
|
*/
|
|
2219
|
-
async request(method, path, body) {
|
|
2220
|
-
const res = await this._auth.request(method, path, body);
|
|
2262
|
+
async request(method, path, body, options) {
|
|
2263
|
+
const res = await this._auth.request(method, path, body, options?.headers);
|
|
2221
2264
|
if (!res.ok) {
|
|
2222
2265
|
const e = await res.json().catch(() => ({}));
|
|
2223
2266
|
throw createErrorFromResponse(res.status, e, "Request failed: " + res.status);
|
|
@@ -2237,8 +2280,8 @@ var GeonicDB = class extends EventEmitter {
|
|
|
2237
2280
|
* Make an authenticated API request and return the raw Response object.
|
|
2238
2281
|
* Use this when you need access to response headers (e.g. NGSILD-Results-Count).
|
|
2239
2282
|
*/
|
|
2240
|
-
async requestRaw(method, path, body) {
|
|
2241
|
-
return this._auth.request(method, path, body);
|
|
2283
|
+
async requestRaw(method, path, body, options) {
|
|
2284
|
+
return this._auth.request(method, path, body, options?.headers);
|
|
2242
2285
|
}
|
|
2243
2286
|
// --- WebSocket ---
|
|
2244
2287
|
/** Establish WebSocket connection (authentication is automatic). */
|