@confect/core 9.0.0-next.8 → 9.0.0

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 (45) hide show
  1. package/CHANGELOG.md +170 -4
  2. package/dist/FunctionProvenance.d.ts +87 -93
  3. package/dist/FunctionProvenance.d.ts.map +1 -1
  4. package/dist/FunctionSpec.d.ts +178 -218
  5. package/dist/FunctionSpec.d.ts.map +1 -1
  6. package/dist/GenericId.d.ts +6 -13
  7. package/dist/GenericId.d.ts.map +1 -1
  8. package/dist/GroupPath.d.ts +10 -16
  9. package/dist/GroupPath.d.ts.map +1 -1
  10. package/dist/GroupSpec.d.ts +38 -37
  11. package/dist/GroupSpec.d.ts.map +1 -1
  12. package/dist/GroupSpec.js.map +1 -1
  13. package/dist/Identifier.d.ts +2 -7
  14. package/dist/Identifier.d.ts.map +1 -1
  15. package/dist/Lazy.d.ts +1 -6
  16. package/dist/Lazy.d.ts.map +1 -1
  17. package/dist/PaginationResult.d.ts +10 -17
  18. package/dist/PaginationResult.d.ts.map +1 -1
  19. package/dist/Ref.d.ts +54 -52
  20. package/dist/Ref.d.ts.map +1 -1
  21. package/dist/Refs.d.ts +21 -21
  22. package/dist/Refs.d.ts.map +1 -1
  23. package/dist/Refs.js +2 -10
  24. package/dist/Refs.js.map +1 -1
  25. package/dist/Registry.d.ts +5 -10
  26. package/dist/Registry.d.ts.map +1 -1
  27. package/dist/RuntimeAndFunctionType.d.ts +36 -41
  28. package/dist/RuntimeAndFunctionType.d.ts.map +1 -1
  29. package/dist/Spec.d.ts +23 -33
  30. package/dist/Spec.d.ts.map +1 -1
  31. package/dist/Spec.js +7 -50
  32. package/dist/Spec.js.map +1 -1
  33. package/dist/SystemFields.d.ts +9 -15
  34. package/dist/SystemFields.d.ts.map +1 -1
  35. package/dist/Types.d.ts +27 -27
  36. package/dist/Types.d.ts.map +1 -1
  37. package/dist/UserIdentity.d.ts +55 -62
  38. package/dist/UserIdentity.d.ts.map +1 -1
  39. package/dist/index.d.ts +17 -17
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/tsconfig.src.tsbuildinfo +1 -0
  42. package/package.json +3 -11
  43. package/src/GroupSpec.ts +7 -6
  44. package/src/Refs.ts +10 -44
  45. package/src/Spec.ts +16 -83
package/CHANGELOG.md CHANGED
@@ -1,5 +1,163 @@
1
1
  # @confect/core
2
2
 
