@terrascale/sdk 0.0.5 → 0.0.7

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/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.0.7 — live shape reconnect, browser bootstrap and read replica
4
+
5
+ `subscribeShape` keeps its state and retries the same position after a lost
6
+ connection, follows the bootstrap `307` in browsers, and accepts
7
+ `replica: { load, save }` to restore its last resumable state across restarts
8
+ and offline periods. `indexedDbShapeReplica(key)` stores it in IndexedDB.
9
+ Writes are never queued locally. Also publishes the query aggregates and geo
10
+ filters below.
11
+
12
+ ## Unreleased — query aggregates and geo filters
13
+
14
+ `query({ aggregate: { groupBy, sum, avg, min, max } })` returns typed
15
+ `groups` (`{ key, count, sum?, avg?, min?, max? }`) with empty `items`.
16
+ `v1Filter.withinRadius(path, { lat, lon, meters })` and
17
+ `v1Filter.withinBox(path, { south, west, north, east })` build `within`
18
+ filters, and `sort: [{ near: { path, lat, lon } }]` orders by meters, returned
19
+ as each item's `distance`.
20
+
21
+ ## 0.0.6 — relational SQL
22
+
23
+ `db.execute(sql, args)`, `db.query(sql, args)` and `db.batch(statements)` call
24
+ TerraBase's `POST /v1/projects/{project}/databases/{database}/sql/execute`.
25
+ Each request is one transaction. Results are typed
26
+ `{ columns, rows, rowsAffected, lastInsertRowid }`; a refused statement throws
27
+ `SqlError` (a `TerraBaseV1Error`) with `statement` and `sqliteCode`. The
28
+ read-only `db.sql` route is unchanged.
29
+
3
30
  ## Unreleased — collection TTL and vector near sort
4
31
 
5
32
  `collection.putTtl(path)`, `getTtl()` and `deleteTtl()` call
package/README.md CHANGED
@@ -110,15 +110,17 @@ OpenAPI and immutable release qualification remain open gates.
110
110
  | Collections and declared JSON Schema | `db.collections.create/get/list/drop`; `collection.getSchema/putSchema/deleteSchema` |
111
111
  | Collection TTL | `collection.putTtl/getTtl/deleteTtl` |
112
112
  | Databases | `client.databases.create/list/get/update/delete/branch` |
113
- | SQL | `db.sql/checkSql/explainSql` |
113
+ | Relational SQL | `db.execute/query/batch` |
114
+ | Read-only SQL (older) | `db.sql/checkSql/explainSql` |
114
115
  | Changes | `db.changes` (SSE async iterator) |
115
116
  | Export | `db.export` (NDJSON async iterator) |
116
117
 
117
118
  Project, collection catalog, and database catalog IDs are canonical uppercase
118
119
  26-character ULIDs. `generateId()`, `isValidId()` and `requireId()` retain that
119
- entity-ID contract. Document keys independently accept 1–256 UTF-16 code units,
120
- without controls or lone surrogates; natural keys, slashes and Unicode travel as
121
- one query parameter. A root payload `id` is ordinary data unless it equals the
120
+ entity-ID contract. Document point operations and transaction writes require canonical
121
+ ULIDs; the producer rejects other forms with `invalid_document_id`. SQL-backed
122
+ collections can still return their stored primary keys in query, stream and export
123
+ results. A root payload `id` is ordinary data unless it equals the
122
124
  key; the producer then strips that redundant member.
123
125
  Documents return
124
126
  `{ id, version, state: "value", document }`; a causal read can answer
@@ -149,6 +151,32 @@ const { items } = await docs.query({
149
151
  });
150
152
  ```
151
153
 
154
+ Geo points are `{ lat, lon }` objects (WGS 84 degrees). `v1Filter.withinRadius`
155
+ matches points within `meters` (haversine), `v1Filter.withinBox` points in a box
156
+ (`west > east` crosses the antimeridian); both nest under `and`, `or` and `not`
157
+ but shape filters reject them. A geo `near` sort orders by meters from a point,
158
+ with the same one-page, at-most-100 rule as the vector `near`:
159
+
160
+ ```js
161
+ const nearby = await places.query({
162
+ filter: v1Filter.withinRadius("/loc", { lat: -23.55, lon: -46.63, meters: 1000 }),
163
+ sort: [{ near: { path: "/loc", lat: -23.55, lon: -46.63 } }], limit: 10,
164
+ }); // each item carries distance in meters
165
+ ```
166
+
167
+ `aggregate` answers `groups` instead of items. `groupBy` takes 0-4 paths;
168
+ `sum`, `avg`, `min` and `max` take at most 16 JSON Pointers in total and
169
+ consider numbers only (`sum` is 0 and the others null without any). `count`
170
+ is a decimal string. It takes no `sort`, `project`, `cursor` or `count`, and
171
+ `limit` bounds the groups (more answer 400 `invalid_query`):
172
+
173
+ ```js
174
+ const { groups } = await orders.query({
175
+ filter: v1Filter.gte("/created", 1761264000000),
176
+ aggregate: { groupBy: ["/status"], sum: ["/amount"], avg: ["/amount"] }, limit: 100,
177
+ }); // [{ key: ["paid"], count: "250", sum: { "/amount": 12500.5 }, avg: { "/amount": 50.002 } }]
178
+ ```
179
+
152
180
  A collection TTL deletes documents whose member holds a past RFC 3339 UTC time.
153
181
  An hourly home-region sweep does the delete, up to about an hour late; until
154
182
  then expired documents stay readable.
@@ -161,6 +189,37 @@ or replay mutations after an uncertain result; this release does not promise
161
189
  mutation deduplication. Validation, authentication, authorization and
162
190
  precondition failures are not automatically retried.
163
191
 
192
+ Relational SQL runs statements on tables created with `CREATE TABLE` (rows
193
+ are documents). `execute` runs one statement, `query` returns its rows as
194
+ objects keyed by column name, and `batch` sends 1 to 256 statements as one
195
+ transaction: all commit or none do. `BEGIN`, `COMMIT` and `ROLLBACK` are
196
+ refused. Arguments are positional (`?`) or named (`:name`, `@name`, `$name`,
197
+ passed without the prefix). Each is `null`, a number, an int64 `bigint`, a
198
+ boolean (stored as 1 or 0) or a string. Reads need `documents:read`; writes and
199
+ DDL also need `documents:write`.
200
+
201
+ ```js
202
+ await db.batch([
203
+ "CREATE TABLE people (id INTEGER PRIMARY KEY, name TEXT NOT NULL)",
204
+ { sql: "INSERT INTO people (id, name) VALUES (?, ?)", args: [1, "Ada"] },
205
+ { sql: "INSERT INTO people (id, name) VALUES (:id, :name)", named: { id: 2, name: "Grace" } },
206
+ ]);
207
+ const people = await db.query("SELECT id, name FROM people WHERE id > ?", [0]);
208
+ const { columns, rows, rowsAffected, lastInsertRowid } = await db.execute("DELETE FROM people WHERE id = :id", { id: 2 });
209
+ ```
210
+
211
+ A refused statement throws `SqlError`, a `TerraBaseV1Error` that adds
212
+ `statement` (zero-based index) and `sqliteCode` (such as
213
+ `SQLITE_CONSTRAINT_PRIMARYKEY`). Its `code` is `sql_error` (400),
214
+ `forbidden_scope` (403), `sql_conflict` (409) or `sql_too_large` (413).
215
+ Authentication, quota and availability errors keep their usual error classes.
216
+
217
+ TerraBase sends integers as JSON numbers. A plain JavaScript number cannot hold
218
+ an integer above 2^53 exactly, so the SDK decodes such a value (a row value or
219
+ `lastInsertRowid`) as an `ExactDecimal` that keeps every digit. Convert it with
220
+ `BigInt(String(value))`. Pass large integer arguments as `bigint`.
221
+
222
+ The older `db.sql` route below is read-only.
164
223
  SQL is the producer's bounded read-only subset: `{ matched, truncated, rows }`,
165
224
  with row `{ id, value }` and no pagination cursor. `checkSql` returns `ok: false`
166
225
  for invalid SQL; `explainSql` returns an HTTP error for invalid SQL. All three
@@ -205,7 +264,7 @@ feed, not authorized bounded-query snapshots or the planned reactive WebSocket A
205
264
 
206
265
  ## Free shape subscriptions (protocol v1)
207
266
 
208
- `collection.subscribeShape({ where? }, { onUpdate?, signal? })` follows a collection's
267
+ `collection.subscribeShape({ where? }, { onUpdate?, signal?, replica? })` follows a collection's
209
268
  sealed snapshot, log chunks, and live long-polls. Its `state` is a map from document
210
269
  id to `{ version, document }`; `upToDate` becomes true only after a fresh response
211
270
  reports `up_to_date`. Each callback sees the complete applied response or a
@@ -225,23 +284,49 @@ try {
225
284
  ```
