@reddb-io/sdk 1.23.1-rc.340 → 1.23.1-rc.342

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reddb-io/sdk",
3
- "version": "1.23.1-rc.340",
3
+ "version": "1.23.1-rc.342",
4
4
  "description": "Official embedded RedDB SDK — launches a local red binary over stdio JSON-RPC. Use @reddb-io/client for remote HTTP, gRPC, and RedWire.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -52,6 +52,9 @@ export const HELPER_SPEC_VERSION = '1.0'
52
52
 
53
53
  const MIN_INSERT_ID_ENGINE_VERSION = '1.0.9'
54
54
  const NESTED_TX_NOT_SUPPORTED = 'NESTED_TX_NOT_SUPPORTED'
55
+ const MIN_I64 = -(1n << 63n)
56
+ const MAX_I64 = (1n << 63n) - 1n
57
+ const MAX_U64 = (1n << 64n) - 1n
55
58
 
56
59
  /**
57
60
  * Connect to a RedDB instance.
@@ -94,6 +97,9 @@ export async function connect(uri, options = {}) {
94
97
  // stdio/HTTP query parameter envelopes.
95
98
  function serializeParam(value) {
96
99
  assertSupportedParam(value)
100
+ if (typeof value === 'bigint') {
101
+ return exactIntegerEnvelope(value)
102
+ }
97
103
  if (value instanceof Float32Array || value instanceof Float64Array) {
98
104
  return Array.from(value)
99
105
  }
@@ -113,10 +119,39 @@ function serializeParam(value) {
113
119
  return value
114
120
  }
115
121
 
122
+ function serializeJsonValue(value) {
123
+ if (typeof value === 'bigint') {
124
+ return exactIntegerEnvelope(value)
125
+ }
126
+ if (Array.isArray(value)) {
127
+ return value.map(serializeJsonValue)
128
+ }
129
+ if (value && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype) {
130
+ if ('$number' in value || '$decimalText' in value) {
131
+ throw new RedDBError('UNSUPPORTED_EXACT_NUMBER', 'superseded exact-number envelope')
132
+ }
133
+ const out = {}
134
+ for (const [key, item] of Object.entries(value)) out[key] = serializeJsonValue(item)
135
+ return out
136
+ }
137
+ return value
138
+ }
139
+
140
+ function exactIntegerEnvelope(value) {
141
+ if (value >= MIN_I64 && value <= MAX_I64) {
142
+ return { $int: value.toString() }
143
+ }
144
+ if (value >= 0n && value <= MAX_U64) {
145
+ return { $uint: value.toString() }
146
+ }
147
+ throw new RedDBError('UNSUPPORTED_PARAM', 'integer value is outside i64/u64 range')
148
+ }
149
+
116
150
  function assertSupportedParam(value) {
117
151
  if (value == null) return
118
152
  if (
119
153
  typeof value === 'boolean'
154
+ || typeof value === 'bigint'
120
155
  || typeof value === 'number'
121
156
  || typeof value === 'string'
122
157
  ) {
@@ -199,6 +234,13 @@ function normalizeResult(value) {
199
234
  if (value.$float === 'Infinity' || value.$float === '+Infinity') return Infinity
200
235
  if (value.$float === '-Infinity') return -Infinity
201
236
  }
237
+ if (typeof value.$int === 'string' || typeof value.$uint === 'string') {
238
+ return BigInt(value.$int ?? value.$uint)
239
+ }
240
+ if (typeof value.$decimal === 'string') return value.$decimal
241
+ if ('$number' in value || '$decimalText' in value) {
242
+ throw new RedDBError('UNSUPPORTED_EXACT_NUMBER', 'superseded exact-number envelope')
243
+ }
202
244
  if (typeof value.$ts === 'string' || typeof value.$ts === 'number') {
203
245
  const raw = typeof value.$ts === 'string'
204
246
  ? BigInt(value.$ts)
@@ -459,7 +501,10 @@ export class RedDB {
459
501
 
460
502
  /** Insert one row. Returns `{ affected, rid, id }`; `id` is a legacy alias. */
