spacetimedb 1.11.2 → 1.11.4

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.
Files changed (75) hide show
  1. package/LICENSE.txt +2 -2
  2. package/dist/browser/react/index.mjs +307 -4
  3. package/dist/browser/react/index.mjs.map +1 -1
  4. package/dist/index.browser.mjs +424 -1
  5. package/dist/index.browser.mjs.map +1 -1
  6. package/dist/index.cjs +429 -0
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.ts +2 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.mjs +424 -1
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/lib/algebraic_type.d.ts.map +1 -1
  13. package/dist/lib/indexes.d.ts +1 -1
  14. package/dist/lib/indexes.d.ts.map +1 -1
  15. package/dist/lib/procedures.d.ts +6 -0
  16. package/dist/lib/procedures.d.ts.map +1 -1
  17. package/dist/lib/reducers.d.ts +4 -1
  18. package/dist/lib/reducers.d.ts.map +1 -1
  19. package/dist/lib/result.d.ts +20 -0
  20. package/dist/lib/result.d.ts.map +1 -0
  21. package/dist/lib/schema.d.ts.map +1 -1
  22. package/dist/lib/table.d.ts +2 -2
  23. package/dist/lib/table.d.ts.map +1 -1
  24. package/dist/lib/timestamp.d.ts +2 -0
  25. package/dist/lib/timestamp.d.ts.map +1 -1
  26. package/dist/lib/type_builders.d.ts +42 -0
  27. package/dist/lib/type_builders.d.ts.map +1 -1
  28. package/dist/lib/uuid.d.ts +179 -0
  29. package/dist/lib/uuid.d.ts.map +1 -0
  30. package/dist/min/index.browser.mjs +1 -1
  31. package/dist/min/index.browser.mjs.map +1 -1
  32. package/dist/min/react/index.mjs +1 -1
  33. package/dist/min/react/index.mjs.map +1 -1
  34. package/dist/min/sdk/index.browser.mjs +1 -1
  35. package/dist/min/sdk/index.browser.mjs.map +1 -1
  36. package/dist/react/index.cjs +307 -4
  37. package/dist/react/index.cjs.map +1 -1
  38. package/dist/react/index.mjs +307 -4
  39. package/dist/react/index.mjs.map +1 -1
  40. package/dist/sdk/index.browser.mjs +424 -1
  41. package/dist/sdk/index.browser.mjs.map +1 -1
  42. package/dist/sdk/index.cjs +427 -0
  43. package/dist/sdk/index.cjs.map +1 -1
  44. package/dist/sdk/index.mjs +424 -1
  45. package/dist/sdk/index.mjs.map +1 -1
  46. package/dist/sdk/table_cache.d.ts +2 -2
  47. package/dist/sdk/table_cache.d.ts.map +1 -1
  48. package/dist/server/errors.d.ts +20 -20
  49. package/dist/server/index.cjs +599 -64
  50. package/dist/server/index.cjs.map +1 -1
  51. package/dist/server/index.d.ts +2 -0
  52. package/dist/server/index.d.ts.map +1 -1
  53. package/dist/server/index.mjs +595 -65
  54. package/dist/server/index.mjs.map +1 -1
  55. package/dist/server/procedures.d.ts.map +1 -1
  56. package/dist/server/runtime.d.ts +40 -3
  57. package/dist/server/runtime.d.ts.map +1 -1
  58. package/package.json +2 -2
  59. package/src/index.ts +2 -0
  60. package/src/lib/algebraic_type.ts +61 -0
  61. package/src/lib/indexes.ts +1 -1
  62. package/src/lib/procedures.ts +4 -0
  63. package/src/lib/reducers.ts +4 -1
  64. package/src/lib/result.ts +36 -0
  65. package/src/lib/schema.ts +6 -0
  66. package/src/lib/table.ts +2 -2
  67. package/src/lib/timestamp.ts +5 -0
  68. package/src/lib/type_builders.ts +219 -0
  69. package/src/lib/uuid.ts +337 -0
  70. package/src/react/useTable.ts +5 -4
  71. package/src/sdk/table_cache.ts +10 -7
  72. package/src/server/index.ts +2 -0
  73. package/src/server/procedures.ts +30 -3
  74. package/src/server/runtime.ts +128 -71
  75. package/src/server/view.test-d.ts +1 -0
package/LICENSE.txt CHANGED
@@ -5,7 +5,7 @@ Business Source License 1.1
5
5
  Parameters
6
6
 