226
285
 
227
286
  `close()` cancels a pending read. Server errors reject `done` using the existing
228
- TerraBase error types; malformed responses and network failures also stop it.
287
+ TerraBase error types; malformed responses also stop it. A lost connection
288
+ (a fetch rejection or a body failing in transit) keeps state and retries the same
289
+ position with backoff, because shape reads are replay-safe `GET`s.
229
290
  Observe `done` to detect terminal errors. A throwing `onUpdate` stops the
230
291
  subscription and rejects `done` with the callback's error; already applied state
231
292
  remains available. Calling `close()` or aborting takes precedence over a later
232
293
  callback exception and resolves `done`. Document
233
294
  upserts replace the prior value and deletes of unknown ids are harmless. Repeated
234
295
  events are applied: a sealed value can be newer than its event, including after
235
- failover. There are no durable local writes or offline mutation queue.
296
+ failover. There are no durable local writes or offline mutation queue: every
297
+ write goes to the server, and a live subscription delivers it back.
298
+
299
+ Pass a token provider (`token: () => getAccessToken()`) to keep a subscription
300
+ alive across token renewal: each long-poll asks it for the current token. A
301
+ `401` or `403` still stops the subscription.
302
+
303
+ ### Read replica
304
+
305
+ `replica: { load, save }` keeps the last resumable state as exact JSON text. On
306
+ start the subscription restores those documents with `upToDate` false, calls
307
+ `onUpdate`, and catches up from the saved handle and offset; while offline it
308
+ keeps retrying and the restored state stays readable. A `409 must_refetch`
309
+ clears the replica with the state. A replica saved for another database,
310
+ collection or filter is ignored. `indexedDbShapeReplica(key)` stores it in
311
+ browser IndexedDB; use one key per signed-in subject and shape, and clear it on
312
+ sign-out. A failing store rejects `done`.
313
+
314
+ ```js
315
+ import { indexedDbShapeReplica } from "@terrascale/sdk";
316
+ const open = todos.subscribeShape({ where: v1Filter.eq("/done", false) }, {
317
+ replica: indexedDbShapeReplica(`${userId}/todos/open`),
318
+ onUpdate: s => render(s.state, s.upToDate),
319
+ });
320
+ ```
236
321
 
237
322
  The client preserves state for one proven cursor-resume attempt when a different
238
323
  machine rejects its handle. It never resumes an incomplete snapshot. A failed
239
324
  resume or another `409 must_refetch` clears state and starts a fresh snapshot.
240
325
  Opaque resume tokens travel verbatim in the query, or `TB-Shape-Resume` when the
241
326
  request target would exceed the protocol limit. Only documented transient
242
- `shape_busy`, `unavailable`, and `shape_too_large` errors retry with backoff and
243
- `Retry-After` until success or cancellation; authorization, validation, and
244
- network errors stop the subscription. The backoff delay is capped at 30 seconds
327
+ `shape_busy`, `unavailable`, and `shape_too_large` errors and lost connections
328
+ retry with backoff and `Retry-After` until success or cancellation;
329
+ authorization and validation errors stop the subscription. The backoff delay is capped at 30 seconds
245
330
  unless `Retry-After` requires longer. The maximum signed-64-bit live bucket is
246
331
  accepted as a response, as §4 allows, but cannot be sent as the next input;
247
332
  `done` rejects with a `TypeError` if that protocol limit is reached.
@@ -261,8 +346,10 @@ latest served epoch advances; historical objects fetch their keys again without
261
346
  retaining them. Any `409 must_refetch` on the shape or key route clears that
262
347
  collection's key cache. A failed tag, binding, frame, or response validation
263
348
  applies nothing. Key ids follow §12's 26 ASCII bytes without assuming a ULID.
