@gaganref/confect-test 10.3.1-fork.9 → 10.3.1-fork.90

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 (71) hide show
  1. package/dist/TestConfect.d.ts +37 -11
  2. package/dist/TestConfect.d.ts.map +1 -1
  3. package/dist/TestConfect.js +22 -7
  4. package/dist/TestConfect.js.map +1 -1
  5. package/dist/internal/Attempt.d.ts +77 -0
  6. package/dist/internal/Attempt.d.ts.map +1 -0
  7. package/dist/internal/Attempt.js +154 -0
  8. package/dist/internal/Attempt.js.map +1 -0
  9. package/dist/internal/Clock.d.ts +29 -0
  10. package/dist/internal/Clock.d.ts.map +1 -0
  11. package/dist/internal/Clock.js +66 -0
  12. package/dist/internal/Clock.js.map +1 -0
  13. package/dist/internal/ConvexTest.d.ts +66 -0
  14. package/dist/internal/ConvexTest.d.ts.map +1 -0
  15. package/dist/internal/ConvexTest.js +62 -0
  16. package/dist/internal/ConvexTest.js.map +1 -0
  17. package/dist/internal/Execution.d.ts +247 -0
  18. package/dist/internal/Execution.d.ts.map +1 -0
  19. package/dist/internal/Execution.js +1024 -0
  20. package/dist/internal/Execution.js.map +1 -0
  21. package/dist/internal/Globals.d.ts +11 -0
  22. package/dist/internal/Globals.d.ts.map +1 -0
  23. package/dist/internal/Globals.js +88 -0
  24. package/dist/internal/Globals.js.map +1 -0
  25. package/dist/internal/Invocation.d.ts +68 -0
  26. package/dist/internal/Invocation.d.ts.map +1 -0
  27. package/dist/internal/Invocation.js +158 -0
  28. package/dist/internal/Invocation.js.map +1 -0
  29. package/dist/internal/Kernel.d.ts +95 -0
  30. package/dist/internal/Kernel.d.ts.map +1 -0
  31. package/dist/internal/Kernel.js +91 -0
  32. package/dist/internal/Kernel.js.map +1 -0
  33. package/dist/internal/KernelQuery.d.ts +55 -0
  34. package/dist/internal/KernelQuery.d.ts.map +1 -0
  35. package/dist/internal/KernelQuery.js +205 -0
  36. package/dist/internal/KernelQuery.js.map +1 -0
  37. package/dist/internal/KernelRefusal.d.ts +102 -0
  38. package/dist/internal/KernelRefusal.d.ts.map +1 -0
  39. package/dist/internal/KernelRefusal.js +94 -0
  40. package/dist/internal/KernelRefusal.js.map +1 -0
  41. package/dist/internal/KernelValues.d.ts +138 -0
  42. package/dist/internal/KernelValues.d.ts.map +1 -0
  43. package/dist/internal/KernelValues.js +281 -0
  44. package/dist/internal/KernelValues.js.map +1 -0
  45. package/dist/internal/MountedHttp.d.ts +1 -1
  46. package/dist/internal/MountedHttp.d.ts.map +1 -1
  47. package/dist/internal/MountedHttp.js +3 -3
  48. package/dist/internal/MountedHttp.js.map +1 -1
  49. package/dist/internal/ReadSet.d.ts +55 -0
  50. package/dist/internal/ReadSet.d.ts.map +1 -0
  51. package/dist/internal/ReadSet.js +29 -0
  52. package/dist/internal/ReadSet.js.map +1 -0
  53. package/dist/internal/Scheduling.d.ts +71 -0
  54. package/dist/internal/Scheduling.d.ts.map +1 -0
  55. package/dist/internal/Scheduling.js +60 -0
  56. package/dist/internal/Scheduling.js.map +1 -0
  57. package/package.json +5 -5
  58. package/src/TestConfect.ts +84 -19
  59. package/src/internal/Attempt.ts +185 -0
  60. package/src/internal/Clock.ts +95 -0
  61. package/src/internal/ConvexTest.ts +163 -0
  62. package/src/internal/Execution.ts +1795 -0
  63. package/src/internal/Globals.ts +113 -0
  64. package/src/internal/Invocation.ts +316 -0
  65. package/src/internal/Kernel.ts +190 -0
  66. package/src/internal/KernelQuery.ts +405 -0
  67. package/src/internal/KernelRefusal.ts +112 -0
  68. package/src/internal/KernelValues.ts +765 -0
  69. package/src/internal/MountedHttp.ts +13 -6
  70. package/src/internal/ReadSet.ts +108 -0
  71. package/src/internal/Scheduling.ts +126 -0
@@ -1,17 +1,28 @@
1
- import { App, Ref } from "@confect/core";
1
+ import { App, type Mount, Ref } from "@confect/core";
2
2
  import type { DatabaseSchema } from "@confect/server";
3
3
  import { RegisteredConvexFunction } from "@confect/server";
4
- import type { TestConvexForDataModelAndIdentity } from "convex-test";
5
- import type { GenericDataModel, GenericSchema, SchemaDefinition, UserIdentity } from "convex/server";
4
+ import type { GenericSchema, SchemaDefinition, UserIdentity } from "convex/server";
6
5
  import type { Value } from "convex/values";
7
6
  import * as Context from "effect/Context";
8
7
  import * as Effect from "effect/Effect";
9
8
  import * as Layer from "effect/Layer";
10
9
  import * as Schema from "effect/Schema";
10
+ /**
11
+ * How a kit registers a component beyond its schema and modules.
12
+ */
13
+ export type RegisterOptions = {
14
+ /**
15
+ * The component's functions, as `module:export`, that schedule their own next
16
+ * run, such as the crons component's `public:rescheduler`. The test kernel
17
+ * never treats a job that runs one, or that one schedules, as work
18
+ * `finishAllScheduledFunctions` must finish. convex-test ignores it.
19
+ */
20
+ readonly standing?: ReadonlyArray<string>;
21
+ };
11
22
  /**
12
23
  * Register a component's Convex schema and modules at its installation path.
13
24
  */
14
- export type RegisterComponent = TestConvexForDataModelAndIdentity<GenericDataModel>["registerComponent"];
25
+ export type RegisterComponent = (componentPath: string, schema: SchemaDefinition<GenericSchema, boolean>, modules: Record<string, () => Promise<any>>, options?: RegisterOptions) => void;
15
26
  /**
16
27
  * An installed component path and the HTTP prefix exposed by its host.
17
28
  */
@@ -19,7 +30,20 @@ export type HttpMount = {
19
30
  readonly componentPath: string;
20
31
  readonly httpPrefix: string;
21
32
  };
22
- export type LayerOptions = {
33
+ /**
34
+ * The in-process backend a test layer runs on.
35
+ */
36
+ export type Target = "convex-test" | "kernel";
37
+ export type TargetOptions = {
38
+ /**
39
+ * `"kernel"` runs every function and component the layer registers on
40
+ * Confect's test kernel, which runs scheduled functions on its own clock and
41
+ * reads `registerComponent`'s `standing`. Defaults to `"convex-test"`. The
42
+ * option goes once the kernel replaces convex-test.
43
+ */
44
+ readonly target?: Target;
45
+ };
46
+ export type LayerOptions = TargetOptions & {
23
47
  /**
24
48
  * Register component kits synchronously before the test service is available.
25
49
  */
@@ -42,14 +66,14 @@ export type TestConfectWithoutIdentity<ConfectSchema extends DatabaseSchema.AnyW
42
66
  finishAllScheduledFunctions: (advanceTimers: () => void) => Effect.Effect<void>;
43
67
  };
44
68
  export type TestConfect<ConfectSchema extends DatabaseSchema.AnyWithProps> = {
45
- registerComponent: (componentPath: string, schema: SchemaDefinition<GenericSchema, boolean>, modules: Record<string, () => Promise<any>>) => Effect.Effect<void>;
69
+ registerComponent: (componentPath: string, schema: SchemaDefinition<GenericSchema, boolean>, modules: Record<string, () => Promise<any>>, options?: RegisterOptions) => Effect.Effect<void>;
46
70
  withIdentity: (userIdentity: Partial<UserIdentity>) => TestConfectWithoutIdentity<ConfectSchema>;
47
71
  } & TestConfectWithoutIdentity<ConfectSchema>;
48
72
  export declare const TestConfect: <ConfectSchema extends DatabaseSchema.AnyWithProps>() => Context.Service<TestConfect<ConfectSchema>, TestConfect<ConfectSchema>>;
49
73
  /**
50
74
  * How a test registers one installed component: its own schema and modules, or
51
- * the `register(t, name)` a component package exports from `<package>/test`,
52
- * which also registers the package's own children.
75
+ * the `register(t, name)` a component package exports from `<package>/testing`
76
+ * or `<package>/test`, which also registers the package's own children.
53
77
  */
54
78
  export type ComponentKit = {
55
79
  readonly schema: SchemaDefinition<GenericSchema, boolean>;
@@ -77,10 +101,12 @@ export type DeclaredApp<DatabaseSchema_ extends DatabaseSchema.AnyWithProps> = R
77
101
  /**
78
102
  * Build a fresh test backend from a declaration and its generated
79
103
  * `confect/_generated/testing` registry, without restating component mounts.
104
+ * Pass `{ target: "kernel" }` to run it on Confect's test kernel instead of
105
+ * convex-test.
80
106
  */
81
- export declare function layer<DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(app: DeclaredApp<DatabaseSchema_>): Layer.Layer<TestConfect<DatabaseSchema_>>;
107
+ export declare function layer<DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(app: DeclaredApp<DatabaseSchema_>, options?: TargetOptions): Layer.Layer<TestConfect<DatabaseSchema_>>;
82
108
  export declare function layer<A extends App.Any, DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(app: A, registry: Registry<DatabaseSchema_> & {
83
- readonly components: Readonly<Record<keyof NoInfer<A>["mounts"], Registry<DatabaseSchema_>["components"][string]>>;
84
- }): Layer.Layer<TestConfect<DatabaseSchema_>>;
109
+ readonly components: Readonly<Record<Mount.NameOf<NoInfer<A>["mounts"][number]>, Registry<DatabaseSchema_>["components"][string]>>;
110
+ }, options?: TargetOptions): Layer.Layer<TestConfect<DatabaseSchema_>>;
85
111
  export declare function layer<DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(databaseSchema: DatabaseSchema_, convexSchemaDefinition: SchemaDefinition<GenericSchema, true>, modules: Record<string, () => Promise<any>>, options?: LayerOptions): Layer.Layer<TestConfect<DatabaseSchema_>>;