7
7
  Licensor: Clockwork Laboratories, Inc.
8
- Licensed Work: SpacetimeDB 1.11.1
8
+ Licensed Work: SpacetimeDB 1.11.2
9
9
  The Licensed Work is
10
10
  (c) 2023 Clockwork Laboratories, Inc.
11
11
 
@@ -21,7 +21,7 @@ Additional Use Grant: You may make use of the Licensed Work provided your
21
21
  Licensed Work by creating tables whose schemas are
22
22
  controlled by such third parties.
23
23
 
24
- Change Date: 2030-12-18
24
+ Change Date: 2031-01-08
25
25
 
26
26
  Change License: GNU Affero General Public License v3.0 with a linking
27
27
  exception
@@ -99,6 +99,10 @@ var Timestamp = class _Timestamp {
99
99
  static now() {
100
100
  return _Timestamp.fromDate(/* @__PURE__ */ new Date());
101
101
  }
102
+ /** Convert to milliseconds since Unix epoch. */
103
+ toMillis() {
104
+ return this.microsSinceUnixEpoch / 1000n;
105
+ }
102
106
  /**
103
107
  * Get a `Timestamp` representing the same point in time as `date`.
104
108
  */
@@ -129,6 +133,257 @@ var Timestamp = class _Timestamp {
129
133
  );
130
134
  }
131
135
  };