264
- Native browser Fetch hides manual redirect metadata, so subscription bootstrap
265
- currently requires server fetch. TBS1 decryption uses WebCrypto in either runtime.
349
+ Native browser Fetch hides a manual `307` behind an opaque redirect, so in a
350
+ browser the bootstrap is sent again with `redirect: "follow"` and the final URL
351
+ is held to the same same-route `Location` rules. TBS1 decryption uses WebCrypto
352
+ in either runtime.
266
353
 
267
354
  This implements the [proposed protocol](contracts/shape-v1/shape-reads.md) at
268
355
  `993927ce7ecf8f9b889d24d4d1d21ec96eaf9416`, using `documents:read`. HTTP fakes and the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@terrascale/sdk",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "JavaScript SDK, typed with JSDoc, for project-scoped C# TerraBase v1 and hosted TerraScale identity.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -71,6 +71,7 @@
71
71
  {"method":"PUT","path":"/v1/projects/{project}/databases/{database}/schema/{collection}","operation":"declareCollectionSchema","scopes":["databases:write"],"requestMediaTypes":["application/json"],"statuses":[200],"responseMediaType":"application/json","source":"src/TerraBase/Features/Management/Schema/PutCollectionSchemaEndpoint.cs","request":"UniqueSchemaRequest"},
72
72
  {"method":"POST","path":"/v1/projects/{project}/databases/{database}/sql","operation":"runSql","scopes":["databases:read"],"requestMediaTypes":["application/json"],"statuses":[200],"responseMediaType":"application/json","source":"src/TerraBase/Features/Management/Queries/RunSqlEndpoint.cs","request":"SqlRequest"},
73
73
  {"method":"POST","path":"/v1/projects/{project}/databases/{database}/sql/check","operation":"checkSql","scopes":["databases:read"],"requestMediaTypes":["application/json"],"statuses":[200],"responseMediaType":"application/json","source":"src/TerraBase/Features/Management/Queries/CheckSqlEndpoint.cs","request":"SqlRequest"},
74
+ {"method":"POST","path":"/v1/projects/{project}/databases/{database}/sql/execute","operation":"executeSql","scopes":["documents:read"],"requestMediaTypes":["application/json"],"statuses":[200],"responseMediaType":"application/json","source":"src/TerraBase/Features/Sql/SqlExecuteEndpoint.cs","request":"SqlExecuteRequest","producerChange":"TerraScale/terrascale#420"},
74
75
  {"method":"POST","path":"/v1/projects/{project}/databases/{database}/sql/explain","operation":"explainSql","scopes":["databases:read"],"requestMediaTypes":["application/json"],"statuses":[200],"responseMediaType":"application/json","source":"src/TerraBase/Features/Management/Queries/ExplainSqlEndpoint.cs","request":"SqlRequest"},
75
76
  {"method":"POST","path":"/v1/projects/{project}/databases/{database}/transactions","operation":"runTransaction","scopes":["documents:write"],"requestMediaTypes":["application/json"],"statuses":[200],"responseMediaType":"application/json","source":"src/TerraBase/Features/Documents/TransactionEndpoint.cs","request":"TransactionRequest"},
76
77
  {"method":"GET","path":"/v1/projects/{project}/databases/{database}/usage","operation":"getDatabaseUsage","scopes":["databases:read"],"requestMediaTypes":[],"statuses":[200],"responseMediaType":"application/json","source":"src/TerraBase/Features/Management/Usage/GetDatabaseUsageEndpoint.cs","request":"none"},
@@ -80,6 +81,10 @@
80
81
  {"method":"DELETE","path":"/v1/projects/{project}/saved-queries/{query}","operation":"deleteSavedQuery","scopes":["databases:write"],"requestMediaTypes":[],"statuses":[204],"responseMediaType":"","source":"src/TerraBase/Features/Management/Queries/DeleteSavedQueryEndpoint.cs","request":"none"},
81
82
  {"method":"GET","path":"/v1/projects/{project}/saved-queries/{query}","operation":"getSavedQuery","scopes":["databases:read"],"requestMediaTypes":[],"statuses":[200],"responseMediaType":"application/json","source":"src/TerraBase/Features/Management/Queries/GetSavedQueryEndpoint.cs","request":"none"},
82
83
  {"method":"PUT","path":"/v1/projects/{project}/saved-queries/{query}","operation":"updateSavedQuery","scopes":["databases:write"],"requestMediaTypes":["application/json"],"statuses":[200],"responseMediaType":"application/json","source":"src/TerraBase/Features/Management/Queries/UpdateSavedQueryEndpoint.cs","request":"SavedQueryRequest"},
83
- {"method":"GET","path":"/v1/projects/{project}/usage","operation":"getProjectUsage","scopes":["databases:read"],"requestMediaTypes":[],"statuses":[200],"responseMediaType":"application/json","source":"src/TerraBase/Features/Management/Usage/GetProjectUsageEndpoint.cs","request":"none"}
84
+ {"method":"GET","path":"/v1/projects/{project}/usage","operation":"getProjectUsage","scopes":["databases:read"],"requestMediaTypes":[],"statuses":[200],"responseMediaType":"application/json","source":"src/TerraBase/Features/Management/Usage/GetProjectUsageEndpoint.cs","request":"none"},
85
+ {"method":"POST","path":"/v1/projects/{project}/databases/{database}/collections/{collection}/webhooks","operation":"createChangeWebhook","scopes":["documents:read","documents:write"],"requestMediaTypes":["application/json"],"statuses":[201],"responseMediaType":"application/json","contract":"contracts/change-webhooks.md","request":"CreateWebhookRequest"},
86
+ {"method":"GET","path":"/v1/projects/{project}/databases/{database}/collections/{collection}/webhooks","operation":"listChangeWebhooks","scopes":["documents:read"],"requestMediaTypes":[],"statuses":[200],"responseMediaType":"application/json","contract":"contracts/change-webhooks.md","request":"none"},
87
+ {"method":"DELETE","path":"/v1/projects/{project}/databases/{database}/collections/{collection}/webhooks/{webhook}","operation":"deleteChangeWebhook","scopes":["documents:read","documents:write"],"requestMediaTypes":[],"statuses":[204],"responseMediaType":"","contract":"contracts/change-webhooks.md","request":"none"},
88
+ {"method":"GET","path":"/v1/projects/{project}/databases/{database}/collections/{collection}/webhooks/{webhook}/deliveries","operation":"listChangeWebhookDeliveries","scopes":["documents:read"],"requestMediaTypes":[],"statuses":[200],"responseMediaType":"application/json","contract":"contracts/change-webhooks.md","request":"none"}
84
89
  ]
