@bjornpagen/bumbledb 0.20.3 → 1.0.1

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 (192) hide show
  1. package/COOKBOOK.md +283 -1611
  2. package/README.md +156 -118
  3. package/dist/capacity.d.ts +16 -12
  4. package/dist/capacity.d.ts.map +1 -1
  5. package/dist/capacity.js +16 -48
  6. package/dist/capacity.js.map +1 -1
  7. package/dist/changes.d.ts +54 -0
  8. package/dist/changes.d.ts.map +1 -0
  9. package/dist/changes.js +245 -0
  10. package/dist/changes.js.map +1 -0
  11. package/dist/close.d.ts +24 -0
  12. package/dist/close.d.ts.map +1 -0
  13. package/dist/close.js +34 -0
  14. package/dist/close.js.map +1 -0
  15. package/dist/closed.d.ts +1 -3
  16. package/dist/closed.d.ts.map +1 -1
  17. package/dist/closed.js +24 -12
  18. package/dist/closed.js.map +1 -1
  19. package/dist/codec.d.ts +56 -0
  20. package/dist/codec.d.ts.map +1 -0
  21. package/dist/codec.js +289 -0
  22. package/dist/codec.js.map +1 -0
  23. package/dist/compile.d.ts +67 -0
  24. package/dist/compile.d.ts.map +1 -0
  25. package/dist/compile.js +75 -0
  26. package/dist/compile.js.map +1 -0
  27. package/dist/db-native.d.ts +161 -0
  28. package/dist/db-native.d.ts.map +1 -0
  29. package/dist/db-native.js +5 -0
  30. package/dist/db-native.js.map +1 -0
  31. package/dist/db.d.ts +101 -233
  32. package/dist/db.d.ts.map +1 -1
  33. package/dist/db.js +232 -1084
  34. package/dist/db.js.map +1 -1
  35. package/dist/errors.d.ts +53 -0
  36. package/dist/errors.d.ts.map +1 -0
  37. package/dist/errors.js +28 -0
  38. package/dist/errors.js.map +1 -0
  39. package/dist/face.d.ts.map +1 -1
  40. package/dist/face.js +2 -2
  41. package/dist/face.js.map +1 -1
  42. package/dist/fields.d.ts +64 -24
  43. package/dist/fields.d.ts.map +1 -1
  44. package/dist/fields.js +94 -24
  45. package/dist/fields.js.map +1 -1
  46. package/dist/index.d.ts +37 -32
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +17 -21
  49. package/dist/index.js.map +1 -1
  50. package/dist/internal/log.d.ts +24 -0
  51. package/dist/internal/log.d.ts.map +1 -0
  52. package/dist/internal/log.js +10 -0
  53. package/dist/internal/log.js.map +1 -0
  54. package/dist/law.d.ts +8 -13
  55. package/dist/law.d.ts.map +1 -1
  56. package/dist/law.js +6 -59
  57. package/dist/law.js.map +1 -1
  58. package/dist/lower.d.ts +0 -13
  59. package/dist/lower.d.ts.map +1 -1
  60. package/dist/lower.js +9 -17
  61. package/dist/lower.js.map +1 -1
  62. package/dist/migration.d.ts +32 -0
  63. package/dist/migration.d.ts.map +1 -0
  64. package/dist/migration.js +47 -0
  65. package/dist/migration.js.map +1 -0
  66. package/dist/native.d.ts +256 -301
  67. package/dist/native.d.ts.map +1 -1
  68. package/dist/native.js +65 -108
  69. package/dist/native.js.map +1 -1
  70. package/dist/query/atom.d.ts +24 -13
  71. package/dist/query/atom.d.ts.map +1 -1
  72. package/dist/query/atom.js +7 -3
  73. package/dist/query/atom.js.map +1 -1
  74. package/dist/query/compute.d.ts +68 -0
  75. package/dist/query/compute.d.ts.map +1 -0
  76. package/dist/query/compute.js +141 -0
  77. package/dist/query/compute.js.map +1 -0
  78. package/dist/query/find.d.ts +15 -8
  79. package/dist/query/find.d.ts.map +1 -1
  80. package/dist/query/find.js +6 -2
  81. package/dist/query/find.js.map +1 -1
  82. package/dist/query/lower.d.ts +23 -2
  83. package/dist/query/lower.d.ts.map +1 -1
  84. package/dist/query/lower.js +433 -80
  85. package/dist/query/lower.js.map +1 -1
  86. package/dist/query/parse-ir.d.ts.map +1 -1
  87. package/dist/query/parse-ir.js +17 -8
  88. package/dist/query/parse-ir.js.map +1 -1
  89. package/dist/query/run.d.ts +12 -2
  90. package/dist/query/run.d.ts.map +1 -1
  91. package/dist/query/run.js +26 -9
  92. package/dist/query/run.js.map +1 -1
  93. package/dist/query/scope.d.ts +47 -3
  94. package/dist/query/scope.d.ts.map +1 -1
  95. package/dist/query/scope.js +83 -19
  96. package/dist/query/scope.js.map +1 -1
  97. package/dist/relation.d.ts +3 -8
  98. package/dist/relation.d.ts.map +1 -1
  99. package/dist/relation.js +16 -10
  100. package/dist/relation.js.map +1 -1
  101. package/dist/result.d.ts +47 -0
  102. package/dist/result.d.ts.map +1 -0
  103. package/dist/result.js +50 -0
  104. package/dist/result.js.map +1 -0
  105. package/dist/rows.d.ts +69 -0
  106. package/dist/rows.d.ts.map +1 -0
  107. package/dist/rows.js +325 -0
  108. package/dist/rows.js.map +1 -0
  109. package/dist/runtime-codes.d.ts +2 -0
  110. package/dist/runtime-codes.d.ts.map +1 -0
  111. package/dist/runtime-codes.js +19 -0
  112. package/dist/runtime-codes.js.map +1 -0
  113. package/dist/runtime-errors.d.ts +106 -0
  114. package/dist/runtime-errors.d.ts.map +1 -0
  115. package/dist/runtime-errors.js +62 -0
  116. package/dist/runtime-errors.js.map +1 -0
  117. package/dist/runtime-native.d.ts +159 -0
  118. package/dist/runtime-native.d.ts.map +1 -0
  119. package/dist/runtime-native.js +5 -0
  120. package/dist/runtime-native.js.map +1 -0
  121. package/dist/runtime.d.ts +73 -0
  122. package/dist/runtime.d.ts.map +1 -0
  123. package/dist/runtime.js +292 -0
  124. package/dist/runtime.js.map +1 -0
  125. package/dist/scalar.d.ts +165 -0
  126. package/dist/scalar.d.ts.map +1 -0
  127. package/dist/scalar.js +344 -0
  128. package/dist/scalar.js.map +1 -0
  129. package/dist/schema.d.ts +1 -1
  130. package/dist/schema.d.ts.map +1 -1
  131. package/dist/schema.js +34 -37
  132. package/dist/schema.js.map +1 -1
  133. package/dist/shape.d.ts +27 -0
  134. package/dist/shape.d.ts.map +1 -0
  135. package/dist/shape.js +2 -0
  136. package/dist/shape.js.map +1 -0
  137. package/dist/spec.d.ts +27 -3
  138. package/dist/spec.d.ts.map +1 -1
  139. package/dist/spec.js +22 -1
  140. package/dist/spec.js.map +1 -1
  141. package/dist/statements.d.ts +16 -3
  142. package/dist/statements.d.ts.map +1 -1
  143. package/dist/statements.js +54 -28
  144. package/dist/statements.js.map +1 -1
  145. package/dist/uuid.d.ts +23 -0
  146. package/dist/uuid.d.ts.map +1 -0
  147. package/dist/uuid.js +54 -0
  148. package/dist/uuid.js.map +1 -0
  149. package/pack-provenance.json +7 -0
  150. package/package.json +12 -16
  151. package/src/capacity.ts +34 -54
  152. package/src/changes.ts +361 -0
  153. package/src/close.ts +53 -0
  154. package/src/closed.ts +25 -19
  155. package/src/codec.ts +379 -0
  156. package/src/compile.ts +148 -0
  157. package/src/db-native.ts +238 -0
  158. package/src/db.ts +461 -1632
  159. package/src/errors.ts +46 -0
  160. package/src/face.ts +2 -2
  161. package/src/fields.ts +181 -55
  162. package/src/index.ts +62 -126
  163. package/src/internal/log.ts +49 -0
  164. package/src/law.ts +13 -28
  165. package/src/lower.ts +9 -4
  166. package/src/migration.ts +68 -0
  167. package/src/native.ts +326 -487
  168. package/src/query/atom.ts +61 -25
  169. package/src/query/compute.ts +237 -0
  170. package/src/query/find.ts +31 -12
  171. package/src/query/lower.ts +531 -143
  172. package/src/query/parse-ir.ts +18 -13
  173. package/src/query/run.ts +32 -16
  174. package/src/query/scope.ts +140 -8
  175. package/src/relation.ts +17 -21
  176. package/src/result.ts +130 -0
  177. package/src/rows.ts +401 -0
  178. package/src/runtime-codes.ts +18 -0
  179. package/src/runtime-errors.ts +69 -0
  180. package/src/runtime-native.ts +222 -0
  181. package/src/runtime.ts +439 -0
  182. package/src/scalar.ts +560 -0
  183. package/src/schema.ts +35 -37
  184. package/src/shape.ts +30 -0
  185. package/src/spec.ts +33 -3
  186. package/src/statements.ts +75 -68
  187. package/src/uuid.ts +69 -0
  188. package/dist/marshal.d.ts +0 -44
  189. package/dist/marshal.d.ts.map +0 -1
  190. package/dist/marshal.js +0 -165
  191. package/dist/marshal.js.map +0 -1
  192. package/src/marshal.ts +0 -200