136
+
137
+ // src/lib/uuid.ts
138
+ var Uuid = class _Uuid {
139
+ __uuid__;
140
+ /**
141
+ * The nil UUID (all zeros).
142
+ *
143
+ * @example
144
+ * ```ts
145
+ * const uuid = Uuid.NIL;
146
+ * console.assert(
147
+ * uuid.toString() === "00000000-0000-0000-0000-000000000000"
148
+ * );
149
+ * ```
150
+ */
151
+ static NIL = new _Uuid(0n);
152
+ static MAX_UUID_BIGINT = 0xffffffffffffffffffffffffffffffffn;
153
+ /**
154
+ * The max UUID (all ones).
155
+ *
156
+ * @example
157
+ * ```ts
158
+ * const uuid = Uuid.MAX;
159
+ * console.assert(
160
+ * uuid.toString() === "ffffffff-ffff-ffff-ffff-ffffffffffff"
161
+ * );
162
+ * ```
163
+ */
164
+ static MAX = new _Uuid(_Uuid.MAX_UUID_BIGINT);
165
+ /**
166
+ * Create a UUID from a raw 128-bit value.
167
+ *
168
+ * @param u - Unsigned 128-bit integer
169
+ * @throws {Error} If the value is outside the valid UUID range
170
+ */
171
+ constructor(u) {
172
+ if (u < 0n || u > _Uuid.MAX_UUID_BIGINT) {
173
+ throw new Error("Invalid UUID: must be between 0 and `MAX_UUID_BIGINT`");
174
+ }
175
+ this.__uuid__ = u;
176
+ }
177
+ /**
178
+ * Create a UUID `v4` from explicit random bytes.
179
+ *
180
+ * This method assumes the bytes are already sufficiently random.
181
+ * It only sets the appropriate bits for the UUID version and variant.
182
+ *
183
+ * @param bytes - Exactly 16 random bytes
184
+ * @returns A UUID `v4`
185
+ * @throws {Error} If `bytes.length !== 16`
186
+ *
187
+ * @example
188
+ * ```ts
189
+ * const randomBytes = new Uint8Array(16);
190
+ * const uuid = Uuid.fromRandomBytesV4(randomBytes);
191
+ *
192
+ * console.assert(
193
+ * uuid.toString() === "00000000-0000-4000-8000-000000000000"
194
+ * );
195
+ * ```
196
+ */
197
+ static fromRandomBytesV4(bytes) {
198
+ if (bytes.length !== 16) throw new Error("UUID v4 requires 16 bytes");
199
+ const arr = new Uint8Array(bytes);
200
+ arr[6] = arr[6] & 15 | 64;
201
+ arr[8] = arr[8] & 63 | 128;
202
+ return new _Uuid(_Uuid.bytesToBigInt(arr));
203
+ }
204
+ /**
205
+ * Generate a UUID `v7` using a monotonic counter from `0` to `2^31 - 1`,
206
+ * a timestamp, and 4 random bytes.
207
+ *
208
+ * The counter wraps around on overflow.
209
+ *
210
+ * The UUID `v7` is structured as follows:
211
+ *
212
+ * ```ascii
213
+ * ┌───────────────────────────────────────────────┬───────────────────┐
214
+ * | B0 | B1 | B2 | B3 | B4 | B5 | B6 |
215
+ * ├───────────────────────────────────────────────┼───────────────────┤
216
+ * | unix_ts_ms | version 7 |
217
+ * └───────────────────────────────────────────────┴───────────────────┘
218
+ * ┌──────────────┬─────────┬──────────────────┬───────────────────────┐
219
+ * | B7 | B8 | B9 | B10 | B11 | B12 | B13 | B14 | B15 |
220
+ * ├──────────────┼─────────┼──────────────────┼───────────────────────┤
221
+ * | counter_high | variant | counter_low | random |
222
+ * └──────────────┴─────────┴──────────────────┴───────────────────────┘
223
+ * ```
224
+ *
225
+ * @param counter - Mutable monotonic counter (31-bit)
226
+ * @param now - Timestamp since the Unix epoch
227
+ * @param randomBytes - Exactly 4 random bytes
228
+ * @returns A UUID `v7`
229
+ *
230
+ * @throws {Error} If the `counter` is negative
231
+ * @throws {Error} If the `timestamp` is before the Unix epoch
232
+ * @throws {Error} If `randomBytes.length !== 4`
233
+ *
234
+ * @example
235
+ * ```ts
236
+ * const now = Timestamp.fromMillis(1_686_000_000_000n);
237
+ * const counter = { value: 1 };
238
+ * const randomBytes = new Uint8Array(4);
239
+ *
240
+ * const uuid = Uuid.fromCounterV7(counter, now, randomBytes);
241
+ *
242
+ * console.assert(
243
+ * uuid.toString() === "0000647e-5180-7000-8000-000200000000"
244
+ * );
245
+ * ```
246
+ */
247
+ static fromCounterV7(counter, now, randomBytes) {
248
+ if (randomBytes.length !== 4) {
249
+ throw new Error("`fromCounterV7` requires `randomBytes.length == 4`");
250
+ }
251
+ if (counter.value < 0) {
252
+ throw new Error("`fromCounterV7` uuid `counter` must be non-negative");
253
+ }
254
+ if (now.__timestamp_micros_since_unix_epoch__ < 0) {
255
+ throw new Error("`fromCounterV7` `timestamp` before unix epoch");
256
+ }
257
+ const counterVal = counter.value;
258
+ counter.value = counterVal + 1 & 2147483647;
259
+ const tsMs = now.toMillis() & 0xffffffffffffn;
260
+ const bytes = new Uint8Array(16);
261
+ bytes[0] = Number(tsMs >> 40n & 0xffn);
262
+ bytes[1] = Number(tsMs >> 32n & 0xffn);
263
+ bytes[2] = Number(tsMs >> 24n & 0xffn);
264
+ bytes[3] = Number(tsMs >> 16n & 0xffn);
265
+ bytes[4] = Number(tsMs >> 8n & 0xffn);
266
+ bytes[5] = Number(tsMs & 0xffn);
267
+ bytes[7] = counterVal >>> 23 & 255;
268
+ bytes[9] = counterVal >>> 15 & 255;
269
+ bytes[10] = counterVal >>> 7 & 255;
270
+ bytes[11] = (counterVal & 127) << 1 & 255;
271
+ bytes[12] |= randomBytes[0] & 127;
272
+ bytes[13] = randomBytes[1];
273
+ bytes[14] = randomBytes[2];
274
+ bytes[15] = randomBytes[3];
275
+ bytes[6] = bytes[6] & 15 | 112;
276
+ bytes[8] = bytes[8] & 63 | 128;
277
+ return new _Uuid(_Uuid.bytesToBigInt(bytes));
278
+ }
279
+ /**
280
+ * Parse a UUID from a string representation.
281
+ *
282
+ * @param s - UUID string
283
+ * @returns Parsed UUID
284
+ * @throws {Error} If the string is not a valid UUID
285
+ *
286
+ * @example
287
+ * ```ts
288
+ * const s = "01888d6e-5c00-7000-8000-000000000000";
289
+ * const uuid = Uuid.parse(s);
290
+ *
291
+ * console.assert(uuid.toString() === s);
292
+ * ```
293
+ */
294
+ static parse(s) {
295
+ const hex = s.replace(/-/g, "");
296
+ if (hex.length !== 32) throw new Error("Invalid hex UUID");
297
+ let v = 0n;
298
+ for (let i = 0; i < 32; i += 2) {
299
+ v = v << 8n | BigInt(parseInt(hex.slice(i, i + 2), 16));
300
+ }
301
+ return new _Uuid(v);
302
+ }
303
+ /** Convert to string (hyphenated form). */
304
+ toString() {
305
+ const bytes = _Uuid.bigIntToBytes(this.__uuid__);
306
+ const hex = [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
307
+ return hex.slice(0, 8) + "-" + hex.slice(8, 12) + "-" + hex.slice(12, 16) + "-" + hex.slice(16, 20) + "-" + hex.slice(20);
308
+ }
309
+ /** Convert to bigint (u128). */
310
+ asBigInt() {
311
+ return this.__uuid__;
312
+ }
313
+ /** Return a `Uint8Array` of 16 bytes. */
314
+ toBytes() {
315
+ return _Uuid.bigIntToBytes(this.__uuid__);
316
+ }
317
+ static bytesToBigInt(bytes) {
318
+ let result = 0n;
319
+ for (const b of bytes) result = result << 8n | BigInt(b);
320
+ return result;
321
+ }
322
+ static bigIntToBytes(value) {
323
+ const bytes = new Uint8Array(16);
324
+ for (let i = 15; i >= 0; i--) {
325
+ bytes[i] = Number(value & 0xffn);
326
+ value >>= 8n;
327
+ }
328
+ return bytes;
329
+ }
330
+ /**
331
+ * Returns the version of this UUID.
332
+ *
333
+ * This represents the algorithm used to generate the value.
334
+ *
335
+ * @returns A `UuidVersion`
336
+ * @throws {Error} If the version field is not recognized
337
+ */
338
+ getVersion() {
339
+ const version = this.toBytes()[6] >> 4 & 15;
340
+ switch (version) {
341
+ case 4:
342
+ return "V4";
343
+ case 7:
344
+ return "V7";
345
+ default:
346
+ if (this == _Uuid.NIL) {
347
+ return "Nil";
348
+ }
349
+ if (this == _Uuid.MAX) {
350
+ return "Max";
351
+ }
352
+ throw new Error(`Unsupported UUID version: ${version}`);
353
+ }
354
+ }
355
+ /**
356
+ * Extract the monotonic counter from a UUIDv7.
357
+ *
358
+ * Intended for testing and diagnostics.
359
+ * Behavior is undefined if called on a non-V7 UUID.
360
+ *
361
+ * @returns 31-bit counter value
362
+ */
363
+ getCounter() {
364
+ const bytes = this.toBytes();
365
+ const high = bytes[7];
366
+ const mid1 = bytes[9];
367
+ const mid2 = bytes[10];
368
+ const low = bytes[11] >>> 1;
369
+ return high << 23 | mid1 << 15 | mid2 << 7 | low | 0;
370
+ }
371
+ compareTo(other) {
372
+ if (this.__uuid__ < other.__uuid__) return -1;
373
+ if (this.__uuid__ > other.__uuid__) return 1;
374
+ return 0;
375
+ }
376
+ static getAlgebraicType() {
377
+ return AlgebraicType.Product({
378
+ elements: [
379
+ {
380
+ name: "__uuid__",
381
+ algebraicType: AlgebraicType.U128
382
+ }
383
+ ]
384
+ });
385
+ }
386
+ };
132
387
  var BinaryWriter = class {
133
388
  #buffer;
134
389
  #view;
@@ -753,6 +1008,9 @@ var ProductType = {
753
1008
  if (ty.elements[0].name === "__connection_id__") {
754
1009
  return new ConnectionId(reader.readU128());
755
1010
  }
1011
+ if (ty.elements[0].name === "__uuid__") {
1012
+ return new Uuid(reader.readU128());
1013
+ }
756
1014
  }
757
1015
  for (const element of ty.elements) {
758
1016
  result[element.name] = AlgebraicType.deserializeValue(
@@ -777,6 +1035,9 @@ var ProductType = {
777
1035
  if (ty.elements[0].name === "__connection_id__") {
778
1036
  return value.__connection_id__;
779
1037
  }
1038
+ if (ty.elements[0].name === "__uuid__") {
1039
+ return value.__uuid__;
1040
+ }
780
1041
  }
781
1042
  const writer = new BinaryWriter(10);
782
1043
  AlgebraicType.serializeValue(writer, AlgebraicType.Product(ty), value);
@@ -797,6 +1058,29 @@ var SumType = {
797
1058
  } else {
798
1059
  writer.writeByte(1);
799
1060
  }
1061
+ } else if (ty.variants.length == 2 && ty.variants[0].name === "ok" && ty.variants[1].name === "err") {
1062
+ let variantName;
1063
+ let innerValue;
1064
+ let index;
1065
+ if ("ok" in value) {
1066
+ variantName = "ok";
1067
+ innerValue = value.ok;
1068
+ index = 0;
1069
+ } else {
1070
+ variantName = "err";
1071
+ innerValue = value.err;
1072
+ index = 1;
1073
+ }
1074
+ if (index < 0) {
1075
+ throw `Result serialization error: variant '${variantName}' not found in ${JSON.stringify(ty)}`;
1076
+ }
1077
+ writer.writeU8(index);
1078
+ AlgebraicType.serializeValue(
1079
+ writer,
1080
+ ty.variants[index].algebraicType,
1081
+ innerValue,
1082
+ typespace
1083
+ );
800
1084
  } else {
801
1085
  const variant = value["tag"];
802
1086
  const index = ty.variants.findIndex((v) => v.name === variant);
@@ -826,6 +1110,24 @@ var SumType = {
826
1110
  } else {
827
1111
  throw `Can't deserialize an option type, couldn't find ${tag} tag`;
828
1112
  }
1113
+ } else if (ty.variants.length == 2 && ty.variants[0].name === "ok" && ty.variants[1].name === "err") {
1114
+ if (tag === 0) {
1115
+ const value = AlgebraicType.deserializeValue(
1116
+ reader,
1117
+ ty.variants[0].algebraicType,
1118
+ typespace
1119
+ );
1120
+ return { ok: value };
1121
+ } else if (tag === 1) {
1122
+ const value = AlgebraicType.deserializeValue(
1123
+ reader,
1124
+ ty.variants[1].algebraicType,
1125
+ typespace
1126
+ );
1127
+ return { err: value };
1128
+ } else {
1129
+ throw `Can't deserialize a result type, couldn't find ${tag} tag`;
1130
+ }
829
1131
  } else {
830
1132
  const variant = ty.variants[tag];
831
1133
  const value = AlgebraicType.deserializeValue(
@@ -1068,6 +1370,7 @@ function classifyMembership(where2, oldRow, newRow) {
1068
1370
  }
1069
1371
  function useTable(tableDef, whereClauseOrCallbacks, callbacks) {
1070
1372
  const tableName = tableDef.name;
1373
+ const accessorName = tableDef.accessorName;
1071
1374
  let whereClause;
1072
1375
  if (whereClauseOrCallbacks && typeof whereClauseOrCallbacks === "object" && "type" in whereClauseOrCallbacks) {
1073
1376
  whereClause = whereClauseOrCallbacks;
@@ -1092,12 +1395,12 @@ function useTable(tableDef, whereClauseOrCallbacks, callbacks) {
1092
1395
  if (!connection) {
1093
1396
  return [[], false];
1094
1397
  }
1095
- const table = connection.db[tableName];
1398
+ const table = connection.db[accessorName];
1096
1399
  const result = whereClause ? Array.from(table.iter()).filter(
1097
1400
  (row) => evaluate(whereClause, row)
1098
1401
  ) : Array.from(table.iter());
1099
1402
  return [result, subscribeApplied];
1100
- }, [connectionState, tableName, whereKey, subscribeApplied]);
1403
+ }, [connectionState, accessorName, whereKey, subscribeApplied]);
1101
1404
  useEffect(() => {
1102
1405
  const connection = connectionState.getConnection();
1103
1406
  if (connectionState.isActive && connection) {
@@ -1159,7 +1462,7 @@ function useTable(tableDef, whereClauseOrCallbacks, callbacks) {
1159
1462
  return () => {
1160
1463
  };
1161
1464
  }
1162
- const table = connection.db[tableName];
1465
+ const table = connection.db[accessorName];
1163
1466
  table.onInsert(onInsert);
1164
1467
  table.onDelete(onDelete);
1165
1468
  table.onUpdate?.(onUpdate);
@@ -1172,7 +1475,7 @@ function useTable(tableDef, whereClauseOrCallbacks, callbacks) {
1172
1475
  // eslint-disable-next-line react-hooks/exhaustive-deps
1173
1476
  [
1174
1477
  connectionState,
1175
- tableName,
1478
+ accessorName,
1176
1479
  whereKey,
1177
1480
  callbacks?.onDelete,
1178
1481
  callbacks?.onInsert,