85
90
  }
@@ -178,7 +178,7 @@
178
178
  },
179
179
  "currentSource": {
180
180
  "producer": "TerraScale/terrascale",
181
- "revision": "e30ffdc287530551b161b0130220be53d3c0475e",
181
+ "revision": "0d2582d1d6cc73972b49f6b6089b6f9ed0848da9",
182
182
  "sdkBaseRevision": "eac7e3fca1178d30d81eb18ff35d8629e5f454e4",
183
183
  "evidence": "Read-only source snapshot; not generated OpenAPI or runtime qualification. Imports excluded.",
184
184
  "routes": {
@@ -213,16 +213,16 @@
213
213
  "sha256": "3dbf94f195b41783efb230801831ac85cba31a428a1fb43b0d4df68cf082125e"
214
214
  },
215
215
  "src/TerraBase/Errors/ErrorResponse.cs": {
216
- "sha256": "db83574aa5c2737d8cb7c905b9dbd5c553ba76c4bcf8e21eb8c269916958426d"
216
+ "sha256": "a304375245bed8239bd48a317c81ff02eb50a33aba4aa992c395db383bef4686"
217
217
  },
218
218
  "src/TerraBase/Features/ApiKeys/ApiKeyAuthenticationHandler.cs": {
219
- "sha256": "ff55b316403eaad56ff2941b75d06ce2e561d01bb1ff0cda3fcb3eb49e17e494"
219
+ "sha256": "da12dea0a18f633dbb3e7a43b2f3d8b2ef5b364de4fa807f5c95f49b0fafaf68"
220
220
  },
221
221
  "src/TerraBase/Features/ApiKeys/IApiKeyStore.cs": {
222
222
  "sha256": "3abf96b87470e93fd9eaa4d72bd79dac2ded185399eaed6dd5d487e99dfda066"
223
223
  },
224
224
  "src/TerraBase/Features/Documents/ChangeCursor.cs": {
225
- "sha256": "0ba18e88079fc019f81b708afcfbf949b02ef9746e2aa9420d2f52470bc3224e"
225
+ "sha256": "1e441a7c2f6b7af31ba6cfae40311374488737fa46557822fc230adeaa464613"
226
226
  },
227
227
  "src/TerraBase/Features/Documents/CollectionSchemaRoute.cs": {
228
228
  "sha256": "60665ffa0c29d19fd63895e391c65c1b6015c2109e75f960faf569f701ab7e50"
@@ -231,31 +231,31 @@
231
231
  "sha256": "dfc7b259119127dd6bdafc34b97194659441500c47bdf7a3171e052c1547bc83"
232
232
  },
233
233
  "src/TerraBase/Features/Documents/CreateDocumentEndpoint.cs": {
234
- "sha256": "25678dbe2d651d1291be796b1e9c75f93762e1e476648629427acce027d99fc5"
234
+ "sha256": "54b34b25eb61f2c9ad9464bfd4eb9c90653d9900ad606d45c041c552f9942495"
235
235
  },
236
236
  "src/TerraBase/Features/Documents/DatabaseChangeModels.cs": {
237
237
  "sha256": "157ab37070ec2104f72730bf0e641fa5219946614a3dafe82530885e9a573ed7"
238
238
  },
239
239
  "src/TerraBase/Features/Documents/DatabaseChanges.cs": {
240
- "sha256": "bbe8ee1e1cf3dacc2ba32967538bbbb427530edbe96fbe165bba8e52400a3406"
240
+ "sha256": "653e1b45684fb8778267375f73d381b4417e4e52c65907b3602377c432677b19"
241
241
  },
242
242
  "src/TerraBase/Features/Documents/DeleteCollectionSchemaEndpoint.cs": {
243
243
  "sha256": "63fca1ce65c98aeba3f9caa2b12673c8c46b49b40f18180e8c9e08f233ca6830"
244
244
  },
245
245
  "src/TerraBase/Features/Documents/DeleteDocumentEndpoint.cs": {
246
- "sha256": "c8062dde557574824d5278f77c736bbe62277d4f2b659c602b6fa4d3a44f9908"
246
+ "sha256": "a71f61b2cae9cfaa743aff0cd80394dc3657ff85ad0f647f407d1f349a391b68"
247
247
  },
248
248
  "src/TerraBase/Features/Documents/DocumentModels.cs": {
249
- "sha256": "160e0cc11b4b9a28b10261c3e1718f9d047dd5c782b3b65b288be4ea31db6581"
249
+ "sha256": "0e2c310ebed60fedf41713d20e64595d040dee6691cddecf0fc89ce2330bb089"
250
250
  },
251
251
  "src/TerraBase/Features/Documents/DocumentPatch.cs": {
252
252
  "sha256": "6b75821cc347e30189149bec4386e8995914f31aeedd41eaa97b135835252e5d"
253
253
  },
254
254
  "src/TerraBase/Features/Documents/DocumentRoute.cs": {
255
- "sha256": "1ccdf60170c6ccffdbce3dae444fed0ebefb920658b0700f8f410b3983dc53a8"
255
+ "sha256": "931dd2eaef5711829b09e004beaf9b3cfdfb50e4a085a49209e50c8c848da2c2"
256
256
  },
257
257
  "src/TerraBase/Features/Documents/DropCollectionEndpoint.cs": {
258
- "sha256": "e1a91ca3a740218ea7c994af994ca54301308f92414759f044650d6717f4f2d9"
258
+ "sha256": "08960ed491b565f8ee767c091533e092220686f56e91ad587c5770ed76606f4f"
259
259
  },
260
260
  "src/TerraBase/Features/Documents/GetCollectionEndpoint.cs": {
261
261
  "sha256": "28af27dda8c6dceadebdc00562c33ef93b8f88f8f6b30e784edfa7dea4a18907"
@@ -264,7 +264,7 @@
264
264
  "sha256": "600d89a860177dc3cf20cb90b84e47cc1542afb09041636e300a9d61f3d2a526"
265
265
  },
266
266
  "src/TerraBase/Features/Documents/GetDatabaseChangesEndpoint.cs": {
267
- "sha256": "13ca12352bf33d2e687f4a7fb4d78d6f28f3048f936b14e1db8f9fd947745dd8"
267
+ "sha256": "22a6028fd5d961cdbd307876aef7df171e0d69f6094add382c4d36444f86b191"
268
268
  },
269
269
  "src/TerraBase/Features/Documents/GetDocumentEndpoint.cs": {
270
270
  "sha256": "f2c960cafe784acc67108de412df1134e8c89a2ceac71d1bed6c5654bd5884fa"
@@ -276,31 +276,31 @@
276
276
  "sha256": "99274324f34fcaf92da5637da834bd3963db5d41a39c66515a0cefba0259c207"
277
277
  },
278
278
  "src/TerraBase/Features/Documents/PatchDocumentEndpoint.cs": {
279
- "sha256": "c14d7808bea905c49064f9fce5ba3c4b081fd8ebbc539e508c520f4680b08ae0"
279
+ "sha256": "68ea3acff0b49b62ab94e242046de1cfc0e1cdcef35fbb618054bce23f043903"
280
280
  },
281
281
  "src/TerraBase/Features/Documents/PutCollectionSchemaEndpoint.cs": {
282
282
  "sha256": "836d24b6a8137af9fdfce3e9c800c5c47a917802233658f83f9283a59490d3b2"
283
283
  },
284
284
  "src/TerraBase/Features/Documents/PutDocumentEndpoint.cs": {
285
- "sha256": "894fc735975b86c980a27a73df898fe454f920e7eca0e5c536b5af4cdae25134"
285
+ "sha256": "b130e811ccca916ae07d33287fd57eaa0800421bb131e3caa1486792f2ef3ccf"
286
286
  },
287
287
  "src/TerraBase/Features/Documents/QueryDocumentsEndpoint.cs": {
288
- "sha256": "9052c75d80ec46bbe113312f45b2cee4b198ae1730ffe90d3eb07f7507db2a93"
288
+ "sha256": "dfbdf4a34abc85116e8293f2218010560e6443a9c6e2212edfcec2969259dcd6"
289
289
  },
290
290
  "src/TerraBase/Features/Documents/TransactionEndpoint.cs": {
291
- "sha256": "1e518f9c73f28b13e6e1761f4706e4157e89bf50776b6ac73ad44b6e22150c5c"
291
+ "sha256": "63aedf3a0dcc5367a2811c6f44b01df14599792e742245c861c1bf73d333fa8c"
292
292
  },
293
293
  "src/TerraBase/Features/Management/BranchManagedDatabaseEndpoint.cs": {
294
294
  "sha256": "16729700b6baa72fd26ebe8c8537f51e3414fd1a439a9d0bcbac211dc6266043"
295
295
  },
296
296
  "src/TerraBase/Features/Management/CreateManagedDatabaseEndpoint.cs": {
297
- "sha256": "8302ef780cf65c92aa5f2a86e26fdd811c68e9446fa27f292d53ddf7207aa06a"
297
+ "sha256": "c845cb31cf840f7b3d7a15f1dc36326b5b27316a0a6eaad47ba6a325c1c044f4"
298
298
  },
299
299
  "src/TerraBase/Features/Management/DatabaseRegions.cs": {
300
- "sha256": "b25dd27ce0864e4d2fba10c7f54595aa21b263ef6a59d20583d3b20916722e31"
300
+ "sha256": "16a54232cdf1e6d0d63555a43807a3104807b994a12c5018b5ade3cd051548c6"
301
301
  },
302
302
  "src/TerraBase/Features/Management/DeleteManagedDatabaseEndpoint.cs": {
303
- "sha256": "1f6c26915734fb2e8eefceb613b72a08952c72aafc95a83c658e8caec36f81da"
303
+ "sha256": "1bd3038277ac6397724921491e45b0efc824c0ff3e3cc3fe7261a2782c28bcc5"
304
304
  },
305
305
  "src/TerraBase/Features/Management/GetManagedDatabaseEndpoint.cs": {
306
306
  "sha256": "263b6ee7698bdc95b1546e5947ff2b12368348d14b833919ff4a2684bfb34d91"
@@ -309,7 +309,7 @@
309
309
  "sha256": "ddd6d4f39bd5881b26e3247d23bc50fa6aabde16406ee89c82c28b5a52dd6f9e"
310
310
  },
311
311
  "src/TerraBase/Features/Management/ManagedDatabaseBody.cs": {
312
- "sha256": "eaafeb932f4189f3f5f8246408a16adc33772c36ba11ab1cec972281d8a5a2fc"
312
+ "sha256": "17093b73938a331e100e28345b69f32aa0ad27775ff5739df7ec437dfc619a33"
313
313
  },
314
314
  "src/TerraBase/Features/Management/ProjectApiRoute.cs": {
315
315
  "sha256": "f78ac4888e34b0aa76158e9666efaf5de996d73e2b220018e44167ea2d7372cc"
@@ -321,19 +321,19 @@
321
321
  "sha256": "a491c12f83bae64724bf36258de26b71556822ef29f94b10995e9ba4d75d6ada"
322
322
  },
323
323
  "src/TerraBase/Features/Management/Queries/RunSqlEndpoint.cs": {
324
- "sha256": "a038d67d1c3e4979cc3333d425732c8d1c256035b5528fe5e649e64df93c6279"
324
+ "sha256": "b662ec00f189e042558d4f12f65b41673bd5db33bcfaa991088dc6fed67bbed6"
325
325
  },
326
326
  "src/TerraBase/Features/Management/UpdateManagedDatabaseEndpoint.cs": {
327
- "sha256": "08120d2aa197b7739dfcdb471dd753f08a5f597e96a62c6631b710f7e148021b"
327
+ "sha256": "f34b3a239b785b303e333e5aafd4e5e1670e1411b71c0a085a5c183aa47beba3"
328
328
  },
329
329
  "src/TerraBase/Features/UserAuth/ProjectToken.cs": {
330
330
  "sha256": "dc880e5a063f5148df174bea1455e0058bc4cd5b89f94d26d9f8853e62ad43dc"
331
331
  },
332
332
  "src/TerraBase/Features/UserAuth/UserAuthenticationHandler.cs": {
333
- "sha256": "af40f669b8759b3683dfae8454e4b9fd9b05a5588cbf303a28644768942121c5"
333
+ "sha256": "12aa602d1adf4e171ba859fc05e1ad58461819157567fd075a5b67dd90347918"
334
334
  },
335
335
  "src/TerraBase/Features/UserAuth/UserAuthExtensions.cs": {
336
- "sha256": "ee71fc08d5f34231bd2a11029d4cd99f0213e16100841789e54f994bfcc3c38f"
336
+ "sha256": "0a3bae03a89ea36f49186dc3e1481367e15c65b56016f06e5aadb798774b5079"
337
337
  },
338
338
  "src/TerraBase/Features/Documents/ETags.cs": {
339
339
  "sha256": "a486f8e5297eaf50c2b5844d646b7d4f1b04cb2bcf542865426bb7a12a44fefc"
@@ -345,7 +345,10 @@
345
345
  "sha256": "8f5f4be149663febe469a13741cadc5469cfc08de622527bedaaa8fe0e5893fd"
346
346
  },
347
347
  "src/TerraBase/Features/Management/Queries/QueryService.cs": {
348
- "sha256": "df439371d7df3fd8de35bd26a7c34bc4b91009f860ed76d99f83315fd813bb64"
348
+ "sha256": "a0e095bd9895f2fcf9b2b838c28c3d839f7ad4a3353b3409fe44b128689aa121"
349
+ },
350
+ "src/TerraBase/Primitives/EntityIds.cs": {
351
+ "sha256": "51cff088e94cdf2e5f347c1b0fe53e92fbc2fb885ded83252867a6ea53e7038b"
349
352
  }
350
353
  }