package/src/errors.ts ADDED
@@ -0,0 +1,46 @@
1
+ import { Data } from "effect"
2
+
3
+ /**
4
+ * Pure authoring failures, SDK-invariant defects and internal native-boundary
5
+ * diagnostics. AST misuse can throw synchronously without I/O. Runtime
6
+ * adapters translate operational failures into the public `DbError` class
7
+ * in `#runtime-errors.ts`; contradictions in SDK/native state remain defects.
8
+ */
9
+
10
+ /** A pure schema, query, parameter, or value-authoring refusal. */
11
+ export class AuthoringError extends Data.TaggedError("AuthoringError")<{
12
+ readonly message: string
13
+ }> {}
14
+
15
+ /** A contradiction in an SDK/native result, not an application refusal. */
16
+ export class SdkInvariantError extends Data.TaggedError("SdkInvariantError")<{
17
+ readonly message: string
18
+ }> {}
19
+
20
+ export class NativeLoadError extends Data.TaggedError("NativeLoadError")<{
21
+ readonly package: string
22
+ readonly operation: "resolve" | "load"
23
+ readonly message: string
24
+ readonly cause: unknown
25
+ }> {}
26
+
27
+ /** A native bridge call's contextual failure; the exact thrown value is retained. */
28
+ export class NativeOperationError extends Data.TaggedError("NativeOperationError")<{
29
+ readonly operation: string
30
+ readonly cause: unknown
31
+ }> {
32
+ override get message(): string {
33
+ const cause = this.cause
34
+ const detail =
35
+ typeof cause === "object" && cause !== null && "message" in cause && typeof cause.message === "string"
36
+ ? cause.message
37
+ : String(cause)
38
+ return `${this.operation}: ${detail}`
39
+ }
40
+ }
41
+
42
+ export class NativeReportedError extends Data.TaggedError("NativeReportedError")<{
43
+ readonly kind: string
44
+ readonly message: string
45
+ readonly cause: unknown
46
+ }> {}
package/src/face.ts CHANGED
@@ -1,5 +1,5 @@
1
- import * as errors from "@superbuilders/errors"
2
1
  import type { AnyClosed, AnySelectedClosed, PayloadField } from "#closed.ts"