3
+ ## 9.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - a905072: Rearchitect Confect so that cold-starting a Convex function only evaluates its own group's module graph, cutting cold-start execution time on large projects. The change touches how you author tables, specs, and impls, and removes the project-wide aggregation that used to make every function evaluate every other function's code—and every table's schema—the first time it ran.
8
+
9
+ Convex bundles a deployment into a single artifact, but a function's cold start only _evaluates_ the module graph reachable from its own entry point. Previously, all impls were assembled into a single root `confect/impl.ts` that every generated `convex/` module imported, so cold-starting any one query, mutation, or action transitively evaluated the impl of every other function in the project, plus every function spec and every table schema, at module-load time. Cold-start execution time scaled with the size of the whole project. In v9, `confect codegen` emits one registry per group and each generated `convex/` module imports only its own group—so a function's cold-start work scales with its own group, not the project.
10
+
11
+ ### Filesystem-driven groups
12
+
13
+ Your API is now authored as colocated `*.spec.ts`/`*.impl.ts` pairs, one pair per group, and **the file's path within `confect/` is the group's name** (its stem for top-level groups, the dot-joined directory path for nested groups). `GroupSpec.make()` and `GroupSpec.makeNode()` no longer take a name argument.
14
+
15
+ - Each `*.spec.ts` `export default`s its `GroupSpec` (named co-exports like error classes are still allowed).
16
+ - Each `*.impl.ts` default-imports its sibling spec, passes it to `FunctionImpl.make` / `GroupImpl.make`, and ends the layer pipeline with `GroupImpl.finalize`—a compile-time completeness check that only typechecks once every function the spec declares has a `FunctionImpl` provided.
17
+ - The root `confect/spec.ts`, `confect/impl.ts`, `confect/nodeSpec.ts`, and `confect/nodeImpl.ts` files are gone, along with `Impl.make` and `Impl.finalize`. `confect codegen` deletes any of these (and the stale aggregate `_generated/registeredFunctions.ts` / `_generated/nodeRegisteredFunctions.ts`) on upgrade.
18
+
19
+ ### Tables are the source of truth, named by their filename
20
+
21
+ Your schema now lives entirely in `confect/tables/`, one `Table` per file, and **the filename is the table name**—`confect/tables/notes.ts` defines the `notes` table. `Table.make` no longer takes a name argument. The user-authored `confect/schema.ts` is removed; codegen scans `confect/tables/*.ts` and generates everything else.
22
+
23
+ Each table file is a default-export-only module, and its field schema is wrapped in a `() =>` callback so it is built lazily—a function only pays a table's schema-construction cost at cold start for tables it actually reads.
24
+
25
+ ```ts confect/tables/notes.ts
26
+ import { Table } from "@confect/server";
27
+ import { Schema } from "effect";
28
+ import { Id } from "../_generated/id";
29
+
30
+ export default Table.make(() =>
31
+ Schema.Struct({
32
+ userId: Schema.optional(Id("users")),
33
+ text: Schema.String,
34
+ })
35
+ );
36
+ ```
37
+
38
+ Codegen emits, alongside it:
39
+
40
+ - `_generated/schema.ts`—the runtime `DatabaseSchema`. Never imports `convex/server`, so a runtime cold start no longer evaluates `defineSchema(...)`.
41
+ - `_generated/convexSchema.ts`—the Convex deploy `SchemaDefinition`, re-exported from `convex/schema.ts`.
42
+ - `_generated/id.ts`—a type-safe `Id` constructor whose argument is constrained to your table names. Use `Id("notes")` everywhere you previously wrote `GenericId.GenericId("notes")`; cross-table `_id` typos are now caught at compile time.
43
+ - `_generated/tables/<name>.ts`—a thin wrapper that binds the filename to the table. Read a table's `Doc`, `Fields`, and `tableName` from this wrapper (`import notes from "../_generated/tables/notes"`), not from `confect/tables/`.
44
+
45
+ A bound table's `name` property is renamed to `tableName` (avoiding a collision with `Function.prototype.name`).
46
+
47
+ ### Specs and impls: lazy schemas, and impls take the `DatabaseSchema`
48
+
49
+ `FunctionSpec.*` constructors now take `args`, `returns`, and the optional `error` as `() => Schema` thunks, so importing a spec builds no schemas until a function is invoked. `FunctionImpl.make` and `GroupImpl.make` take the runtime `DatabaseSchema` (the default export of `_generated/schema`) as their first argument instead of the whole `Api`—which keeps the project-wide spec graph out of a function's cold-start module graph. The `Api` module (`Api.make`, the `Api` type) and the generated `_generated/api.ts` / `_generated/nodeApi.ts` files are removed.
50
+
51
+ **Before:**
52
+
53
+ ```ts confect/notes.spec.ts
54
+ export const notes = GroupSpec.make("notes").addFunction(
55
+ FunctionSpec.publicQuery({
56
+ name: "list",
57
+ args: Schema.Struct({}),
58
+ returns: Schema.Array(Notes.Doc),
59
+ })
60
+ );
61
+ ```
62
+
63
+ ```ts confect/notes.impl.ts
64
+ const list = FunctionImpl.make(api, "notes", "list", handler);
65
+ export const notes = GroupImpl.make(api, "notes").pipe(Layer.provide(list));
66
+ ```
67
+
68
+ **After:**
69
+
70
+ ```ts confect/notes.spec.ts
71
+ import notes from "./_generated/tables/notes";
72
+
73
+ export default GroupSpec.make().addFunction(
74
+ FunctionSpec.publicQuery({
75
+ name: "list",
76
+ args: () => Schema.Struct({}),
77
+ returns: () => Schema.Array(notes.Doc),
78
+ })
79
+ );
80
+ ```
81
+
82
+ ```ts confect/notes.impl.ts
83
+ import databaseSchema from "./_generated/schema";
84
+ import notes from "./notes.spec";
85
+
86
+ const list = FunctionImpl.make(databaseSchema, notes, "list", handler);
87
+ export default GroupImpl.make(databaseSchema, notes).pipe(
88
+ Layer.provide(list),
89
+ GroupImpl.finalize
90
+ );
91
+ ```
92
+
93
+ ### Node functions are first-class
94
+
95
+ A group's runtime is now declared solely by its spec—`GroupSpec.makeNode()` for a Node action group, `GroupSpec.make()` otherwise—mirroring vanilla Convex's per-file `"use node"` directive. The separate `node` namespace is gone: Node specs/impls are ordinary colocated pairs that can live anywhere in `confect/`, and codegen emits the `"use node"` directive based on the spec.
96
+
97
+ - A Node group at `confect/email.spec.ts` is now reached at `refs.public.email.send` instead of `refs.public.node.email.send`.
98
+ - `@confect/core` removes `Spec.makeNode`, `Spec.merge`, and `Spec.isConvexSpec` / `Spec.isNodeSpec`; `Spec.make()` is a single mixed-runtime container and `Refs.make(spec)` takes one argument. `GroupSpec.makeNode()`, `FunctionSpec.publicNodeAction()` / `internalNodeAction()` are unchanged.
99
+
100
+ ### Less work at cold start
101
+
102
+ Confect's own packages now import Effect from its submodule paths (`import * as Schema from "effect/Schema"`) instead of the `"effect"` barrel. A barrel import of a namespace re-export pulls the entire namespace into the module graph a function evaluates at cold start, even when only a small part is used; importing the submodule path evaluates only what's needed. On a minimal function this cut cold-start module-evaluation time by ~35%. This is an internal change with no effect on your code—but to get the full win, import Effect from its submodule paths in your own `confect/` files too, since a single barrel import anywhere in a function's module graph re-pins the whole namespace.
103
+
104
+ ### Stable React hook results
105
+
106
+ `@confect/react` hooks now hold stable identities across renders, matching Convex's own hooks. `useQuery` memoizes the decoded `QueryResult` by the (referentially stable) Convex result, so unchanged data keeps the same `QueryResult` instead of a fresh one each render—fixing effect/memo loops (including `Maximum update depth exceeded`) for code that derives off the result. `useMutation` and `useAction` return a stable `useCallback`, and `Ref.getFunctionReference` caches the Convex function reference per function name.
107
+
108
+ ### Codegen robustness
109
+
110
+ The codegen bundler now uses [`bundle-require`](https://github.com/egoist/bundle-require), so impls may import third-party packages and use `tsconfig.json` `paths` aliases (`~/*`, `@/*`, …) for their own source. A parent `confect/{path}.spec.ts` may now declare functions alongside a sibling `confect/{path}/` subdirectory of further specs, and codegen reports a clear error on a name collision between the two.
111
+
112
+ ### Migration
113
+
114
+ 1. **Tables.** Delete `confect/schema.ts`. Rename each table file to a valid JS identifier (e.g. `confect/tables/notes.ts`); the basename becomes the table name. Drop the name argument from `Table.make`, wrap the field struct in `() =>`, and replace `GenericId.GenericId("x")` with `Id("x")` from `_generated/id`. If you read `table.name` off a bound table, rename it to `table.tableName`.
115
+ 2. **Specs.** Split each group into a colocated `*.spec.ts` that `export default`s `GroupSpec.make()` (no name). Wrap every `args`/`returns`/`error` in `() =>`. Import a table's `Doc`/`Fields` from its wrapper, `import notes from "./_generated/tables/notes"`.
116
+ 3. **Impls.** In each `*.impl.ts`, default-import the sibling spec, import `databaseSchema` from `_generated/schema`, pass it to `FunctionImpl.make` / `GroupImpl.make` in place of `api`, end the pipeline with `GroupImpl.finalize`, and `export default` it. Delete the root `confect/spec.ts`, `impl.ts`, `nodeSpec.ts`, and `nodeImpl.ts` (codegen will also remove them).
117
+ 4. **Node groups.** Move any `confect/node/<path>` files anywhere you like under `confect/`; the `node/` directory no longer has special meaning. Drop the `node` segment from call sites (`refs.public.node.<group>` → `refs.public.<group>`) and replace `Refs.make(spec, nodeSpec)` with `Refs.make(spec)`.
118
+ 5. **Tests.** If you use `@confect/test`, import `confectSchema` from `_generated/schema`, import the generated `convexSchema` from `_generated/convexSchema`, and pass `convexSchema` as the new second argument to `TestConfect.layer`.
119
+ 6. **Optional.** Adopt submodule Effect imports (`import * as Schema from "effect/Schema"`) in your own `confect/` files for the full cold-start savings.
120
+ 7. Run `confect codegen`. It re-emits the entire `convex/` tree and `confect/_generated/`, deleting any stale files from earlier versions.
121
+
122
+ ### Patch Changes
123
+
124
+ - 9eec71c: Generate the published `.d.ts` declarations with the TypeScript compiler instead of tsdown's declaration bundler. tsdown now emits JavaScript only (`dts: false`); each package has a composite `tsconfig.src.json`, and `tsc -b` emits the declarations into `dist/` as part of the build. (`@confect/cli` is the exception: it ships only a binary, so it emits no declarations at all.)
125
+
126
+ The emitted types are equivalent to before—same exported surface, same inferred shapes—so no consumer-facing type changes. One incidental improvement comes with the switch: declaration maps (`.d.ts.map`) now ship alongside the types (with `src/` included in the published files, so "go to definition" lands on the original source).
127
+
128
+ ## 9.0.0-next.10
129
+
130
+ ### Patch Changes
131
+
132
+ - 9eec71c: Generate the published `.d.ts` declarations with the TypeScript compiler instead of tsdown's declaration bundler. tsdown now emits JavaScript only (`dts: false`); each package has a composite `tsconfig.src.json`, and `tsc -b` emits the declarations into `dist/` as part of the build. (`@confect/cli` is the exception: it ships only a binary, so it emits no declarations at all.)
133
+
134
+ The emitted types are equivalent to before—same exported surface, same inferred shapes—so no consumer-facing type changes. One incidental improvement comes with the switch: declaration maps (`.d.ts.map`) now ship alongside the types (with `src/` included in the published files, so "go to definition" lands on the original source).
135
+
136
+ ## 9.0.0-next.9
137
+
138
+ ### Major Changes
139
+
140
+ - 4894959: Make Node-runtime functions first-class and remove the separate `node` namespace.
141
+
142
+ A function group's runtime is now declared solely by its spec — `GroupSpec.makeNode()` for a Node action group, `GroupSpec.make()` for a Convex group — exactly like vanilla Convex's per-file `"use node"` directive. The `confect/node/` directory is no longer special: Node specs/impls are ordinary colocated `.spec.ts`/`.impl.ts` pairs that can live anywhere in `confect/`, and codegen emits the `"use node"` directive into the generated `convex/` module based on the spec. This is safe because v9's per-group registries already isolate each Convex function's bundle from every other group's impl, so Node-only code can no longer leak into a Convex-runtime bundle regardless of namespace.
143
+
144
+ ### Why
145
+
146
+ The `node` namespace existed only because the pre-v9 architecture aggregated every function's impl into one module that all generated `convex/` modules imported; Node functions had to be quarantined into a separate spec/impl/registry tree so Convex-runtime functions wouldn't transitively import Node-only code. v9's per-group isolation removed that constraint, so the namespace was no longer load-bearing — only ergonomic overhead that diverged from vanilla Convex (which identifies Node modules per-file, with no directory requirement).
147
+
148
+ ### Breaking changes
149
+
150
+ - **API namespace removed.** A Node group at `confect/email.spec.ts` is now referenced as `refs.public.email.send` instead of `refs.public.node.email.send`. Node groups are ordinary groups in the refs tree, nesting preserved like any other group.
151
+ - **Generated layout changed.** Node modules are emitted at `convex/<path>.ts` (carrying `"use node"`) instead of `convex/node/<path>.ts`, and their registries at `confect/_generated/registeredFunctions/<path>.ts`. The single assembled `confect/_generated/spec.ts` now contains every group regardless of runtime; `confect/_generated/nodeSpec.ts` is no longer generated (codegen deletes any stale copy on upgrade).
152
+ - **`@confect/core` API.** Removed `Spec.makeNode`, `Spec.merge`, and `Spec.isConvexSpec`/`Spec.isNodeSpec`. `Spec` is now a single mixed-runtime container (`Spec.make()` accepts groups of any runtime). `Refs.make(spec)` takes a single argument (the unified spec) instead of `(convexSpec, nodeSpec)`. `GroupSpec.makeNode()`/`makeNodeAt()` and `FunctionSpec.publicNodeAction()`/`internalNodeAction()` are unchanged; `GroupSpec` subgroups may now be of any runtime (a group is just a namespace for its children).
153
+
154
+ ### Migration
155
+
156
+ 1. Move any `confect/node/<path>.spec.ts`/`.impl.ts` files to wherever you want them under `confect/` (e.g. `confect/<path>.spec.ts`); the `node/` directory has no special meaning anymore. Their specs already use `GroupSpec.makeNode()`, so no spec-body change is needed — only fix the impl's relative import of `_generated/schema` if its depth changed.
157
+ 2. Update call sites to drop the `node` segment: `refs.public.node.<group>.<fn>` → `refs.public.<group>.<fn>`.
158
+ 3. Replace `Refs.make(spec, nodeSpec)` with `Refs.make(spec)` (codegen does this for `_generated/refs.ts` automatically).
159
+ 4. Run `confect codegen`. The `convex/` tree and `confect/_generated/` are re-emitted; the stale `_generated/nodeSpec.ts` is removed.
160
+
3
161
  ## 9.0.0-next.8
4
162
 
5
163
  ### Patch Changes
@@ -101,6 +259,7 @@
101
259
  Previously, `confect/schema.ts` was user-authored and `DatabaseSchema` carried a `convexSchemaDefinition` field that was eagerly rebuilt on every `.addTable(...)`. That field was an `O(n²)` allocation for `n` tables, and it forced both the deploy CLI (which only needs `defineSchema(...)`) and the runtime (which only needs the table codec lookup) through the same module — so any runtime function bundle dragged in `convex/server`'s `defineSchema`. Issue 1.
102
260
 
103
261
  Codegen now scans `confect/tables/*.ts` (every file must default-export a `Table`) and emits two siblings:
262
+
104
263
  - `confect/_generated/schema.ts` — the runtime `DatabaseSchema`, consumed by `_generated/api.ts`. Imports `@confect/server` but never `convex/server`.
105
264
  - `confect/_generated/convexSchema.ts` — the Convex deploy `SchemaDefinition`, re-exported one-line from `convex/schema.ts`. Imports `convex/server` but never `@confect/server`.
106
265
 
@@ -113,6 +272,7 @@
113
272
  This eliminates a class of subtle infelicities: the file basename and the table name can never drift out of sync, cross-table `_id` references are type-constrained against the actual set of declared tables (catching typos at compile time), and ESM cycle hazards for mutual cross-table `Id` references are gone because authoring files no longer transitively import each other.
114
273
 
115
274
  Codegen now emits two new sets of files alongside `_generated/schema.ts` and `_generated/convexSchema.ts`:
275
+
116
276
  - `confect/_generated/id.ts` — a single `Id` constructor whose argument is type-constrained to the union of your table names. Use `Id("notes")` everywhere you previously wrote `GenericId.GenericId("notes")`.
117
277
  - `confect/_generated/tables/<name>.ts` — one thin wrapper per table that binds the unnamed value from `confect/tables/<name>.ts` to its filename. This is what other modules (specs, impls, HTTP handlers) default-import to reach a table's `Doc`, `Fields`, and `tableName`.
118
278
 
@@ -129,6 +289,7 @@
129
289
  The bound `Table` now exposes `Fields` / `Doc` / `tableDefinition` as lazy getters that compute their value on first access, then replace themselves with a plain non-writable data property so second-and-subsequent accesses are observably indistinguishable from a plain property (and skip all function-call overhead). The result: a function bundle only pays the schema-construction cost for tables it actually touches via `db.table(name)` (which reaches `Fields` through `Document.decode`). The `UnnamedTable` callable no longer exposes `Fields` or `tableDefinition` — read these off the bound `Table` (the generated `_generated/tables/<name>.ts` wrapper already binds the name).
130
290
 
131
291
  ### Migration
292
+
132
293
  1. Delete your `confect/schema.ts`. Codegen will refuse to run while a stray copy is present.
133
294
  2. Rename each `confect/tables/<Name>.ts` to a valid JS identifier in your chosen casing convention (e.g. `confect/tables/notes.ts`). The basename becomes the table name; you no longer pass it as an argument.
134
295
  3. Convert each table file to a **default-export-only** unnamed module: drop the name argument from `Table.make`, wrap the field-schema struct in a `() => ...` callback, and switch any `GenericId.GenericId("users")` references to `Id("users")` imported from `../_generated/id`:
@@ -204,6 +365,7 @@
204
365
  Since `9.0.0-next.1`, codegen has wrapped every parent leaf that has sibling subdirectory specs in `<parent>.addGroupAt("child", <child>)`. Because `GroupSpec.addGroupAt` is immutable, that produced a fresh object in the assembled tree, while the parent's `*.impl.ts` continued to hold a reference to the original imported leaf. The runtime resolver compared by `===`, so every such impl failed `validateImpl` with "Could not resolve group path for the provided GroupSpec." Child impls happened to work only because `GroupSpec.withName` was secretly mutating its argument in place to keep the child's identity stable — an asymmetry that was load-bearing for one half of the API and broken for the other.
205
366
 
206
367
  ### What changed
368
+
207
369
  - `@confect/core/Spec` carries a new `readonly paths: ReadonlyMap<GroupSpec.AnyWithProps, string>` field and exposes a chainable `Spec#addPath(group, path)` builder. `add` / `addAt` / `merge` propagate `paths` unchanged; `merge` re-prefixes a node spec's entries with `"node."` to match the merged tree.
208
370
  - `@confect/core/GroupSpec.withName` is now pure: it returns a fresh copy when the name differs and no longer rewrites the input in place. No new identity-tracking machinery is introduced.
209
371
  - `@confect/server/FunctionImpl.make` and `GroupImpl.make` resolve their group path via `api.spec.paths.get(group)` — an O(1) map lookup instead of a tree walk — and throw a clearer error pointing at `Spec.addPath` when the spec hasn't been registered.
@@ -211,6 +373,7 @@
211
373
  - `@confect/cli` codegen emits one `.addPath(<binding>, "<dot.path>")` call per leaf in `_generated/spec.ts` (and `_generated/nodeSpec.ts`) so the imported leaves carry their full paths into the assembled spec value.
212
374
 
213
375
  ### User-facing impact
376
+
214
377
  - Spec authoring (`*.spec.ts`) and impl authoring (`*.impl.ts`) APIs are unchanged. `FunctionImpl.make(api, spec, name, handler)` and `GroupImpl.make(api, spec)` keep their exact signatures.
215
378
  - Generated `_generated/spec.ts` (and `_generated/nodeSpec.ts`) pick up one `.addPath(...)` chain entry per leaf on the next `confect codegen` run. The shape is fully immutable — no module-load mutation, no hidden side effects.
216
379
  - Hand-rolled tests that construct a `Spec` and pass it to `Api.make` must now also call `.addPath(spec, "dot.path")` for any group they intend to look up.
@@ -238,6 +401,7 @@
238
401
  Splitting impl across colocated `*.impl.ts` files is the vehicle for fixing that. With this change, `confect codegen` emits one `_generated/registeredFunctions/{path}.ts` per group, and each generated `convex/` module imports only its own group's per-group registry — which in turn imports only its own sibling `.impl.ts`. A Convex function's cold-start bundle now scales with its own group's impl rather than with the size of the whole project.
239
402
 
240
403
  ### Breaking changes
404
+
241
405
  - `GroupSpec.make()` and `GroupSpec.makeNode()` no longer take a name argument; the group name is derived from the spec file's path within `confect/`.
242
406
  - `FunctionImpl.make(api, groupSpec, fn, handler)` and `GroupImpl.make(api, groupSpec)` now take the imported sibling spec object as their second argument instead of a dot-path string.
243
407
  - Every `GroupImpl` pipeline must end with `GroupImpl.finalize`, which only typechecks once every function declared by the spec has a corresponding `FunctionImpl` provided to the group layer. `GroupImpl.finalize` snapshots the names of every registered function onto the produced `Finalized` `GroupImpl` service value, and `confect codegen` reads those names to verify per-function coverage against the spec at runtime.
@@ -246,6 +410,7 @@
246
410
  - Every module under `convex/` is re-emitted to import from `_generated/registeredFunctions/{path}` instead of the previous aggregate file. Users who commit `convex/` to source control should expect a full rewrite of that directory on first codegen.
247
411
 
248
412
  ### Migration
413
+
249
414
  1. For each existing group, create a colocated `confect/{path}.spec.ts` and `confect/{path}.impl.ts` pair (under a subdirectory for nested groups).
250
415
  - In each spec, call `GroupSpec.make()` (or `GroupSpec.makeNode()`) without a name and `export default` the result.
251
416
  - In each impl, default-import the sibling spec (e.g. `import notes from "./notes.spec"`), pass it to `FunctionImpl.make`/`GroupImpl.make` in place of the previous dot-path string, append `GroupImpl.finalize` to the pipeline, and `export default` the resulting `GroupImpl` layer:
@@ -253,7 +418,7 @@
253
418
  export default GroupImpl.make(api, notes).pipe(
254
419
  Layer.provide(list),
255
420
  Layer.provide(insert),
256
- GroupImpl.finalize,
421
+ GroupImpl.finalize
257
422
  );
258
423
  ```
259
424
  2. Delete root `confect/spec.ts`, `confect/impl.ts`, `confect/nodeSpec.ts`, `confect/nodeImpl.ts`, and any parent aggregator spec/impl files. (`confect codegen` will also delete any of these it finds, plus the stale `_generated/registeredFunctions.ts` and `_generated/nodeRegisteredFunctions.ts`, so this step can be skipped.)
@@ -291,7 +456,7 @@
291
456
 
292
457
  export class NoteNotFound extends Schema.TaggedError<NoteNotFound>()(
293
458
  "NoteNotFound",
294
- { noteId: GenericId.GenericId("notes") },
459
+ { noteId: GenericId.GenericId("notes") }
295
460
  ) {}
296
461
 
297
462
  export const notes = GroupSpec.make("notes").addFunction(
@@ -300,7 +465,7 @@
300
465
  args: Schema.Struct({ noteId: GenericId.GenericId("notes") }),
301
466
  returns: Notes.Doc,
302
467
  error: NoteNotFound,
303
- }),
468
+ })
304
469
  );
305
470
  ```
306
471
 
@@ -320,7 +485,7 @@
320
485
  .table("notes")
321
486
  .get(noteId)
322
487
  .pipe(Effect.mapError(() => new NoteNotFound({ noteId })));
323
- }),
488
+ })
324
489
  );
