@geolonia/geonicdb-sdk 0.10.0 → 0.11.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/geonicdb.d.ts CHANGED
@@ -1,30 +1,503 @@
1
+ // Generated by dts-bundle-generator v9.5.1
2
+
3
+ /**
4
+ * Copyright (c) 2026 Geolonia Inc.
5
+ * Released under the MIT License. See src/sdk/LICENSE for details.
6
+ */
7
+ /** Options for the GeonicDB SDK constructor. */
8
+ export interface GeonicDBOptions {
9
+ /** API key (or use data-api-key attribute on script tag) */
10
+ apiKey?: string;
11
+ /** Tenant name (or use data-tenant attribute on script tag) */
12
+ tenant?: string;
13
+ /** API base URL (auto-detected from script src if omitted) */
14
+ baseUrl?: string;
15
+ /** WebSocket endpoint URL (auto-detected from baseUrl if omitted) */
16
+ wsEndpoint?: string;
17
+ /** Enable debug logging to console (default: false) */
18
+ debug?: boolean;
19
+ /**
20
+ * Enable in-memory client-side cache with automatic ETag/If-None-Match
21
+ * handling and request deduplication. (Phase A, default: true)
22
+ */
23
+ cache?: boolean;
24
+ /**
25
+ * Maximum number of cached entries (LRU eviction beyond this size).
26
+ * Only meaningful when `cache` is enabled. Default: 1000.
27
+ */
28
+ cacheMaxEntries?: number;
29
+ /**
30
+ * #1105: Anonymous mode. When true, the SDK skips token acquisition and
31
+ * sends requests without an `Authorization` header. The server treats
32
+ * such requests as `role: 'anonymous'` and lets the XACML policy engine
33
+ * decide whether to permit them.
34
+ *
35
+ * - Cannot be combined with `apiKey` (constructor throws).
36
+ * - `login()` / `setCredentials()` switches the SDK out of anonymous mode
37
+ * for subsequent requests.
38
+ * - `logout()` reverts to anonymous mode.
39
+ * - WebSocket `connect()` is not supported in anonymous mode and throws.
40
+ */
41
+ anonymous?: boolean;
42
+ }
43
+ /** Options for the SDK polling helper. */
44
+ export interface PollOptions<T = unknown> {
45
+ /** Polling interval in milliseconds (default: 5000). */
46
+ interval?: number;
47
+ /** Called when fresh data is received from the server (200). */
48
+ onData?: (data: T) => void;
49
+ /** Called when the server responded 304 (no change since last poll). */
50
+ onNoChange?: () => void;
51
+ /** Called on transport / HTTP errors. Polling continues unless the handler stops it. */
52
+ onError?: (error: unknown) => void;
53
+ }
54
+ /** Handle returned by `db.poll(...)` to control the polling loop. */
55
+ export interface PollHandle {
56
+ /** Stop the polling loop. Idempotent. */
57
+ stop(): void;
58
+ }
59
+ /** Options for setting credentials externally. */
60
+ export interface CredentialsOptions {
61
+ /** Access token (JWT) */
62
+ token: string;
63
+ /** Token type — default: 'Bearer' */
64
+ tokenType?: "Bearer" | "DPoP";
65
+ /** Token lifetime in seconds (default: 3600) */
66
+ expiresIn?: number;
67
+ /** Refresh token for auto-renewal */
68
+ refreshToken?: string;
69
+ }
70
+ /** Credentials returned after a token refresh. */
71
+ export interface RefreshedCredentials {
72
+ /** New access token */
73
+ token: string;
74
+ /** Token type */
75
+ tokenType: string;
76
+ /** Token lifetime in seconds */
77
+ expiresIn: number;
78
+ /** New refresh token */
79
+ refreshToken: string;
80
+ }
81
+ /**
82
+ * Parameters for querying entities.
83
+ *
84
+ * NGSI-LD 1.6 §5.7.2 Query Entities が定める主要パラメータを網羅する (#1132)。
85
+ * 以前はサーバ側が georel / scopeQ / attrs / pick / omit / lang などを実装
86
+ * しているのに SDK 側で型と URL builder が `type / limit / offset / q` の
87
+ * 4 つしか持たず、`db.request()` に逃げる必要があった。
88
+ */
89
+ export interface GetEntitiesParams {
90
+ /** Entity type filter */
91
+ type?: string;
92
+ /** Max results */
93
+ limit?: number;
94
+ /** Pagination offset */
95
+ offset?: number;
96
+ /** NGSI-LD query expression */
97
+ q?: string;
98
+ /** NGSI-LD scope query expression (`/foo`, `/foo/#`, `/foo/+`, `;` で OR) */
99
+ scopeQ?: string;
100
+ /** Geo-relation: `near`, `within`, `contains`, `intersects`, `disjoint`, `equals` */
101
+ georel?: string;
102
+ /** Geometry type: `Point`, `Polygon`, `LineString`, ... */
103
+ geometry?: string;
104
+ /** Coordinates string (semicolon-delimited pairs or flat comma-separated) */
105
+ coordinates?: string;
106
+ /** Comma-separated attribute names to retrieve */
107
+ attrs?: string;
108
+ /** Comma-separated attribute names to keep (alternative to attrs) */
109
+ pick?: string;
110
+ /** Comma-separated attribute names to remove */
111
+ omit?: string;
112
+ /** Language tag for LanguageProperty filtering */
113
+ lang?: string;
114
+ /** Order by field */
115
+ orderBy?: string;
116
+ /** Order direction: `asc` (default) or `desc` */
117
+ orderDirection?: "asc" | "desc";
118
+ /** Sort points by distance from a `near` query */
119
+ orderByDistance?: boolean;
120
+ /** Whether the response should include a count (server returns `NGSILD-Results-Count` header) */
121
+ count?: boolean;
122
+ /** GeoProperty key to use (default `location`) */
123
+ geoproperty?: string;
124
+ }
125
+ /** Parameters for counting entities. */
126
+ export interface CountEntitiesParams {
127
+ /** Entity type filter */
128
+ type?: string;
129
+ /** NGSI-LD query expression */
130
+ q?: string;
131
+ /** NGSI-LD scope query expression (#1132) */
132
+ scopeQ?: string;
133
+ }
134
+ /** Options for subscribing to entity events via WebSocket. */
135
+ export interface SubscribeOptions {
136
+ /** Entity types to subscribe to */
137
+ entityTypes?: string[];
138
+ /** Entity ID regex pattern */
139
+ idPattern?: string;
140
+ /** NGSI-LD scope query expression (#1132). Server-side filter; only events whose entity scope matches are delivered. */
141
+ scopeQ?: string;
142
+ }
143
+ /** Entity event received via WebSocket. */
144
+ export interface EntityEvent {
145
+ /** Event type */
146
+ type: "entityCreated" | "entityUpdated" | "entityDeleted";
147
+ /** Tenant name */
148
+ tenant: string;
149
+ /** Service path */
150
+ servicePath: string;
151
+ /** Entity ID */
152
+ entityId: string;
153
+ /** Entity type */
154
+ entityType: string;
155
+ /** Entity attributes */
156
+ data: Record<string, unknown>;
157
+ /** Complete NGSI-LD entity (id + type + attributes from data). Undefined when data is unavailable (e.g. some delete events). */
158
+ entity?: Record<string, unknown>;
159
+ /** Changed attribute names (update only) */
160
+ changedAttributes?: string[];
161
+ /** ISO 8601 timestamp */
162
+ timestamp: string;
163
+ }
164
+ /** Event fired when a reconnection attempt is starting. */
165
+ export interface ReconnectingEvent {
166
+ /** Current reconnection attempt number */
167
+ attempt: number;
168
+ /** Delay in ms before this attempt */
169
+ delay: number;
170
+ }
171
+ /** Options for `db.login(...)`. */
172
+ export interface LoginOptions {
173
+ /**
174
+ * If true, keep the user signed in across page reloads by persisting the
175
+ * session to IndexedDB. After a reload, call `db.restoreSession()` to
176
+ * rehydrate the session; `db.logout()` clears the persisted entry.
177
+ *
178
+ * The session is bound to a non-extractable key (DPoP, RFC 9449) stored via
179
+ * the structured clone algorithm — `extractable: false` is preserved, so the
180
+ * key cannot be read back as JWK / PEM even with full DOM access. A token
181
+ * leaked from localStorage stays unusable without this origin's IndexedDB.
182
+ *
183
+ * Default: false. Opt-out by design: shared-device flows should not enable
184
+ * this. Has no effect when the runtime lacks Web Crypto — the session cannot
185
+ * be sender-constrained, so it is not persisted.
186
+ */
187
+ rememberSession?: boolean;
188
+ }
189
+ /** Response from the login endpoint. */
190
+ export interface LoginResponse {
191
+ accessToken: string;
192
+ refreshToken: string;
193
+ expiresIn: number;
194
+ /**
195
+ * Token scheme: `Bearer` (default) or `DPoP` when the session has been
196
+ * sender-constrained via `/auth/dpop-bind` (RFC 9449). Optional for
197
+ * backward compatibility with older server responses.
198
+ */
199
+ tokenType?: "Bearer" | "DPoP";
200
+ }
201
+ /** Cache event payloads. */
202
+ export interface CacheEvent {
203
+ /** Cache key (typically `${method}:${path}` form). */
204
+ key: string;
205
+ /** Resource path (without method prefix). */
206
+ path: string;
207
+ }
208
+ /** Map of event names to their payload types. */
209
+ export interface GeonicDBEventMap {
210
+ entityCreated: EntityEvent;
211
+ entityUpdated: EntityEvent;
212
+ entityDeleted: EntityEvent;
213
+ open: undefined;
214
+ connected: undefined;
215
+ close: {
216
+ code: number;
217
+ reason: string;
218
+ };
219
+ disconnected: undefined;
220
+ reconnecting: ReconnectingEvent;
221
+ error: Error;
222
+ message: Record<string, unknown>;
223
+ tokenRefresh: RefreshedCredentials;
224
+ /** Fired when a request is served from the in-memory cache (304 received). */
225
+ cacheHit: CacheEvent;
226
+ /** Fired when a request misses cache and is fetched from the origin. */
227
+ cacheMiss: CacheEvent;
228
+ /** Fired when a cache entry is invalidated (e.g. by a WebSocket entity event). */
229
+ cacheInvalidated: CacheEvent;
230
+ }
231
+ /** Parameters for querying temporal entities. */
232
+ export interface GetTemporalEntitiesParams {
233
+ /** Entity type filter */
234
+ type?: string;
235
+ /** Entity ID */
236
+ id?: string;
237
+ /** Entity ID pattern (regex) */
238
+ idPattern?: string;
239
+ /** Attribute names to retrieve */
240
+ attrs?: string;
241
+ /** NGSI-LD query expression */
242
+ q?: string;
243
+ /** Time property to use (observedAt, createdAt, modifiedAt) */
244
+ timeproperty?: string;
245
+ /** Start time (ISO 8601) */
246
+ timeAt?: string;
247
+ /** End time (ISO 8601) */
248
+ endTimeAt?: string;
249
+ /** Temporal relation (before, after, between) */
250
+ timerel?: string;
251
+ /** NGSI-LD scope query expression (#1132) */
252
+ scopeQ?: string;
253
+ /** Max results */
254
+ limit?: number;
255
+ /** Pagination offset */
256
+ offset?: number;
257
+ }
258
+ export type Listener<T> = (data: T) => void;
259
+ declare class EventEmitter {
260
+ private _listeners;
261
+ on<K extends keyof GeonicDBEventMap>(event: K, callback: Listener<GeonicDBEventMap[K]>): this;
262
+ on(event: string, callback: Listener<unknown>): this;
263
+ off<K extends keyof GeonicDBEventMap>(event: K, callback?: Listener<GeonicDBEventMap[K]>): this;
264
+ off(event: string, callback?: Listener<unknown>): this;
265
+ protected emit<K extends keyof GeonicDBEventMap>(event: K, data?: GeonicDBEventMap[K]): void;
266
+ protected emit(event: string, data?: unknown): void;
267
+ }
268
+ /**
269
+ * Copyright (c) 2026 Geolonia Inc.
270
+ * Released under the MIT License. See src/sdk/LICENSE for details.
271
+ */
272
+ /**
273
+ * Base error class for GeonicDB SDK.
274
+ * All SDK errors extend this class, allowing `instanceof GeonicDBError` checks.
275
+ */
276
+ export declare class GeonicDBError extends Error {
277
+ /** HTTP status code (if applicable) */
278
+ readonly statusCode: number;
279
+ constructor(message: string, statusCode?: number);
280
+ }
281
+ /** 401 — Authentication failed (invalid credentials, expired token). */
282
+ export declare class AuthenticationError extends GeonicDBError {
283
+ constructor(message?: string);
284
+ }
285
+ /** 403 — Authorization denied (insufficient permissions). */
286
+ export declare class AuthorizationError extends GeonicDBError {
287
+ constructor(message?: string);
288
+ }
289
+ /** 404 — Resource not found. */
290
+ export declare class NotFoundError extends GeonicDBError {
291
+ constructor(message?: string);
292
+ }
293
+ /** 409 — Conflict (e.g. entity already exists). */
294
+ export declare class ConflictError extends GeonicDBError {
295
+ constructor(message?: string);
296
+ }
297
+ /** 422 — Validation error (bad request payload). */
298
+ export declare class ValidationError extends GeonicDBError {
299
+ constructor(message?: string);
300
+ }
301
+ /** 429 — Rate limited. */
302
+ export declare class RateLimitError extends GeonicDBError {
303
+ /** Seconds to wait before retrying (from Retry-After header) */
304
+ readonly retryAfter: number;
305
+ constructor(message?: string, retryAfter?: number);
306
+ }
307
+ /** Network error (fetch failed, DNS resolution, timeout). */
308
+ export declare class NetworkError extends GeonicDBError {
309
+ constructor(message?: string);
310
+ }
311
+ /**
312
+ * GeonicDB SDK client.
313
+ *
314
+ * Handles API key auth (DPoP + PoW), Bearer JWT, entity CRUD,
315
+ * WebSocket event streaming, and automatic reconnection.
316
+ *
317
+ * @example
318
+ * ```typescript
319
+ * import GeonicDB from '@geolonia/geonicdb-sdk';
320
+ *
321
+ * const db = new GeonicDB({
322
+ * apiKey: 'your-api-key',
323
+ * tenant: 'your-tenant',
324
+ * baseUrl: 'https://your-geonicdb.example.com',
325
+ * });
326
+ *
327
+ * const entities = await db.getEntities({ type: 'Room' });
328
+ * ```
329
+ */
330
+ export declare class GeonicDB extends EventEmitter {
331
+ private _auth;
332
+ private _ws;
333
+ /**
334
+ * Legacy callback for token refresh events.
335
+ * Prefer `db.on('tokenRefresh', callback)` for new code.
336
+ * @deprecated Use `db.on('tokenRefresh', callback)` instead.
337
+ */
338
+ onTokenRefresh: ((creds: RefreshedCredentials) => void) | null;
339
+ constructor(options?: GeonicDBOptions);
340
+ /**
341
+ * Drop every cached response. Useful in tests and on manual auth changes.
342
+ *
343
+ * Emits a `cacheInvalidated` event for each removed entry so listeners can
344
+ * track explicit flushes (the WebSocket-driven auto-invalidation was removed
345
+ * in #1060 to preserve the ETag/304 revalidation path; `clearCache()` is now
346
+ * the only path that emits this event).
347
+ */
348
+ clearCache(): void;
349
+ /**
350
+ * Login with email and password.
351
+ *
352
+ * The session is sender-constrained with DPoP (RFC 9449) automatically and
353
+ * transparently — there is no DPoP option to set. A token leaked from
354
+ * storage (e.g. localStorage XSS) is therefore unusable from another origin.
355
+ * On runtimes without Web Crypto, the SDK silently keeps a plain Bearer
356
+ * session and login still succeeds.
357
+ *
358
+ * @example
359
+ * ```ts
360
+ * // Standard login — DPoP applied transparently when supported.
361
+ * await db.login('user@example.com', 'password');
362
+ *
363
+ * // Keep the user signed in across page reloads (browser SPA UX).
364
+ * await db.login('user@example.com', 'password', { rememberSession: true });
365
+ * ```
366
+ */
367
+ login(email: string, password: string, options?: LoginOptions): Promise<LoginResponse>;
368
+ /**
369
+ * Rehydrate a session previously persisted via
370
+ * `login(email, password, { rememberSession: true })`.
371
+ *
372
+ * Returns true if a session for this tenant was found and loaded; false
373
+ * if there was no entry, IndexedDB is unavailable, or the persisted
374
+ * session was malformed. Call this at app startup before deciding
375
+ * whether to render the login form.
376
+ *
377
+ * @example
378
+ * ```ts
379
+ * const db = new GeonicDB({ baseUrl, tenant });
380
+ * if (await db.restoreSession()) {
381
+ * // Session (tokens + non-extractable key) recovered — boot the app.
382
+ * } else {
383
+ * // No session; show the login form.
384
+ * }
385
+ * ```
386
+ */
387
+ restoreSession(): Promise<boolean>;
388
+ /**
389
+ * Whether the SDK is currently operating in anonymous mode (no token held).
390
+ * Returns true only when `anonymous: true` was passed to the constructor
391
+ * AND no credentials have been set via `login()` / `setCredentials()`.
392
+ */
393
+ isAnonymous(): boolean;
394
+ /**
395
+ * Set credentials externally (e.g. from a login API response).
396
+ * When tokenType is 'Bearer' with a refreshToken, DPoP/PoW is bypassed entirely.
397
+ */
398
+ setCredentials(opts: CredentialsOptions): this;
399
+ /** Clear all credentials and disconnect. */
400
+ logout(): void;
401
+ /** Create a new entity. */
402
+ createEntity(entity: Record<string, unknown>): Promise<{
403
+ created: true;
404
+ }>;
405
+ /** Get a single entity by ID. */
406
+ getEntity(entityId: string): Promise<Record<string, unknown>>;
407
+ /** Query entities with optional filters. */
408
+ getEntities(params?: GetEntitiesParams): Promise<Record<string, unknown>[]>;
409
+ /**
410
+ * Poll for entity list changes using ETag-based revalidation (#991 Phase A).
411
+ *
412
+ * The handle's `stop()` ends the loop. Each tick performs a normal
413
+ * `getEntities()` call; the SDK's cache layer issues `If-None-Match`
414
+ * automatically. The poll detects "no change" by comparing the previous
415
+ * ETag with the response's ETag (the cache exposes the cached ETag on 304
416
+ * replays as well, so the comparison stays valid in both 200 and 304
417
+ * paths).
418
+ *
419
+ * @example
420
+ * ```typescript
421
+ * const handle = db.poll({ type: 'Room' }, {
422
+ * interval: 5000,
423
+ * onData: (rooms) => render(rooms),
424
+ * onNoChange: () => {},
425
+ * });
426
+ * // ...later
427
+ * handle.stop();
428
+ * ```
429
+ */
430
+ poll(params: GetEntitiesParams | undefined, options: PollOptions<Record<string, unknown>[]>): PollHandle;
431
+ /** Count entities matching the given filters. */
432
+ count(params?: CountEntitiesParams): Promise<number>;
433
+ /** Update entity attributes (partial). */
434
+ updateEntity(entityId: string, attrs: Record<string, unknown>): Promise<{
435
+ updated: true;
436
+ }>;
437
+ /** Delete an entity. */
438
+ deleteEntity(entityId: string): Promise<{
439
+ deleted: true;
440
+ }>;
441
+ /** List all entity types. */
442
+ getTypes(): Promise<Record<string, unknown>[]>;
443
+ /** Get details for a specific entity type. */
444
+ getType(typeName: string): Promise<Record<string, unknown>>;
445
+ /** List all attributes. */
446
+ getAttributes(): Promise<Record<string, unknown>[]>;
447
+ /** Get details for a specific attribute. */
448
+ getAttribute(attrName: string): Promise<Record<string, unknown>>;
449
+ /** Query temporal entities. */
450
+ getTemporalEntities(params?: GetTemporalEntitiesParams): Promise<Record<string, unknown>[]>;
451
+ /** Get temporal representation of a single entity. */
452
+ getTemporalEntity(entityId: string): Promise<Record<string, unknown>>;
453
+ /** Create multiple entities in a single request. */
454
+ batchCreate(entities: Record<string, unknown>[]): Promise<Record<string, unknown>>;
455
+ /** Upsert multiple entities in a single request. */
456
+ batchUpsert(entities: Record<string, unknown>[]): Promise<Record<string, unknown>>;
457
+ /** Update multiple entities in a single request. */
458
+ batchUpdate(entities: Record<string, unknown>[]): Promise<Record<string, unknown>>;
459
+ /** Delete multiple entities by ID. */
460
+ batchDelete(entityIds: string[]): Promise<Record<string, unknown>>;
461
+ /** GET request that returns parsed JSON or throws. */
462
+ private _jsonGet;
463
+ /** POST request that returns parsed JSON or throws. */
464
+ private _jsonPost;
465
+ /**
466
+ * Make an authenticated API request.
467
+ * Automatically checks response status, parses JSON, and throws on error.
468
+ *
469
+ * Empty bodies (`Content-Length: 0` 含む) は Content-Type に関係なく `null`
470
+ * を返す (#1145)。NGSI-LD の POST / DELETE / PATCH 系は仕様上ボディが
471
+ * 空だが、サーバ実装が `Content-Type: application/ld+json` を付けて返す
472
+ * ケースがあり、そこで `res.json()` が SyntaxError を投げて止まっていた。
473
+ */
474
+ request(method: string, path: string, body?: unknown): Promise<unknown>;
475
+ /**
476
+ * Make an authenticated API request and return the raw Response object.
477
+ * Use this when you need access to response headers (e.g. NGSILD-Results-Count).
478
+ */
479
+ requestRaw(method: string, path: string, body?: unknown): Promise<Response>;
480
+ /** Establish WebSocket connection (authentication is automatic). */
481
+ connect(): Promise<void>;
482
+ /** Force-reconnect (closes existing connection, preserves subscriptions). */
483
+ reconnect(): Promise<void>;
484
+ /** Disconnect WebSocket (does not fire 'disconnected' event). */
485
+ disconnect(): void;
486
+ /** Check if WebSocket is currently open. */
487
+ isConnected(): boolean;
488
+ /** Subscribe to entity events (can be called before or after connect). */
489
+ subscribe(options?: SubscribeOptions): void;
490
+ }
491
+ /**
492
+ * 汎用クエリ文字列ビルダ。`undefined` / `null` は省略、`boolean` は
493
+ * `'true'` / `'false'` の文字列、`number` は `String(n)`、それ以外は文字列化。
494
+ * 配列 / オブジェクトはサポート対象外 (NGSI-LD 仕様内の全パラメータは
495
+ * primitive で表現できるため不要)。
496
+ */
497
+ export declare function buildPathWithParams(path: string, params?: Record<string, unknown>): string;
498
+
1
499
  export {
2
- AuthenticationError,
3
- AuthorizationError,
4
- ConflictError,
5
- GeonicDB,
6
- GeonicDBError,
7
- NetworkError,
8
- NotFoundError,
9
- RateLimitError,
10
- ValidationError,
11
- buildPathWithParams,
12
- } from './index';
13
- export type {
14
- CacheEvent,
15
- CountEntitiesParams,
16
- CredentialsOptions,
17
- EntityEvent,
18
- GeonicDBEventMap,
19
- GeonicDBOptions,
20
- GetEntitiesParams,
21
- GetTemporalEntitiesParams,
22
- LoginOptions,
23
- LoginResponse,
24
- PollHandle,
25
- PollOptions,
26
- ReconnectingEvent,
27
- RefreshedCredentials,
28
- SubscribeOptions,
29
- } from './index';
30
- export { default } from './index';
500
+ GeonicDB as default,
501
+ };
502
+
503
+ export {};