2
+ import { AuthoringError } from "#errors.ts"
3
3
  import type { AnyField, SignatureOf } from "#fields.ts"
4
4
  import type { Same } from "#judgment.ts"
5
5
  import type { AnyRelation, AnySelected, FieldsShape, RelationFields, SelectionBinding } from "#relation.ts"
@@ -121,7 +121,7 @@ function on<S extends FaceSource>(source: S, fields: string | readonly string[])
121
121
  })
122
122
  const value = Object.freeze({ source, projection, data })
123
123
  if (!faceMinted<S, readonly string[]>(value, source, projection)) {
124
- throw errors.new(`face over ${parts.owner.name}: face construction incomplete`)
124
+ throw new AuthoringError({ message: `face over ${parts.owner.name}: face construction incomplete` })
125
125
  }
126
126
  return value
127
127
  }
package/src/fields.ts CHANGED
@@ -1,17 +1,19 @@
1
- import * as errors from "@superbuilders/errors"
2
1
  import { regex } from "arkregex"
2
+ import { Result } from "effect"
3
+ import { AuthoringError } from "#errors.ts"
4
+ import { DbError } from "#runtime-errors.ts"
3
5
  import type { LiteralSpec } from "#spec.ts"
6
+ import { Uuid } from "#uuid.ts"
4
7
 
