@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 +1 -1
- package/src/index.js +51 -3
- package/src/redwire.js +20 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reddb-io/sdk",
|
|
3
|
-
"version": "1.23.1-rc.
|
|
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', {
|
|
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', {
|
|
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
|
-
|
|
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}`)
|