461
503
  async insert(collection, payload) {
462
- const result = await this.client.call('insert', { collection, payload })
504
+ const result = await this.client.call('insert', {
505
+ collection,
506
+ payload: serializeJsonValue(payload),
507
+ }).then(normalizeResult)
463
508
  return requireInsertId(result, 'insert')
464
509
  }
465
510
 
@@ -469,7 +514,10 @@ export class RedDB {
469
514
  if (Array.isArray(payloads) && payloads.length === 0) {
470
515
  return { affected: 0, rids: [], ids: [] }
471
516
  }
472
- const result = await this.client.call('bulk_insert', { collection, payloads })
517
+ const result = await this.client.call('bulk_insert', {
518
+ collection,
519
+ payloads: serializeJsonValue(payloads),
520
+ }).then(normalizeResult)
473
521
  return requireInsertIds(result, payloads.length)
474
522
  }
475
523
 
@@ -529,7 +577,7 @@ export class RedDB {
529
577
 
530
578
  /** Get an entity by id. Returns `{ entity }` (entity is `null` if not found). */
531
579
  get(collection, id) {
532
- return this.client.call('get', { collection, id: String(id) })
580
+ return this.client.call('get', { collection, id: String(id) }).then(normalizeResult)
533
581
  }
534
582
 
535
583
  /** Delete an entity by id. Returns `{ affected }`. */
package/src/redwire.js CHANGED
@@ -55,6 +55,9 @@ export const ValueTag = Object.freeze({
55
55
  Bytes: 0x05, Vector: 0x06, Json: 0x07, Timestamp: 0x08, Uuid: 0x09,
56
56
  })
57
57
 
58
+ const MIN_I64 = -(1n << 63n)
59
+ const MAX_I64 = (1n << 63n) - 1n
60
+
58
61
  /**
59
62
  * Typed value tags for the binary fast path. Identical to the
60
63
  * engine-side `wire::protocol::VAL_*` table.
@@ -809,10 +812,7 @@ export function encodeValue(v) {
809
812
  if (v === null || v === undefined) return Uint8Array.of(ValueTag.Null)
810
813
  if (typeof v === 'boolean') return Uint8Array.of(ValueTag.Bool, v ? 1 : 0)
811
814
  if (typeof v === 'bigint') {
812
- const out = new Uint8Array(1 + 8)
813
- out[0] = ValueTag.Int
814
- new DataView(out.buffer).setBigInt64(1, v, true)
815
- return out
815
+ return encodeInt(v)
816
816
  }
817
817
  if (typeof v === 'number') {
818
818
  if (Number.isInteger(v) && v >= -(2 ** 53) && v <= 2 ** 53) {
@@ -840,6 +840,12 @@ export function encodeValue(v) {
840
840
  const keys = Object.keys(v)
841
841
  if (keys.length === 1) {
842
842
  const k = keys[0]
843
+ if (k === '$int' && typeof v.$int === 'string') {
844
+ return encodeInt(BigInt(v.$int))
845
+ }
846
+ if (k === '$uint' || k === '$decimal') {
847
+ throw new RedDBError('UNSUPPORTED_PARAM', `${k} params require a JSON body transport`)
848
+ }
843
849
  if (k === '$bytes' && typeof v.$bytes === 'string') {
844
850
  return encodeLenPrefixed(ValueTag.Bytes, base64ToBytes(v.$bytes))
845
851
  }
@@ -866,6 +872,16 @@ export function encodeValue(v) {
866
872
  throw new RedDBError('UNSUPPORTED_PARAM', `cannot encode param of type ${typeof v}`)
867
873
  }
868
874
 
875
+ function encodeInt(value) {
876
+ if (value < MIN_I64 || value > MAX_I64) {
877
+ throw new RedDBError('UNSUPPORTED_PARAM', 'integer param is outside i64 range')
878
+ }
879
+ const out = new Uint8Array(1 + 8)
880
+ out[0] = ValueTag.Int
881
+ new DataView(out.buffer).setBigInt64(1, value, true)
882
+ return out
883
+ }
884
+
869
885
  function encodeLenPrefixed(tag, bytes) {
870
886
  if (bytes.length > MAX_VALUE_PAYLOAD_LEN) {
871
887
  throw new RedDBError('PAYLOAD_TOO_LARGE', `value len ${bytes.length} > ${MAX_VALUE_PAYLOAD_LEN}`)