351
354
  },
@@ -369,7 +372,7 @@
369
372
  "operation": "putDocument",
370
373
  "producerOperationId": "putDocument",
371
374
  "sourcePath": "src/TerraBase/Features/Documents/PutDocumentEndpoint.cs",
372
- "sha256": "894fc735975b86c980a27a73df898fe454f920e7eca0e5c536b5af4cdae25134",
375
+ "sha256": "b130e811ccca916ae07d33287fd57eaa0800421bb131e3caa1486792f2ef3ccf",
373
376
  "method": "PUT",
374
377
  "pathTemplate": "/v1/projects/{project}/databases/{database}/collections/{collection}/documents/by-key",
375
378
  "authorizationPolicy": "ApiKeyScopes.DocumentsWrite",
@@ -387,7 +390,7 @@
387
390
  "operation": "createDocument",
388
391
  "producerOperationId": "createDocument",
389
392
  "sourcePath": "src/TerraBase/Features/Documents/CreateDocumentEndpoint.cs",
390
- "sha256": "25678dbe2d651d1291be796b1e9c75f93762e1e476648629427acce027d99fc5",
393
+ "sha256": "54b34b25eb61f2c9ad9464bfd4eb9c90653d9900ad606d45c041c552f9942495",
391
394
  "method": "POST",