86
112
  //# sourceMappingURL=TestConfect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TestConfect.d.ts","sourceRoot":"","sources":["../src/TestConfect.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TestConfect.d.ts","sourceRoot":"","sources":["../src/TestConfect.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
+ import { convexTest as convexTest$1 } from "./internal/ConvexTest.js";
2
3
  import { make } from "./internal/MountedHttp.js";
3
4
  import { App, Ref } from "@confect/core";
4
5
  import { RegisteredConvexFunction } from "@confect/server";
@@ -45,7 +46,7 @@ var TestConfectImpl = class {
45
46
  this.testConfectImplWithoutIdentity = new TestConfectImplWithoutIdentity(confectSchema, testConvex, mountedHttp);
46
47
  }
47
48
  withIdentity = (userIdentity) => new TestConfectImplWithoutIdentity(this.confectSchema, this.testConvex.withIdentity(userIdentity), this.mountedHttp);
48
- registerComponent = Effect.fn("TestConfect.registerComponent")((componentPath, schema, modules) => Effect.sync(() => this.mountedHttp.register(componentPath, schema, modules)));
49
+ registerComponent = Effect.fn("TestConfect.registerComponent")((componentPath, schema, modules, options) => Effect.sync(() => this.mountedHttp.register(componentPath, schema, modules, options)));
49
50
  query = (queryRef, ...args) => this.testConfectImplWithoutIdentity.query(queryRef, ...args);
50
51
  mutation = (mutationRef, ...args) => this.testConfectImplWithoutIdentity.mutation(mutationRef, ...args);
51
52
  action = (actionRef, ...args) => this.testConfectImplWithoutIdentity.action(actionRef, ...args);
@@ -54,15 +55,24 @@ var TestConfectImpl = class {
54
55
  finishInProgressScheduledFunctions = () => this.testConfectImplWithoutIdentity.finishInProgressScheduledFunctions();
55
56
  finishAllScheduledFunctions = (advanceTimers) => this.testConfectImplWithoutIdentity.finishAllScheduledFunctions(advanceTimers);
56
57
  };
58
+ var InvalidComponentKit = class extends Schema.TaggedError()("InvalidComponentKit", {
59
+ componentPath: Schema.String,
60
+ message: Schema.String
61
+ }) {};
57
62
  const registerKit = (registerComponent, name, kit) => {
58
63
  if ("register" in kit) kit.register({ registerComponent }, name);
59
- else registerComponent(name, kit.schema, kit.modules);
64
+ else if ("schema" in kit && "modules" in kit) registerComponent(name, kit.schema, kit.modules);
65
+ else throw new InvalidComponentKit({
66
+ componentPath: name,
67
+ message: `The test kit for ${JSON.stringify(name)} must export register(t, name), or schema and modules.`
68
+ });
60
69
  };
