@confect/core 9.0.0-next.1 → 9.0.0-next.10
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 +266 -4
- package/dist/FunctionProvenance.d.ts +101 -95
- package/dist/FunctionProvenance.d.ts.map +1 -1
- package/dist/FunctionProvenance.js +25 -6
- package/dist/FunctionProvenance.js.map +1 -1
- package/dist/FunctionSpec.d.ts +178 -218
- package/dist/FunctionSpec.d.ts.map +1 -1
- package/dist/FunctionSpec.js +2 -2
- package/dist/FunctionSpec.js.map +1 -1
- package/dist/GenericId.d.ts +7 -12
- package/dist/GenericId.d.ts.map +1 -1
- package/dist/GenericId.js +2 -1
- package/dist/GenericId.js.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/GroupSpec.js +9 -3
- package/dist/GroupSpec.js.map +1 -1
- package/dist/Identifier.d.ts +14 -0
- package/dist/Identifier.d.ts.map +1 -0
- package/dist/{internal/utils.js → Identifier.js} +26 -3
- package/dist/Identifier.js.map +1 -0
- package/dist/Lazy.d.ts +22 -0
- package/dist/Lazy.d.ts.map +1 -0
- package/dist/Lazy.js +44 -0
- package/dist/Lazy.js.map +1 -0
- package/dist/PaginationResult.d.ts +11 -18
- package/dist/PaginationResult.d.ts.map +1 -1
- package/dist/PaginationResult.js +1 -1
- package/dist/PaginationResult.js.map +1 -1
- package/dist/Ref.d.ts +55 -51
- package/dist/Ref.d.ts.map +1 -1
- package/dist/Ref.js +17 -6
- package/dist/Ref.js.map +1 -1
- package/dist/Refs.d.ts +21 -21
- package/dist/Refs.d.ts.map +1 -1
- package/dist/Refs.js +5 -10
- package/dist/Refs.js.map +1 -1
- package/dist/Registry.d.ts +7 -11
- package/dist/Registry.d.ts.map +1 -1
- package/dist/Registry.js +2 -1
- package/dist/Registry.js.map +1 -1
- package/dist/RuntimeAndFunctionType.d.ts +36 -41
- package/dist/RuntimeAndFunctionType.d.ts.map +1 -1
- package/dist/Spec.d.ts +23 -32
- package/dist/Spec.d.ts.map +1 -1
- package/dist/Spec.js +9 -48
- package/dist/Spec.js.map +1 -1
- package/dist/SystemFields.d.ts +10 -16
- package/dist/SystemFields.d.ts.map +1 -1
- package/dist/SystemFields.js +1 -1
- package/dist/SystemFields.js.map +1 -1
- package/dist/Types.d.ts +27 -27
- package/dist/Types.d.ts.map +1 -1
- package/dist/UserIdentity.d.ts +56 -63
- package/dist/UserIdentity.d.ts.map +1 -1
- package/dist/UserIdentity.js +1 -1
- package/dist/UserIdentity.js.map +1 -1
- package/dist/index.d.ts +17 -15
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -1
- package/dist/tsconfig.src.tsbuildinfo +1 -0
- package/package.json +37 -46
- package/src/FunctionProvenance.ts +32 -10
- package/src/FunctionSpec.ts +5 -5
- package/src/GenericId.ts +3 -1
- package/src/GroupSpec.ts +16 -11
- package/src/{internal/utils.ts → Identifier.ts} +34 -0
- package/src/Lazy.ts +40 -0
- package/src/PaginationResult.ts +1 -1
- package/src/Ref.ts +23 -8
- package/src/Refs.ts +13 -44
- package/src/Registry.ts +2 -1
- package/src/Spec.ts +18 -81
- package/src/SystemFields.ts +1 -1
- package/src/UserIdentity.ts +1 -1
- package/src/index.ts +2 -0
- package/dist/internal/utils.d.ts +0 -5
- package/dist/internal/utils.d.ts.map +0 -1
- package/dist/internal/utils.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DefaultFunctionArgs } from "convex/server";
|
|
2
2
|
import type { Schema } from "effect";
|
|
3
|
-
import
|
|
3
|
+
import * as Data from "effect/Data";
|
|
4
|
+
import * as Lazy from "./Lazy";
|
|
4
5
|
|
|
5
6
|
export type FunctionProvenance = Data.TaggedEnum<{
|
|
6
7
|
Confect: {
|
|
@@ -43,20 +44,41 @@ export interface AnyConvex extends Convex<DefaultFunctionArgs, any> {}
|
|
|
43
44
|
|
|
44
45
|
export const FunctionProvenance = Data.taggedEnum<FunctionProvenance>();
|
|
45
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Build a `Confect` provenance from lazy schema thunks. `args`, `returns`,
|
|
49
|
+
* and `error` are exposed as sync lazy memoised getters (via {@link Lazy.defineProperty})
|
|
50
|
+
* that only evaluate their thunk on first access, mirroring how `Table`
|
|
51
|
+
* defers `Fields`/`Doc`/`tableDefinition`. This keeps importing the assembled
|
|
52
|
+
* `_generated/spec.ts` cheap — no `Schema.Struct(...)` / `Schema.Array(...)`
|
|
53
|
+
* work runs at module load; it is deferred to the first invocation that
|
|
54
|
+
* actually compiles validators or runs a codec.
|
|
55
|
+
*
|
|
56
|
+
* The object is built by hand rather than through `FunctionProvenance.Confect`
|
|
57
|
+
* because the `Data` constructor copies its input with `Object.assign`, which
|
|
58
|
+
* would force the getters at construction time and defeat the laziness.
|
|
59
|
+
* `error` is only installed when an `errorThunk` is provided, so its absence
|
|
60
|
+
* is observable via `"error" in provenance` without forcing anything; nothing
|
|
61
|
+
* relies on `Data`'s structural `Equal`/`Hash` for provenance values.
|
|
62
|
+
*/
|
|
46
63
|
export const Confect = <
|
|
47
64
|
Args extends Schema.Schema.AnyNoContext,
|
|
48
65
|
Returns extends Schema.Schema.AnyNoContext,
|
|
49
66
|
Error extends Schema.Schema.AnyNoContext = never,
|
|
50
67
|
>(
|
|
51
|
-
args: Args,
|
|
52
|
-
returns: Returns,
|
|
53
|
-
error?: Error,
|
|
54
|
-
) =>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
68
|
+
args: () => Args,
|
|
69
|
+
returns: () => Returns,
|
|
70
|
+
error?: () => Error,
|
|
71
|
+
): Confect<Args, Returns, Error> => {
|
|
72
|
+
const provenance = { _tag: "Confect" as const };
|
|
73
|
+
|
|
74
|
+
Lazy.defineProperty(provenance, "args", args);
|
|
75
|
+
Lazy.defineProperty(provenance, "returns", returns);
|
|
76
|
+
if (error !== undefined) {
|
|
77
|
+
Lazy.defineProperty(provenance, "error", error);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return provenance as Confect<Args, Returns, Error>;
|
|
81
|
+
};
|
|
60
82
|
|
|
61
83
|
export const Convex = <_Args extends DefaultFunctionArgs, _Returns>() =>
|
|
62
84
|
FunctionProvenance.Convex(
|
package/src/FunctionSpec.ts
CHANGED
|
@@ -6,9 +6,9 @@ import type {
|
|
|
6
6
|
RegisteredQuery,
|
|
7
7
|
} from "convex/server";
|
|
8
8
|
import type { Schema } from "effect";
|
|
9
|
-
import
|
|
9
|
+
import * as Predicate from "effect/Predicate";
|
|
10
10
|
import * as FunctionProvenance from "./FunctionProvenance";
|
|
11
|
-
import { validateConfectFunctionIdentifier } from "./
|
|
11
|
+
import { validateConfectFunctionIdentifier } from "./Identifier";
|
|
12
12
|
import * as RuntimeAndFunctionType from "./RuntimeAndFunctionType";
|
|
13
13
|
|
|
14
14
|
export const TypeId = "@confect/core/FunctionSpec";
|
|
@@ -225,9 +225,9 @@ const make =
|
|
|
225
225
|
error,
|
|
226
226
|
}: {
|
|
227
227
|
name: Name_;
|
|
228
|
-
args: Args_;
|
|
229
|
-
returns: Returns_;
|
|
230
|
-
error?: Error_;
|
|
228
|
+
args: () => Args_;
|
|
229
|
+
returns: () => Returns_;
|
|
230
|
+
error?: () => Error_;
|
|
231
231
|
}): FunctionSpec<
|
|
232
232
|
RuntimeAndFunctionType_,
|
|
233
233
|
FunctionVisibility_,
|
package/src/GenericId.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { GenericId as ConvexGenericId } from "convex/values";
|
|
2
|
-
import {
|
|
2
|
+
import type { Option } from "effect";
|
|
3
|
+
import * as Schema from "effect/Schema";
|
|
4
|
+
import * as SchemaAST from "effect/SchemaAST";
|
|
3
5
|
|
|
4
6
|
const ConvexId = Symbol.for("ConvexId");
|
|
5
7
|
|
package/src/GroupSpec.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Predicate from "effect/Predicate";
|
|
2
|
+
import * as Record from "effect/Record";
|
|
2
3
|
import type * as FunctionSpec from "./FunctionSpec";
|
|
3
4
|
import type * as RuntimeAndFunctionType from "./RuntimeAndFunctionType";
|
|
4
|
-
import { validateConfectFunctionIdentifier } from "./
|
|
5
|
+
import { validateConfectFunctionIdentifier } from "./Identifier";
|
|
5
6
|
|
|
6
7
|
export const TypeId = "@confect/core/GroupSpec";
|
|
7
8
|
export type TypeId = typeof TypeId;
|
|
@@ -13,7 +14,11 @@ export interface GroupSpec<
|
|
|
13
14
|
Runtime extends RuntimeAndFunctionType.Runtime,
|
|
14
15
|
Name_ extends string,
|
|
15
16
|
Functions_ extends FunctionSpec.AnyWithPropsWithRuntime<Runtime> = never,
|
|
16
|
-
|
|
17
|
+
// Subgroups may be of any runtime, independent of this group's own runtime: a
|
|
18
|
+
// group is only a namespace for its children, which are otherwise-independent
|
|
19
|
+
// modules. Functions, by contrast, stay homogeneous (a Node group only accepts
|
|
20
|
+
// Node actions) — `addFunction` keeps the `<Runtime>` bound below.
|
|
21
|
+
Groups_ extends AnyWithProps = never,
|
|
17
22
|
> {
|
|
18
23
|
readonly [TypeId]: TypeId;
|
|
19
24
|
readonly runtime: Runtime;
|
|
@@ -31,14 +36,11 @@ export interface GroupSpec<
|
|
|
31
36
|
function_: Function,
|
|
32
37
|
): GroupSpec<Runtime, Name_, Functions_ | Function, Groups_>;
|
|
33
38
|
|
|
34
|
-
addGroup<Group extends
|
|
39
|
+
addGroup<Group extends AnyWithProps>(
|
|
35
40
|
group: Group,
|
|
36
41
|
): GroupSpec<Runtime, Name_, Functions_, Groups_ | Group>;
|
|
37
42
|
|
|
38
|
-
addGroupAt<
|
|
39
|
-
const AtName extends string,
|
|
40
|
-
Group extends AnyWithPropsWithRuntime<Runtime>,
|
|
41
|
-
>(
|
|
43
|
+
addGroupAt<const AtName extends string, Group extends AnyWithProps>(
|
|
42
44
|
name: AtName,
|
|
43
45
|
group: Group,
|
|
44
46
|
): GroupSpec<Runtime, Name_, Functions_, Groups_ | NamedAt<Group, AtName>>;
|
|
@@ -209,7 +211,10 @@ export const withName = <const Name_ extends string>(
|
|
|
209
211
|
return group_;
|
|
210
212
|
}
|
|
211
213
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
214
|
+
return makeProto({
|
|
215
|
+
runtime: group_.runtime,
|
|
216
|
+
name,
|
|
217
|
+
functions: group_.functions,
|
|
218
|
+
groups: group_.groups,
|
|
219
|
+
});
|
|
215
220
|
};
|
|
@@ -56,6 +56,12 @@ const RESERVED_CONVEX_FILE_NAMES = new Set(["schema", "http", "crons"]);
|
|
|
56
56
|
|
|
57
57
|
const jsIdentifierRegex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
58
58
|
|
|
59
|
+
// Stricter than `jsIdentifierRegex`: tables cannot start with `_` (Convex
|
|
60
|
+
// reserves leading underscores for system tables) or `$` (Convex's table
|
|
61
|
+
// naming grammar does not accept it). Letters/digits/underscore only,
|
|
62
|
+
// letter-leading.
|
|
63
|
+
const tableNameRegex = /^[a-zA-Z][a-zA-Z0-9_]*$/;
|
|
64
|
+
|
|
59
65
|
const isReservedJsIdentifier = (identifier: string) =>
|
|
60
66
|
RESERVED_JS_IDENTIFIERS.has(identifier);
|
|
61
67
|
|
|
@@ -65,6 +71,9 @@ const isReservedConvexFileName = (fileName: string) =>
|
|
|
65
71
|
const matchesJsIdentifierPattern = (identifier: string) =>
|
|
66
72
|
jsIdentifierRegex.test(identifier);
|
|
67
73
|
|
|
74
|
+
const matchesTableNamePattern = (identifier: string) =>
|
|
75
|
+
tableNameRegex.test(identifier);
|
|
76
|
+
|
|
68
77
|
export const validateConfectFunctionIdentifier = (identifier: string) => {
|
|
69
78
|
if (!matchesJsIdentifierPattern(identifier)) {
|
|
70
79
|
throw new Error(
|
|
@@ -84,3 +93,28 @@ export const validateConfectFunctionIdentifier = (identifier: string) => {
|
|
|
84
93
|
);
|
|
85
94
|
}
|
|
86
95
|
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Validate that `identifier` is suitable as a Convex table name (and, equivalently,
|
|
99
|
+
* as a `confect/tables/<identifier>.ts` filename).
|
|
100
|
+
*
|
|
101
|
+
* Rules:
|
|
102
|
+
* - Must match `/^[A-Za-z][A-Za-z0-9_]*$/` — letter-leading, alphanumeric plus
|
|
103
|
+
* underscore. No `$` (not a valid Convex table name character); no leading
|
|
104
|
+
* `_` (Convex reserves `_<name>` for its system tables).
|
|
105
|
+
* - Must not be a reserved JavaScript identifier, so the name can also be used
|
|
106
|
+
* as a binding name in generated code without escaping.
|
|
107
|
+
*/
|
|
108
|
+
export const validateConfectTableIdentifier = (identifier: string) => {
|
|
109
|
+
if (!matchesTableNamePattern(identifier)) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
`Expected a valid Confect table identifier, but received: "${identifier}". Valid table identifiers must start with a letter and can only contain letters, numbers, and underscores. Leading underscores are reserved for Convex system tables.`,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (isReservedJsIdentifier(identifier)) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Expected a valid Confect table identifier, but received: "${identifier}". "${identifier}" is a reserved JavaScript identifier.`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
};
|
package/src/Lazy.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install a lazy memoised property on `target`. The first access runs
|
|
3
|
+
* `compute()` and replaces the getter with a plain, non-writable data
|
|
4
|
+
* property whose value is the computed result. Subsequent accesses hit
|
|
5
|
+
* the V8 fast path for own data properties — no function call, identical
|
|
6
|
+
* returned reference — so first and second-and-subsequent accesses are
|
|
7
|
+
* observably indistinguishable.
|
|
8
|
+
*
|
|
9
|
+
* The replacement property is `enumerable: true` so the lazy property
|
|
10
|
+
* still participates in `Object.keys` / `JSON.stringify` after it
|
|
11
|
+
* materialises, matching the shape of a plain data property. The property
|
|
12
|
+
* is also `enumerable` before materialising, so presence checks
|
|
13
|
+
* (`"key" in target`, `Object.hasOwn(target, key)`) observe it without
|
|
14
|
+
* forcing the computation.
|
|
15
|
+
*
|
|
16
|
+
* This is the single shared implementation consumed across packages (e.g.
|
|
17
|
+
* `@confect/core`'s lazy `FunctionSpec` schemas and `@confect/server`'s lazy
|
|
18
|
+
* `Table` `Fields` / `Doc` / `tableDefinition`), so there is no chance of the
|
|
19
|
+
* two drifting apart.
|
|
20
|
+
*/
|
|
21
|
+
export const defineProperty = <T extends object, K extends PropertyKey>(
|
|
22
|
+
target: T,
|
|
23
|
+
key: K,
|
|
24
|
+
compute: () => unknown,
|
|
25
|
+
): void => {
|
|
26
|
+
Object.defineProperty(target, key, {
|
|
27
|
+
configurable: true,
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get(this: T) {
|
|
30
|
+
const value = compute();
|
|
31
|
+
Object.defineProperty(this, key, {
|
|
32
|
+
value,
|
|
33
|
+
writable: false,
|
|
34
|
+
enumerable: true,
|
|
35
|
+
configurable: false,
|
|
36
|
+
});
|
|
37
|
+
return value;
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
};
|
package/src/PaginationResult.ts
CHANGED
package/src/Ref.ts
CHANGED
|
@@ -6,7 +6,10 @@ import { makeFunctionReference } from "convex/server";
|
|
|
6
6
|
import type { Value } from "convex/values";
|
|
7
7
|
import { ConvexError } from "convex/values";
|
|
8
8
|
import type { ParseResult } from "effect";
|
|
9
|
-
import
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as Match from "effect/Match";
|
|
11
|
+
import * as Option from "effect/Option";
|
|
12
|
+
import * as Schema from "effect/Schema";
|
|
10
13
|
import type * as FunctionSpec from "./FunctionSpec";
|
|
11
14
|
import type * as RuntimeAndFunctionType from "./RuntimeAndFunctionType";
|
|
12
15
|
|
|
@@ -190,17 +193,29 @@ export const make = <FunctionSpec_ extends FunctionSpec.AnyWithProps>(
|
|
|
190
193
|
export const getConvexFunctionName = (ref: Any): string =>
|
|
191
194
|
`${ref.functionNamespace}:${ref.functionSpec.name}`;
|
|
192
195
|
|
|
196
|
+
const functionReferenceCache = new Map<string, FunctionReference<Any>>();
|
|
197
|
+
|
|
193
198
|
export const getFunctionReference = <Ref_ extends Any>(
|
|
194
199
|
ref: Ref_,
|
|
195
|
-
): FunctionReference<Ref_> =>
|
|
196
|
-
|
|
200
|
+
): FunctionReference<Ref_> => {
|
|
201
|
+
const functionName = getConvexFunctionName(ref);
|
|
202
|
+
|
|
203
|
+
const cached = functionReferenceCache.get(functionName);
|
|
204
|
+
if (cached !== undefined) {
|
|
205
|
+
return cached as FunctionReference<Ref_>;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const functionReference = makeFunctionReference(functionName);
|
|
209
|
+
functionReferenceCache.set(functionName, functionReference);
|
|
210
|
+
|
|
211
|
+
return functionReference as FunctionReference<Ref_>;
|
|
212
|
+
};
|
|
197
213
|
|
|
198
214
|
export const hasErrorSchema = (ref: Any): boolean =>
|
|
199
215
|
Match.value(ref.functionSpec.functionProvenance).pipe(
|
|
200
216
|
Match.tag(
|
|
201
217
|
"Confect",
|
|
202
|
-
(confectFunctionProvenance) =>
|
|
203
|
-
confectFunctionProvenance.error !== undefined,
|
|
218
|
+
(confectFunctionProvenance) => "error" in confectFunctionProvenance,
|
|
204
219
|
),
|
|
205
220
|
Match.tag("Convex", () => false),
|
|
206
221
|
Match.exhaustive,
|
|
@@ -296,7 +311,7 @@ export const decodeError = <Ref_ extends Any>(
|
|
|
296
311
|
): Effect.Effect<Option.Option<Error<Ref_>>, ParseResult.ParseError> =>
|
|
297
312
|
Match.value(ref.functionSpec.functionProvenance).pipe(
|
|
298
313
|
Match.tag("Confect", (confectFunctionProvenance) =>
|
|
299
|
-
|
|
314
|
+
"error" in confectFunctionProvenance
|
|
300
315
|
? Effect.map(
|
|
301
316
|
Schema.decode(confectFunctionProvenance.error)(encodedError),
|
|
302
317
|
Option.some,
|
|
@@ -317,7 +332,7 @@ export const decodeErrorSync = <Ref_ extends Any>(
|
|
|
317
332
|
): Option.Option<Error<Ref_>> =>
|
|
318
333
|
Match.value(ref.functionSpec.functionProvenance).pipe(
|
|
319
334
|
Match.tag("Confect", (confectFunctionProvenance) =>
|
|
320
|
-
|
|
335
|
+
"error" in confectFunctionProvenance
|
|
321
336
|
? Option.some(
|
|
322
337
|
Schema.decodeSync(confectFunctionProvenance.error)(
|
|
323
338
|
encodedError,
|
|
@@ -336,7 +351,7 @@ export const maybeDecodeErrorSync = <Ref_ extends Any>(
|
|
|
336
351
|
isConvexError(error)
|
|
337
352
|
? Match.value(ref.functionSpec.functionProvenance).pipe(
|
|
338
353
|
Match.tag("Confect", (confectFunctionProvenance) =>
|
|
339
|
-
|
|
354
|
+
"error" in confectFunctionProvenance
|
|
340
355
|
? Schema.decodeSync(confectFunctionProvenance.error)(error.data)
|
|
341
356
|
: error,
|
|
342
357
|
),
|
package/src/Refs.ts
CHANGED
|
@@ -1,30 +1,16 @@
|
|
|
1
1
|
import type { Types } from "effect";
|
|
2
|
-
import {
|
|
2
|
+
import { pipe } from "effect/Function";
|
|
3
|
+
import * as Option from "effect/Option";
|
|
4
|
+
import * as Record from "effect/Record";
|
|
3
5
|
import type * as FunctionSpec from "./FunctionSpec";
|
|
4
|
-
import * as GroupSpec from "./GroupSpec";
|
|
6
|
+
import type * as GroupSpec from "./GroupSpec";
|
|
5
7
|
import * as Ref from "./Ref";
|
|
6
8
|
import type * as Spec from "./Spec";
|
|
7
9
|
|
|
8
10
|
export type Refs<
|
|
9
|
-
|
|
10
|
-
NodeSpec extends Spec.AnyWithPropsWithRuntime<"Node"> = never,
|
|
11
|
+
Spec_ extends Spec.AnyWithProps,
|
|
11
12
|
Predicate extends Ref.Any = Ref.Any,
|
|
12
|
-
> = Types.Simplify<
|
|
13
|
-
OmitEmpty<
|
|
14
|
-
Helper<
|
|
15
|
-
| Spec.Groups<ConvexSpec>
|
|
16
|
-
| (NodeSpec extends never
|
|
17
|
-
? never
|
|
18
|
-
: GroupSpec.GroupSpec<
|
|
19
|
-
"Node",
|
|
20
|
-
"node",
|
|
21
|
-
never,
|
|
22
|
-
NodeSpec["groups"][keyof NodeSpec["groups"]]
|
|
23
|
-
>),
|
|
24
|
-
Predicate
|
|
25
|
-
>
|
|
26
|
-
>
|
|
27
|
-
>;
|
|
13
|
+
> = Types.Simplify<OmitEmpty<Helper<Spec.Groups<Spec_>, Predicate>>>;
|
|
28
14
|
|
|
29
15
|
type GroupRefs<
|
|
30
16
|
Group extends GroupSpec.AnyWithProps,
|
|
@@ -86,33 +72,16 @@ type Any =
|
|
|
86
72
|
}
|
|
87
73
|
| Ref.Any;
|
|
88
74
|
|
|
89
|
-
export const make = <
|
|
90
|
-
|
|
91
|
-
NodeSpec extends Spec.AnyWithPropsWithRuntime<"Node"> = never,
|
|
92
|
-
>(
|
|
93
|
-
convexSpec: ConvexSpec,
|
|
94
|
-
nodeSpec?: NodeSpec,
|
|
75
|
+
export const make = <Spec_ extends Spec.AnyWithProps>(
|
|
76
|
+
spec: Spec_,
|
|
95
77
|
): {
|
|
96
|
-
public: Refs<
|
|
97
|
-
internal: Refs<
|
|
78
|
+
public: Refs<Spec_, Ref.AnyPublic>;
|
|
79
|
+
internal: Refs<Spec_, Ref.AnyInternal>;
|
|
98
80
|
} => {
|
|
99
|
-
const
|
|
100
|
-
Option.map((nodeSpec_) =>
|
|
101
|
-
Array.reduce(
|
|
102
|
-
Record.toEntries(nodeSpec_.groups),
|
|
103
|
-
GroupSpec.makeNodeAt("node"),
|
|
104
|
-
(nodeGroupSpec, [name, group]) => nodeGroupSpec.addGroupAt(name, group),
|
|
105
|
-
),
|
|
106
|
-
),
|
|
107
|
-
Option.match({
|
|
108
|
-
onNone: () => convexSpec.groups,
|
|
109
|
-
onSome: (nodeGroup) => ({ ...convexSpec.groups, node: nodeGroup }),
|
|
110
|
-
}),
|
|
111
|
-
);
|
|
112
|
-
const refs = makeHelper(groups);
|
|
81
|
+
const refs = makeHelper(spec.groups);
|
|
113
82
|
return {
|
|
114
|
-
public: refs as Refs<
|
|
115
|
-
internal: refs as Refs<
|
|
83
|
+
public: refs as Refs<Spec_, Ref.AnyPublic>,
|
|
84
|
+
internal: refs as Refs<Spec_, Ref.AnyInternal>,
|
|
116
85
|
};
|
|
117
86
|
};
|
|
118
87
|
|
package/src/Registry.ts
CHANGED
package/src/Spec.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Predicate from "effect/Predicate";
|
|
2
|
+
import * as Record from "effect/Record";
|
|
2
3
|
import * as GroupSpec from "./GroupSpec";
|
|
3
|
-
import type * as RuntimeAndFunctionType from "./RuntimeAndFunctionType";
|
|
4
4
|
|
|
5
5
|
export const TypeId = "@confect/core/Spec";
|
|
6
6
|
export type TypeId = typeof TypeId;
|
|
@@ -8,24 +8,15 @@ export type TypeId = typeof TypeId;
|
|
|
8
8
|
export const isSpec = (u: unknown): u is AnyWithProps =>
|
|
9
9
|
Predicate.hasProperty(u, TypeId);
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export
|
|
19
|
-
Predicate.hasProperty(u, TypeId) &&
|
|
20
|
-
Predicate.hasProperty(u, "runtime") &&
|
|
21
|
-
u.runtime === "Node";
|
|
22
|
-
|
|
23
|
-
export interface Spec<
|
|
24
|
-
Runtime extends RuntimeAndFunctionType.Runtime,
|
|
25
|
-
Groups_ extends GroupSpec.AnyWithPropsWithRuntime<Runtime> = never,
|
|
26
|
-
> {
|
|
11
|
+
/**
|
|
12
|
+
* A Confect spec: a flat container of function groups. Groups may be of any
|
|
13
|
+
* runtime — a group built with `GroupSpec.makeNode()` (a Node action group) sits
|
|
14
|
+
* alongside `GroupSpec.make()` groups in the same namespace. The runtime of a
|
|
15
|
+
* group lives on the group itself (`GroupSpec.runtime`) and on each function's
|
|
16
|
+
* `RuntimeAndFunctionType`; the spec does not carry a runtime of its own.
|
|
17
|
+
*/
|
|
18
|
+
export interface Spec<Groups_ extends GroupSpec.AnyWithProps = never> {
|
|
27
19
|
readonly [TypeId]: TypeId;
|
|
28
|
-
readonly runtime: Runtime;
|
|
29
20
|
readonly groups: {
|
|
30
21
|
[GroupName in GroupSpec.Name<Groups_>]: GroupSpec.WithName<
|
|
31
22
|
Groups_,
|
|
@@ -33,31 +24,21 @@ export interface Spec<
|
|
|
33
24
|
>;
|
|
34
25
|
};
|
|
35
26
|
|
|
36
|
-
add<Group extends GroupSpec.
|
|
27
|
+
add<Group extends GroupSpec.AnyWithProps>(
|
|
37
28
|
group: Group,
|
|
38
|
-
): Spec<
|
|
29
|
+
): Spec<Groups_ | Group>;
|
|
39
30
|
|
|
40
|
-
addAt<
|
|
41
|
-
const Name extends string,
|
|
42
|
-
Group extends GroupSpec.AnyWithPropsWithRuntime<Runtime>,
|
|
43
|
-
>(
|
|
31
|
+
addAt<const Name extends string, Group extends GroupSpec.AnyWithProps>(
|
|
44
32
|
name: Name,
|
|
45
33
|
group: Group,
|
|
46
|
-
): Spec<
|
|
34
|
+
): Spec<Groups_ | GroupSpec.NamedAt<Group, Name>>;
|
|
47
35
|
}
|
|
48
36
|
|
|
49
37
|
export interface Any {
|
|
50
38
|
readonly [TypeId]: TypeId;
|
|
51
39
|
}
|
|
52
40
|
|
|
53
|
-
export interface AnyWithProps extends Spec<
|
|
54
|
-
RuntimeAndFunctionType.Runtime,
|
|
55
|
-
GroupSpec.AnyWithProps
|
|
56
|
-
> {}
|
|
57
|
-
|
|
58
|
-
export interface AnyWithPropsWithRuntime<
|
|
59
|
-
Runtime extends RuntimeAndFunctionType.Runtime,
|
|
60
|
-
> extends Spec<Runtime, GroupSpec.AnyWithPropsWithRuntime<Runtime>> {}
|
|
41
|
+
export interface AnyWithProps extends Spec<GroupSpec.AnyWithProps> {}
|
|
61
42
|
|
|
62
43
|
export type Groups<Spec_ extends AnyWithProps> =
|
|
63
44
|
Spec_["groups"][keyof Spec_["groups"]];
|
|
@@ -67,7 +48,6 @@ const Proto = {
|
|
|
67
48
|
|
|
68
49
|
add<Group extends GroupSpec.AnyWithProps>(this: AnyWithProps, group: Group) {
|
|
69
50
|
return makeProto({
|
|
70
|
-
runtime: this.runtime,
|
|
71
51
|
groups: Record.set(this.groups, group.name, group),
|
|
72
52
|
});
|
|
73
53
|
},
|
|
@@ -78,61 +58,18 @@ const Proto = {
|
|
|
78
58
|
group: Group,
|
|
79
59
|
) {
|
|
80
60
|
return makeProto({
|
|
81
|
-
runtime: this.runtime,
|
|
82
61
|
groups: Record.set(this.groups, name, GroupSpec.withName(name, group)),
|
|
83
62
|
});
|
|
84
63
|
},
|
|
85
64
|
};
|
|
86
65
|
|
|
87
|
-
const makeProto = <
|
|
88
|
-
Runtime extends RuntimeAndFunctionType.Runtime,
|
|
89
|
-
Groups_ extends GroupSpec.AnyWithPropsWithRuntime<Runtime>,
|
|
90
|
-
>({
|
|
91
|
-
runtime,
|
|
66
|
+
const makeProto = <Groups_ extends GroupSpec.AnyWithProps>({
|
|
92
67
|
groups,
|
|
93
68
|
}: {
|
|
94
|
-
runtime: Runtime;
|
|
95
69
|
groups: Record.ReadonlyRecord<string, Groups_>;
|
|
96
|
-
}): Spec<
|
|
70
|
+
}): Spec<Groups_> =>
|
|
97
71
|
Object.assign(Object.create(Proto), {
|
|
98
|
-
runtime,
|
|
99
72
|
groups,
|
|
100
73
|
});
|
|
101
74
|
|
|
102
|
-
export const make = (): Spec
|
|
103
|
-
makeProto({ runtime: "Convex", groups: {} });
|
|
104
|
-
|
|
105
|
-
export const makeNode = (): Spec<"Node"> =>
|
|
106
|
-
makeProto({ runtime: "Node", groups: {} });
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Merges a Convex spec with an optional Node spec for use with `Api.make`.
|
|
110
|
-
* When `nodeSpec` is provided, its groups are merged under a "node" namespace,
|
|
111
|
-
* mirroring the structure used by `Refs.make`.
|
|
112
|
-
*/
|
|
113
|
-
export const merge = <
|
|
114
|
-
ConvexSpec extends AnyWithPropsWithRuntime<"Convex">,
|
|
115
|
-
NodeSpec extends AnyWithPropsWithRuntime<"Node">,
|
|
116
|
-
>(
|
|
117
|
-
convexSpec: ConvexSpec,
|
|
118
|
-
nodeSpec?: NodeSpec,
|
|
119
|
-
): AnyWithProps => {
|
|
120
|
-
const groups = Option.fromNullable(nodeSpec).pipe(
|
|
121
|
-
Option.map((nodeSpec_) =>
|
|
122
|
-
Array.reduce(
|
|
123
|
-
Record.toEntries(nodeSpec_.groups),
|
|
124
|
-
GroupSpec.makeNodeAt("node"),
|
|
125
|
-
(nodeGroupSpec, [name, group]) => nodeGroupSpec.addGroupAt(name, group),
|
|
126
|
-
),
|
|
127
|
-
),
|
|
128
|
-
Option.match({
|
|
129
|
-
onNone: () => convexSpec.groups,
|
|
130
|
-
onSome: (nodeGroup) => ({ ...convexSpec.groups, node: nodeGroup }),
|
|
131
|
-
}),
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
return Object.assign(Object.create(Proto), {
|
|
135
|
-
runtime: "Convex" as const,
|
|
136
|
-
groups,
|
|
137
|
-
}) as AnyWithProps;
|
|
138
|
-
};
|
|
75
|
+
export const make = (): Spec => makeProto({ groups: {} });
|
package/src/SystemFields.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
IdField,
|
|
4
4
|
SystemFields as NonIdSystemFields,
|
|
5
5
|
} from "convex/server";
|
|
6
|
-
import
|
|
6
|
+
import * as Schema from "effect/Schema";
|
|
7
7
|
import * as GenericId from "./GenericId";
|
|
8
8
|
|
|
9
9
|
type SystemFieldsSchema<TableName extends string> = Schema.Struct<{
|
package/src/UserIdentity.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -3,6 +3,8 @@ export * as FunctionSpec from "./FunctionSpec";
|
|
|
3
3
|
export * as GenericId from "./GenericId";
|
|
4
4
|
export * as GroupPath from "./GroupPath";
|
|
5
5
|
export * as GroupSpec from "./GroupSpec";
|
|
6
|
+
export * as Identifier from "./Identifier";
|
|
7
|
+
export * as Lazy from "./Lazy";
|
|
6
8
|
export * as PaginationResult from "./PaginationResult";
|
|
7
9
|
export * as Ref from "./Ref";
|
|
8
10
|
export * as Refs from "./Refs";
|
package/dist/internal/utils.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","names":[],"sources":["../../src/internal/utils.ts"],"mappings":";cAmEa,iCAAA,GAAqC,UAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../../src/internal/utils.ts"],"sourcesContent":["const RESERVED_JS_IDENTIFIERS = new Set([\n // Reserved keywords\n \"break\",\n \"case\",\n \"catch\",\n \"class\",\n \"const\",\n \"continue\",\n \"debugger\",\n \"default\",\n \"delete\",\n \"do\",\n \"else\",\n \"export\",\n \"extends\",\n \"finally\",\n \"for\",\n \"function\",\n \"if\",\n \"import\",\n \"in\",\n \"instanceof\",\n \"new\",\n \"return\",\n \"super\",\n \"switch\",\n \"this\",\n \"throw\",\n \"try\",\n \"typeof\",\n \"var\",\n \"void\",\n \"while\",\n \"with\",\n \"yield\",\n // Future reserved keywords\n \"await\",\n \"enum\",\n \"implements\",\n \"interface\",\n \"let\",\n \"package\",\n \"private\",\n \"protected\",\n \"public\",\n \"static\",\n // Literal values that cannot be reassigned\n \"null\",\n \"true\",\n \"false\",\n // Global objects that shouldn't be shadowed\n \"undefined\",\n]);\n\nconst RESERVED_CONVEX_FILE_NAMES = new Set([\"schema\", \"http\", \"crons\"]);\n\nconst jsIdentifierRegex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;\n\nconst isReservedJsIdentifier = (identifier: string) =>\n RESERVED_JS_IDENTIFIERS.has(identifier);\n\nconst isReservedConvexFileName = (fileName: string) =>\n RESERVED_CONVEX_FILE_NAMES.has(fileName);\n\nconst matchesJsIdentifierPattern = (identifier: string) =>\n jsIdentifierRegex.test(identifier);\n\nexport const validateConfectFunctionIdentifier = (identifier: string) => {\n if (!matchesJsIdentifierPattern(identifier)) {\n throw new Error(\n `Expected a valid Confect function identifier, but received: \"${identifier}\". Valid identifiers must start with a letter, underscore, or dollar sign, and can only contain letters, numbers, underscores, or dollar signs.`,\n );\n }\n\n if (isReservedJsIdentifier(identifier)) {\n throw new Error(\n `Expected a valid Confect function identifier, but received: \"${identifier}\". \"${identifier}\" is a reserved JavaScript identifier.`,\n );\n }\n\n if (isReservedConvexFileName(identifier)) {\n throw new Error(\n `Expected a valid Confect function identifier, but received: \"${identifier}\". \"${identifier}\" is a reserved Convex file name.`,\n );\n }\n};\n"],"mappings":";AAAA,MAAM,0BAA0B,IAAI,IAAI;CAEtC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CAEA;CACD,CAAC;AAEF,MAAM,6BAA6B,IAAI,IAAI;CAAC;CAAU;CAAQ;CAAQ,CAAC;AAEvE,MAAM,oBAAoB;AAE1B,MAAM,0BAA0B,eAC9B,wBAAwB,IAAI,WAAW;AAEzC,MAAM,4BAA4B,aAChC,2BAA2B,IAAI,SAAS;AAE1C,MAAM,8BAA8B,eAClC,kBAAkB,KAAK,WAAW;AAEpC,MAAa,qCAAqC,eAAuB;AACvE,KAAI,CAAC,2BAA2B,WAAW,CACzC,OAAM,IAAI,MACR,gEAAgE,WAAW,iJAC5E;AAGH,KAAI,uBAAuB,WAAW,CACpC,OAAM,IAAI,MACR,gEAAgE,WAAW,MAAM,WAAW,wCAC7F;AAGH,KAAI,yBAAyB,WAAW,CACtC,OAAM,IAAI,MACR,gEAAgE,WAAW,MAAM,WAAW,mCAC7F"}
|