392
395
  "pathTemplate": "/v1/projects/{project}/databases/{database}/collections/{collection}/documents",
393
396
  "authorizationPolicy": "ApiKeyScopes.DocumentsWrite",
@@ -404,7 +407,7 @@
404
407
  "operation": "patchDocument",
405
408
  "producerOperationId": "patchDocument",
406
409
  "sourcePath": "src/TerraBase/Features/Documents/PatchDocumentEndpoint.cs",
407
- "sha256": "c14d7808bea905c49064f9fce5ba3c4b081fd8ebbc539e508c520f4680b08ae0",
410
+ "sha256": "68ea3acff0b49b62ab94e242046de1cfc0e1cdcef35fbb618054bce23f043903",
408
411
  "method": "PATCH",
409
412
  "pathTemplate": "/v1/projects/{project}/databases/{database}/collections/{collection}/documents/by-key",
410
413
  "authorizationPolicy": "ApiKeyScopes.DocumentsWrite",
@@ -422,7 +425,7 @@
422
425
  "operation": "deleteDocument",
423
426
  "producerOperationId": "deleteDocument",
424
427
  "sourcePath": "src/TerraBase/Features/Documents/DeleteDocumentEndpoint.cs",
425
- "sha256": "c8062dde557574824d5278f77c736bbe62277d4f2b659c602b6fa4d3a44f9908",
428
+ "sha256": "a71f61b2cae9cfaa743aff0cd80394dc3657ff85ad0f647f407d1f349a391b68",
426
429
  "method": "DELETE",
427
430
  "pathTemplate": "/v1/projects/{project}/databases/{database}/collections/{collection}/documents/by-key",
428
431
  "authorizationPolicy": "ApiKeyScopes.DocumentsWrite",
@@ -437,7 +440,7 @@
437
440
  "operation": "commitTransaction",
438
441
  "producerOperationId": "runTransaction",
439
442
  "sourcePath": "src/TerraBase/Features/Documents/TransactionEndpoint.cs",
440
- "sha256": "1e518f9c73f28b13e6e1761f4706e4157e89bf50776b6ac73ad44b6e22150c5c",
443
+ "sha256": "63aedf3a0dcc5367a2811c6f44b01df14599792e742245c861c1bf73d333fa8c",
441
444
  "method": "POST",
442
445
  "pathTemplate": "/v1/projects/{project}/databases/{database}/transactions",
443
446
  "authorizationPolicy": "ApiKeyScopes.DocumentsWrite",
@@ -454,7 +457,7 @@
454
457
  "operation": "queryDocuments",
455
458
  "producerOperationId": "queryDocuments",
456
459
  "sourcePath": "src/TerraBase/Features/Documents/QueryDocumentsEndpoint.cs",
457
- "sha256": "9052c75d80ec46bbe113312f45b2cee4b198ae1730ffe90d3eb07f7507db2a93",
460
+ "sha256": "dfbdf4a34abc85116e8293f2218010560e6443a9c6e2212edfcec2969259dcd6",
458
461
  "method": "POST",
459
462
  "pathTemplate": "/v1/projects/{project}/databases/{database}/collections/{collection}/query",
460
463
  "authorizationPolicy": "ApiKeyScopes.DocumentsRead",
@@ -518,7 +521,7 @@
518
521
  "operation": "dropCollection",
519
522
  "producerOperationId": "dropCollection",
520
523
  "sourcePath": "src/TerraBase/Features/Documents/DropCollectionEndpoint.cs",