5
8
  const INTEGER_INDEX_NAME = regex("^(?:0|[1-9][0-9]*)$")
6
9
 
7
10
  /**
8
- * A half-open interval `[start, end)` as a plain value object — the ONE
9
- * interval value type, whatever the field's element type or width label.
10
- * The ray is representable (`end` = the element type's MAX_END); widths
11
- * and signedness are NOT modeled on the value — they are descriptor-type
12
- * labels the engine judges at the typed write boundary. Interval fields
13
- * derive no order (the Rust refusal,,
14
- * so no comparators exist on the value type.
11
+ * A half-open integer interval `[start, end)` as a plain value object —
12
+ * the ONE discrete interval value type, whatever the field's element type
13
+ * or width label. The ray is representable (`end` = the element type's
14
+ * MAX_END); widths and signedness are NOT modeled on the value — they are
15
+ * descriptor-type labels the engine judges at the typed write boundary.
16
+ * Interval fields derive no order, so no comparators exist on the value.
15
17
  */
16
18
  interface IntervalValue {
17
19
  readonly start: bigint
@@ -19,17 +21,54 @@ interface IntervalValue {
19
21
  }
20
22
 
21
23
  /**
22
- * Constructs an interval literal — the `start..end` spelling. Half-open
23
- * and nonempty by construction: `start >= end` is a typed construction
24
- * error (parse, don't validate — the same invariant Rust's
25
- * `Interval::new` enforces at the host boundary). The value is bare and
26
- * structural: it is assignable to any interval field.
24
+ * A half-open dense float interval `[start, end)` as a plain value object:
25
+ * two canonical binary64 bounds on the dense numeric line.
26
+ * NaN is never an endpoint, signed zero is normalized at the checked
27
+ * constructor and again by the native boundary, and strict `start < end`
28
+ * makes empty spans unrepresentable through {@link span}. Infinite bounds
29
+ * denote a missing bound, not a member point.
27
30
  */
28
- function span(start: bigint, end: bigint): IntervalValue {
29
- if (start >= end) {
30
- throw errors.new(`interval is half-open and nonempty: start must be < end (got ${start}..${end})`)
31
+ interface FloatIntervalValue {
32
+ readonly start: number
33
+ readonly end: number
34
+ }
35
+
36
+ /**
37
+ * Constructs a checked interval literal — the `start..end` spelling.
38
+ * Half-open and nonempty by construction. Fallible pure parsing
39
+ * returns `Result` (use `Effect.fromResult(span(...))` inside a generator),
40
+ * never hidden I/O and never a thrown domain outcome.
41
+ *
42
+ * Two element domains, selected by argument type: `span(0n, 60n)` is a
43
+ * discrete integer interval; `span(0.5, 1.5)` is a dense float interval
44
+ * with canonical endpoints (NaN refused, `-0` normalized to `+0`,
45
+ * `-Infinity` legal only as the lower bound and `+Infinity` only as the
46
+ * upper bound — both enforced by strict numeric `start < end`).
47
+ */
48
+ function span(start: bigint, end: bigint): Result.Result<IntervalValue, DbError>
49
+ function span(start: number, end: number): Result.Result<FloatIntervalValue, DbError>
50
+ function span(
51
+ start: bigint | number,
52
+ end: bigint | number
53
+ ): Result.Result<IntervalValue, DbError> | Result.Result<FloatIntervalValue, DbError> {
54
+ if (typeof start === "bigint" && typeof end === "bigint") {
55
+ if (start >= end) {
56
+ return Result.fail(new DbError({ operation: "span", reason: { _tag: "InvalidArgument" } }))
57
+ }
58
+ return Result.succeed(Object.freeze({ start, end }))
59
+ }
60
+ if (typeof start === "number" && typeof end === "number") {
61
+ if (Number.isNaN(start) || Number.isNaN(end)) {
62
+ return Result.fail(new DbError({ operation: "span", reason: { _tag: "InvalidArgument" } }))
63
+ }
64
+ const lo = Object.is(start, -0) ? 0 : start
65
+ const hi = Object.is(end, -0) ? 0 : end
66
+ if (!(lo < hi)) {
67
+ return Result.fail(new DbError({ operation: "span", reason: { _tag: "InvalidArgument" } }))
68
+ }
69
+ return Result.succeed(Object.freeze({ start: lo, end: hi }))
31
70
  }
32
- return Object.freeze({ start, end })
71
+ return Result.fail(new DbError({ operation: "span", reason: { _tag: "InvalidArgument" } }))
33
72
  }
34
73
 
35
74
  /**
@@ -56,27 +95,37 @@ interface StrField {
56
95
  readonly kind: "str"
57
96
  }
58
97
 
59
- interface FreshU64Field {
60
- readonly kind: "u64"
61
- readonly fresh: true
62
- }
63
-
64
98
  interface U64Field {
65
99
  readonly kind: "u64"
66
- readonly fresh: FreshU64Field
67
100
  }
68
101
 
69
102
  interface I64Field {
70
103
  readonly kind: "i64"
71
104
  }
72
105
 
106
+ interface F64Field {
107
+ readonly kind: "f64"
108
+ }
109
+
110
+ /**
111
+ * The application-owned 128-bit identity scalar: sixteen
112
+ * exact bytes, spelled as the canonical hyphenated UUID {@link Uuid}
113
+ * host value. There is no `fresh` mark anywhere: the database issues no
114
+ * identity, and key laws are declared statements.
115
+ */
116
+ interface UuidField {
117
+ readonly kind: "uuid"
118
+ }
119
+
73
120
  interface BytesField<Width extends number = number> {
74
121
  readonly kind: "bytes"
75
122
  readonly width: Width
76
123
  }
77
124
 
125
+ type IntervalElementKind = "u64" | "i64" | "f64"
126
+
78
127
  interface IntervalField<
79
- Element extends "u64" | "i64" = "u64" | "i64",
128
+ Element extends IntervalElementKind = IntervalElementKind,
80
129
  Width extends bigint | undefined = bigint | undefined
81
130
  > {
82
131
  readonly kind: "interval"
@@ -96,8 +145,9 @@ type AnyField =
96
145
  | BoolField
97
146
  | StrField
98
147
  | U64Field
99
- | FreshU64Field
100
148
  | I64Field
149
+ | F64Field
150
+ | UuidField
101
151
  | BytesField
102
152
  | IntervalField
103
153
  | AnyClosedIdField
@@ -131,20 +181,26 @@ type Infer<F extends AnyField> = F extends { readonly kind: "bool" }
131
181
  ? bigint
132
182
  : F extends { readonly kind: "i64" }
133
183
  ? bigint
134
- : F extends { readonly kind: "bytes" }
135
- ? Uint8Array
136
- : F extends { readonly kind: "interval" }
137
- ? IntervalValue
138
- : never
184
+ : F extends { readonly kind: "f64" }
185
+ ? number
186
+ : F extends { readonly kind: "uuid" }
187
+ ? Uuid
188
+ : F extends { readonly kind: "bytes" }
189
+ ? Uint8Array
190
+ : F extends { readonly kind: "interval"; readonly element: "f64" }
191
+ ? FloatIntervalValue
192
+ : F extends { readonly kind: "interval" }
193
+ ? IntervalValue
194
+ : never
139
195
 
140
196
  /**
141
197
  * The typed shape refusal shared by every literal machine — the selection
142
- * lowering here, the row marshaler (`marshal.ts`), and the query-literal
198
+ * lowering here, the row codec (`rows.ts`), and the query-literal
143
199
  * tagger (`query/lower.ts`) all throw through this ONE voice; reached only
144
200
  * through ill-typed input (the well-typed surfaces make it unrepresentable).
145
201
  */
146
202
  function literalShapeError(context: string, expected: string, value: unknown): Error {
147
- return errors.new(`${context}: expected ${expected}, got ${typeof value}`)
203
+ return new AuthoringError({ message: `${context}: expected ${expected}, got ${typeof value}` })
148
204
  }
149
205
 
150
206
  function rosterOf(field: AnyField | undefined): AnyClosedRoster | undefined {
@@ -196,17 +252,48 @@ function isIntervalValue(value: unknown): value is IntervalValue {
196
252
  )
197
253
  }
198
254
 
255
+ function isFloatIntervalValue(value: unknown): value is FloatIntervalValue {
256
+ return (
257
+ typeof value === "object" &&
258
+ value !== null &&
259
+ "start" in value &&
260
+ "end" in value &&
261
+ typeof value.start === "number" &&
262
+ typeof value.end === "number"
263
+ )
264
+ }
265
+
199
266
  function handleLiteral(closed: AnyClosedRoster, value: unknown): LiteralSpec {
200
267
  if (typeof value !== "string") {
201
268
  throw literalShapeError("selection literal", `a ${closed.name} handle name (string)`, value)
202
269
  }
203
270
  if (!closed.handles.includes(value)) {
204
- throw errors.new(`"${value}" is not a handle of ${closed.name} — the roster is ${closed.handles.join(", ")}`)
271
+ throw new AuthoringError({
272
+ message: `"${value}" is not a handle of ${closed.name} — the roster is ${closed.handles.join(", ")}`
273
+ })
205
274
  }
206
275
  return { kind: "handle", handle: value }
207
276
  }
208
277
 
209
- function intervalLiteral(element: "u64" | "i64", value: unknown): LiteralSpec {
278
+ function intervalLiteral(element: IntervalElementKind, value: unknown): LiteralSpec {
279
+ if (element === "f64") {
280
+ if (!isFloatIntervalValue(value)) {
281
+ throw literalShapeError("selection literal", "float interval ({ start, end } numbers)", value)
282
+ }
283
+ if (Number.isNaN(value.start) || Number.isNaN(value.end) || !(value.start < value.end)) {
284
+ throw new AuthoringError({
285
+ message: "selection literal: a float interval is half-open and nonempty with non-NaN canonical endpoints"
286
+ })
287
+ }
288
+ return {
289
+ kind: "value",
290
+ value: {
291
+ kind: "intervalF64",
292
+ start: Object.is(value.start, -0) ? 0 : value.start,
293
+ end: Object.is(value.end, -0) ? 0 : value.end
294
+ }
295
+ }
296
+ }
210
297
  if (!isIntervalValue(value)) {
211
298
  throw literalShapeError("selection literal", "interval ({ start, end } bigints)", value)
212
299
  }
@@ -218,55 +305,76 @@ function intervalLiteral(element: "u64" | "i64", value: unknown): LiteralSpec {
218
305
 
219
306
  function assertDeclarationOrderKey(where: string, name: string): void {
220
307
  if (INTEGER_INDEX_NAME.test(name)) {
221
- throw errors.new(
222
- `${where}: name ${name} is an integer index — JavaScript object keys re-order integer indices, breaking the declaration-order law; use a non-numeric name`
223
- )
308
+ throw new AuthoringError({
309
+ message: `${where}: name ${name} is an integer index — JavaScript object keys re-order integer indices, breaking the declaration-order law; use a non-numeric name`
310
+ })
224
311
  }
225
312
  if (name.includes(".")) {
226
- throw errors.new(
227
- `${where}: name ${name} contains a dot — the law classes key on the \`relation.field\` coordinate, so a dotted name would alias unrelated slots (macro parity: Rust identifiers cannot contain dots); use a dot-free name`
228
- )
313
+ throw new AuthoringError({
314
+ message: `${where}: name ${name} contains a dot — the law classes key on the \`relation.field\` coordinate, so a dotted name would alias unrelated slots (macro parity: Rust identifiers cannot contain dots); use a dot-free name`
315
+ })
229
316
  }
230
317
  }
231
318
 
232
319
  function assertDeclarationRecord(where: string, record: object): void {
233
320
  const proto = Object.getPrototypeOf(record)
234
321
  if (proto !== Object.prototype && proto !== null) {
235
- throw errors.new(
236
- `${where}: the declaration record's prototype was replaced — a plain \`__proto__: {...}\` entry is the prototype setter, so its key silently vanishes from the declaration; spell it computed (["__proto__"]: {...}) to declare it as data`
237
- )
322
+ throw new AuthoringError({
323
+ message: `${where}: the declaration record's prototype was replaced — a plain \`__proto__: {...}\` entry is the prototype setter, so its key silently vanishes from the declaration; spell it computed (["__proto__"]: {...}) to declare it as data`
324
+ })
238
325
  }
239
326
  }
240
327
 
241
- const freshU64: FreshU64Field = Object.freeze({ kind: "u64", fresh: true })
242
-
243
- const u64: U64Field = Object.freeze({ kind: "u64", fresh: freshU64 })
328
+ const u64: U64Field = Object.freeze({ kind: "u64" })
244
329
 
245
330
  const i64: I64Field = Object.freeze({ kind: "i64" })
246
331
 
332
+ /** Binary64. The native value boundary canonicalizes NaN and signed zero. */
333
+ const f64: F64Field = Object.freeze({ kind: "f64" })
334
+
335
+ /** The application-owned 128-bit identity scalar; no fresh mark exists. */
336
+ const uuid: UuidField = Object.freeze({ kind: "uuid" })
337
+
247
338
  const bool: BoolField = Object.freeze({ kind: "bool" })
248
339
 
249
340
  const str: StrField = Object.freeze({ kind: "str" })
250
341
 
251
342
  function bytes<const Width extends number>(width: Width): BytesField<Width> {
252
343
  if (!Number.isInteger(width) || width < 1 || width > 64) {
253
- throw errors.new(`bytes width must be an integer in 1..=64 (got ${width}) — the range is pinned at declaration`)
344
+ throw new AuthoringError({
345
+ message: `bytes width must be an integer in 1..=64 (got ${width}) — the range is pinned at declaration`
346
+ })
254
347
  }
255
348
  return Object.freeze({ kind: "bytes", width })
256
349
  }
257
350
 
258
- function interval<Element extends U64Field | I64Field>(element: Element): IntervalField<Element["kind"], undefined>
351
+ function interval<Element extends U64Field | I64Field | F64Field>(
352
+ element: Element
353
+ ): IntervalField<Element["kind"], undefined>
259
354
  function interval<Element extends U64Field | I64Field, const Width extends bigint>(
260
355
  element: Element,
261
356
  width: Width
262
357
  ): IntervalField<Element["kind"], Width>
263
- function interval(element: U64Field | I64Field, width?: bigint): IntervalField<"u64" | "i64", bigint | undefined> {
358
+ function interval(
359
+ element: U64Field | I64Field | F64Field,
360
+ width?: bigint
361
+ ): IntervalField<IntervalElementKind, bigint | undefined> {
264
362
  const elementKind = element.kind
265
- if (elementKind !== "u64" && elementKind !== "i64") {
266
- throw errors.new(`interval element must be the u64 or i64 field constructor (got ${elementKind})`)
363
+ if (elementKind !== "u64" && elementKind !== "i64" && elementKind !== "f64") {
364
+ throw new AuthoringError({
365
+ message: `interval element must be the u64, i64 or f64 field constructor (got ${elementKind})`
366
+ })
367
+ }
368
+ if (width !== undefined && elementKind === "f64") {
369
+ throw new AuthoringError({
370
+ message:
371
+ "interval(f64) takes no width — a fixed-width float interval is unrepresentable (rounded start + width is not an exact fixed length on the dense line); applications supply two checked bounds"
372
+ })
267
373
  }
268
374
  if (width !== undefined && width < 1n) {
269
- throw errors.new(`interval width must be >= 1 (got ${width}) — w >= 1 is pinned at declaration`)
375
+ throw new AuthoringError({
376
+ message: `interval width must be >= 1 (got ${width}) — w >= 1 is pinned at declaration`
377
+ })
270
378
  }
271
379
  return Object.freeze({ kind: "interval", element: elementKind, width })
272
380
  }
@@ -305,6 +413,18 @@ function literalOf(field: AnyField, value: unknown): LiteralSpec {
305
413
  }
306
414
  return { kind: "value", value: { kind: "string", value } }
307
415
  }
416
+ case "f64": {
417
+ if (typeof value !== "number") {
418
+ throw literalShapeError("selection literal", "number", value)
419
+ }
420
+ return { kind: "value", value: { kind: "f64", value } }
421
+ }
422
+ case "uuid": {
423
+ if (!Uuid.isUuid(value)) {
424
+ throw literalShapeError("selection literal", "a UUID (canonical UUID text)", value)
425
+ }
426
+ return { kind: "value", value: { kind: "uuid", value } }
427
+ }
308
428
  case "bytes": {
309
429
  if (!(value instanceof Uint8Array)) {
310
430
  throw literalShapeError("selection literal", "Uint8Array", value)
@@ -325,22 +445,27 @@ export type {
325
445
  ClosedHandleTuple,
326
446
  ClosedIdField,
327
447
  ClosedRoster,
328
- FreshU64Field,
448
+ F64Field,
449
+ FloatIntervalValue,
329
450
  I64Field,
330
451
  Infer,
452
+ IntervalElementKind,
331
453
  IntervalField,
332
454
  IntervalValue,
333
455
  SignatureOf,
334
456
  StrField,
335
- U64Field
457
+ U64Field,
458
+ UuidField
336
459
  }
337
460
  export {
338
461
  assertDeclarationOrderKey,
339
462
  assertDeclarationRecord,
340
463
  bool,
341
464
  bytes,
465
+ f64,
342
466
  i64,
343
467
  interval,
468
+ isFloatIntervalValue,
344
469
  isIntervalValue,
345
470
  literalOf,
346
471
  literalShapeError,
@@ -349,5 +474,6 @@ export {
349
474
  signaturesAgree,
350
475
  span,
351
476
  str,
352
- u64
477
+ u64,
478
+ uuid
353
479
  }