325
490
  ```
326
491
 
@@ -392,6 +557,7 @@
392
557
  Unspecified failures continue to reject the promise.
393
558
 
394
559
  ### Migration
560
+
395
561
  - For each `useQuery` call site, replace `result === undefined` checks and direct property access with `QueryResult.match` (or the lower-level `QueryResult.isLoading`/`isSuccess`/`isFailure` predicates).
396
562
  - For each `useMutation`/`useAction` call site whose ref now declares an `error` schema, unwrap the resolved `Either` (e.g. with `Either.match`); call sites against refs without an `error` schema need no change.
397
563
 
@@ -1,105 +1,101 @@
1
+ import type { DefaultFunctionArgs } from "convex/server";
2
+ import type { Schema } from "effect";
1
3
  import * as Data from "effect/Data";
2
- import { DefaultFunctionArgs } from "convex/server";
3
- import * as effect_Unify0 from "effect/Unify";
4
- import { Schema } from "effect";
5
-
6
- //#region src/FunctionProvenance.d.ts
7
- declare namespace FunctionProvenance_d_exports {
8
- export { AnyConfect, AnyConvex, Confect, Convex, FunctionProvenance };
9
- }
10
- type FunctionProvenance = Data.TaggedEnum<{
11
- Confect: {
12
- args: Schema.Schema.AnyNoContext;
13
- returns: Schema.Schema.AnyNoContext;
14
- error?: Schema.Schema.AnyNoContext;
15
- };
16
- Convex: {};
4
+ export type FunctionProvenance = Data.TaggedEnum<{
5
+ Confect: {
6
+ args: Schema.Schema.AnyNoContext;
7
+ returns: Schema.Schema.AnyNoContext;
8
+ error?: Schema.Schema.AnyNoContext;
9
+ };
10
+ Convex: {};
17
11
  }>;
18
- interface Confect<Args extends Schema.Schema.AnyNoContext, Returns extends Schema.Schema.AnyNoContext, Error extends Schema.Schema.AnyNoContext = never> {
19
- readonly _tag: "Confect";
20
- readonly args: Args;
21
- readonly returns: Returns;
22
- readonly error?: Error;
12
+ export interface Confect<Args extends Schema.Schema.AnyNoContext, Returns extends Schema.Schema.AnyNoContext, Error extends Schema.Schema.AnyNoContext = never> {
13
+ readonly _tag: "Confect";
14
+ readonly args: Args;
15
+ readonly returns: Returns;
16
+ readonly error?: Error;
23
17
  }
24
- interface AnyConfect extends Confect<Schema.Schema.AnyNoContext, Schema.Schema.AnyNoContext, Schema.Schema.AnyNoContext> {}
25
- interface Convex<Args extends DefaultFunctionArgs, Returns> {
26
- readonly _tag: "Convex";
27
- readonly _args: Args;
28
- readonly _returns: Returns;
18
+ export interface AnyConfect extends Confect<Schema.Schema.AnyNoContext, Schema.Schema.AnyNoContext, Schema.Schema.AnyNoContext> {
29
19
  }
30
- interface AnyConvex extends Convex<DefaultFunctionArgs, any> {}
31
- declare const FunctionProvenance: {
32
- readonly Convex: Data.Case.Constructor<{
33
- readonly _tag: "Convex";
34
- readonly _args: DefaultFunctionArgs;
35
- readonly _returns: any;
36
- }, "_tag">;
37
- readonly Confect: Data.Case.Constructor<{
38
- readonly _tag: "Confect";
39
- readonly args: Schema.Schema.AnyNoContext;
40
- readonly returns: Schema.Schema.AnyNoContext;
41
- readonly error?: Schema.Schema.AnyNoContext;
42
- }, "_tag">;
43
- readonly $is: <Tag extends "Convex" | "Confect">(tag: Tag) => (u: unknown) => u is Extract<{
20
+ export interface Convex<Args extends DefaultFunctionArgs, Returns> {
44
21
  readonly _tag: "Convex";
45
- readonly _args: DefaultFunctionArgs;
46
- readonly _returns: any;
47
- }, {
48
- readonly _tag: Tag;
49
- }> | Extract<{
50
- readonly _tag: "Confect";
51
- readonly args: Schema.Schema.AnyNoContext;
52
- readonly returns: Schema.Schema.AnyNoContext;
53
- readonly error?: Schema.Schema.AnyNoContext;
54
- }, {
55
- readonly _tag: Tag;
56
- }>;
57
- readonly $match: {
58
- <const Cases extends {
59
- readonly Convex: (args: {
60
- readonly _tag: "Convex";
61
- readonly _args: DefaultFunctionArgs;
62
- readonly _returns: any;
63
- }) => any;
64
- readonly Confect: (args: {
22
+ readonly _args: Args;
23
+ readonly _returns: Returns;
24
+ }
25
+ export interface AnyConvex extends Convex<DefaultFunctionArgs, any> {
26
+ }
27
+ export declare const FunctionProvenance: {
28
+ readonly Confect: Data.Case.Constructor<{
65
29
  readonly _tag: "Confect";
66
30
  readonly args: Schema.Schema.AnyNoContext;
67
31
  readonly returns: Schema.Schema.AnyNoContext;
68
32
  readonly error?: Schema.Schema.AnyNoContext;
69
- }) => any;
70
- }>(cases: Cases & { [K in Exclude<keyof Cases, "Convex" | "Confect">]: never }): (value: {
71
- readonly _tag: "Convex";
72
- readonly _args: DefaultFunctionArgs;
73
- readonly _returns: any;
74
- } | {
75
- readonly _tag: "Confect";
76
- readonly args: Schema.Schema.AnyNoContext;
77
- readonly returns: Schema.Schema.AnyNoContext;
78
- readonly error?: Schema.Schema.AnyNoContext;
79
- }) => effect_Unify0.Unify<ReturnType<Cases["Convex" | "Confect"]>>;
80
- <const Cases extends {
81
- readonly Convex: (args: {
33
+ }, "_tag">;
34
+ readonly Convex: Data.Case.Constructor<{
82
35
  readonly _tag: "Convex";
83
36
  readonly _args: DefaultFunctionArgs;
84
37
  readonly _returns: any;
85
- }) => any;
86
- readonly Confect: (args: {
38
+ }, "_tag">;
39
+ readonly $is: <Tag extends "Confect" | "Convex">(tag: Tag) => (u: unknown) => u is Extract<{
87
40
  readonly _tag: "Confect";
88
41
  readonly args: Schema.Schema.AnyNoContext;
89
42
  readonly returns: Schema.Schema.AnyNoContext;
90
43
  readonly error?: Schema.Schema.AnyNoContext;
91
- }) => any;
92
- }>(value: {
93
- readonly _tag: "Convex";
94
- readonly _args: DefaultFunctionArgs;
95
- readonly _returns: any;
96
- } | {
97
- readonly _tag: "Confect";
98
- readonly args: Schema.Schema.AnyNoContext;
99
- readonly returns: Schema.Schema.AnyNoContext;
100
- readonly error?: Schema.Schema.AnyNoContext;
101
- }, cases: Cases & { [K in Exclude<keyof Cases, "Convex" | "Confect">]: never }): effect_Unify0.Unify<ReturnType<Cases["Convex" | "Confect"]>>;
102
- };
44
+ }, {
45
+ readonly _tag: Tag;
46
+ }> | Extract<{
47
+ readonly _tag: "Convex";
48
+ readonly _args: DefaultFunctionArgs;
49
+ readonly _returns: any;
50
+ }, {
51
+ readonly _tag: Tag;
52
+ }>;
53
+ readonly $match: {
54
+ <const Cases extends {
55
+ readonly Confect: (args: {
56
+ readonly _tag: "Confect";
57
+ readonly args: Schema.Schema.AnyNoContext;
58
+ readonly returns: Schema.Schema.AnyNoContext;
59
+ readonly error?: Schema.Schema.AnyNoContext;
60
+ }) => any;
61
+ readonly Convex: (args: {
62
+ readonly _tag: "Convex";
63
+ readonly _args: DefaultFunctionArgs;
64
+ readonly _returns: any;
65
+ }) => any;
66
+ }>(cases: Cases & { [K in Exclude<keyof Cases, "Confect" | "Convex">]: never; }): (value: {
67
+ readonly _tag: "Confect";
68
+ readonly args: Schema.Schema.AnyNoContext;
69
+ readonly returns: Schema.Schema.AnyNoContext;
70
+ readonly error?: Schema.Schema.AnyNoContext;
71
+ } | {
72
+ readonly _tag: "Convex";
73
+ readonly _args: DefaultFunctionArgs;
74
+ readonly _returns: any;
75
+ }) => import("effect/Unify").Unify<ReturnType<Cases["Confect" | "Convex"]>>;
76
+ <const Cases extends {
77
+ readonly Confect: (args: {
78
+ readonly _tag: "Confect";
79
+ readonly args: Schema.Schema.AnyNoContext;
80
+ readonly returns: Schema.Schema.AnyNoContext;
81
+ readonly error?: Schema.Schema.AnyNoContext;
82
+ }) => any;
83
+ readonly Convex: (args: {
84
+ readonly _tag: "Convex";
85
+ readonly _args: DefaultFunctionArgs;
86
+ readonly _returns: any;
87
+ }) => any;
88
+ }>(value: {
89
+ readonly _tag: "Confect";
90
+ readonly args: Schema.Schema.AnyNoContext;
91
+ readonly returns: Schema.Schema.AnyNoContext;
92
+ readonly error?: Schema.Schema.AnyNoContext;
93
+ } | {
94
+ readonly _tag: "Convex";
95
+ readonly _args: DefaultFunctionArgs;
96
+ readonly _returns: any;
97
+ }, cases: Cases & { [K in Exclude<keyof Cases, "Confect" | "Convex">]: never; }): import("effect/Unify").Unify<ReturnType<Cases["Confect" | "Convex"]>>;
98
+ };
103
99
  };
104
100
  /**
105
101
  * Build a `Confect` provenance from lazy schema thunks. `args`, `returns`,
@@ -117,12 +113,10 @@ declare const FunctionProvenance: {
117
113
  * is observable via `"error" in provenance` without forcing anything; nothing
118
114
  * relies on `Data`'s structural `Equal`/`Hash` for provenance values.
119
115
  */
120
- declare const Confect: <Args extends Schema.Schema.AnyNoContext, Returns extends Schema.Schema.AnyNoContext, Error extends Schema.Schema.AnyNoContext = never>(args: () => Args, returns: () => Returns, error?: () => Error) => Confect<Args, Returns, Error>;
121
- declare const Convex: <_Args extends DefaultFunctionArgs, _Returns>() => {
122
- readonly _tag: "Convex";
123
- readonly _args: DefaultFunctionArgs;
124
- readonly _returns: any;
116
+ export declare const Confect: <Args extends Schema.Schema.AnyNoContext, Returns extends Schema.Schema.AnyNoContext, Error extends Schema.Schema.AnyNoContext = never>(args: () => Args, returns: () => Returns, error?: () => Error) => Confect<Args, Returns, Error>;
117
+ export declare const Convex: <_Args extends DefaultFunctionArgs, _Returns>() => {
118
+ readonly _tag: "Convex";
119
+ readonly _args: DefaultFunctionArgs;
120
+ readonly _returns: any;
125
121
  };
126
- //#endregion
127
- export { AnyConfect, AnyConvex, Confect, Convex, FunctionProvenance, FunctionProvenance_d_exports };
128
122
  //# sourceMappingURL=FunctionProvenance.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FunctionProvenance.d.ts","names":[],"sources":["../src/FunctionProvenance.ts"],"mappings":";;;;;;;;;KAKY,kBAAA,GAAqB,IAAA,CAAK,UAAA;EACpC,OAAA;IACE,IAAA,EAAM,MAAA,CAAO,MAAA,CAAO,YAAA;IACpB,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,YAAA;IACvB,KAAA,GAAQ,MAAA,CAAO,MAAA,CAAO,YAAA;EAAA;EAExB,MAAA;AAAA;AAAA,UAQe,OAAA,cACF,MAAA,CAAO,MAAA,CAAO,YAAA,kBACX,MAAA,CAAO,MAAA,CAAO,YAAA,gBAChB,MAAA,CAAO,MAAA,CAAO,YAAA;EAAA,SAEnB,IAAA;EAAA,SACA,IAAA,EAAM,IAAA;EAAA,SACN,OAAA,EAAS,OAAA;EAAA,SACT,KAAA,GAAQ,KAAA;AAAA;AAAA,UAGF,UAAA,SAAmB,OAAA,CAClC,MAAA,CAAO,MAAA,CAAO,YAAA,EACd,MAAA,CAAO,MAAA,CAAO,YAAA,EACd,MAAA,CAAO,MAAA,CAAO,YAAA;AAAA,UAGC,MAAA,cAAoB,mBAAA;EAAA,SAC1B,IAAA;EAAA,SACA,KAAA,EAAO,IAAA;EAAA,SACP,QAAA,EAAU,OAAA;AAAA;AAAA,UAGJ,SAAA,SAAkB,MAAA,CAAO,mBAAA;AAAA,cAE7B,kBAAA;EAAA;;oBA/BF,mBAAA;IAAA;;;;mBAND,MAAA,CAAO,MAAA,CAAO,YAAA;IAAA,kBACX,MAAA,CAAO,MAAA,CAAO,YAAA;IAAA,iBACf,MAAA,CAAO,MAAA,CAAO,YAAA;EAAA;EAAA;;oBAIf,mBAAA;IAAA;;;;;mBAND,MAAA,CAAO,MAAA,CAAO,YAAA;IAAA,kBACX,MAAA,CAAO,MAAA,CAAO,YAAA;IAAA,iBACf,MAAA,CAAO,MAAA,CAAO,YAAA;EAAA;IAAA;;;;;;wBAIf,mBAAA;QAAA;;;;uBAND,MAAA,CAAO,MAAA,CAAO,YAAA;QAAA,kBACX,MAAA,CAAO,MAAA,CAAO,YAAA;QAAA,iBACf,MAAA,CAAO,MAAA,CAAO,YAAA;MAAA;IAAA;;sBAIf,mBAAA;MAAA;;;qBAND,MAAA,CAAO,MAAA,CAAO,YAAA;MAAA,kBACX,MAAA,CAAO,MAAA,CAAO,YAAA;MAAA,iBACf,MAAA,CAAO,MAAA,CAAO,YAAA;IAAA;;;;wBAIf,mBAAA;QAAA;;;;uBAND,MAAA,CAAO,MAAA,CAAO,YAAA;QAAA,kBACX,MAAA,CAAO,MAAA,CAAO,YAAA;QAAA,iBACf,MAAA,CAAO,MAAA,CAAO,YAAA;MAAA;IAAA;;sBAIf,mBAAA;MAAA;;;qBAND,MAAA,CAAO,MAAA,CAAO,YAAA;MAAA,kBACX,MAAA,CAAO,MAAA,CAAO,YAAA;MAAA,iBACf,MAAA,CAAO,MAAA,CAAO,YAAA;IAAA;;;;;;;;;;;;;;;;AAiC1B;;;cAoBa,OAAA,gBACE,MAAA,CAAO,MAAA,CAAO,YAAA,kBACX,MAAA,CAAO,MAAA,CAAO,YAAA,gBAChB,MAAA,CAAO,MAAA,CAAO,YAAA,UAE5B,IAAA,QAAY,IAAA,EACZ,OAAA,QAAe,OAAA,EACf,KAAA,SAAc,KAAA,KACb,OAAA,CAAQ,IAAA,EAAM,OAAA,EAAS,KAAA;AAAA,cAYb,MAAA,iBAAwB,mBAAA;EAAA;kBArE1B,mBAAA;EAAA"}
1
+ {"version":3,"file":"FunctionProvenance.d.ts","sourceRoot":"","sources":["../src/FunctionProvenance.ts"],"names":[],"mappings":"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"}