521
- "sha256": "e1a91ca3a740218ea7c994af994ca54301308f92414759f044650d6717f4f2d9",
524
+ "sha256": "08960ed491b565f8ee767c091533e092220686f56e91ad587c5770ed76606f4f",
522
525
  "method": "DELETE",
523
526
  "pathTemplate": "/v1/projects/{project}/databases/{database}/collections/{collection}",
524
527
  "authorizationPolicy": "ApiKeyScopes.DocumentsWrite",
@@ -533,7 +536,7 @@
533
536
  "operation": "runSql",
534
537
  "producerOperationId": "runSql",
535
538
  "sourcePath": "src/TerraBase/Features/Management/Queries/RunSqlEndpoint.cs",
536
- "sha256": "a038d67d1c3e4979cc3333d425732c8d1c256035b5528fe5e649e64df93c6279",
539
+ "sha256": "b662ec00f189e042558d4f12f65b41673bd5db33bcfaa991088dc6fed67bbed6",
537
540
  "method": "POST",
538
541
  "pathTemplate": "/v1/projects/{project}/databases/{database}/sql",
539
542
  "authorizationPolicy": "ApiKeyScopes.DatabasesRead",
@@ -584,7 +587,7 @@
584
587
  "operation": "streamDatabaseChanges",
585
588
  "producerOperationId": "streamDatabaseChanges",
586
589
  "sourcePath": "src/TerraBase/Features/Documents/GetDatabaseChangesEndpoint.cs",
587
- "sha256": "13ca12352bf33d2e687f4a7fb4d78d6f28f3048f936b14e1db8f9fd947745dd8",
590
+ "sha256": "22a6028fd5d961cdbd307876aef7df171e0d69f6094add382c4d36444f86b191",
588
591
  "method": "GET",
589
592
  "pathTemplate": "/v1/projects/{project}/databases/{database}/changes",
590
593
  "authorizationPolicy": "ApiKeyScopes.DocumentsRead",
@@ -661,7 +664,7 @@
661
664
  "operation": "createDatabase",
662
665
  "producerOperationId": "createDatabase",
663
666
  "sourcePath": "src/TerraBase/Features/Management/CreateManagedDatabaseEndpoint.cs",
664
- "sha256": "8302ef780cf65c92aa5f2a86e26fdd811c68e9446fa27f292d53ddf7207aa06a",
667
+ "sha256": "c845cb31cf840f7b3d7a15f1dc36326b5b27316a0a6eaad47ba6a325c1c044f4",
665
668
  "method": "POST",
666
669
  "pathTemplate": "/v1/projects/{project}/databases",
667
670
  "authorizationPolicy": "ApiKeyScopes.DatabasesWrite",
@@ -708,7 +711,7 @@
708
711
  "operation": "updateDatabase",
709
712
  "producerOperationId": "updateDatabase",
710
713
  "sourcePath": "src/TerraBase/Features/Management/UpdateManagedDatabaseEndpoint.cs",
711
- "sha256": "08120d2aa197b7739dfcdb471dd753f08a5f597e96a62c6631b710f7e148021b",
714
+ "sha256": "f34b3a239b785b303e333e5aafd4e5e1670e1411b71c0a085a5c183aa47beba3",
712
715
  "method": "PATCH",
713
716
  "pathTemplate": "/v1/projects/{project}/databases/{database}",
714
717
  "authorizationPolicy": "ApiKeyScopes.DatabasesWrite",
@@ -725,7 +728,7 @@
725
728
  "operation": "deleteDatabase",
726
729
  "producerOperationId": "deleteDatabase",
727
730
  "sourcePath": "src/TerraBase/Features/Management/DeleteManagedDatabaseEndpoint.cs",
728
- "sha256": "1f6c26915734fb2e8eefceb613b72a08952c72aafc95a83c658e8caec36f81da",
731
+ "sha256": "1bd3038277ac6397724921491e45b0efc824c0ff3e3cc3fe7261a2782c28bcc5",
729
732
  "method": "DELETE",
730
733
  "pathTemplate": "/v1/projects/{project}/databases/{database}",
731
734
  "authorizationPolicy": "ApiKeyScopes.DatabasesWrite",
package/src/index.js CHANGED
@@ -15,11 +15,14 @@ export {
15
15
  V1InvalidKeyError,
16
16
  V1ForbiddenScopeError,
17
17
  V1NotFoundError,
18
+ SqlError,
18
19
  V1ErrorCode,
19
20
  isTerraBaseV1Error,
20
21
  } from "./v1/errors.js";
21
22
  export { v1Filter } from "./v1/filter.js";
22
23
  export { V1ShapeSubscription } from "./v1/shape-subscription.js";
24
+ export { indexedDbShapeReplica } from "./v1/shape-replica.js";
25
+ /** @typedef {import("./v1/shape-subscription.js").V1ShapeReplicaStore} V1ShapeReplicaStore */
23
26
  /** @typedef {import("./v1/shape-subscription.js").V1ShapeSubscribeOptions} V1ShapeSubscribeOptions */
24
27
  /** @typedef {import("./v1/shape-subscription.js").V1ShapeDocument} V1ShapeDocument */
25
28
  /** @typedef {import("./v1/shape-reader.js").V1SealedShapePosition} V1SealedShapePosition */
@@ -38,6 +41,10 @@ export { ExactDecimal } from "./v1/json.js";
38
41
  /** @typedef {import("./v1/terrabase-v1.js").V1Patch} V1Patch */
39
42
  /** @typedef {import("./v1/terrabase-v1.js").V1SortKey} V1SortKey */
40
43
  /** @typedef {import("./v1/terrabase-v1.js").V1NearSortKey} V1NearSortKey */
44
+ /** @typedef {import("./v1/terrabase-v1.js").V1GeoNearSortKey} V1GeoNearSortKey */
45
+ /** @typedef {import("./v1/terrabase-v1.js").V1Aggregate} V1Aggregate */
46
+ /** @typedef {import("./v1/terrabase-v1.js").V1Group} V1Group */
47
+ /** @typedef {import("./v1/terrabase-v1.js").V1ScoreSortKey} V1ScoreSortKey */
41
48
  /** @typedef {import("./v1/terrabase-v1.js").V1Query} V1Query */
