@confect/core 9.0.0-next.9 → 9.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.
- package/CHANGELOG.md +158 -4
- package/dist/FunctionProvenance.d.ts +84 -90
- package/dist/FunctionProvenance.d.ts.map +1 -1
- package/dist/FunctionSpec.d.ts +178 -218
- package/dist/FunctionSpec.d.ts.map +1 -1
- package/dist/GenericId.d.ts +6 -13
- package/dist/GenericId.d.ts.map +1 -1
- package/dist/GroupPath.d.ts +10 -16
- package/dist/GroupPath.d.ts.map +1 -1
- package/dist/GroupSpec.d.ts +38 -37
- package/dist/GroupSpec.d.ts.map +1 -1
- package/dist/Identifier.d.ts +2 -7
- package/dist/Identifier.d.ts.map +1 -1
- package/dist/Lazy.d.ts +1 -6
- package/dist/Lazy.d.ts.map +1 -1
- package/dist/PaginationResult.d.ts +10 -17
- package/dist/PaginationResult.d.ts.map +1 -1
- package/dist/Ref.d.ts +54 -52
- package/dist/Ref.d.ts.map +1 -1
- package/dist/Refs.d.ts +21 -21
- package/dist/Refs.d.ts.map +1 -1
- package/dist/Registry.d.ts +5 -10
- package/dist/Registry.d.ts.map +1 -1
- package/dist/RuntimeAndFunctionType.d.ts +36 -41
- package/dist/RuntimeAndFunctionType.d.ts.map +1 -1
- package/dist/Spec.d.ts +17 -21
- package/dist/Spec.d.ts.map +1 -1
- package/dist/SystemFields.d.ts +9 -15
- package/dist/SystemFields.d.ts.map +1 -1
- package/dist/Types.d.ts +27 -27
- package/dist/Types.d.ts.map +1 -1
- package/dist/UserIdentity.d.ts +55 -62
- package/dist/UserIdentity.d.ts.map +1 -1
- package/dist/index.d.ts +17 -17
- package/dist/index.d.ts.map +1 -0
- package/dist/tsconfig.src.tsbuildinfo +1 -0
- package/package.json +4 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,149 @@
|
|
|
1
1
|
# @confect/core
|
|
2
2
|
|
|
3
|
+
## 9.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 445ea9b: Loosen and align dependency ranges across all packages:
|
|
8
|
+
|
|
9
|
+
- The `convex` peer dependency is now `^1.32.0` in every package (previously pinned exactly to `1.39.1`, or `^1.30.0` in `@confect/react`). The range is validated against convex 1.32.0 through 1.40.0.
|
|
10
|
+
- `@confect/server`'s `@effect/platform-node` peer dependency is now optional — it is only needed when using the `@confect/server/node` entrypoint.
|
|
11
|
+
- `@confect/cli` now uses caret ranges for its `@effect/platform` and `@effect/platform-node` dependencies so they can deduplicate with the versions resolved for `@confect/server`, and no longer declares an unused direct dependency on `@effect/platform-node-shared`.
|
|
12
|
+
- `@confect/test` now accepts any `convex-test` release in `>=0.0.50 <0.1.0` instead of exactly 0.0.50.
|
|
13
|
+
|
|
14
|
+
## 9.0.0
|
|
15
|
+
|
|
16
|
+
### Major Changes
|
|
17
|
+
|
|
18
|
+
- 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.
|
|
19
|
+
|
|
20
|
+
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.
|
|
21
|
+
|
|
22
|
+
### Filesystem-driven groups
|
|
23
|
+
|
|
24
|
+
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.
|
|
25
|
+
|
|
26
|
+
- Each `*.spec.ts` `export default`s its `GroupSpec` (named co-exports like error classes are still allowed).
|
|
27
|
+
- 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.
|
|
28
|
+
- 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.
|
|
29
|
+
|
|
30
|
+
### Tables are the source of truth, named by their filename
|
|
31
|
+
|
|
32
|
+
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.
|
|
33
|
+
|
|
34
|
+
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.
|
|
35
|
+
|
|
36
|
+
```ts confect/tables/notes.ts
|
|
37
|
+
import { Table } from "@confect/server";
|
|
38
|
+
import { Schema } from "effect";
|
|
39
|
+
import { Id } from "../_generated/id";
|
|
40
|
+
|
|
41
|
+
export default Table.make(() =>
|
|
42
|
+
Schema.Struct({
|
|
43
|
+
userId: Schema.optional(Id("users")),
|
|
44
|
+
text: Schema.String,
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Codegen emits, alongside it:
|
|
50
|
+
|
|
51
|
+
- `_generated/schema.ts`—the runtime `DatabaseSchema`. Never imports `convex/server`, so a runtime cold start no longer evaluates `defineSchema(...)`.
|
|
52
|
+
- `_generated/convexSchema.ts`—the Convex deploy `SchemaDefinition`, re-exported from `convex/schema.ts`.
|
|
53
|
+
- `_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.
|
|
54
|
+
- `_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/`.
|
|
55
|
+
|
|
56
|
+
A bound table's `name` property is renamed to `tableName` (avoiding a collision with `Function.prototype.name`).
|
|
57
|
+
|
|
58
|
+
### Specs and impls: lazy schemas, and impls take the `DatabaseSchema`
|
|
59
|
+
|
|
60
|
+
`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.
|
|
61
|
+
|
|
62
|
+
**Before:**
|
|
63
|
+
|
|
64
|
+
```ts confect/notes.spec.ts
|
|
65
|
+
export const notes = GroupSpec.make("notes").addFunction(
|
|
66
|
+
FunctionSpec.publicQuery({
|
|
67
|
+
name: "list",
|
|
68
|
+
args: Schema.Struct({}),
|
|
69
|
+
returns: Schema.Array(Notes.Doc),
|
|
70
|
+
})
|
|
71
|
+
);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```ts confect/notes.impl.ts
|
|
75
|
+
const list = FunctionImpl.make(api, "notes", "list", handler);
|
|
76
|
+
export const notes = GroupImpl.make(api, "notes").pipe(Layer.provide(list));
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**After:**
|
|
80
|
+
|
|
81
|
+
```ts confect/notes.spec.ts
|
|
82
|
+
import notes from "./_generated/tables/notes";
|
|
83
|
+
|
|
84
|
+
export default GroupSpec.make().addFunction(
|
|
85
|
+
FunctionSpec.publicQuery({
|
|
86
|
+
name: "list",
|
|
87
|
+
args: () => Schema.Struct({}),
|
|
88
|
+
returns: () => Schema.Array(notes.Doc),
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```ts confect/notes.impl.ts
|
|
94
|
+
import databaseSchema from "./_generated/schema";
|
|
95
|
+
import notes from "./notes.spec";
|
|
96
|
+
|
|
97
|
+
const list = FunctionImpl.make(databaseSchema, notes, "list", handler);
|
|
98
|
+
export default GroupImpl.make(databaseSchema, notes).pipe(
|
|
99
|
+
Layer.provide(list),
|
|
100
|
+
GroupImpl.finalize
|
|
101
|
+
);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Node functions are first-class
|
|
105
|
+
|
|
106
|
+
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.
|
|
107
|
+
|
|
108
|
+
- A Node group at `confect/email.spec.ts` is now reached at `refs.public.email.send` instead of `refs.public.node.email.send`.
|
|
109
|
+
- `@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.
|
|
110
|
+
|
|
111
|
+
### Less work at cold start
|
|
112
|
+
|
|
113
|
+
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.
|
|
114
|
+
|
|
115
|
+
### Stable React hook results
|
|
116
|
+
|
|
117
|
+
`@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.
|
|
118
|
+
|
|
119
|
+
### Codegen robustness
|
|
120
|
+
|
|
121
|
+
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.
|
|
122
|
+
|
|
123
|
+
### Migration
|
|
124
|
+
|
|
125
|
+
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`.
|
|
126
|
+
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"`.
|
|
127
|
+
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).
|
|
128
|
+
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)`.
|
|
129
|
+
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`.
|
|
130
|
+
6. **Optional.** Adopt submodule Effect imports (`import * as Schema from "effect/Schema"`) in your own `confect/` files for the full cold-start savings.
|
|
131
|
+
7. Run `confect codegen`. It re-emits the entire `convex/` tree and `confect/_generated/`, deleting any stale files from earlier versions.
|
|
132
|
+
|
|
133
|
+
### Patch Changes
|
|
134
|
+
|
|
135
|
+
- 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.)
|
|
136
|
+
|
|
137
|
+
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).
|
|
138
|
+
|
|
139
|
+
## 9.0.0-next.10
|
|
140
|
+
|
|
141
|
+
### Patch Changes
|
|
142
|
+
|
|
143
|
+
- 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.)
|
|
144
|
+
|
|
145
|
+
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).
|
|
146
|
+
|
|
3
147
|
## 9.0.0-next.9
|
|
4
148
|
|
|
5
149
|
### Major Changes
|
|
@@ -13,11 +157,13 @@
|
|
|
13
157
|
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).
|
|
14
158
|
|
|
15
159
|
### Breaking changes
|
|
160
|
+
|
|
16
161
|
- **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.
|
|
17
162
|
- **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).
|
|
18
163
|
- **`@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).
|
|
19
164
|
|
|
20
165
|
### Migration
|
|
166
|
+
|
|
21
167
|
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.
|
|
22
168
|
2. Update call sites to drop the `node` segment: `refs.public.node.<group>.<fn>` → `refs.public.<group>.<fn>`.
|
|
23
169
|
3. Replace `Refs.make(spec, nodeSpec)` with `Refs.make(spec)` (codegen does this for `_generated/refs.ts` automatically).
|
|
@@ -124,6 +270,7 @@
|
|
|
124
270
|
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.
|
|
125
271
|
|
|
126
272
|
Codegen now scans `confect/tables/*.ts` (every file must default-export a `Table`) and emits two siblings:
|
|
273
|
+
|
|
127
274
|
- `confect/_generated/schema.ts` — the runtime `DatabaseSchema`, consumed by `_generated/api.ts`. Imports `@confect/server` but never `convex/server`.
|
|
128
275
|
- `confect/_generated/convexSchema.ts` — the Convex deploy `SchemaDefinition`, re-exported one-line from `convex/schema.ts`. Imports `convex/server` but never `@confect/server`.
|
|
129
276
|
|
|
@@ -136,6 +283,7 @@
|
|
|
136
283
|
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.
|
|
137
284
|
|
|
138
285
|
Codegen now emits two new sets of files alongside `_generated/schema.ts` and `_generated/convexSchema.ts`:
|
|
286
|
+
|
|
139
287
|
- `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")`.
|
|
140
288
|
- `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`.
|
|
141
289
|
|
|
@@ -152,6 +300,7 @@
|
|
|
152
300
|
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).
|
|
153
301
|
|
|
154
302
|
### Migration
|
|
303
|
+
|
|
155
304
|
1. Delete your `confect/schema.ts`. Codegen will refuse to run while a stray copy is present.
|
|
156
305
|
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.
|
|
157
306
|
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`:
|
|
@@ -227,6 +376,7 @@
|
|
|
227
376
|
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.
|
|
228
377
|
|
|
229
378
|
### What changed
|
|
379
|
+
|
|
230
380
|
- `@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.
|
|
231
381
|
- `@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.
|
|
232
382
|
- `@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.
|
|
@@ -234,6 +384,7 @@
|
|
|
234
384
|
- `@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.
|
|
235
385
|
|
|
236
386
|
### User-facing impact
|
|
387
|
+
|
|
237
388
|
- 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.
|
|
238
389
|
- 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.
|
|
239
390
|
- 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.
|
|
@@ -261,6 +412,7 @@
|
|
|
261
412
|
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.
|
|
262
413
|
|
|
263
414
|
### Breaking changes
|
|
415
|
+
|
|
264
416
|
- `GroupSpec.make()` and `GroupSpec.makeNode()` no longer take a name argument; the group name is derived from the spec file's path within `confect/`.
|
|
265
417
|
- `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.
|
|
266
418
|
- 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.
|
|
@@ -269,6 +421,7 @@
|
|
|
269
421
|
- 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.
|
|
270
422
|
|
|
271
423
|
### Migration
|
|
424
|
+
|
|
272
425
|
1. For each existing group, create a colocated `confect/{path}.spec.ts` and `confect/{path}.impl.ts` pair (under a subdirectory for nested groups).
|
|
273
426
|
- In each spec, call `GroupSpec.make()` (or `GroupSpec.makeNode()`) without a name and `export default` the result.
|
|
274
427
|
- 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:
|
|
@@ -276,7 +429,7 @@
|
|
|
276
429
|
export default GroupImpl.make(api, notes).pipe(
|
|
277
430
|
Layer.provide(list),
|
|
278
431
|
Layer.provide(insert),
|
|
279
|
-
GroupImpl.finalize
|
|
432
|
+
GroupImpl.finalize
|
|
280
433
|
);
|
|
281
434
|
```
|
|
282
435
|
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.)
|
|
@@ -314,7 +467,7 @@
|
|
|
314
467
|
|
|
315
468
|
export class NoteNotFound extends Schema.TaggedError<NoteNotFound>()(
|
|
316
469
|
"NoteNotFound",
|
|
317
|
-
{ noteId: GenericId.GenericId("notes") }
|
|
470
|
+
{ noteId: GenericId.GenericId("notes") }
|
|
318
471
|
) {}
|
|
319
472
|
|
|
320
473
|
export const notes = GroupSpec.make("notes").addFunction(
|
|
@@ -323,7 +476,7 @@
|
|
|
323
476
|
args: Schema.Struct({ noteId: GenericId.GenericId("notes") }),
|
|
324
477
|
returns: Notes.Doc,
|
|
325
478
|
error: NoteNotFound,
|
|
326
|
-
})
|
|
479
|
+
})
|
|
327
480
|
);
|
|
328
481
|
```
|
|
329
482
|
|
|
@@ -343,7 +496,7 @@
|
|
|
343
496
|
.table("notes")
|
|
344
497
|
.get(noteId)
|
|
345
498
|
.pipe(Effect.mapError(() => new NoteNotFound({ noteId })));
|
|
346
|
-
})
|
|
499
|
+
})
|
|
347
500
|
);
|
|
348
501
|
```
|
|
349
502
|
|
|
@@ -415,6 +568,7 @@
|
|
|
415
568
|
Unspecified failures continue to reject the promise.
|
|
416
569
|
|
|
417
570
|
### Migration
|
|
571
|
+
|
|
418
572
|
- 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).
|
|
419
573
|
- 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.
|
|
420
574
|
|
|
@@ -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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
|
31
|
-
declare const FunctionProvenance: {
|
|
32
|
-
readonly Confect: Data.Case.Constructor<{
|
|
33
|
-
readonly _tag: "Confect";
|
|
34
|
-
readonly args: Schema.Schema.AnyNoContext;
|
|
35
|
-
readonly returns: Schema.Schema.AnyNoContext;
|
|
36
|
-
readonly error?: Schema.Schema.AnyNoContext;
|
|
37
|
-
}, "_tag">;
|
|
38
|
-
readonly Convex: Data.Case.Constructor<{
|
|
39
|
-
readonly _tag: "Convex";
|
|
40
|
-
readonly _args: DefaultFunctionArgs;
|
|
41
|
-
readonly _returns: any;
|
|
42
|
-
}, "_tag">;
|
|
43
|
-
readonly $is: <Tag extends "Confect" | "Convex">(tag: Tag) => (u: unknown) => u is Extract<{
|
|
44
|
-
readonly _tag: "Confect";
|
|
45
|
-
readonly args: Schema.Schema.AnyNoContext;
|
|
46
|
-
readonly returns: Schema.Schema.AnyNoContext;
|
|
47
|
-
readonly error?: Schema.Schema.AnyNoContext;
|
|
48
|
-
}, {
|
|
49
|
-
readonly _tag: Tag;
|
|
50
|
-
}> | Extract<{
|
|
20
|
+
export interface Convex<Args extends DefaultFunctionArgs, Returns> {
|
|
51
21
|
readonly _tag: "Convex";
|
|
52
|
-
readonly _args:
|
|
53
|
-
readonly _returns:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
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<{
|
|
60
29
|
readonly _tag: "Confect";
|
|
61
30
|
readonly args: Schema.Schema.AnyNoContext;
|
|
62
31
|
readonly returns: Schema.Schema.AnyNoContext;
|
|
63
32
|
readonly error?: Schema.Schema.AnyNoContext;
|
|
64
|
-
|
|
65
|
-
|
|
33
|
+
}, "_tag">;
|
|
34
|
+
readonly Convex: Data.Case.Constructor<{
|
|
66
35
|
readonly _tag: "Convex";
|
|
67
36
|
readonly _args: DefaultFunctionArgs;
|
|
68
37
|
readonly _returns: any;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
readonly _tag: "Confect";
|
|
72
|
-
readonly args: Schema.Schema.AnyNoContext;
|
|
73
|
-
readonly returns: Schema.Schema.AnyNoContext;
|
|
74
|
-
readonly error?: Schema.Schema.AnyNoContext;
|
|
75
|
-
} | {
|
|
76
|
-
readonly _tag: "Convex";
|
|
77
|
-
readonly _args: DefaultFunctionArgs;
|
|
78
|
-
readonly _returns: any;
|
|
79
|
-
}) => effect_Unify0.Unify<ReturnType<Cases["Confect" | "Convex"]>>;
|
|
80
|
-
<const Cases extends {
|
|
81
|
-
readonly Confect: (args: {
|
|
38
|
+
}, "_tag">;
|
|
39
|
+
readonly $is: <Tag extends "Confect" | "Convex">(tag: Tag) => (u: unknown) => u is Extract<{
|
|
82
40
|
readonly _tag: "Confect";
|
|
83
41
|
readonly args: Schema.Schema.AnyNoContext;
|
|
84
42
|
readonly returns: Schema.Schema.AnyNoContext;
|
|
85
43
|
readonly error?: Schema.Schema.AnyNoContext;
|
|
86
|
-
|
|
87
|
-
|
|
44
|
+
}, {
|
|
45
|
+
readonly _tag: Tag;
|
|
46
|
+
}> | Extract<{
|
|
88
47
|
readonly _tag: "Convex";
|
|
89
48
|
readonly _args: DefaultFunctionArgs;
|
|
90
49
|
readonly _returns: any;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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","
|
|
1
|
+
{"version":3,"file":"FunctionProvenance.d.ts","sourceRoot":"","sources":["../src/FunctionProvenance.ts"],"names":[],"mappings":"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"}
|