61
- function layer(appOrSchema, registryOrSchema, modules, options = {}) {
70
+ function layer(appOrSchema, second, third, options = {}) {
62
71
  if (App.isApp(appOrSchema)) {
63
- const registry = registryOrSchema;
72
+ const registry = second;
64
73
  const mounts = App.mounts(appOrSchema);
65
74
  return schemaLayer(registry.schema, registry.convexSchema, registry.modules, {
75
+ ...targetOf(third),
66
76
  httpMounts: mounts.flatMap(({ name, httpPrefix }) => httpPrefix === void 0 ? [] : [{
67
77
  componentPath: name,
68
78
  httpPrefix
@@ -75,17 +85,22 @@ function layer(appOrSchema, registryOrSchema, modules, options = {}) {
75
85
  if ("httpMounts" in appOrSchema) {
76
86
  const app = appOrSchema;
77
87
  return schemaLayer(app.schema, app.convexSchema, app.modules, {
88
+ ...targetOf(second),
78
89
  httpMounts: app.httpMounts,
79
90
  register: (registerComponent) => {
80
91
  for (const [name, component] of Object.entries(app.components)) registerKit(registerComponent, name, component);
81
92
  }
82
93
  });
83
94
  }
84
- return schemaLayer(appOrSchema, registryOrSchema, modules, options);
95
+ return schemaLayer(appOrSchema, second, third, options);
85
96
  }
97
+ const targetOf = (options) => options?.target === void 0 ? {} : { target: options.target };
86
98
  const schemaLayer = (databaseSchema, convexSchemaDefinition, modules, options = {}) => Layer.sync(TestConfect(), () => {
87
- const testConvex = convexTest(convexSchemaDefinition, modules);
88
- const mountedHttp = make(options.httpMounts ?? [], (...args) => testConvex.registerComponent(...args));
99
+ process.env.CONVEX_CLOUD_URL ??= "https://some-deployment.convex.cloud";
100
+ process.env.CONVEX_SITE_URL ??= "https://some.convex.site";
101
+ const testConvex = (options.target === "kernel" ? convexTest$1 : convexTest)(convexSchemaDefinition, modules);
102
+ const registerComponent = testConvex.registerComponent;
103
+ const mountedHttp = make(options.httpMounts ?? [], (...args) => registerComponent(...args));
89
104
  options.register?.(mountedHttp.register);
90
105
  return new TestConfectImpl(databaseSchema, testConvex, mountedHttp);
91
106
  });
@@ -1 +1 @@
1
- {"version":3,"file":"TestConfect.js","names":["MountedHttp.make"],"sources":["../src/TestConfect.ts"],"sourcesContent":["import { App, Ref } from \"@confect/core\";\nimport type { DatabaseSchema, DataModel } from \"@confect/server\";\nimport { RegisteredConvexFunction } from \"@confect/server\";\nimport type {\n TestConvexForDataModel,\n TestConvexForDataModelAndIdentity,\n} from \"convex-test\";\nimport { convexTest } from \"convex-test\";\nimport type {\n GenericDataModel,\n GenericMutationCtx,\n GenericSchema,\n SchemaDefinition,\n UserIdentity,\n} from \"convex/server\";\nimport type { Value } from \"convex/values\";\nimport * as Context from \"effect/Context\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Schema from \"effect/Schema\";\nimport * as MountedHttp from \"./internal/MountedHttp.js\";\n\n/**\n * Register a component's Convex schema and modules at its installation path.\n */\nexport type RegisterComponent =\n TestConvexForDataModelAndIdentity<GenericDataModel>[\"registerComponent\"];\n\n/**\n * An installed component path and the HTTP prefix exposed by its host.\n */\nexport type HttpMount = {\n readonly componentPath: string;\n readonly httpPrefix: string;\n};\n\nexport type LayerOptions = {\n /**\n * Register component kits synchronously before the test service is available.\n */\n readonly register?: (registerComponent: RegisterComponent) => void;\n /**\n * Explicit HTTP mounts. The test layer does not evaluate convex.config.ts.\n */\n readonly httpMounts?: ReadonlyArray<HttpMount>;\n};\n\nexport type TestConfectWithoutIdentity<\n ConfectSchema extends DatabaseSchema.AnyWithProps,\n> = {\n query: <QueryRef extends Ref.AnyQuery>(\n queryRef: QueryRef,\n ...args: Ref.OptionalArgs<QueryRef>\n ) => Effect.Effect<\n Ref.Returns<QueryRef>,\n Ref.Error<QueryRef> | Schema.SchemaError\n >;\n mutation: <MutationRef extends Ref.AnyMutation>(\n mutationRef: MutationRef,\n ...args: Ref.OptionalArgs<MutationRef>\n ) => Effect.Effect<\n Ref.Returns<MutationRef>,\n Ref.Error<MutationRef> | Schema.SchemaError\n >;\n action: <ActionRef extends Ref.AnyAction>(\n actionRef: ActionRef,\n ...args: Ref.OptionalArgs<ActionRef>\n ) => Effect.Effect<\n Ref.Returns<ActionRef>,\n Ref.Error<ActionRef> | Schema.SchemaError\n >;\n run: {\n <E>(\n handler: Effect.Effect<\n void,\n E,\n RegisteredConvexFunction.MutationServices<ConfectSchema>\n >,\n ): Effect.Effect<void>;\n <A, B extends Value, E>(\n handler: Effect.Effect<\n A,\n E,\n RegisteredConvexFunction.MutationServices<ConfectSchema>\n >,\n returns: Schema.Codec<A, B>,\n ): Effect.Effect<A, Schema.SchemaError>;\n };\n fetch: (\n pathQueryFragment: string,\n init?: RequestInit,\n ) => Effect.Effect<Response>;\n finishInProgressScheduledFunctions: () => Effect.Effect<void>;\n finishAllScheduledFunctions: (\n advanceTimers: () => void,\n ) => Effect.Effect<void>;\n};\n\nexport type TestConfect<ConfectSchema extends DatabaseSchema.AnyWithProps> = {\n registerComponent: (\n componentPath: string,\n schema: SchemaDefinition<GenericSchema, boolean>,\n modules: Record<string, () => Promise<any>>,\n ) => Effect.Effect<void>;\n withIdentity: (\n userIdentity: Partial<UserIdentity>,\n ) => TestConfectWithoutIdentity<ConfectSchema>;\n} & TestConfectWithoutIdentity<ConfectSchema>;\n\nexport const TestConfect = <\n ConfectSchema extends DatabaseSchema.AnyWithProps,\n>() => Context.Service<TestConfect<ConfectSchema>>(\"@confect/test/TestConfect\");\n\nclass TestConfectImplWithoutIdentity<\n ConfectSchema extends DatabaseSchema.AnyWithProps,\n> implements TestConfectWithoutIdentity<ConfectSchema> {\n constructor(\n private confectSchema: ConfectSchema,\n private testConvex: TestConvexForDataModel<\n DataModel.ToConvex<DataModel.FromSchema<ConfectSchema>>\n >,\n private mountedHttp: ReturnType<typeof MountedHttp.make>,\n ) {}\n\n readonly query = <QueryRef extends Ref.AnyQuery>(\n queryRef: QueryRef,\n ...args: Ref.OptionalArgs<QueryRef>\n ): Effect.Effect<\n Ref.Returns<QueryRef>,\n Ref.Error<QueryRef> | Schema.SchemaError\n > =>\n Ref.runWithCodec(\n queryRef,\n (args[0] ?? {}) as Ref.Args<QueryRef>,\n (functionReference, encodedArgs) =>\n this.testConvex.query(functionReference as any, encodedArgs),\n );\n\n readonly mutation = <MutationRef extends Ref.AnyMutation>(\n mutationRef: MutationRef,\n ...args: Ref.OptionalArgs<MutationRef>\n ): Effect.Effect<\n Ref.Returns<MutationRef>,\n Ref.Error<MutationRef> | Schema.SchemaError\n > =>\n Ref.runWithCodec(\n mutationRef,\n (args[0] ?? {}) as Ref.Args<MutationRef>,\n (functionReference, encodedArgs) =>\n this.testConvex.mutation(functionReference as any, encodedArgs),\n );\n\n readonly action = <ActionRef extends Ref.AnyAction>(\n actionRef: ActionRef,\n ...args: Ref.OptionalArgs<ActionRef>\n ): Effect.Effect<\n Ref.Returns<ActionRef>,\n Ref.Error<ActionRef> | Schema.SchemaError\n > =>\n Ref.runWithCodec(\n actionRef,\n (args[0] ?? {}) as Ref.Args<ActionRef>,\n (functionReference, encodedArgs) =>\n this.testConvex.action(functionReference as any, encodedArgs),\n );\n\n readonly run: TestConfectWithoutIdentity<ConfectSchema>[\"run\"] = (<\n A,\n B extends Value,\n E,\n >(\n handler: Effect.Effect<\n A,\n E,\n RegisteredConvexFunction.MutationServices<ConfectSchema>\n >,\n returns?: Schema.Codec<A, B>,\n ): Effect.Effect<void> | Effect.Effect<A, Schema.SchemaError> => {\n const makeMutationLayer = (\n mutationCtx: GenericMutationCtx<\n DataModel.ToConvex<DataModel.FromSchema<ConfectSchema>>\n >,\n ): Layer.Layer<RegisteredConvexFunction.MutationServices<ConfectSchema>> =>\n RegisteredConvexFunction.mutationLayer(\n this.confectSchema,\n mutationCtx,\n ) as Layer.Layer<\n RegisteredConvexFunction.MutationServices<ConfectSchema>\n >;\n\n return returns === undefined\n ? Effect.promise(() =>\n this.testConvex.run((mutationCtx) =>\n Effect.runPromise(\n handler.pipe(\n Effect.asVoid,\n Effect.provide(makeMutationLayer(mutationCtx)),\n ),\n ),\n ),\n )\n : Effect.promise(() =>\n this.testConvex.run((mutationCtx) =>\n Effect.runPromise(\n handler.pipe(\n Effect.andThen(Schema.encodeEffect(returns)),\n Effect.provide(makeMutationLayer(mutationCtx)),\n ),\n ),\n ),\n ).pipe(Effect.andThen(Schema.decodeEffect(returns)));\n }) as TestConfectWithoutIdentity<ConfectSchema>[\"run\"];\n\n readonly fetch = <PathQueryFragment extends string>(\n pathQueryFragment: PathQueryFragment,\n init?: RequestInit,\n ) =>\n Effect.promise(() =>\n this.mountedHttp.fetch(this.testConvex, pathQueryFragment, init),\n );\n\n readonly finishInProgressScheduledFunctions = () =>\n Effect.promise(() => this.testConvex.finishInProgressScheduledFunctions());\n\n readonly finishAllScheduledFunctions = (advanceTimers: () => void) =>\n Effect.promise(() =>\n this.testConvex.finishAllScheduledFunctions(advanceTimers),\n );\n}\n\nclass TestConfectImpl<\n ConfectSchema extends DatabaseSchema.AnyWithProps,\n> implements TestConfect<ConfectSchema> {\n private readonly testConfectImplWithoutIdentity: TestConfectImplWithoutIdentity<ConfectSchema>;\n\n constructor(\n private confectSchema: ConfectSchema,\n private testConvex: TestConvexForDataModelAndIdentity<\n DataModel.ToConvex<DataModel.FromSchema<ConfectSchema>>\n >,\n private mountedHttp: ReturnType<typeof MountedHttp.make>,\n ) {\n this.testConfectImplWithoutIdentity = new TestConfectImplWithoutIdentity(\n confectSchema,\n testConvex,\n mountedHttp,\n );\n }\n\n readonly withIdentity = (userIdentity: Partial<UserIdentity>) =>\n new TestConfectImplWithoutIdentity(\n this.confectSchema,\n this.testConvex.withIdentity(userIdentity),\n this.mountedHttp,\n );\n\n readonly registerComponent: TestConfect<ConfectSchema>[\"registerComponent\"] =\n Effect.fn(\"TestConfect.registerComponent\")(\n (componentPath, schema, modules) =>\n Effect.sync(() =>\n this.mountedHttp.register(componentPath, schema, modules),\n ),\n );\n\n readonly query = <QueryRef extends Ref.AnyQuery>(\n queryRef: QueryRef,\n ...args: Ref.OptionalArgs<QueryRef>\n ) => this.testConfectImplWithoutIdentity.query(queryRef, ...args);\n\n readonly mutation = <MutationRef extends Ref.AnyMutation>(\n mutationRef: MutationRef,\n ...args: Ref.OptionalArgs<MutationRef>\n ) => this.testConfectImplWithoutIdentity.mutation(mutationRef, ...args);\n\n readonly action = <ActionRef extends Ref.AnyAction>(\n actionRef: ActionRef,\n ...args: Ref.OptionalArgs<ActionRef>\n ) => this.testConfectImplWithoutIdentity.action(actionRef, ...args);\n\n readonly run: TestConfect<ConfectSchema>[\"run\"] = ((\n handler: any,\n returns?: any,\n ) =>\n this.testConfectImplWithoutIdentity.run(\n handler,\n returns,\n )) as TestConfect<ConfectSchema>[\"run\"];\n\n readonly fetch = <PathQueryFragment extends string>(\n pathQueryFragment: PathQueryFragment,\n init?: RequestInit,\n ) => this.testConfectImplWithoutIdentity.fetch(pathQueryFragment, init);\n\n readonly finishInProgressScheduledFunctions = () =>\n this.testConfectImplWithoutIdentity.finishInProgressScheduledFunctions();\n\n readonly finishAllScheduledFunctions = (advanceTimers: () => void) =>\n this.testConfectImplWithoutIdentity.finishAllScheduledFunctions(\n advanceTimers,\n );\n}\n\n/**\n * How a test registers one installed component: its own schema and modules, or\n * the `register(t, name)` a component package exports from `<package>/test`,\n * which also registers the package's own children.\n */\nexport type ComponentKit =\n | {\n readonly schema: SchemaDefinition<GenericSchema, boolean>;\n readonly modules: Record<string, () => Promise<any>>;\n }\n | {\n register(\n t: { readonly registerComponent: RegisterComponent },\n name: string,\n ): unknown;\n };\n\nconst registerKit = (\n registerComponent: RegisterComponent,\n name: string,\n kit: ComponentKit,\n) => {\n if (\"register\" in kit) {\n kit.register({ registerComponent }, name);\n } else {\n registerComponent(name, kit.schema, kit.modules);\n }\n};\n\n/**\n * Codegen's test-only schema and module registry.\n */\nexport type Registry<DatabaseSchema_ extends DatabaseSchema.AnyWithProps> = {\n readonly schema: DatabaseSchema_;\n readonly convexSchema: SchemaDefinition<GenericSchema, true>;\n readonly modules: Record<string, () => Promise<any>>;\n readonly components: Readonly<Record<string, ComponentKit>>;\n};\n\n/**\n * The declared app's generated, test-only representation.\n */\nexport type DeclaredApp<DatabaseSchema_ extends DatabaseSchema.AnyWithProps> =\n Registry<DatabaseSchema_> & {\n readonly httpMounts: ReadonlyArray<HttpMount>;\n };\n\n/**\n * Build a fresh test backend from a declaration and its generated\n * `confect/_generated/testing` registry, without restating component mounts.\n */\nexport function layer<DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(\n app: DeclaredApp<DatabaseSchema_>,\n): Layer.Layer<TestConfect<DatabaseSchema_>>;\nexport function layer<\n A extends App.Any,\n DatabaseSchema_ extends DatabaseSchema.AnyWithProps,\n>(\n app: A,\n registry: Registry<DatabaseSchema_> & {\n readonly components: Readonly<\n Record<\n keyof NoInfer<A>[\"mounts\"],\n Registry<DatabaseSchema_>[\"components\"][string]\n >\n >;\n },\n): Layer.Layer<TestConfect<DatabaseSchema_>>;\nexport function layer<DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(\n databaseSchema: DatabaseSchema_,\n convexSchemaDefinition: SchemaDefinition<GenericSchema, true>,\n modules: Record<string, () => Promise<any>>,\n options?: LayerOptions,\n): Layer.Layer<TestConfect<DatabaseSchema_>>;\nexport function layer<DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(\n appOrSchema: App.Any | DeclaredApp<DatabaseSchema_> | DatabaseSchema_,\n registryOrSchema?:\n | Registry<DatabaseSchema_>\n | SchemaDefinition<GenericSchema, true>,\n modules?: Record<string, () => Promise<any>>,\n options: LayerOptions = {},\n): Layer.Layer<TestConfect<DatabaseSchema_>> {\n if (App.isApp(appOrSchema)) {\n const registry = registryOrSchema as Registry<DatabaseSchema_>;\n const mounts = App.mounts(appOrSchema);\n return schemaLayer(\n registry.schema,\n registry.convexSchema,\n registry.modules,\n {\n httpMounts: mounts.flatMap(({ name, httpPrefix }) =>\n httpPrefix === undefined ? [] : [{ componentPath: name, httpPrefix }],\n ),\n register: (registerComponent) => {\n for (const [name, component] of Object.entries(registry.components)) {\n if (\n mounts.some(\n (mount) =>\n name === mount.name || name.startsWith(`${mount.name}/`),\n )\n ) {\n registerKit(registerComponent, name, component);\n }\n }\n },\n },\n );\n }\n if (\"httpMounts\" in appOrSchema) {\n const app = appOrSchema as DeclaredApp<DatabaseSchema_>;\n return schemaLayer(app.schema, app.convexSchema, app.modules, {\n httpMounts: app.httpMounts,\n register: (registerComponent) => {\n for (const [name, component] of Object.entries(app.components)) {\n registerKit(registerComponent, name, component);\n }\n },\n });\n }\n return schemaLayer(\n appOrSchema as DatabaseSchema_,\n registryOrSchema as SchemaDefinition<GenericSchema, true>,\n modules!,\n options,\n );\n}\n\nconst schemaLayer = <DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(\n databaseSchema: DatabaseSchema_,\n convexSchemaDefinition: SchemaDefinition<GenericSchema, true>,\n modules: Record<string, () => Promise<any>>,\n options: LayerOptions = {},\n): Layer.Layer<TestConfect<DatabaseSchema_>> =>\n Layer.sync(TestConfect<DatabaseSchema_>(), () => {\n const testConvex = convexTest(convexSchemaDefinition, modules);\n const mountedHttp = MountedHttp.make(options.httpMounts ?? [], (...args) =>\n testConvex.registerComponent(...args),\n );\n options.register?.(mountedHttp.register);\n return new TestConfectImpl(databaseSchema, testConvex as any, mountedHttp);\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"TestConfect.js","names":["kernelTest","MountedHttp.make"],"sources":["../src/TestConfect.ts"],"sourcesContent":["import { App, type Mount, Ref } from \"@confect/core\";\nimport type { DatabaseSchema, DataModel } from \"@confect/server\";\nimport { RegisteredConvexFunction } from \"@confect/server\";\nimport type {\n TestConvexForDataModel,\n TestConvexForDataModelAndIdentity,\n} from \"convex-test\";\nimport { convexTest } from \"convex-test\";\nimport type {\n GenericMutationCtx,\n GenericSchema,\n SchemaDefinition,\n UserIdentity,\n} from \"convex/server\";\nimport type { Value } from \"convex/values\";\nimport * as Context from \"effect/Context\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Schema from \"effect/Schema\";\nimport { convexTest as kernelTest } from \"./internal/ConvexTest.js\";\nimport * as MountedHttp from \"./internal/MountedHttp.js\";\n\ndeclare const process: { env: Record<string, string | undefined> };\n\n/**\n * How a kit registers a component beyond its schema and modules.\n */\nexport type RegisterOptions = {\n /**\n * The component's functions, as `module:export`, that schedule their own next\n * run, such as the crons component's `public:rescheduler`. The test kernel\n * never treats a job that runs one, or that one schedules, as work\n * `finishAllScheduledFunctions` must finish. convex-test ignores it.\n */\n readonly standing?: ReadonlyArray<string>;\n};\n\n/**\n * Register a component's Convex schema and modules at its installation path.\n */\nexport type RegisterComponent = (\n componentPath: string,\n schema: SchemaDefinition<GenericSchema, boolean>,\n modules: Record<string, () => Promise<any>>,\n options?: RegisterOptions,\n) => void;\n\n/**\n * An installed component path and the HTTP prefix exposed by its host.\n */\nexport type HttpMount = {\n readonly componentPath: string;\n readonly httpPrefix: string;\n};\n\n/**\n * The in-process backend a test layer runs on.\n */\nexport type Target = \"convex-test\" | \"kernel\";\n\nexport type TargetOptions = {\n /**\n * `\"kernel\"` runs every function and component the layer registers on\n * Confect's test kernel, which runs scheduled functions on its own clock and\n * reads `registerComponent`'s `standing`. Defaults to `\"convex-test\"`. The\n * option goes once the kernel replaces convex-test.\n */\n readonly target?: Target;\n};\n\nexport type LayerOptions = TargetOptions & {\n /**\n * Register component kits synchronously before the test service is available.\n */\n readonly register?: (registerComponent: RegisterComponent) => void;\n /**\n * Explicit HTTP mounts. The test layer does not evaluate convex.config.ts.\n */\n readonly httpMounts?: ReadonlyArray<HttpMount>;\n};\n\nexport type TestConfectWithoutIdentity<\n ConfectSchema extends DatabaseSchema.AnyWithProps,\n> = {\n query: <QueryRef extends Ref.AnyQuery>(\n queryRef: QueryRef,\n ...args: Ref.OptionalArgs<QueryRef>\n ) => Effect.Effect<\n Ref.Returns<QueryRef>,\n Ref.Error<QueryRef> | Schema.SchemaError\n >;\n mutation: <MutationRef extends Ref.AnyMutation>(\n mutationRef: MutationRef,\n ...args: Ref.OptionalArgs<MutationRef>\n ) => Effect.Effect<\n Ref.Returns<MutationRef>,\n Ref.Error<MutationRef> | Schema.SchemaError\n >;\n action: <ActionRef extends Ref.AnyAction>(\n actionRef: ActionRef,\n ...args: Ref.OptionalArgs<ActionRef>\n ) => Effect.Effect<\n Ref.Returns<ActionRef>,\n Ref.Error<ActionRef> | Schema.SchemaError\n >;\n run: {\n <E>(\n handler: Effect.Effect<\n void,\n E,\n RegisteredConvexFunction.MutationServices<ConfectSchema>\n >,\n ): Effect.Effect<void>;\n <A, B extends Value, E>(\n handler: Effect.Effect<\n A,\n E,\n RegisteredConvexFunction.MutationServices<ConfectSchema>\n >,\n returns: Schema.Codec<A, B>,\n ): Effect.Effect<A, Schema.SchemaError>;\n };\n fetch: (\n pathQueryFragment: string,\n init?: RequestInit,\n ) => Effect.Effect<Response>;\n finishInProgressScheduledFunctions: () => Effect.Effect<void>;\n finishAllScheduledFunctions: (\n advanceTimers: () => void,\n ) => Effect.Effect<void>;\n};\n\nexport type TestConfect<ConfectSchema extends DatabaseSchema.AnyWithProps> = {\n registerComponent: (\n componentPath: string,\n schema: SchemaDefinition<GenericSchema, boolean>,\n modules: Record<string, () => Promise<any>>,\n options?: RegisterOptions,\n ) => Effect.Effect<void>;\n withIdentity: (\n userIdentity: Partial<UserIdentity>,\n ) => TestConfectWithoutIdentity<ConfectSchema>;\n} & TestConfectWithoutIdentity<ConfectSchema>;\n\nexport const TestConfect = <\n ConfectSchema extends DatabaseSchema.AnyWithProps,\n>() => Context.Service<TestConfect<ConfectSchema>>(\"@confect/test/TestConfect\");\n\nclass TestConfectImplWithoutIdentity<\n ConfectSchema extends DatabaseSchema.AnyWithProps,\n> implements TestConfectWithoutIdentity<ConfectSchema> {\n constructor(\n private confectSchema: ConfectSchema,\n private testConvex: TestConvexForDataModel<\n DataModel.ToConvex<DataModel.FromSchema<ConfectSchema>>\n >,\n private mountedHttp: ReturnType<typeof MountedHttp.make>,\n ) {}\n\n readonly query = <QueryRef extends Ref.AnyQuery>(\n queryRef: QueryRef,\n ...args: Ref.OptionalArgs<QueryRef>\n ): Effect.Effect<\n Ref.Returns<QueryRef>,\n Ref.Error<QueryRef> | Schema.SchemaError\n > =>\n Ref.runWithCodec(\n queryRef,\n (args[0] ?? {}) as Ref.Args<QueryRef>,\n (functionReference, encodedArgs) =>\n this.testConvex.query(functionReference as any, encodedArgs),\n );\n\n readonly mutation = <MutationRef extends Ref.AnyMutation>(\n mutationRef: MutationRef,\n ...args: Ref.OptionalArgs<MutationRef>\n ): Effect.Effect<\n Ref.Returns<MutationRef>,\n Ref.Error<MutationRef> | Schema.SchemaError\n > =>\n Ref.runWithCodec(\n mutationRef,\n (args[0] ?? {}) as Ref.Args<MutationRef>,\n (functionReference, encodedArgs) =>\n this.testConvex.mutation(functionReference as any, encodedArgs),\n );\n\n readonly action = <ActionRef extends Ref.AnyAction>(\n actionRef: ActionRef,\n ...args: Ref.OptionalArgs<ActionRef>\n ): Effect.Effect<\n Ref.Returns<ActionRef>,\n Ref.Error<ActionRef> | Schema.SchemaError\n > =>\n Ref.runWithCodec(\n actionRef,\n (args[0] ?? {}) as Ref.Args<ActionRef>,\n (functionReference, encodedArgs) =>\n this.testConvex.action(functionReference as any, encodedArgs),\n );\n\n readonly run: TestConfectWithoutIdentity<ConfectSchema>[\"run\"] = (<\n A,\n B extends Value,\n E,\n >(\n handler: Effect.Effect<\n A,\n E,\n RegisteredConvexFunction.MutationServices<ConfectSchema>\n >,\n returns?: Schema.Codec<A, B>,\n ): Effect.Effect<void> | Effect.Effect<A, Schema.SchemaError> => {\n const makeMutationLayer = (\n mutationCtx: GenericMutationCtx<\n DataModel.ToConvex<DataModel.FromSchema<ConfectSchema>>\n >,\n ): Layer.Layer<RegisteredConvexFunction.MutationServices<ConfectSchema>> =>\n RegisteredConvexFunction.mutationLayer(\n this.confectSchema,\n mutationCtx,\n ) as Layer.Layer<\n RegisteredConvexFunction.MutationServices<ConfectSchema>\n >;\n\n return returns === undefined\n ? Effect.promise(() =>\n this.testConvex.run((mutationCtx) =>\n Effect.runPromise(\n handler.pipe(\n Effect.asVoid,\n Effect.provide(makeMutationLayer(mutationCtx)),\n ),\n ),\n ),\n )\n : Effect.promise(() =>\n this.testConvex.run((mutationCtx) =>\n Effect.runPromise(\n handler.pipe(\n Effect.andThen(Schema.encodeEffect(returns)),\n Effect.provide(makeMutationLayer(mutationCtx)),\n ),\n ),\n ),\n ).pipe(Effect.andThen(Schema.decodeEffect(returns)));\n }) as TestConfectWithoutIdentity<ConfectSchema>[\"run\"];\n\n readonly fetch = <PathQueryFragment extends string>(\n pathQueryFragment: PathQueryFragment,\n init?: RequestInit,\n ) =>\n Effect.promise(() =>\n this.mountedHttp.fetch(this.testConvex, pathQueryFragment, init),\n );\n\n readonly finishInProgressScheduledFunctions = () =>\n Effect.promise(() => this.testConvex.finishInProgressScheduledFunctions());\n\n readonly finishAllScheduledFunctions = (advanceTimers: () => void) =>\n Effect.promise(() =>\n this.testConvex.finishAllScheduledFunctions(advanceTimers),\n );\n}\n\nclass TestConfectImpl<\n ConfectSchema extends DatabaseSchema.AnyWithProps,\n> implements TestConfect<ConfectSchema> {\n private readonly testConfectImplWithoutIdentity: TestConfectImplWithoutIdentity<ConfectSchema>;\n\n constructor(\n private confectSchema: ConfectSchema,\n private testConvex: TestConvexForDataModelAndIdentity<\n DataModel.ToConvex<DataModel.FromSchema<ConfectSchema>>\n >,\n private mountedHttp: ReturnType<typeof MountedHttp.make>,\n ) {\n this.testConfectImplWithoutIdentity = new TestConfectImplWithoutIdentity(\n confectSchema,\n testConvex,\n mountedHttp,\n );\n }\n\n readonly withIdentity = (userIdentity: Partial<UserIdentity>) =>\n new TestConfectImplWithoutIdentity(\n this.confectSchema,\n this.testConvex.withIdentity(userIdentity),\n this.mountedHttp,\n );\n\n readonly registerComponent: TestConfect<ConfectSchema>[\"registerComponent\"] =\n Effect.fn(\"TestConfect.registerComponent\")(\n (componentPath, schema, modules, options) =>\n Effect.sync(() =>\n this.mountedHttp.register(componentPath, schema, modules, options),\n ),\n );\n\n readonly query = <QueryRef extends Ref.AnyQuery>(\n queryRef: QueryRef,\n ...args: Ref.OptionalArgs<QueryRef>\n ) => this.testConfectImplWithoutIdentity.query(queryRef, ...args);\n\n readonly mutation = <MutationRef extends Ref.AnyMutation>(\n mutationRef: MutationRef,\n ...args: Ref.OptionalArgs<MutationRef>\n ) => this.testConfectImplWithoutIdentity.mutation(mutationRef, ...args);\n\n readonly action = <ActionRef extends Ref.AnyAction>(\n actionRef: ActionRef,\n ...args: Ref.OptionalArgs<ActionRef>\n ) => this.testConfectImplWithoutIdentity.action(actionRef, ...args);\n\n readonly run: TestConfect<ConfectSchema>[\"run\"] = ((\n handler: any,\n returns?: any,\n ) =>\n this.testConfectImplWithoutIdentity.run(\n handler,\n returns,\n )) as TestConfect<ConfectSchema>[\"run\"];\n\n readonly fetch = <PathQueryFragment extends string>(\n pathQueryFragment: PathQueryFragment,\n init?: RequestInit,\n ) => this.testConfectImplWithoutIdentity.fetch(pathQueryFragment, init);\n\n readonly finishInProgressScheduledFunctions = () =>\n this.testConfectImplWithoutIdentity.finishInProgressScheduledFunctions();\n\n readonly finishAllScheduledFunctions = (advanceTimers: () => void) =>\n this.testConfectImplWithoutIdentity.finishAllScheduledFunctions(\n advanceTimers,\n );\n}\n\n/**\n * How a test registers one installed component: its own schema and modules, or\n * the `register(t, name)` a component package exports from `<package>/testing`\n * or `<package>/test`, which also registers the package's own children.\n */\nexport type ComponentKit =\n | {\n readonly schema: SchemaDefinition<GenericSchema, boolean>;\n readonly modules: Record<string, () => Promise<any>>;\n }\n | {\n register(\n t: { readonly registerComponent: RegisterComponent },\n name: string,\n ): unknown;\n };\n\nclass InvalidComponentKit extends Schema.TaggedError<InvalidComponentKit>()(\n \"InvalidComponentKit\",\n { componentPath: Schema.String, message: Schema.String },\n) {}\n\nconst registerKit = (\n registerComponent: RegisterComponent,\n name: string,\n kit: ComponentKit,\n) => {\n if (\"register\" in kit) {\n kit.register({ registerComponent }, name);\n } else if (\"schema\" in kit && \"modules\" in kit) {\n registerComponent(name, kit.schema, kit.modules);\n } else {\n // Codegen accepts a kit whose exports it cannot list, such as CommonJS.\n throw new InvalidComponentKit({\n componentPath: name,\n message: `The test kit for ${JSON.stringify(name)} must export register(t, name), or schema and modules.`,\n });\n }\n};\n\n/**\n * Codegen's test-only schema and module registry.\n */\nexport type Registry<DatabaseSchema_ extends DatabaseSchema.AnyWithProps> = {\n readonly schema: DatabaseSchema_;\n readonly convexSchema: SchemaDefinition<GenericSchema, true>;\n readonly modules: Record<string, () => Promise<any>>;\n readonly components: Readonly<Record<string, ComponentKit>>;\n};\n\n/**\n * The declared app's generated, test-only representation.\n */\nexport type DeclaredApp<DatabaseSchema_ extends DatabaseSchema.AnyWithProps> =\n Registry<DatabaseSchema_> & {\n readonly httpMounts: ReadonlyArray<HttpMount>;\n };\n\n/**\n * Build a fresh test backend from a declaration and its generated\n * `confect/_generated/testing` registry, without restating component mounts.\n * Pass `{ target: \"kernel\" }` to run it on Confect's test kernel instead of\n * convex-test.\n */\nexport function layer<DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(\n app: DeclaredApp<DatabaseSchema_>,\n options?: TargetOptions,\n): Layer.Layer<TestConfect<DatabaseSchema_>>;\nexport function layer<\n A extends App.Any,\n DatabaseSchema_ extends DatabaseSchema.AnyWithProps,\n>(\n app: A,\n registry: Registry<DatabaseSchema_> & {\n readonly components: Readonly<\n Record<\n Mount.NameOf<NoInfer<A>[\"mounts\"][number]>,\n Registry<DatabaseSchema_>[\"components\"][string]\n >\n >;\n },\n options?: TargetOptions,\n): Layer.Layer<TestConfect<DatabaseSchema_>>;\nexport function layer<DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(\n databaseSchema: DatabaseSchema_,\n convexSchemaDefinition: SchemaDefinition<GenericSchema, true>,\n modules: Record<string, () => Promise<any>>,\n options?: LayerOptions,\n): Layer.Layer<TestConfect<DatabaseSchema_>>;\nexport function layer<DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(\n appOrSchema: App.Any | DeclaredApp<DatabaseSchema_> | DatabaseSchema_,\n second?:\n | Registry<DatabaseSchema_>\n | SchemaDefinition<GenericSchema, true>\n | TargetOptions,\n third?: Record<string, () => Promise<any>> | TargetOptions,\n options: LayerOptions = {},\n): Layer.Layer<TestConfect<DatabaseSchema_>> {\n if (App.isApp(appOrSchema)) {\n const registry = second as Registry<DatabaseSchema_>;\n const mounts = App.mounts(appOrSchema);\n return schemaLayer(\n registry.schema,\n registry.convexSchema,\n registry.modules,\n {\n ...targetOf(third as TargetOptions | undefined),\n httpMounts: mounts.flatMap(({ name, httpPrefix }) =>\n httpPrefix === undefined ? [] : [{ componentPath: name, httpPrefix }],\n ),\n register: (registerComponent) => {\n for (const [name, component] of Object.entries(registry.components)) {\n if (\n mounts.some(\n (mount) =>\n name === mount.name || name.startsWith(`${mount.name}/`),\n )\n ) {\n registerKit(registerComponent, name, component);\n }\n }\n },\n },\n );\n }\n if (\"httpMounts\" in appOrSchema) {\n const app = appOrSchema as DeclaredApp<DatabaseSchema_>;\n return schemaLayer(app.schema, app.convexSchema, app.modules, {\n ...targetOf(second as TargetOptions | undefined),\n httpMounts: app.httpMounts,\n register: (registerComponent) => {\n for (const [name, component] of Object.entries(app.components)) {\n registerKit(registerComponent, name, component);\n }\n },\n });\n }\n return schemaLayer(\n appOrSchema as DatabaseSchema_,\n second as SchemaDefinition<GenericSchema, true>,\n third as Record<string, () => Promise<any>>,\n options,\n );\n}\n\nconst targetOf = (options: TargetOptions | undefined): TargetOptions =>\n options?.target === undefined ? {} : { target: options.target };\n\nconst schemaLayer = <DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(\n databaseSchema: DatabaseSchema_,\n convexSchemaDefinition: SchemaDefinition<GenericSchema, true>,\n modules: Record<string, () => Promise<any>>,\n options: LayerOptions = {},\n): Layer.Layer<TestConfect<DatabaseSchema_>> =>\n Layer.sync(TestConfect<DatabaseSchema_>(), () => {\n process.env.CONVEX_CLOUD_URL ??= \"https://some-deployment.convex.cloud\";\n process.env.CONVEX_SITE_URL ??= \"https://some.convex.site\";\n const testConvex = (options.target === \"kernel\" ? kernelTest : convexTest)(\n convexSchemaDefinition,\n modules,\n );\n // convex-test takes three arguments and ignores the options. The kernel\n // reads `standing`.\n const registerComponent =\n testConvex.registerComponent as unknown as RegisterComponent;\n const mountedHttp = MountedHttp.make(options.httpMounts ?? [], (...args) =>\n registerComponent(...args),\n );\n options.register?.(mountedHttp.register);\n return new TestConfectImpl(databaseSchema, testConvex as any, mountedHttp);\n });\n"],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import type { Attempt as AttemptNumber } from "./Invocation.js";
2
+ import * as Kernel from "./Kernel.js";
3
+ import type { DocumentId, StoredDocument } from "./KernelValues.js";
4
+ import type * as ReadSet from "./ReadSet.js";
5
+ /**
6
+ * One frame of an attempt at a query or mutation: the committed state the
7
+ * attempt started from, its caller's frame and its own pending writes. The
8
+ * outermost frame belongs to the top-level function. Each nested mutation opens
9
+ * a child frame, which merges into its caller's frame when it returns and is
10
+ * dropped when it fails. Reads belong to the whole attempt and are never
11
+ * dropped: a failed nested mutation's reads stay in the attempt.
12
+ *
13
+ * Each frame has its own lifetime. A frame takes reads and writes until it is
14
+ * closed. A mutation's frame closes once its function has returned and no
15
+ * syscall it started is still running, so a write a detached fiber makes after
16
+ * the handler settled still lands in it, as on the binary. A nested mutation's
17
+ * frame closes before it merges into its caller's, so no write reaches it after
18
+ * its writes became its caller's.
19
+ *
20
+ * A frame belongs to one invocation, which alone writes to it, so a caller's
21
+ * write made while its nested mutation is in flight stays the caller's.
22
+ * `Kernel.apply` publishes the outermost frame's writes.
23
+ */
24
+ export declare class KernelAttempt {
25
+ readonly snapshot: Kernel.State;
26
+ readonly number: AttemptNumber;
27
+ private readonly parent?;
28
+ private readonly overlay;
29
+ private readonly life;
30
+ private readonly allReads;
31
+ constructor(snapshot: Kernel.State, number?: AttemptNumber, parent?: KernelAttempt | undefined);
32
+ get reads(): ReadonlyArray<ReadSet.Read>;
33
+ get closed(): boolean;
34
+ readDocument(componentPath: string, id: DocumentId): void;
35
+ /**
36
+ * Record a read of an interval. The returned function advances how far the
37
+ * query examined it.
38
+ */
39
+ readInterval(read: Omit<ReadSet.IntervalRead, "through">): (through: ReadSet.Key | "end") => void;
40
+ /**
41
+ * A syscall began. `end` runs when it settles.
42
+ */
43
+ begin(): () => void;
44
+ /**
45
+ * Resolves once a whole turn of the event loop passes with no syscall of this
46
+ * frame running or started. A nested call is a syscall of its caller's frame
47
+ * until it has drained.
48
+ */
49
+ drained(): Promise<void>;
50
+ close(): void;
51
+ /**
52
+ * The pending writes this frame sees, from the outermost frame to this one.
53
+ */
54
+ private overlays;
55
+ get(componentPath: string, id: DocumentId): StoredDocument | null;
56
+ /**
57
+ * The table as this frame sees it, committed rows under every pending write
58
+ * from the outermost frame to this one.
59
+ */
60
+ scan(componentPath: string, tableName: string): Array<StoredDocument>;
61
+ write(componentPath: string, id: DocumentId, doc: StoredDocument | null): void;
62
+ /**
63
+ * A nested mutation begins, in a frame of its own. Dropping a failed one is
64
+ * forgetting it.
65
+ */
66
+ child(): KernelAttempt;
67
+ /**
68
+ * A nested mutation returned and its frame closed. Its writes become its
69
+ * caller's.
70
+ */
71
+ merge(): void;
72
+ /**
73
+ * The outermost frame's writes, for `Kernel.apply`.
74
+ */
75
+ writes(): Array<Kernel.Write>;
76
+ }
77
+ //# sourceMappingURL=Attempt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Attempt.d.ts","sourceRoot":"","sources":["../../src/internal/Attempt.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEpE,OAAO,KAAK,KAAK,OAAO,MAAM,cAAc,CAAC;AAiB7C;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,aAAa;IAMtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK;IAC/B,QAAQ,CAAC,MAAM,EAAE,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAP1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgD;IACrE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;IAE/C,YACW,QAAQ,EAAE,MAAM,CAAC,KAAK,EACtB,MAAM,GAAE,aAAiB,EACjB,MAAM,CAAC,EAAE,aAAa,YAAA,EAGxC;IAED,IAAI,KAAK,IAAI,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAEvC;IAED,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,QAEjD;IAED;;;OAGG;IACH,YAAY,CACV,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,SAAS,CAAC,GAC1C,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,GAAG,KAAK,KAAK,IAAI,CAMxC;IAED;;OAEG;IACH,KAAK,IAAI,MAAM,IAAI,CAOlB;IAED;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAOvB;IAED,KAAK,SAEJ;IAED;;OAEG;IACH,OAAO,CAAC,QAAQ;IAMhB,GAAG,CAAC,aAAa,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,cAAc,GAAG,IAAI,CAMhE;IAED;;;OAGG;IACH,IAAI,CAAC,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC,cAAc,CAAC,CAapE;IAED,KAAK,CAAC,aAAa,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,cAAc,GAAG,IAAI,QAItE;IAED;;;OAGG;IACH,KAAK,IAAI,aAAa,CAErB;IAED;;;OAGG;IACH,KAAK,SASJ;IAED;;OAEG;IACH,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAI5B;CACF"}
@@ -0,0 +1,154 @@
1
+ import { tableNameFromId } from "./KernelValues.js";
2
+ import { get, rows } from "./Kernel.js";
3
+ import { setImmediate } from "node:timers/promises";
4
+ //#region src/internal/Attempt.ts
5
+ /**
6
+ * One frame of an attempt at a query or mutation: the committed state the
7
+ * attempt started from, its caller's frame and its own pending writes. The
8
+ * outermost frame belongs to the top-level function. Each nested mutation opens
9
+ * a child frame, which merges into its caller's frame when it returns and is
10
+ * dropped when it fails. Reads belong to the whole attempt and are never
11
+ * dropped: a failed nested mutation's reads stay in the attempt.
12
+ *
13
+ * Each frame has its own lifetime. A frame takes reads and writes until it is
14
+ * closed. A mutation's frame closes once its function has returned and no
15
+ * syscall it started is still running, so a write a detached fiber makes after
16
+ * the handler settled still lands in it, as on the binary. A nested mutation's
17
+ * frame closes before it merges into its caller's, so no write reaches it after
18
+ * its writes became its caller's.
19
+ *
20
+ * A frame belongs to one invocation, which alone writes to it, so a caller's
21
+ * write made while its nested mutation is in flight stays the caller's.
22
+ * `Kernel.apply` publishes the outermost frame's writes.
23
+ */
24
+ var KernelAttempt = class KernelAttempt {
25
+ snapshot;
26
+ number;
27
+ parent;
28
+ overlay = /* @__PURE__ */ new Map();
29
+ life = {
30
+ running: 0,
31
+ started: 0,
32
+ open: true
33
+ };
34
+ allReads;
35
+ constructor(snapshot, number = 1, parent) {
36
+ this.snapshot = snapshot;
37
+ this.number = number;
38
+ this.parent = parent;
39
+ this.allReads = parent?.allReads ?? [];
40
+ }
41
+ get reads() {
42
+ return this.allReads;
43
+ }
44
+ get closed() {
45
+ return !this.life.open;
46
+ }
47
+ readDocument(componentPath, id) {
48
+ this.allReads.push({
49
+ kind: "document",
50
+ componentPath,
51
+ id
52
+ });
53
+ }
54
+ /**
55
+ * Record a read of an interval. The returned function advances how far the
56
+ * query examined it.
57
+ */
58
+ readInterval(read) {
59
+ const interval = {
60
+ ...read,
61
+ through: null
62
+ };
63
+ this.allReads.push(interval);
64
+ return (through) => {
65
+ interval.through = through;
66
+ };
67
+ }
68
+ /**
69
+ * A syscall began. `end` runs when it settles.
70
+ */
71
+ begin() {
72
+ const life = this.life;
73
+ life.running++;
74
+ life.started++;
75
+ return () => {
76
+ life.running--;
77
+ };
78
+ }
79
+ /**
80
+ * Resolves once a whole turn of the event loop passes with no syscall of this
81
+ * frame running or started. A nested call is a syscall of its caller's frame
82
+ * until it has drained.
83
+ */
84
+ drained() {
85
+ const before = this.life.started;
86
+ return setImmediate().then(() => this.life.running === 0 && this.life.started === before ? void 0 : this.drained());
87
+ }
88
+ close() {
89
+ this.life.open = false;
90
+ }
91
+ /**
92
+ * The pending writes this frame sees, from the outermost frame to this one.
93
+ */
94
+ overlays() {
95
+ return this.parent === void 0 ? [this.overlay] : [...this.parent.overlays(), this.overlay];
96
+ }
97
+ get(componentPath, id) {
98
+ for (const overlay of this.overlays().toReversed()) {
99
+ const write = overlay.get(componentPath)?.get(id);
100
+ if (write !== void 0) return write;
101
+ }
102
+ return get(this.snapshot, componentPath, id)?.doc ?? null;
103
+ }
104
+ /**
105
+ * The table as this frame sees it, committed rows under every pending write
106
+ * from the outermost frame to this one.
107
+ */
108
+ scan(componentPath, tableName) {
109
+ const ids = /* @__PURE__ */ new Set();
110
+ for (const row of rows(this.snapshot, componentPath, tableName)) ids.add(row.doc._id);
111
+ for (const overlay of this.overlays()) for (const id of overlay.get(componentPath)?.keys() ?? []) if (tableNameFromId(id) === tableName) ids.add(id);
112
+ const docs = [];
113
+ for (const id of ids) {
114
+ const doc = this.get(componentPath, id);
115
+ if (doc !== null) docs.push(doc);
116
+ }
117
+ return docs;
118
+ }
119
+ write(componentPath, id, doc) {
120
+ const writes = this.overlay.get(componentPath) ?? /* @__PURE__ */ new Map();
121
+ this.overlay.set(componentPath, writes);
122
+ writes.set(id, doc);
123
+ }
124
+ /**
125
+ * A nested mutation begins, in a frame of its own. Dropping a failed one is
126
+ * forgetting it.
127
+ */
128
+ child() {
129
+ return new KernelAttempt(this.snapshot, this.number, this);
130
+ }
131
+ /**
132
+ * A nested mutation returned and its frame closed. Its writes become its
133
+ * caller's.
134
+ */
135
+ merge() {
136
+ if (this.parent === void 0) throw new Error("The outermost frame of an attempt has no caller.");
137
+ if (this.life.open) throw new Error("A nested mutation's frame merges only once closed.");
138
+ for (const [componentPath, writes] of this.overlay) for (const [id, doc] of writes) this.parent.write(componentPath, id, doc);
139
+ }
140
+ /**
141
+ * The outermost frame's writes, for `Kernel.apply`.
142
+ */
143
+ writes() {
144
+ return Array.from(this.overlay, ([componentPath, writes]) => Array.from(writes, ([id, doc]) => ({
145
+ componentPath,
146
+ id,
147
+ doc
148
+ }))).flat();
149
+ }
150
+ };
151
+ //#endregion
152
+ export { KernelAttempt };
153
+
154
+ //# sourceMappingURL=Attempt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Attempt.js","names":["Kernel.get","Kernel.rows"],"sources":["../../src/internal/Attempt.ts"],"sourcesContent":["// oxlint-disable-next-line effecttsgo/node-builtin-import, no-restricted-imports -- An attempt's drain waits one real turn of the event loop, which is no deadline. Fake timers in a test replace the global `setImmediate`, not this one.\nimport { setImmediate } from \"node:timers/promises\";\nimport type { Attempt as AttemptNumber } from \"./Invocation.js\";\nimport * as Kernel from \"./Kernel.js\";\nimport type { DocumentId, StoredDocument } from \"./KernelValues.js\";\nimport { tableNameFromId } from \"./KernelValues.js\";\nimport type * as ReadSet from \"./ReadSet.js\";\n\n/**\n * Pending writes, keyed by component path, then document ID. `null` deletes.\n */\ntype Overlay = Map<string, Map<DocumentId, StoredDocument | null>>;\n\n/**\n * How long one frame takes syscalls: those it has running, those it has\n * started, and whether it still takes them.\n */\ninterface Life {\n running: number;\n started: number;\n open: boolean;\n}\n\n/**\n * One frame of an attempt at a query or mutation: the committed state the\n * attempt started from, its caller's frame and its own pending writes. The\n * outermost frame belongs to the top-level function. Each nested mutation opens\n * a child frame, which merges into its caller's frame when it returns and is\n * dropped when it fails. Reads belong to the whole attempt and are never\n * dropped: a failed nested mutation's reads stay in the attempt.\n *\n * Each frame has its own lifetime. A frame takes reads and writes until it is\n * closed. A mutation's frame closes once its function has returned and no\n * syscall it started is still running, so a write a detached fiber makes after\n * the handler settled still lands in it, as on the binary. A nested mutation's\n * frame closes before it merges into its caller's, so no write reaches it after\n * its writes became its caller's.\n *\n * A frame belongs to one invocation, which alone writes to it, so a caller's\n * write made while its nested mutation is in flight stays the caller's.\n * `Kernel.apply` publishes the outermost frame's writes.\n */\nexport class KernelAttempt {\n private readonly overlay: Overlay = new Map();\n private readonly life: Life = { running: 0, started: 0, open: true };\n private readonly allReads: Array<ReadSet.Read>;\n\n constructor(\n readonly snapshot: Kernel.State,\n readonly number: AttemptNumber = 1,\n private readonly parent?: KernelAttempt,\n ) {\n this.allReads = parent?.allReads ?? [];\n }\n\n get reads(): ReadonlyArray<ReadSet.Read> {\n return this.allReads;\n }\n\n get closed(): boolean {\n return !this.life.open;\n }\n\n readDocument(componentPath: string, id: DocumentId) {\n this.allReads.push({ kind: \"document\", componentPath, id });\n }\n\n /**\n * Record a read of an interval. The returned function advances how far the\n * query examined it.\n */\n readInterval(\n read: Omit<ReadSet.IntervalRead, \"through\">,\n ): (through: ReadSet.Key | \"end\") => void {\n const interval: ReadSet.IntervalRead = { ...read, through: null };\n this.allReads.push(interval);\n return (through) => {\n interval.through = through;\n };\n }\n\n /**\n * A syscall began. `end` runs when it settles.\n */\n begin(): () => void {\n const life = this.life;\n life.running++;\n life.started++;\n return () => {\n life.running--;\n };\n }\n\n /**\n * Resolves once a whole turn of the event loop passes with no syscall of this\n * frame running or started. A nested call is a syscall of its caller's frame\n * until it has drained.\n */\n drained(): Promise<void> {\n const before = this.life.started;\n return setImmediate().then(() =>\n this.life.running === 0 && this.life.started === before\n ? undefined\n : this.drained(),\n );\n }\n\n close() {\n this.life.open = false;\n }\n\n /**\n * The pending writes this frame sees, from the outermost frame to this one.\n */\n private overlays(): Array<Overlay> {\n return this.parent === undefined\n ? [this.overlay]\n : [...this.parent.overlays(), this.overlay];\n }\n\n get(componentPath: string, id: DocumentId): StoredDocument | null {\n for (const overlay of this.overlays().toReversed()) {\n const write = overlay.get(componentPath)?.get(id);\n if (write !== undefined) return write;\n }\n return Kernel.get(this.snapshot, componentPath, id)?.doc ?? null;\n }\n\n /**\n * The table as this frame sees it, committed rows under every pending write\n * from the outermost frame to this one.\n */\n scan(componentPath: string, tableName: string): Array<StoredDocument> {\n const ids = new Set<DocumentId>();\n for (const row of Kernel.rows(this.snapshot, componentPath, tableName))\n ids.add(row.doc._id);\n for (const overlay of this.overlays())\n for (const id of overlay.get(componentPath)?.keys() ?? [])\n if (tableNameFromId(id) === tableName) ids.add(id);\n const docs: Array<StoredDocument> = [];\n for (const id of ids) {\n const doc = this.get(componentPath, id);\n if (doc !== null) docs.push(doc);\n }\n return docs;\n }\n\n write(componentPath: string, id: DocumentId, doc: StoredDocument | null) {\n const writes = this.overlay.get(componentPath) ?? new Map();\n this.overlay.set(componentPath, writes);\n writes.set(id, doc);\n }\n\n /**\n * A nested mutation begins, in a frame of its own. Dropping a failed one is\n * forgetting it.\n */\n child(): KernelAttempt {\n return new KernelAttempt(this.snapshot, this.number, this);\n }\n\n /**\n * A nested mutation returned and its frame closed. Its writes become its\n * caller's.\n */\n merge() {\n if (this.parent === undefined) {\n throw new Error(\"The outermost frame of an attempt has no caller.\");\n }\n if (this.life.open) {\n throw new Error(\"A nested mutation's frame merges only once closed.\");\n }\n for (const [componentPath, writes] of this.overlay)\n for (const [id, doc] of writes) this.parent.write(componentPath, id, doc);\n }\n\n /**\n * The outermost frame's writes, for `Kernel.apply`.\n */\n writes(): Array<Kernel.Write> {\n return Array.from(this.overlay, ([componentPath, writes]) =>\n Array.from(writes, ([id, doc]) => ({ componentPath, id, doc })),\n ).flat();\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Convex pins `Date` inside a query or mutation to the time it started, and its
3
+ * scheduler reads `Date.now()` for `runAfter`. The kernel wraps the realm's
4
+ * `Date` so it answers a kernel invocation's time inside one and the host's
5
+ * everywhere else. It sets no host timer.
6
+ */
7
+ type DateConstructor = typeof globalThis.Date;
8
+ /**
9
+ * Wrap the realm's current `Date`, unless the kernel already did. `pinned`
10
+ * answers the running invocation's time, or `undefined` outside one, and
11
+ * `inside` says whether one is running. The first install's callbacks answer
12
+ * for every later one, as with `globalThis.Convex`. A test that fakes `Date`
13
+ * replaces the wrapper while the fake is installed, and the next install wraps
14
+ * the `Date` the test restores.
15
+ */
16
+ export declare const install: (pinned: () => number | undefined, inside: () => boolean) => void;
17
+ /**
18
+ * Whether `date` is the kernel's wrapper inside a running kernel invocation, so
19
+ * it already answers that invocation's time on the kernel's clock.
20
+ */
21
+ export declare const answersInvocation: (date: DateConstructor) => boolean;
22
+ /**
23
+ * The host's time in milliseconds, never a kernel invocation's: the real clock,
24
+ * or a test's fake one while it is installed. It reads the test environment's
25
+ * `Date`, never the copy a bound handler pinned.
26
+ */
27
+ export declare const hostNow: () => number;
28
+ export {};
29
+ //# sourceMappingURL=Clock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Clock.d.ts","sourceRoot":"","sources":["../../src/internal/Clock.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,KAAK,eAAe,GAAG,OAAO,UAAU,CAAC,IAAI,CAAC;AA6C9C;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,WACV,MAAM,MAAM,GAAG,SAAS,UACxB,MAAM,OAAO,SAStB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,SAAU,eAAe,KAAG,OAGzD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,OAAO,QAAO,MAKvB,CAAC"}
@@ -0,0 +1,66 @@
1
+ import { host } from "./Globals.js";
2
+ //#region src/internal/Clock.ts
3
+ /**
4
+ * Convex pins `Date` inside a query or mutation to the time it started, and its
5
+ * scheduler reads `Date.now()` for `runAfter`. The kernel wraps the realm's
6
+ * `Date` so it answers a kernel invocation's time inside one and the host's
7
+ * everywhere else. It sets no host timer.
8
+ */
9
+ const key = Symbol.for("@confect/test/Clock");
10
+ const wrap = (base, pinned) => {
11
+ const proxy = new Proxy(base, {
12
+ get: (target, property) => property === "now" ? () => pinned() ?? target.now() : Reflect.get(target, property, target),
13
+ construct: (target, args, newTarget) => {
14
+ const at = args.length === 0 ? pinned() : void 0;
15
+ return Reflect.construct(target, at === void 0 ? args : [at], newTarget === proxy ? target : newTarget);
16
+ },
17
+ apply: (target, self, args) => {
18
+ const at = pinned();
19
+ return at === void 0 ? Reflect.apply(target, self, args) : new target(at).toString();
20
+ }
21
+ });
22
+ return proxy;
23
+ };
24
+ /**
25
+ * Wrap the realm's current `Date`, unless the kernel already did. `pinned`
26
+ * answers the running invocation's time, or `undefined` outside one, and
27
+ * `inside` says whether one is running. The first install's callbacks answer
28
+ * for every later one, as with `globalThis.Convex`. A test that fakes `Date`
29
+ * replaces the wrapper while the fake is installed, and the next install wraps
30
+ * the `Date` the test restores.
31
+ */
32
+ const install = (pinned, inside) => {
33
+ const global = globalThis;
34
+ const state = global[key] ??= {
35
+ bases: /* @__PURE__ */ new WeakMap(),
36
+ pinned,
37
+ inside
38
+ };
39
+ const current = global.Date;
40
+ if (state.bases.has(current)) return;
41
+ const wrapper = wrap(current, () => state.pinned());
42
+ state.bases.set(wrapper, current);
43
+ global.Date = wrapper;
44
+ };
45
+ /**
46
+ * Whether `date` is the kernel's wrapper inside a running kernel invocation, so
47
+ * it already answers that invocation's time on the kernel's clock.
48
+ */
49
+ const answersInvocation = (date) => {
50
+ const state = globalThis[key];
51
+ return state !== void 0 && state.bases.has(date) && state.inside();
52
+ };
53
+ /**
54
+ * The host's time in milliseconds, never a kernel invocation's: the real clock,
55
+ * or a test's fake one while it is installed. It reads the test environment's
56
+ * `Date`, never the copy a bound handler pinned.
57
+ */
58
+ const hostNow = () => host(() => {
59
+ const global = globalThis;
60
+ const current = global.Date;
61
+ return (global[key]?.bases.get(current) ?? current).now();
62
+ });
63
+ //#endregion
64
+ export { answersInvocation, hostNow, install };
65
+
66
+ //# sourceMappingURL=Clock.js.map