42
49
  /** @typedef {import("./v1/terrabase-v1.js").V1Count} V1Count */
43
50
  /** @typedef {import("./v1/terrabase-v1.js").V1QueryPage} V1QueryPage */
@@ -51,6 +58,8 @@ export { ExactDecimal } from "./v1/json.js";
51
58
  /** @typedef {import("./v1/filter.js").V1Filter} V1Filter */
52
59
  /** @typedef {import("./v1/filter.js").V1Path} V1Path */
53
60
  /** @typedef {import("./v1/filter.js").V1Scalar} V1Scalar */
61
+ /** @typedef {import("./v1/filter.js").V1GeoCircle} V1GeoCircle */
62
+ /** @typedef {import("./v1/filter.js").V1GeoBox} V1GeoBox */
54
63
  /** @typedef {import("./v1/json.js").JsonValue} V1JsonValue */
55
64
  /** @typedef {import("./v1/json.js").JsonObject} V1JsonObject */
56
65
  /** @typedef {import("./v1/json.js").JsonInput} V1JsonInput */
@@ -76,6 +85,12 @@ export { V1SavedQueries } from "./v1/saved-queries.js";
76
85
  /** @typedef {import("./v1/sql.js").V1SqlResult} V1SqlResult */
77
86
  /** @typedef {import("./v1/sql.js").V1SqlIndexSuggestion} V1SqlIndexSuggestion */
78
87
  /** @typedef {import("./v1/sql.js").V1SqlCheck} V1SqlCheck */
88
+ /** @typedef {import("./v1/sql-execute.js").V1SqlArgument} V1SqlArgument */
89
+ /** @typedef {import("./v1/sql-execute.js").V1SqlArguments} V1SqlArguments */
90
+ /** @typedef {import("./v1/sql-execute.js").V1SqlStatement} V1SqlStatement */
91
+ /** @typedef {import("./v1/sql-execute.js").V1SqlValue} V1SqlValue */
92
+ /** @typedef {import("./v1/sql-execute.js").V1SqlColumn} V1SqlColumn */
93
+ /** @typedef {import("./v1/sql-execute.js").V1SqlExecuteResult} V1SqlExecuteResult */
79
94
  /** @typedef {import("./v1/changes.js").V1ChangeStreamRequest} V1ChangeStreamRequest */
80
95
  /** @typedef {import("./v1/changes.js").V1DatabaseChange} V1DatabaseChange */
81
96
  /** @typedef {import("./v1/changes.js").V1DatabaseChangeCursor} V1DatabaseChangeCursor */
@@ -99,6 +114,7 @@ export { V1DatabaseSchemaClient } from "./v1/database-schema.js";
99
114
 
100
115
  export { V1Indexes } from "./v1/indexes.js";
101
116
  /** @typedef {import("./v1/indexes.js").V1Index} V1Index */
117
+ /** @typedef {import("./v1/indexes.js").V1IndexKind} V1IndexKind */
102
118
  /** @typedef {import("./v1/indexes.js").V1IndexList} V1IndexList */
103
119
  /** @typedef {import("./v1/indexes.js").V1AutoIndexPolicy} V1AutoIndexPolicy */
104
120
  /** @typedef {import("./v1/indexes.js").V1IndexRecommendations} V1IndexRecommendations */
@@ -114,6 +130,11 @@ export { V1ProjectUsageClient, V1DatabaseUsageClient } from "./v1/usage.js";
114
130
  /** @typedef {import("./v1/usage.js").V1AnalyticsRequest} V1AnalyticsRequest */
115
131
 
116
132
  export { V1Backups, V1BackupDestinationClient } from "./v1/backups.js";
133
+ export { V1ChangeWebhooks } from "./v1/change-webhooks.js";
134
+ /** @typedef {import("./v1/change-webhooks.js").V1ChangeWebhook} V1ChangeWebhook */
135
+ /** @typedef {import("./v1/change-webhooks.js").V1CreatedChangeWebhook} V1CreatedChangeWebhook */
136
+ /** @typedef {import("./v1/change-webhooks.js").V1ChangeWebhookDelivery} V1ChangeWebhookDelivery */
137
+ /** @typedef {import("./v1/change-webhooks.js").V1ChangeWebhookListRequest} V1ChangeWebhookListRequest */
117
138
  /** @typedef {import("./v1/backups.js").V1Backup} V1Backup */
118
139
  /** @typedef {import("./v1/backups.js").V1BackupPage} V1BackupPage */
119
140
  /** @typedef {import("./v1/backups.js").V1BackupPolicy} V1BackupPolicy */
@@ -1,4 +1,4 @@
1
- import { generateId } from "../ids.js";
1
+ import { generateId, isValidId } from "../ids.js";
2
2
  import {
3
3
  createHash,
4
4
  createHmac,
@@ -171,7 +171,7 @@ export class TerraScaleLocalRouter {
171
171
  );
172
172
  if (match === null) return problemResponse(404, "unknown_route");
173
173
  const collection = requireDatabaseId(match[1]);
174
- const document = requireDatabaseId(match[2]);
174
+ const document = documentId(match[2]);
175
175
  return await this.#store.exclusive(() => {
176
176
  this.#binding(collection);
177
177
  return jsonResponse(this.#point(collection, document));
@@ -752,6 +752,15 @@ function transactionKey(raw) {
752
752
  const id = object(raw.transaction_id);
753
753
  return `${text(id.expires_at_unix_ms)}:${text(id.nonce)}`;
754
754
  }
755
+ /**
756
+ * @param {unknown} value
757
+ * @returns {string}
758
+ */
759
+ function documentId(value) {
760
+ if (!isValidId(value)) throw new NativeLocalError(400, "invalid_document_id");
761
+ return value;
762
+ }
763
+
755
764
  /**
756
765
  * @param {unknown} value
757
766
  * @returns {readonly DatabaseField[]}
@@ -815,7 +824,7 @@ function decodeCommit(raw) {
815
824
  collection: requireDatabaseId(write.collection),
816
825
  schema_generation: decimal(write.schema_generation),
817
826
  schema_digest: text(write.schema_digest),
818
- document: requireDatabaseId(write.document),
827
+ document: documentId(write.document),
819
828
  condition: /** @type {DatabaseCondition} */ (parsedCondition),
820
829
  observed: write.observed.map((rawObserved) => {
821
830
  const observed = object(rawObserved);