@gaganref/confect-server 10.3.1-fork.9 → 10.3.1-fork.91
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/dist/ActionCall.d.ts +30 -0
- package/dist/ActionCall.d.ts.map +1 -0
- package/dist/ActionCall.js +41 -0
- package/dist/ActionCall.js.map +1 -0
- package/dist/ActionRunner.d.ts +1 -1
- package/dist/ActionRunner.d.ts.map +1 -1
- package/dist/ActionRunner.js +3 -3
- package/dist/ActionRunner.js.map +1 -1
- package/dist/AiGatewayDecisionClient.js +1 -1
- package/dist/AiGatewayLanguageClient.js +1 -1
- package/dist/Auth.d.ts +31 -2
- package/dist/Auth.d.ts.map +1 -1
- package/dist/Auth.js +23 -3
- package/dist/Auth.js.map +1 -1
- package/dist/Callback.d.ts +1 -1
- package/dist/Callback.d.ts.map +1 -1
- package/dist/Callback.js +6 -6
- package/dist/Callback.js.map +1 -1
- package/dist/ComponentCtx.d.ts +4 -0
- package/dist/ComponentCtx.d.ts.map +1 -1
- package/dist/ConvexConfigProvider.js +2 -2
- package/dist/ConvexFunctionDefinitions.d.ts.map +1 -1
- package/dist/ConvexFunctionDefinitions.js +4 -4
- package/dist/ConvexFunctionDefinitions.js.map +1 -1
- package/dist/ConvexLogger.js +1 -1
- package/dist/CronJobs.d.ts.map +1 -1
- package/dist/CronJobs.js +7 -6
- package/dist/CronJobs.js.map +1 -1
- package/dist/DatabaseSchema.js +2 -2
- package/dist/DatabaseWriter.d.ts +44 -2
- package/dist/DatabaseWriter.d.ts.map +1 -1
- package/dist/DatabaseWriter.js +59 -9
- package/dist/DatabaseWriter.js.map +1 -1
- package/dist/ExecutionMetadata.js +1 -1
- package/dist/FunctionImpl.js +2 -2
- package/dist/FunctionRegistryItem.d.ts +1 -0
- package/dist/FunctionRegistryItem.d.ts.map +1 -1
- package/dist/FunctionRegistryItem.js +2 -1
- package/dist/FunctionRegistryItem.js.map +1 -1
- package/dist/GroupImpl.d.ts +21 -2
- package/dist/GroupImpl.d.ts.map +1 -1
- package/dist/GroupImpl.js +21 -22
- package/dist/GroupImpl.js.map +1 -1
- package/dist/GroupRegistry.d.ts +1 -0
- package/dist/GroupRegistry.d.ts.map +1 -1
- package/dist/GroupRegistry.js +10 -3
- package/dist/GroupRegistry.js.map +1 -1
- package/dist/Handler.d.ts +8 -4
- package/dist/Handler.d.ts.map +1 -1
- package/dist/Handler.js.map +1 -1
- package/dist/HttpRouter.d.ts +3 -0
- package/dist/HttpRouter.d.ts.map +1 -1
- package/dist/HttpRouter.js +29 -10
- package/dist/HttpRouter.js.map +1 -1
- package/dist/MiddlewareImpl.js +1 -1
- package/dist/MountInit.d.ts +31 -0
- package/dist/MountInit.d.ts.map +1 -0
- package/dist/MountInit.js +49 -0
- package/dist/MountInit.js.map +1 -0
- package/dist/MutationRunner.d.ts +1 -1
- package/dist/MutationRunner.d.ts.map +1 -1
- package/dist/MutationRunner.js +3 -3
- package/dist/MutationRunner.js.map +1 -1
- package/dist/MutationTransactionContext.d.ts.map +1 -1
- package/dist/MutationTransactionContext.js +4 -3
- package/dist/MutationTransactionContext.js.map +1 -1
- package/dist/OfficialComponent.d.ts +60 -0
- package/dist/OfficialComponent.d.ts.map +1 -0
- package/dist/OfficialComponent.js +72 -0
- package/dist/OfficialComponent.js.map +1 -0
- package/dist/OrderedQuery.d.ts +4 -5
- package/dist/OrderedQuery.d.ts.map +1 -1
- package/dist/OrderedQuery.js.map +1 -1
- package/dist/QueryInitializer.js +2 -2
- package/dist/QueryRunner.js +2 -2
- package/dist/QueryStream.d.ts +120 -12
- package/dist/QueryStream.d.ts.map +1 -1
- package/dist/QueryStream.js +143 -41
- package/dist/QueryStream.js.map +1 -1
- package/dist/QueryStreamCursor.js +1 -1
- package/dist/QueryStreamIndexPrefix.js +1 -1
- package/dist/QueryStreamIndexRange.js +2 -2
- package/dist/QueryStreamKey.js +1 -1
- package/dist/QueryStreamKeyBounds.js +2 -2
- package/dist/QueryStreamKeyLayout.js +2 -2
- package/dist/QueryStreamKeyValues.js +2 -2
- package/dist/QueryStreamPagination.js +1 -1
- package/dist/QueryStreamReadBudget.d.ts +3 -2
- package/dist/QueryStreamReadBudget.d.ts.map +1 -1
- package/dist/QueryStreamReadBudget.js +8 -5
- package/dist/QueryStreamReadBudget.js.map +1 -1
- package/dist/QueryTransactionContext.js +2 -2
- package/dist/RegisteredConvexFunction.d.ts +10 -5
- package/dist/RegisteredConvexFunction.d.ts.map +1 -1
- package/dist/RegisteredConvexFunction.js +49 -29
- package/dist/RegisteredConvexFunction.js.map +1 -1
- package/dist/RegisteredFunction.d.ts +48 -22
- package/dist/RegisteredFunction.d.ts.map +1 -1
- package/dist/RegisteredFunction.js +163 -42
- package/dist/RegisteredFunction.js.map +1 -1
- package/dist/RegisteredNodeFunction.d.ts +1 -1
- package/dist/RegisteredNodeFunction.d.ts.map +1 -1
- package/dist/RegisteredNodeFunction.js +10 -6
- package/dist/RegisteredNodeFunction.js.map +1 -1
- package/dist/RegistryItems.d.ts +7 -0
- package/dist/RegistryItems.d.ts.map +1 -1
- package/dist/RegistryItems.js +8 -3
- package/dist/RegistryItems.js.map +1 -1
- package/dist/RequestMetadata.js +1 -1
- package/dist/Scheduler.d.ts +1 -1
- package/dist/Scheduler.d.ts.map +1 -1
- package/dist/Scheduler.js +14 -13
- package/dist/Scheduler.js.map +1 -1
- package/dist/Storage.js +1 -1
- package/dist/StorageActionWriter.js +1 -1
- package/dist/StorageReader.js +1 -1
- package/dist/StorageWriter.js +1 -1
- package/dist/Table.d.ts +6 -6
- package/dist/Table.d.ts.map +1 -1
- package/dist/TableInfo.d.ts +7 -7
- package/dist/TableInfo.d.ts.map +1 -1
- package/dist/TableInfo.js.map +1 -1
- package/dist/TransactionMetadata.js +1 -1
- package/dist/VectorSearch.js +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -18
- package/dist/internal/AiGatewayDecisionClient.js +1 -1
- package/dist/internal/AiGatewayLanguageClient.js +1 -1
- package/dist/internal/AiGatewayServiceToken.js +1 -1
- package/dist/internal/DocumentPatch.d.ts +16 -0
- package/dist/internal/DocumentPatch.d.ts.map +1 -0
- package/dist/internal/DocumentPatch.js +36 -0
- package/dist/internal/DocumentPatch.js.map +1 -0
- package/dist/internal/httpBody.d.ts +13 -0
- package/dist/internal/httpBody.d.ts.map +1 -0
- package/dist/internal/httpBody.js +47 -0
- package/dist/internal/httpBody.js.map +1 -0
- package/dist/internal/httpOptions.d.ts +4 -0
- package/dist/internal/httpOptions.d.ts.map +1 -0
- package/dist/internal/httpOptions.js +83 -0
- package/dist/internal/httpOptions.js.map +1 -0
- package/dist/internal/observability.d.ts +5 -0
- package/dist/internal/observability.d.ts.map +1 -0
- package/dist/internal/observability.js +21 -0
- package/dist/internal/observability.js.map +1 -0
- package/dist/internal/reservedArgument.d.ts +8 -0
- package/dist/internal/reservedArgument.d.ts.map +1 -0
- package/dist/internal/reservedArgument.js +30 -0
- package/dist/internal/reservedArgument.js.map +1 -0
- package/package.json +5 -5
- package/src/ActionCall.ts +83 -0
- package/src/ActionRunner.ts +3 -2
- package/src/Auth.ts +49 -1
- package/src/Callback.ts +3 -2
- package/src/ComponentCtx.ts +2 -0
- package/src/ConvexFunctionDefinitions.ts +2 -1
- package/src/CronJobs.ts +2 -1
- package/src/DatabaseWriter.ts +190 -26
- package/src/FunctionRegistryItem.ts +4 -0
- package/src/GroupImpl.ts +61 -8
- package/src/GroupRegistry.ts +7 -3
- package/src/Handler.ts +21 -5
- package/src/HttpRouter.ts +69 -5
- package/src/MountInit.ts +80 -0
- package/src/MutationRunner.ts +3 -2
- package/src/MutationTransactionContext.ts +2 -1
- package/src/OfficialComponent.ts +168 -0
- package/src/OrderedQuery.ts +4 -5
- package/src/QueryStream.ts +391 -61
- package/src/QueryStreamReadBudget.ts +19 -6
- package/src/RegisteredConvexFunction.ts +39 -2
- package/src/RegisteredFunction.ts +305 -49
- package/src/RegisteredNodeFunction.ts +11 -1
- package/src/RegistryItems.ts +31 -0
- package/src/Scheduler.ts +17 -19
- package/src/TableInfo.ts +18 -22
- package/src/index.ts +3 -0
- package/src/internal/DocumentPatch.ts +87 -0
- package/src/internal/httpBody.ts +72 -0
- package/src/internal/httpOptions.ts +154 -0
- package/src/internal/observability.ts +27 -0
- package/src/internal/reservedArgument.ts +56 -0
package/dist/CronJobs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CronJobs.js","names":["makeConvexCrons"],"sources":["../src/CronJobs.ts"],"sourcesContent":["import { Ref } from \"@confect/core\";\nimport type { CronJob as ConvexCronJob } from \"convex/server\";\nimport { cronJobs as makeConvexCrons, type Crons } from \"convex/server\";\nimport { pipe } from \"effect/Function\";\nimport * as Array from \"effect/Array\";\nimport * as Cron from \"effect/Cron\";\nimport * as DateTime from \"effect/DateTime\";\nimport * as Duration from \"effect/Duration\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as Order from \"effect/Order\";\nimport * as Predicate from \"effect/Predicate\";\nimport * as Record from \"effect/Record\";\nimport type * as CronJob from \"./CronJob.js\";\n\nexport const TypeId = \"~@confect/server/CronJobs\";\nexport type TypeId = typeof TypeId;\n\nexport interface CronJobs {\n readonly [TypeId]: TypeId;\n readonly cronJobs: Record<string, CronJob.CronJob>;\n readonly convexCronJobs: Crons;\n\n add(cron: CronJob.CronJob): CronJobs;\n}\n\nexport const isCronJobs = (u: unknown): u is CronJobs =>\n Predicate.hasProperty(u, TypeId);\n\nconst Proto = {\n [TypeId]: TypeId,\n\n add(this: CronJobs, cronJob: CronJob.CronJob) {\n const newConvexCrons = Object.assign(makeConvexCrons(), {\n crons: { ...this.convexCronJobs.crons },\n });\n\n const functionReference =
|
|
1
|
+
{"version":3,"file":"CronJobs.js","names":["makeConvexCrons"],"sources":["../src/CronJobs.ts"],"sourcesContent":["import { Ref } from \"@confect/core\";\nimport { getFunctionReference } from \"@confect/core/RefInternal\";\nimport type { CronJob as ConvexCronJob } from \"convex/server\";\nimport { cronJobs as makeConvexCrons, type Crons } from \"convex/server\";\nimport { pipe } from \"effect/Function\";\nimport * as Array from \"effect/Array\";\nimport * as Cron from \"effect/Cron\";\nimport * as DateTime from \"effect/DateTime\";\nimport * as Duration from \"effect/Duration\";\nimport * as Match from \"effect/Match\";\nimport * as Option from \"effect/Option\";\nimport * as Order from \"effect/Order\";\nimport * as Predicate from \"effect/Predicate\";\nimport * as Record from \"effect/Record\";\nimport type * as CronJob from \"./CronJob.js\";\n\nexport const TypeId = \"~@confect/server/CronJobs\";\nexport type TypeId = typeof TypeId;\n\nexport interface CronJobs {\n readonly [TypeId]: TypeId;\n readonly cronJobs: Record<string, CronJob.CronJob>;\n readonly convexCronJobs: Crons;\n\n add(cron: CronJob.CronJob): CronJobs;\n}\n\nexport const isCronJobs = (u: unknown): u is CronJobs =>\n Predicate.hasProperty(u, TypeId);\n\nconst Proto = {\n [TypeId]: TypeId,\n\n add(this: CronJobs, cronJob: CronJob.CronJob) {\n const newConvexCrons = Object.assign(makeConvexCrons(), {\n crons: { ...this.convexCronJobs.crons },\n });\n\n const functionReference = getFunctionReference(cronJob.ref);\n const encodedArgs = Ref.encodeArgsSync(cronJob.ref, cronJob.args);\n\n Match.value(cronJob.schedule).pipe(\n Match.when(Cron.isCron, (cron) => {\n newConvexCrons.cron(\n cronJob.identifier,\n cronToConvexCronString(cron),\n functionReference,\n encodedArgs,\n );\n }),\n Match.when(Duration.isDuration, (duration) => {\n newConvexCrons.interval(\n cronJob.identifier,\n durationToConvexIntervalSchedule(duration),\n functionReference,\n encodedArgs,\n );\n }),\n Match.exhaustive,\n );\n\n return makeProto(\n Record.set(this.cronJobs, cronJob.identifier, cronJob),\n newConvexCrons,\n );\n },\n};\n\nconst makeProto = (\n cronJobs: Record<string, CronJob.CronJob>,\n convexCronJobs: Crons,\n): CronJobs =>\n Object.assign(Object.create(Proto), {\n cronJobs,\n convexCronJobs,\n });\n\nexport const make = (): CronJobs => makeProto({}, makeConvexCrons());\n\nexport const cronToConvexCronString = (cron: Cron.Cron): string => {\n pipe(\n cron.tz,\n Option.filter((tz) =>\n pipe(\n tz,\n Match.value,\n Match.tag(\"Offset\", ({ offset }) => offset !== 0),\n Match.tag(\"Named\", ({ id }) => id !== \"UTC\" && id !== \"Etc/UTC\"),\n Match.exhaustive,\n ),\n ),\n Option.map((tz) => {\n throw new Error(\n `Convex cron expressions are always evaluated in UTC, but this cron ` +\n `specifies the time zone \"${DateTime.zoneToString(tz)}\". ` +\n `Either omit the timezone or specify UTC.`,\n );\n }),\n );\n\n const hasNonDefaultSeconds = cron.seconds.size !== 1 || !cron.seconds.has(0);\n if (hasNonDefaultSeconds) {\n throw new Error(\n \"Convex cron expressions do not support a seconds field. \" +\n \"The seconds field must be the default {0}. \" +\n \"Sub-minute scheduling is supported only by interval schedules defined using a Duration.\",\n );\n }\n\n return Array.join(\n [\n setToField(cron.minutes),\n setToField(cron.hours),\n setToField(cron.days),\n setToField(cron.months),\n setToField(cron.weekdays),\n ],\n \" \",\n );\n};\n\nconst setToField = (set: ReadonlySet<number>): string => {\n if (set.size === 0) return \"*\";\n return pipe(\n set,\n Array.sort(Order.Number),\n Array.map((n) => n.toString()),\n Array.join(\",\"),\n );\n};\n\nexport const durationToConvexIntervalSchedule = (\n duration: Duration.Duration,\n): IntervalSchedule => {\n const millis = Duration.toMillis(duration);\n if (millis <= 0) {\n throw new Error(\"Interval must be a positive duration.\");\n }\n\n const oneHourInMillis = Duration.hours(1).pipe(Duration.toMillis);\n const hours = millis / oneHourInMillis;\n if (Number.isInteger(hours)) {\n return { type: \"interval\", hours };\n }\n\n const oneMinuteInMillis = Duration.minutes(1).pipe(Duration.toMillis);\n const minutes = millis / oneMinuteInMillis;\n if (Number.isInteger(minutes)) {\n return { type: \"interval\", minutes };\n }\n\n const oneSecondInMillis = Duration.seconds(1).pipe(Duration.toMillis);\n const seconds = millis / oneSecondInMillis;\n if (Number.isInteger(seconds)) {\n return { type: \"interval\", seconds };\n }\n\n throw new Error(\n \"Interval must be a whole number of seconds, minutes, or hours.\",\n );\n};\n\ntype IntervalSchedule = Extract<\n ConvexCronJob[\"schedule\"],\n { type: \"interval\" }\n>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAgBA,MAAa,SAAS;AAWtB,MAAa,cAAc,MACzB,UAAU,YAAY,GAAG,MAAM;AAEjC,MAAM,QAAQ;EACX,SAAS;CAEV,IAAoB,SAA0B;EAC5C,MAAM,iBAAiB,OAAO,OAAOA,SAAgB,GAAG,EACtD,OAAO,EAAE,GAAG,KAAK,eAAe,MAAM,EACxC,CAAC;EAED,MAAM,oBAAoB,qBAAqB,QAAQ,GAAG;EAC1D,MAAM,cAAc,IAAI,eAAe,QAAQ,KAAK,QAAQ,IAAI;EAEhE,MAAM,MAAM,QAAQ,QAAQ,CAAC,CAAC,KAC5B,MAAM,KAAK,KAAK,SAAS,SAAS;GAChC,eAAe,KACb,QAAQ,YACR,uBAAuB,IAAI,GAC3B,mBACA,WACF;EACF,CAAC,GACD,MAAM,KAAK,SAAS,aAAa,aAAa;GAC5C,eAAe,SACb,QAAQ,YACR,iCAAiC,QAAQ,GACzC,mBACA,WACF;EACF,CAAC,GACD,MAAM,UACR;EAEA,OAAO,UACL,OAAO,IAAI,KAAK,UAAU,QAAQ,YAAY,OAAO,GACrD,cACF;CACF;AACF;AAEA,MAAM,aACJ,UACA,mBAEA,OAAO,OAAO,OAAO,OAAO,KAAK,GAAG;CAClC;CACA;AACF,CAAC;AAEH,MAAa,aAAuB,UAAU,CAAC,GAAGA,SAAgB,CAAC;AAEnE,MAAa,0BAA0B,SAA4B;CACjE,KACE,KAAK,IACL,OAAO,QAAQ,OACb,KACE,IACA,MAAM,OACN,MAAM,IAAI,WAAW,EAAE,aAAa,WAAW,CAAC,GAChD,MAAM,IAAI,UAAU,EAAE,SAAS,OAAO,SAAS,OAAO,SAAS,GAC/D,MAAM,UACR,CACF,GACA,OAAO,KAAK,OAAO;EACjB,MAAM,IAAI,MACR,+FAC8B,SAAS,aAAa,EAAE,EAAE,4CAE1D;CACF,CAAC,CACH;CAGA,IAD6B,KAAK,QAAQ,SAAS,KAAK,CAAC,KAAK,QAAQ,IAAI,CAAC,GAEzE,MAAM,IAAI,MACR,4LAGF;CAGF,OAAO,MAAM,KACX;EACE,WAAW,KAAK,OAAO;EACvB,WAAW,KAAK,KAAK;EACrB,WAAW,KAAK,IAAI;EACpB,WAAW,KAAK,MAAM;EACtB,WAAW,KAAK,QAAQ;CAC1B,GACA,GACF;AACF;AAEA,MAAM,cAAc,QAAqC;CACvD,IAAI,IAAI,SAAS,GAAG,OAAO;CAC3B,OAAO,KACL,KACA,MAAM,KAAK,MAAM,MAAM,GACvB,MAAM,KAAK,MAAM,EAAE,SAAS,CAAC,GAC7B,MAAM,KAAK,GAAG,CAChB;AACF;AAEA,MAAa,oCACX,aACqB;CACrB,MAAM,SAAS,SAAS,SAAS,QAAQ;CACzC,IAAI,UAAU,GACZ,MAAM,IAAI,MAAM,uCAAuC;CAIzD,MAAM,QAAQ,SADU,SAAS,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,QACnB;CACrC,IAAI,OAAO,UAAU,KAAK,GACxB,OAAO;EAAE,MAAM;EAAY;CAAM;CAInC,MAAM,UAAU,SADU,SAAS,QAAQ,CAAC,CAAC,CAAC,KAAK,SAAS,QACnB;CACzC,IAAI,OAAO,UAAU,OAAO,GAC1B,OAAO;EAAE,MAAM;EAAY;CAAQ;CAIrC,MAAM,UAAU,SADU,SAAS,QAAQ,CAAC,CAAC,CAAC,KAAK,SAAS,QACnB;CACzC,IAAI,OAAO,UAAU,OAAO,GAC1B,OAAO;EAAE,MAAM;EAAY;CAAQ;CAGrC,MAAM,IAAI,MACR,gEACF;AACF"}
|
package/dist/DatabaseSchema.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
|
+
import * as Data from "effect/Data";
|
|
2
3
|
import * as Predicate from "effect/Predicate";
|
|
3
|
-
import * as Result from "effect/Result";
|
|
4
4
|
import * as Record from "effect/Record";
|
|
5
|
-
import * as
|
|
5
|
+
import * as Result from "effect/Result";
|
|
6
6
|
import * as IdScope from "@confect/core/IdScope";
|
|
7
7
|
//#region src/DatabaseSchema.ts
|
|
8
8
|
var DatabaseSchema_exports = /* @__PURE__ */ __exportAll({
|
package/dist/DatabaseWriter.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { GenericDatabaseWriter } from "convex/server";
|
|
2
|
+
import type { CommitTsPlaceholder } from "convex/values";
|
|
2
3
|
import * as Context from "effect/Context";
|
|
3
4
|
import * as Effect from "effect/Effect";
|
|
4
5
|
import * as Layer from "effect/Layer";
|
|
@@ -30,6 +31,13 @@ export interface DatabaseWriterTableAccessor<DataModel_ extends DataModel.AnyWit
|
|
|
30
31
|
*/
|
|
31
32
|
export interface DatabaseWriterService<DatabaseSchema_ extends DatabaseSchema.AnyWithProps, Docs = {}> {
|
|
32
33
|
readonly table: <const TableName extends DataModel.TableNames<DataModel.FromSchema<DatabaseSchema_>>>(tableName: TableName) => DatabaseWriterTableAccessor<DataModel.FromSchema<DatabaseSchema_>, TableName, TableName extends keyof Docs ? Docs[TableName] : DocumentByName_<DataModel.FromSchema<DatabaseSchema_>, TableName>>;
|
|
34
|
+
/**
|
|
35
|
+
* Values not known until the mutation commits. Write `vars.commitTs` into a
|
|
36
|
+
* `CommitTs` field to store the transaction's commit timestamp.
|
|
37
|
+
*/
|
|
38
|
+
readonly vars: {
|
|
39
|
+
readonly commitTs: CommitTsPlaceholder;
|
|
40
|
+
};
|
|
33
41
|
}
|
|
34
42
|
/**
|
|
35
43
|
* The tag's _Identifier_ is `Docs`-independent (see `DatabaseReaderTag`); only
|
|
@@ -37,8 +45,42 @@ export interface DatabaseWriterService<DatabaseSchema_ extends DatabaseSchema.An
|
|
|
37
45
|
* interfaces.
|
|
38
46
|
*/
|
|
39
47
|
export type DatabaseWriterTag<DatabaseSchema_ extends DatabaseSchema.AnyWithProps, Docs = {}> = Context.Service<DatabaseWriterService<DatabaseSchema_>, DatabaseWriterService<DatabaseSchema_, Docs>>;
|
|
40
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Decoded documents surrounding one successful write.
|
|
50
|
+
*/
|
|
51
|
+
export type Change<S extends DatabaseSchema.AnyWithProps> = {
|
|
52
|
+
[Name in DataModel.TableNames<DataModel.FromSchema<S>>]: {
|
|
53
|
+
readonly tableName: Name;
|
|
54
|
+
} & ({
|
|
55
|
+
readonly operation: "insert";
|
|
56
|
+
readonly oldDoc: null;
|
|
57
|
+
readonly newDoc: DocumentByName_<DataModel.FromSchema<S>, Name>;
|
|
58
|
+
} | {
|
|
59
|
+
readonly operation: "update";
|
|
60
|
+
readonly oldDoc: DocumentByName_<DataModel.FromSchema<S>, Name>;
|
|
61
|
+
readonly newDoc: DocumentByName_<DataModel.FromSchema<S>, Name>;
|
|
62
|
+
} | {
|
|
63
|
+
readonly operation: "delete";
|
|
64
|
+
readonly oldDoc: DocumentByName_<DataModel.FromSchema<S>, Name>;
|
|
65
|
+
readonly newDoc: null;
|
|
66
|
+
});
|
|
67
|
+
}[DataModel.TableNames<DataModel.FromSchema<S>>];
|
|
68
|
+
/**
|
|
69
|
+
* Runs after the write, in its transaction. A defect aborts the mutation.
|
|
70
|
+
*
|
|
71
|
+
* Only writes through this writer are observed. Raw `ctx.db`, `MutationCtx`
|
|
72
|
+
* writes and a second `DatabaseWriter.make` bypass the hook, so a host that
|
|
73
|
+
* relies on it keeps raw writers out of its functions. Component writers and
|
|
74
|
+
* nested `runMutation` calls each need their own hook installation.
|
|
75
|
+
*
|
|
76
|
+
* Concurrent writes to one document (for example under `Effect.all`) can
|
|
77
|
+
* interleave the read-write-read steps. Await them sequentially when the hook
|
|
78
|
+
* needs exact per-write snapshots. The writer takes no lock, because a hook
|
|
79
|
+
* that writes through the same writer would deadlock under one.
|
|
80
|
+
*/
|
|
81
|
+
export type Hook<S extends DatabaseSchema.AnyWithProps> = (change: Change<S>) => Effect.Effect<void>;
|
|
82
|
+
export declare const make: <DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(databaseSchema: DatabaseSchema_, convexDatabaseWriter: GenericDatabaseWriter<DataModel.ToConvex<DataModel.FromSchema<DatabaseSchema_>>>, hook?: Hook<DatabaseSchema_>) => DatabaseWriterService<DatabaseSchema_>;
|
|
41
83
|
export declare const DatabaseWriter: <DatabaseSchema_ extends DatabaseSchema.AnyWithProps, Docs = {}>() => DatabaseWriterTag<DatabaseSchema_, Docs>;
|
|
42
84
|
export type DatabaseWriter<DatabaseSchema_ extends DatabaseSchema.AnyWithProps> = DatabaseWriterService<DatabaseSchema_>;
|
|
43
|
-
export declare const layer: <DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(databaseSchema: DatabaseSchema_, convexDatabaseWriter: GenericDatabaseWriter<DataModel.ToConvex<DataModel.FromSchema<DatabaseSchema_
|
|
85
|
+
export declare const layer: <DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(databaseSchema: DatabaseSchema_, convexDatabaseWriter: GenericDatabaseWriter<DataModel.ToConvex<DataModel.FromSchema<DatabaseSchema_>>>, hook?: Hook<DatabaseSchema_>) => Layer.Layer<DatabaseWriterService<DatabaseSchema_, {}>, never, never>;
|
|
44
86
|
//# sourceMappingURL=DatabaseWriter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatabaseWriter.d.ts","sourceRoot":"","sources":["../src/DatabaseWriter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAIV,qBAAqB,EAEtB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"DatabaseWriter.d.ts","sourceRoot":"","sources":["../src/DatabaseWriter.ts"],"names":[],"mappings":"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"}
|
package/dist/DatabaseWriter.js
CHANGED
|
@@ -1,46 +1,96 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { tables } from "./DatabaseSchema.js";
|
|
3
|
-
import { encode } from "./Document.js";
|
|
4
|
-
import { getById } from "./QueryInitializer.js";
|
|
3
|
+
import { DocumentEncodeError, decode, encode } from "./Document.js";
|
|
4
|
+
import { GetByIdFailure, getById } from "./QueryInitializer.js";
|
|
5
|
+
import { encoder } from "./internal/DocumentPatch.js";
|
|
5
6
|
import * as Context from "effect/Context";
|
|
6
|
-
import * as Layer from "effect/Layer";
|
|
7
7
|
import * as Effect from "effect/Effect";
|
|
8
|
-
import
|
|
8
|
+
import * as Layer from "effect/Layer";
|
|
9
|
+
import * as Predicate from "effect/Predicate";
|
|
9
10
|
import * as Record from "effect/Record";
|
|
11
|
+
import { pipe } from "effect/Function";
|
|
12
|
+
import * as Result from "effect/Result";
|
|
10
13
|
//#region src/DatabaseWriter.ts
|
|
11
14
|
var DatabaseWriter_exports = /* @__PURE__ */ __exportAll({
|
|
12
15
|
DatabaseWriter: () => DatabaseWriter,
|
|
13
16
|
layer: () => layer,
|
|
14
17
|
make: () => make
|
|
15
18
|
});
|
|
16
|
-
const make = (databaseSchema, convexDatabaseWriter) => {
|
|
19
|
+
const make = (databaseSchema, convexDatabaseWriter, hook) => {
|
|
17
20
|
const table = (tableName) => {
|
|
18
21
|
const tableDef = tables(databaseSchema)[tableName];
|
|
19
22
|
const insert = Effect.fn("DatabaseWriter.insert")(function* (document) {
|
|
20
23
|
const encodedDocument = yield* encode(document, tableDef);
|
|
21
24
|
return yield* Effect.promise(() => convexDatabaseWriter.insert(tableName, encodedDocument));
|
|
22
25
|
});
|
|
23
|
-
const
|
|
26
|
+
const replacePatched = (id, patchedValues) => Effect.gen(function* () {
|
|
24
27
|
const originalDecodedDoc = yield* getById(convexDatabaseWriter, tableDef)(id);
|
|
25
28
|
const updatedEncodedDoc = yield* pipe(patchedValues, Record.reduce(originalDecodedDoc, (acc, value, key) => value === void 0 ? Record.remove(acc, key) : Record.set(acc, key, value)), encode(tableDef));
|
|
26
29
|
yield* Effect.promise(() => convexDatabaseWriter.replace(id, updatedEncodedDoc));
|
|
27
30
|
});
|
|
31
|
+
const patch = Effect.fn("DatabaseWriter.patch")(function* (id, patchedValues) {
|
|
32
|
+
const encodePatch = encoder(tableDef);
|
|
33
|
+
if (encodePatch === void 0) return yield* replacePatched(id, patchedValues);
|
|
34
|
+
const storedDoc = yield* pipe(Effect.promise(() => convexDatabaseWriter.get(id)), Effect.andThen((value) => Effect.fromResult(Result.fromNullishOr(value, () => new GetByIdFailure({
|
|
35
|
+
tableName,
|
|
36
|
+
id
|
|
37
|
+
})))));
|
|
38
|
+
const encodedPatch = yield* pipe(encodePatch(patchedValues), Effect.mapError(({ message }) => message), Effect.tap((delta) => pipe({
|
|
39
|
+
...storedDoc,
|
|
40
|
+
...delta
|
|
41
|
+
}, Record.filter(Predicate.isNotUndefined), decode(tableDef), Effect.mapError(({ parseError }) => parseError))), Effect.catch((parseError) => pipe(decode(storedDoc, tableDef), Effect.andThen(Effect.fail(new DocumentEncodeError({
|
|
42
|
+
tableName,
|
|
43
|
+
id,
|
|
44
|
+
parseError
|
|
45
|
+
}))))));
|
|
46
|
+
yield* Effect.promise(() => convexDatabaseWriter.patch(id, encodedPatch));
|
|
47
|
+
});
|
|
28
48
|
const replace = Effect.fn("DatabaseWriter.replace")(function* (id, value) {
|
|
29
49
|
const updatedEncodedDoc = yield* encode(value, tableDef);
|
|
30
50
|
yield* Effect.promise(() => convexDatabaseWriter.replace(id, updatedEncodedDoc));
|
|
31
51
|
});
|
|
32
52
|
const delete_ = (id) => Effect.promise(() => convexDatabaseWriter.delete(id));
|
|
33
|
-
|
|
53
|
+
const accessor = {
|
|
34
54
|
insert,
|
|
35
55
|
patch,
|
|
36
56
|
replace,
|
|
37
57
|
delete: delete_
|
|
38
58
|
};
|
|
59
|
+
if (hook === void 0) return accessor;
|
|
60
|
+
const read = (id) => getById(convexDatabaseWriter, tableDef)(id);
|
|
61
|
+
const notify = (operation, oldDoc, newDoc) => hook({
|
|
62
|
+
tableName,
|
|
63
|
+
operation,
|
|
64
|
+
oldDoc,
|
|
65
|
+
newDoc
|
|
66
|
+
});
|
|
67
|
+
const update = (before, write) => (id, ...args) => Effect.gen(function* () {
|
|
68
|
+
const oldDoc = yield* before(id);
|
|
69
|
+
yield* write(id, ...args);
|
|
70
|
+
yield* notify("update", oldDoc, yield* read(id).pipe(Effect.orDie));
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
insert: (document) => Effect.gen(function* () {
|
|
74
|
+
const id = yield* insert(document);
|
|
75
|
+
yield* notify("insert", null, yield* read(id).pipe(Effect.orDie));
|
|
76
|
+
return id;
|
|
77
|
+
}),
|
|
78
|
+
patch: update(read, patch),
|
|
79
|
+
replace: update((id) => read(id).pipe(Effect.orDie), replace),
|
|
80
|
+
delete: (id) => Effect.gen(function* () {
|
|
81
|
+
const oldDoc = yield* read(id).pipe(Effect.orDie);
|
|
82
|
+
yield* delete_(id);
|
|
83
|
+
yield* notify("delete", oldDoc, null);
|
|
84
|
+
})
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
table,
|
|
89
|
+
vars: convexDatabaseWriter.vars
|
|
39
90
|
};
|
|
40
|
-
return { table };
|
|
41
91
|
};
|
|
42
92
|
const DatabaseWriter = () => Context.Service("@confect/server/DatabaseWriter");
|
|
43
|
-
const layer = (databaseSchema, convexDatabaseWriter) => Layer.succeed(DatabaseWriter(), make(databaseSchema, convexDatabaseWriter));
|
|
93
|
+
const layer = (databaseSchema, convexDatabaseWriter, hook) => Layer.succeed(DatabaseWriter(), make(databaseSchema, convexDatabaseWriter, hook));
|
|
44
94
|
//#endregion
|
|
45
95
|
export { DatabaseWriter, DatabaseWriter_exports, layer, make };
|
|
46
96
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatabaseWriter.js","names":["DatabaseSchema.tables","Document.encode","QueryInitializer.getById"],"sources":["../src/DatabaseWriter.ts"],"sourcesContent":["import type {\n BetterOmit,\n DocumentByName,\n Expand,\n GenericDatabaseWriter,\n WithoutSystemFields,\n} from \"convex/server\";\nimport type { GenericId } from \"convex/values\";\nimport { pipe } from \"effect/Function\";\nimport * as Context from \"effect/Context\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Record from \"effect/Record\";\nimport * as DatabaseSchema from \"./DatabaseSchema.js\";\nimport type * as DataModel from \"./DataModel.js\";\nimport type { DocumentByName as DocumentByName_ } from \"./DataModel.js\";\nimport * as Document from \"./Document.js\";\nimport * as QueryInitializer from \"./QueryInitializer.js\";\nimport type * as Table from \"./Table.js\";\n\n/**\n * The argument accepted by `patch`: like `Partial<Doc>` without system fields,\n * but the fields that are already optional also accept `undefined`, since\n * setting a field to `undefined` unsets it.\n */\nexport type PatchValue<Doc> = {\n [\n K in keyof Doc as K extends \"_id\" | \"_creationTime\" ? never : K\n ]?: undefined extends Doc[K] ? Doc[K] | undefined : Doc[K];\n};\n\nexport interface DatabaseWriterTableAccessor<\n DataModel_ extends DataModel.AnyWithProps,\n TableName extends DataModel.TableNames<DataModel_>,\n Doc = DocumentByName_<DataModel_, TableName>,\n> {\n readonly insert: (\n document: Document.WithoutSystemFields<Doc>,\n ) => Effect.Effect<\n DataModel.Id<DataModel_, TableName>,\n Document.DocumentEncodeError\n >;\n readonly patch: (\n id: DataModel.Id<DataModel_, TableName>,\n patchedValues: PatchValue<Doc>,\n ) => Effect.Effect<\n void,\n | QueryInitializer.GetByIdFailure\n | Document.DocumentDecodeError\n | Document.DocumentEncodeError\n >;\n readonly replace: (\n id: DataModel.Id<DataModel_, TableName>,\n value: Document.WithoutSystemFields<Doc>,\n ) => Effect.Effect<void, Document.DocumentEncodeError>;\n readonly delete: (\n id: DataModel.Id<DataModel_, TableName>,\n ) => Effect.Effect<void>;\n}\n\n/**\n * The service shape backing the `DatabaseWriter` tag. Named (rather than an\n * inferred anonymous object) so declaration emit prints\n * `DatabaseWriterService<…>` by reference instead of expanding the data model.\n * `Docs` is the optional named document registry (see\n * `DatabaseReaderService`).\n */\nexport interface DatabaseWriterService<\n DatabaseSchema_ extends DatabaseSchema.AnyWithProps,\n Docs = {},\n> {\n readonly table: <\n const TableName extends DataModel.TableNames<\n DataModel.FromSchema<DatabaseSchema_>\n >,\n >(\n tableName: TableName,\n ) => DatabaseWriterTableAccessor<\n DataModel.FromSchema<DatabaseSchema_>,\n TableName,\n TableName extends keyof Docs\n ? Docs[TableName]\n : DocumentByName_<DataModel.FromSchema<DatabaseSchema_>, TableName>\n >;\n}\n\n/**\n * The tag's _Identifier_ is `Docs`-independent (see `DatabaseReaderTag`); only\n * the _Service_ carries `Docs` so writer inputs print the named doc\n * interfaces.\n */\nexport type DatabaseWriterTag<\n DatabaseSchema_ extends DatabaseSchema.AnyWithProps,\n Docs = {},\n> = Context.Service<\n DatabaseWriterService<DatabaseSchema_>,\n DatabaseWriterService<DatabaseSchema_, Docs>\n>;\n\nexport const make = <DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(\n databaseSchema: DatabaseSchema_,\n convexDatabaseWriter: GenericDatabaseWriter<\n DataModel.ToConvex<DataModel.FromSchema<DatabaseSchema_>>\n >,\n): DatabaseWriterService<DatabaseSchema_> => {\n type DataModel_ = DataModel.FromSchema<DatabaseSchema_>;\n\n const table = <const TableName extends DataModel.TableNames<DataModel_>>(\n tableName: TableName,\n ) => {\n const tableDef = DatabaseSchema.tables(databaseSchema)[tableName];\n\n const insert = Effect.fn(\"DatabaseWriter.insert\")(function* (\n document: Document.WithoutSystemFields<\n DocumentByName_<DataModel_, TableName>\n >,\n ) {\n const encodedDocument = yield* Document.encode(document, tableDef);\n\n const id = yield* Effect.promise(() =>\n convexDatabaseWriter.insert(\n tableName,\n encodedDocument as WithoutSystemFields<\n DocumentByName<DataModel.ToConvex<DataModel_>, TableName>\n >,\n ),\n );\n\n // The database supplies the ID in this table's execution scope. Its\n // scope brand is erased at the Convex syscall boundary.\n return id as unknown as DataModel.Id<DataModel_, TableName>;\n });\n\n const patch = Effect.fn(\"DatabaseWriter.patch\")(function* (\n id: DataModel.Id<DataModel_, TableName>,\n patchedValues: PatchValue<\n Document.WithoutSystemFields<DocumentByName_<DataModel_, TableName>>\n >,\n ) {\n const originalDecodedDoc = yield* QueryInitializer.getById<\n Table.AnyWithProps,\n TableName\n >(\n convexDatabaseWriter as any,\n tableDef,\n )(id as unknown as GenericId<TableName>);\n\n const updatedEncodedDoc = yield* pipe(\n patchedValues,\n Record.reduce(originalDecodedDoc, (acc, value, key) =>\n value === undefined\n ? Record.remove(acc, key)\n : Record.set(acc, key, value),\n ),\n Document.encode(tableDef),\n );\n\n yield* Effect.promise(() =>\n convexDatabaseWriter.replace(\n id as unknown as GenericId<TableName>,\n updatedEncodedDoc as Expand<\n BetterOmit<\n DocumentByName<DataModel.ToConvex<DataModel_>, TableName>,\n \"_creationTime\" | \"_id\"\n >\n >,\n ),\n );\n });\n\n const replace = Effect.fn(\"DatabaseWriter.replace\")(function* (\n id: DataModel.Id<DataModel_, TableName>,\n value: Document.WithoutSystemFields<\n DocumentByName_<DataModel_, TableName>\n >,\n ) {\n const updatedEncodedDoc = yield* Document.encode(value, tableDef);\n\n yield* Effect.promise(() =>\n convexDatabaseWriter.replace(\n id as unknown as GenericId<TableName>,\n updatedEncodedDoc as Expand<\n BetterOmit<\n DocumentByName<DataModel.ToConvex<DataModel_>, TableName>,\n \"_creationTime\" | \"_id\"\n >\n >,\n ),\n );\n });\n\n const delete_ = (id: DataModel.Id<DataModel_, TableName>) =>\n Effect.promise(() =>\n convexDatabaseWriter.delete(id as unknown as GenericId<TableName>),\n );\n\n return {\n insert,\n patch,\n replace,\n delete: delete_,\n };\n };\n\n return {\n table,\n } as DatabaseWriterService<DatabaseSchema_>;\n};\n\nexport const DatabaseWriter = <\n DatabaseSchema_ extends DatabaseSchema.AnyWithProps,\n Docs = {},\n>(): DatabaseWriterTag<DatabaseSchema_, Docs> =>\n Context.Service<\n DatabaseWriterService<DatabaseSchema_>,\n DatabaseWriterService<DatabaseSchema_, Docs>\n >(\"@confect/server/DatabaseWriter\");\n\nexport type DatabaseWriter<\n DatabaseSchema_ extends DatabaseSchema.AnyWithProps,\n> = DatabaseWriterService<DatabaseSchema_>;\n\nexport const layer = <DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(\n databaseSchema: DatabaseSchema_,\n convexDatabaseWriter: GenericDatabaseWriter<\n DataModel.ToConvex<DataModel.FromSchema<DatabaseSchema_>>\n >,\n) =>\n Layer.succeed(\n DatabaseWriter<DatabaseSchema_>(),\n make(databaseSchema, convexDatabaseWriter),\n );\n"],"mappings":";;;;;;;;;;;;;;;AAmGA,MAAa,QACX,gBACA,yBAG2C;CAG3C,MAAM,SACJ,cACG;EACH,MAAM,WAAWA,OAAsB,cAAc,CAAC,CAAC;EAEvD,MAAM,SAAS,OAAO,GAAG,uBAAuB,CAAC,CAAC,WAChD,UAGA;GACA,MAAM,kBAAkB,OAAOC,OAAgB,UAAU,QAAQ;GAajE,OAAO,OAXW,OAAO,cACvB,qBAAqB,OACnB,WACA,eAGF,CACF;EAKF,CAAC;EAED,MAAM,QAAQ,OAAO,GAAG,sBAAsB,CAAC,CAAC,WAC9C,IACA,eAGA;GACA,MAAM,qBAAqB,OAAOC,QAIhC,sBACA,QACF,CAAC,CAAC,EAAqC;GAEvC,MAAM,oBAAoB,OAAO,KAC/B,eACA,OAAO,OAAO,qBAAqB,KAAK,OAAO,QAC7C,UAAU,KAAA,IACN,OAAO,OAAO,KAAK,GAAG,IACtB,OAAO,IAAI,KAAK,KAAK,KAAK,CAChC,GACAD,OAAgB,QAAQ,CAC1B;GAEA,OAAO,OAAO,cACZ,qBAAqB,QACnB,IACA,iBAMF,CACF;EACF,CAAC;EAED,MAAM,UAAU,OAAO,GAAG,wBAAwB,CAAC,CAAC,WAClD,IACA,OAGA;GACA,MAAM,oBAAoB,OAAOA,OAAgB,OAAO,QAAQ;GAEhE,OAAO,OAAO,cACZ,qBAAqB,QACnB,IACA,iBAMF,CACF;EACF,CAAC;EAED,MAAM,WAAW,OACf,OAAO,cACL,qBAAqB,OAAO,EAAqC,CACnE;EAEF,OAAO;GACL;GACA;GACA;GACA,QAAQ;EACV;CACF;CAEA,OAAO,EACL,MACF;AACF;AAEA,MAAa,uBAIX,QAAQ,QAGN,gCAAgC;AAMpC,MAAa,SACX,gBACA,yBAIA,MAAM,QACJ,eAAgC,GAChC,KAAK,gBAAgB,oBAAoB,CAC3C"}
|
|
1
|
+
{"version":3,"file":"DatabaseWriter.js","names":["DatabaseSchema.tables","Document.encode","QueryInitializer.getById","DocumentPatch.encoder","QueryInitializer.GetByIdFailure","Document.decode","Document.DocumentEncodeError"],"sources":["../src/DatabaseWriter.ts"],"sourcesContent":["import type {\n BetterOmit,\n DocumentByName,\n Expand,\n GenericDatabaseWriter,\n WithoutSystemFields,\n} from \"convex/server\";\nimport type { CommitTsPlaceholder, GenericId } from \"convex/values\";\nimport { pipe } from \"effect/Function\";\nimport * as Context from \"effect/Context\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Predicate from \"effect/Predicate\";\nimport * as Record from \"effect/Record\";\nimport * as Result from \"effect/Result\";\nimport * as DatabaseSchema from \"./DatabaseSchema.js\";\nimport type * as DataModel from \"./DataModel.js\";\nimport type { DocumentByName as DocumentByName_ } from \"./DataModel.js\";\nimport * as Document from \"./Document.js\";\nimport * as DocumentPatch from \"./internal/DocumentPatch.js\";\nimport * as QueryInitializer from \"./QueryInitializer.js\";\nimport type * as Table from \"./Table.js\";\n\n/**\n * The argument accepted by `patch`: like `Partial<Doc>` without system fields,\n * but the fields that are already optional also accept `undefined`, since\n * setting a field to `undefined` unsets it.\n */\nexport type PatchValue<Doc> = {\n [\n K in keyof Doc as K extends \"_id\" | \"_creationTime\" ? never : K\n ]?: undefined extends Doc[K] ? Doc[K] | undefined : Doc[K];\n};\n\nexport interface DatabaseWriterTableAccessor<\n DataModel_ extends DataModel.AnyWithProps,\n TableName extends DataModel.TableNames<DataModel_>,\n Doc = DocumentByName_<DataModel_, TableName>,\n> {\n readonly insert: (\n document: Document.WithoutSystemFields<Doc>,\n ) => Effect.Effect<\n DataModel.Id<DataModel_, TableName>,\n Document.DocumentEncodeError\n >;\n readonly patch: (\n id: DataModel.Id<DataModel_, TableName>,\n patchedValues: PatchValue<Doc>,\n ) => Effect.Effect<\n void,\n | QueryInitializer.GetByIdFailure\n | Document.DocumentDecodeError\n | Document.DocumentEncodeError\n >;\n readonly replace: (\n id: DataModel.Id<DataModel_, TableName>,\n value: Document.WithoutSystemFields<Doc>,\n ) => Effect.Effect<void, Document.DocumentEncodeError>;\n readonly delete: (\n id: DataModel.Id<DataModel_, TableName>,\n ) => Effect.Effect<void>;\n}\n\n/**\n * The service shape backing the `DatabaseWriter` tag. Named (rather than an\n * inferred anonymous object) so declaration emit prints\n * `DatabaseWriterService<…>` by reference instead of expanding the data model.\n * `Docs` is the optional named document registry (see\n * `DatabaseReaderService`).\n */\nexport interface DatabaseWriterService<\n DatabaseSchema_ extends DatabaseSchema.AnyWithProps,\n Docs = {},\n> {\n readonly table: <\n const TableName extends DataModel.TableNames<\n DataModel.FromSchema<DatabaseSchema_>\n >,\n >(\n tableName: TableName,\n ) => DatabaseWriterTableAccessor<\n DataModel.FromSchema<DatabaseSchema_>,\n TableName,\n TableName extends keyof Docs\n ? Docs[TableName]\n : DocumentByName_<DataModel.FromSchema<DatabaseSchema_>, TableName>\n >;\n /**\n * Values not known until the mutation commits. Write `vars.commitTs` into a\n * `CommitTs` field to store the transaction's commit timestamp.\n */\n readonly vars: { readonly commitTs: CommitTsPlaceholder };\n}\n\n/**\n * The tag's _Identifier_ is `Docs`-independent (see `DatabaseReaderTag`); only\n * the _Service_ carries `Docs` so writer inputs print the named doc\n * interfaces.\n */\nexport type DatabaseWriterTag<\n DatabaseSchema_ extends DatabaseSchema.AnyWithProps,\n Docs = {},\n> = Context.Service<\n DatabaseWriterService<DatabaseSchema_>,\n DatabaseWriterService<DatabaseSchema_, Docs>\n>;\n\n/**\n * Decoded documents surrounding one successful write.\n */\nexport type Change<S extends DatabaseSchema.AnyWithProps> = {\n [Name in DataModel.TableNames<DataModel.FromSchema<S>>]: {\n readonly tableName: Name;\n } & (\n | {\n readonly operation: \"insert\";\n readonly oldDoc: null;\n readonly newDoc: DocumentByName_<DataModel.FromSchema<S>, Name>;\n }\n | {\n readonly operation: \"update\";\n readonly oldDoc: DocumentByName_<DataModel.FromSchema<S>, Name>;\n readonly newDoc: DocumentByName_<DataModel.FromSchema<S>, Name>;\n }\n | {\n readonly operation: \"delete\";\n readonly oldDoc: DocumentByName_<DataModel.FromSchema<S>, Name>;\n readonly newDoc: null;\n }\n );\n}[DataModel.TableNames<DataModel.FromSchema<S>>];\n\n/**\n * Runs after the write, in its transaction. A defect aborts the mutation.\n *\n * Only writes through this writer are observed. Raw `ctx.db`, `MutationCtx`\n * writes and a second `DatabaseWriter.make` bypass the hook, so a host that\n * relies on it keeps raw writers out of its functions. Component writers and\n * nested `runMutation` calls each need their own hook installation.\n *\n * Concurrent writes to one document (for example under `Effect.all`) can\n * interleave the read-write-read steps. Await them sequentially when the hook\n * needs exact per-write snapshots. The writer takes no lock, because a hook\n * that writes through the same writer would deadlock under one.\n */\nexport type Hook<S extends DatabaseSchema.AnyWithProps> = (\n change: Change<S>,\n) => Effect.Effect<void>;\n\nexport const make = <DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(\n databaseSchema: DatabaseSchema_,\n convexDatabaseWriter: GenericDatabaseWriter<\n DataModel.ToConvex<DataModel.FromSchema<DatabaseSchema_>>\n >,\n hook?: Hook<DatabaseSchema_>,\n): DatabaseWriterService<DatabaseSchema_> => {\n type DataModel_ = DataModel.FromSchema<DatabaseSchema_>;\n\n const table = <const TableName extends DataModel.TableNames<DataModel_>>(\n tableName: TableName,\n ) => {\n const tableDef = DatabaseSchema.tables(databaseSchema)[tableName];\n\n const insert = Effect.fn(\"DatabaseWriter.insert\")(function* (\n document: Document.WithoutSystemFields<\n DocumentByName_<DataModel_, TableName>\n >,\n ) {\n const encodedDocument = yield* Document.encode(document, tableDef);\n\n const id = yield* Effect.promise(() =>\n convexDatabaseWriter.insert(\n tableName,\n encodedDocument as WithoutSystemFields<\n DocumentByName<DataModel.ToConvex<DataModel_>, TableName>\n >,\n ),\n );\n\n // The database supplies the ID in this table's execution scope. Its\n // scope brand is erased at the Convex syscall boundary.\n return id as unknown as DataModel.Id<DataModel_, TableName>;\n });\n\n // A codec whose encoding spans fields cannot encode a patch on its own, so\n // the patch is merged into the decoded document and the result replaces it.\n const replacePatched = (\n id: DataModel.Id<DataModel_, TableName>,\n patchedValues: PatchValue<\n Document.WithoutSystemFields<DocumentByName_<DataModel_, TableName>>\n >,\n ) =>\n Effect.gen(function* () {\n const originalDecodedDoc = yield* QueryInitializer.getById<\n Table.AnyWithProps,\n TableName\n >(\n convexDatabaseWriter as any,\n tableDef,\n )(id as unknown as GenericId<TableName>);\n\n const updatedEncodedDoc = yield* pipe(\n patchedValues,\n Record.reduce(originalDecodedDoc, (acc, value, key) =>\n value === undefined\n ? Record.remove(acc, key)\n : Record.set(acc, key, value),\n ),\n Document.encode(tableDef),\n );\n\n yield* Effect.promise(() =>\n convexDatabaseWriter.replace(\n id as unknown as GenericId<TableName>,\n updatedEncodedDoc as Expand<\n BetterOmit<\n DocumentByName<DataModel.ToConvex<DataModel_>, TableName>,\n \"_creationTime\" | \"_id\"\n >\n >,\n ),\n );\n });\n\n const patch = Effect.fn(\"DatabaseWriter.patch\")(function* (\n id: DataModel.Id<DataModel_, TableName>,\n patchedValues: PatchValue<\n Document.WithoutSystemFields<DocumentByName_<DataModel_, TableName>>\n >,\n ) {\n const encodePatch = DocumentPatch.encoder(tableDef);\n if (encodePatch === undefined) {\n return yield* replacePatched(id, patchedValues);\n }\n\n const storedDoc = yield* pipe(\n Effect.promise(() =>\n convexDatabaseWriter.get(id as unknown as GenericId<TableName>),\n ),\n Effect.andThen((value) =>\n Effect.fromResult(\n Result.fromNullishOr(\n value,\n () =>\n new QueryInitializer.GetByIdFailure({\n tableName,\n id,\n }),\n ),\n ),\n ),\n );\n // The patch must encode and the patched document must decode. When\n // either fails, the stored document decides whose fault that is.\n const encodedPatch = yield* pipe(\n encodePatch(patchedValues),\n Effect.mapError(({ message }) => message),\n Effect.tap((delta) =>\n pipe(\n { ...storedDoc, ...delta },\n Record.filter(Predicate.isNotUndefined),\n Document.decode(tableDef),\n Effect.mapError(({ parseError }) => parseError),\n ),\n ),\n Effect.catch((parseError) =>\n pipe(\n Document.decode(storedDoc, tableDef),\n Effect.andThen(\n Effect.fail(\n new Document.DocumentEncodeError({\n tableName,\n id,\n parseError,\n }),\n ),\n ),\n ),\n ),\n );\n\n yield* Effect.promise(() =>\n convexDatabaseWriter.patch(\n id as unknown as GenericId<TableName>,\n encodedPatch as Partial<\n DocumentByName<DataModel.ToConvex<DataModel_>, TableName>\n >,\n ),\n );\n });\n\n const replace = Effect.fn(\"DatabaseWriter.replace\")(function* (\n id: DataModel.Id<DataModel_, TableName>,\n value: Document.WithoutSystemFields<\n DocumentByName_<DataModel_, TableName>\n >,\n ) {\n const updatedEncodedDoc = yield* Document.encode(value, tableDef);\n\n yield* Effect.promise(() =>\n convexDatabaseWriter.replace(\n id as unknown as GenericId<TableName>,\n updatedEncodedDoc as Expand<\n BetterOmit<\n DocumentByName<DataModel.ToConvex<DataModel_>, TableName>,\n \"_creationTime\" | \"_id\"\n >\n >,\n ),\n );\n });\n\n const delete_ = (id: DataModel.Id<DataModel_, TableName>) =>\n Effect.promise(() =>\n convexDatabaseWriter.delete(id as unknown as GenericId<TableName>),\n );\n\n const accessor = { insert, patch, replace, delete: delete_ };\n if (hook === undefined) return accessor;\n\n const read = (id: DataModel.Id<DataModel_, TableName>) =>\n QueryInitializer.getById<Table.AnyWithProps, TableName>(\n convexDatabaseWriter as any,\n tableDef,\n )(id as unknown as GenericId<TableName>);\n const notify = (\n operation: \"insert\" | \"update\" | \"delete\",\n oldDoc: unknown,\n newDoc: unknown,\n ) =>\n hook({ tableName, operation, oldDoc, newDoc } as Change<DatabaseSchema_>);\n const update =\n <A extends ReadonlyArray<unknown>, E, BeforeError>(\n before: (\n id: DataModel.Id<DataModel_, TableName>,\n ) => Effect.Effect<unknown, BeforeError>,\n write: (\n id: DataModel.Id<DataModel_, TableName>,\n ...args: A\n ) => Effect.Effect<void, E>,\n ) =>\n (id: DataModel.Id<DataModel_, TableName>, ...args: A) =>\n Effect.gen(function* () {\n const oldDoc = yield* before(id);\n yield* write(id, ...args);\n yield* notify(\"update\", oldDoc, yield* read(id).pipe(Effect.orDie));\n });\n\n return {\n insert: (document: Parameters<typeof insert>[0]) =>\n Effect.gen(function* () {\n const id = yield* insert(document);\n yield* notify(\"insert\", null, yield* read(id).pipe(Effect.orDie));\n return id;\n }),\n patch: update(read, patch),\n replace: update((id) => read(id).pipe(Effect.orDie), replace),\n delete: (id: DataModel.Id<DataModel_, TableName>) =>\n Effect.gen(function* () {\n const oldDoc = yield* read(id).pipe(Effect.orDie);\n yield* delete_(id);\n yield* notify(\"delete\", oldDoc, null);\n }),\n };\n };\n\n return {\n table,\n vars: convexDatabaseWriter.vars,\n } as DatabaseWriterService<DatabaseSchema_>;\n};\n\nexport const DatabaseWriter = <\n DatabaseSchema_ extends DatabaseSchema.AnyWithProps,\n Docs = {},\n>(): DatabaseWriterTag<DatabaseSchema_, Docs> =>\n Context.Service<\n DatabaseWriterService<DatabaseSchema_>,\n DatabaseWriterService<DatabaseSchema_, Docs>\n >(\"@confect/server/DatabaseWriter\");\n\nexport type DatabaseWriter<\n DatabaseSchema_ extends DatabaseSchema.AnyWithProps,\n> = DatabaseWriterService<DatabaseSchema_>;\n\nexport const layer = <DatabaseSchema_ extends DatabaseSchema.AnyWithProps>(\n databaseSchema: DatabaseSchema_,\n convexDatabaseWriter: GenericDatabaseWriter<\n DataModel.ToConvex<DataModel.FromSchema<DatabaseSchema_>>\n >,\n hook?: Hook<DatabaseSchema_>,\n) =>\n Layer.succeed(\n DatabaseWriter<DatabaseSchema_>(),\n make(databaseSchema, convexDatabaseWriter, hook),\n );\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
2
|
import * as Context from "effect/Context";
|
|
3
|
-
import * as Layer from "effect/Layer";
|
|
4
3
|
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Layer from "effect/Layer";
|
|
5
5
|
//#region src/ExecutionMetadata.ts
|
|
6
6
|
var ExecutionMetadata_exports = /* @__PURE__ */ __exportAll({
|
|
7
7
|
ExecutionMetadata: () => ExecutionMetadata,
|
package/dist/FunctionImpl.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { Registry } from "./Registry.js";
|
|
3
|
-
import { make as make$1 } from "./FunctionRegistryItem.js";
|
|
4
3
|
import { setNestedProperty } from "./internal/utils.js";
|
|
4
|
+
import { make as make$1 } from "./FunctionRegistryItem.js";
|
|
5
5
|
import * as Context from "effect/Context";
|
|
6
|
-
import * as Layer from "effect/Layer";
|
|
7
6
|
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as Layer from "effect/Layer";
|
|
8
8
|
import * as Ref from "effect/Ref";
|
|
9
9
|
//#region src/FunctionImpl.ts
|
|
10
10
|
var FunctionImpl_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -15,6 +15,7 @@ export interface ConfectFunctionRegistryItem {
|
|
|
15
15
|
readonly [TypeId]: TypeId;
|
|
16
16
|
readonly _tag: "Confect";
|
|
17
17
|
readonly name: string;
|
|
18
|
+
readonly reservedArgument?: string;
|
|
18
19
|
readonly functionVisibility: FunctionVisibility;
|
|
19
20
|
readonly functionType: FunctionType;
|
|
20
21
|
readonly args: Schema.Codec<any, any>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FunctionRegistryItem.d.ts","sourceRoot":"","sources":["../src/FunctionRegistryItem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,oBAAoB,MAAM,oCAAoC,CAAC;AAChF,OAAO,KAAK,KAAK,YAAY,MAAM,4BAA4B,CAAC;AAEhE,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGtE,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,KAAK,OAAO,MAAM,cAAc,CAAC;AAE7C,eAAO,MAAM,MAAM,0CAA0C,CAAC;AAC9D,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC;AAEnC,eAAO,MAAM,sBAAsB,UAAW,OAAO,KAAG,KAAK,IAAI,YAC3B,CAAC;AAMvC;;;GAGG;AACH,MAAM,MAAM,YAAY,GACpB,2BAA2B,GAC3B,0BAA0B,CAAC;AAE/B,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;IAChD,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACxC,QAAQ,CAAC,qBAAqB,EAAE,aAAa,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,CAAC;IACzF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,oBAAoB,CAAC;CAChD;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,mBAAmB,CAAC;CAC/C;AAED,eAAO,MAAM,IAAI,2DAId;IACD,YAAY,EAAE,YAAY,CAAC,YAAY,CAAC;IACxC,0BAA0B,EAAE,aAAa,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,CAAC;IACrF,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC;CACtB,KAAG,
|
|
1
|
+
{"version":3,"file":"FunctionRegistryItem.d.ts","sourceRoot":"","sources":["../src/FunctionRegistryItem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,oBAAoB,MAAM,oCAAoC,CAAC;AAChF,OAAO,KAAK,KAAK,YAAY,MAAM,4BAA4B,CAAC;AAEhE,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGtE,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,KAAK,OAAO,MAAM,cAAc,CAAC;AAE7C,eAAO,MAAM,MAAM,0CAA0C,CAAC;AAC9D,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC;AAEnC,eAAO,MAAM,sBAAsB,UAAW,OAAO,KAAG,KAAK,IAAI,YAC3B,CAAC;AAMvC;;;GAGG;AACH,MAAM,MAAM,YAAY,GACpB,2BAA2B,GAC3B,0BAA0B,CAAC;AAE/B,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAC;IAChD,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACxC,QAAQ,CAAC,qBAAqB,EAAE,aAAa,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,CAAC;IACzF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,oBAAoB,CAAC;CAChD;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,mBAAmB,CAAC;CAC/C;AAED,eAAO,MAAM,IAAI,2DAId;IACD,YAAY,EAAE,YAAY,CAAC,YAAY,CAAC;IACxC,0BAA0B,EAAE,aAAa,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,CAAC;IACrF,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC;CACtB,KAAG,YAiCD,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
|
-
import * as Match from "effect/Match";
|
|
3
2
|
import * as Predicate from "effect/Predicate";
|
|
3
|
+
import * as Match from "effect/Match";
|
|
4
4
|
import * as Lazy from "@confect/core/Lazy";
|
|
5
5
|
//#region src/FunctionRegistryItem.ts
|
|
6
6
|
var FunctionRegistryItem_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -18,6 +18,7 @@ const make = ({ functionSpec, groupMiddlewareAttachments, handler }) => Match.va
|
|
|
18
18
|
const item = Object.assign(Object.create(FunctionRegistryItemProto), {
|
|
19
19
|
_tag: "Confect",
|
|
20
20
|
name: functionSpec.name,
|
|
21
|
+
...functionSpec.reservedArgument === void 0 ? {} : { reservedArgument: functionSpec.reservedArgument },
|
|
21
22
|
functionVisibility: functionSpec.functionVisibility,
|
|
22
23
|
functionType: functionSpec.runtimeAndFunctionType.functionType,
|
|
23
24
|
middlewareAttachments: [...groupMiddlewareAttachments, ...functionSpec.middlewareAttachments],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FunctionRegistryItem.js","names":[],"sources":["../src/FunctionRegistryItem.ts"],"sourcesContent":["import type * as MiddlewareAttachment from \"@confect/core/MiddlewareAttachment\";\nimport type * as FunctionSpec from \"@confect/core/FunctionSpec\";\nimport * as Lazy from \"@confect/core/Lazy\";\nimport type { FunctionType, FunctionVisibility } from \"convex/server\";\nimport * as Match from \"effect/Match\";\nimport * as Predicate from \"effect/Predicate\";\nimport type * as Schema from \"effect/Schema\";\nimport type * as Handler from \"./Handler.js\";\n\nexport const TypeId = \"~@confect/server/FunctionRegistryItem\";\nexport type TypeId = typeof TypeId;\n\nexport const isFunctionRegistryItem = (value: unknown): value is AnyWithProps =>\n Predicate.hasProperty(value, TypeId);\n\nconst FunctionRegistryItemProto = {\n [TypeId]: TypeId,\n};\n\n/**\n * A function registered by `FunctionImpl.make`, one of two shapes keyed by the\n * spec's provenance.\n */\nexport type AnyWithProps =\n | ConfectFunctionRegistryItem\n | ConvexFunctionRegistryItem;\n\nexport interface ConfectFunctionRegistryItem {\n readonly [TypeId]: TypeId;\n readonly _tag: \"Confect\";\n readonly name: string;\n readonly functionVisibility: FunctionVisibility;\n readonly functionType: FunctionType;\n readonly args: Schema.Codec<any, any>;\n readonly returns: Schema.Codec<any, any>;\n readonly error?: Schema.Codec<any, any>;\n readonly middlewareAttachments: ReadonlyArray<MiddlewareAttachment.MiddlewareAttachment>;\n readonly handler: Handler.AnyConfectProvenance;\n}\n\nexport interface ConvexFunctionRegistryItem {\n readonly [TypeId]: TypeId;\n readonly _tag: \"Convex\";\n readonly handler: Handler.AnyConvexProvenance;\n}\n\nexport const make = ({\n functionSpec,\n groupMiddlewareAttachments,\n handler,\n}: {\n functionSpec: FunctionSpec.AnyWithProps;\n groupMiddlewareAttachments: ReadonlyArray<MiddlewareAttachment.MiddlewareAttachment>;\n handler: Handler.Any;\n}): AnyWithProps =>\n Match.value(functionSpec.functionProvenance).pipe(\n Match.tag(\"Convex\", (): AnyWithProps =>\n Object.assign(Object.create(FunctionRegistryItemProto), {\n _tag: \"Convex\" as const,\n handler: handler as Handler.AnyConvexProvenance,\n }),\n ),\n Match.tag(\"Confect\", (provenance): AnyWithProps => {\n const item = Object.assign(Object.create(FunctionRegistryItemProto), {\n _tag: \"Confect\" as const,\n name: functionSpec.name,\n functionVisibility: functionSpec.functionVisibility,\n functionType: functionSpec.runtimeAndFunctionType.functionType,\n middlewareAttachments: [\n ...groupMiddlewareAttachments,\n ...functionSpec.middlewareAttachments,\n ],\n handler: handler as Handler.AnyConfectProvenance,\n });\n\n Lazy.defineProperty(item, \"args\", () => provenance.args);\n Lazy.defineProperty(item, \"returns\", () => provenance.returns);\n if (\"error\" in provenance) {\n Lazy.defineProperty(item, \"error\", () => provenance.error);\n }\n\n return item as AnyWithProps;\n }),\n Match.exhaustive,\n );\n"],"mappings":";;;;;;;;;;AASA,MAAa,SAAS;AAGtB,MAAa,0BAA0B,UACrC,UAAU,YAAY,OAAO,MAAM;AAErC,MAAM,4BAA4B,GAC/B,SAAS,OACZ;
|
|
1
|
+
{"version":3,"file":"FunctionRegistryItem.js","names":[],"sources":["../src/FunctionRegistryItem.ts"],"sourcesContent":["import type * as MiddlewareAttachment from \"@confect/core/MiddlewareAttachment\";\nimport type * as FunctionSpec from \"@confect/core/FunctionSpec\";\nimport * as Lazy from \"@confect/core/Lazy\";\nimport type { FunctionType, FunctionVisibility } from \"convex/server\";\nimport * as Match from \"effect/Match\";\nimport * as Predicate from \"effect/Predicate\";\nimport type * as Schema from \"effect/Schema\";\nimport type * as Handler from \"./Handler.js\";\n\nexport const TypeId = \"~@confect/server/FunctionRegistryItem\";\nexport type TypeId = typeof TypeId;\n\nexport const isFunctionRegistryItem = (value: unknown): value is AnyWithProps =>\n Predicate.hasProperty(value, TypeId);\n\nconst FunctionRegistryItemProto = {\n [TypeId]: TypeId,\n};\n\n/**\n * A function registered by `FunctionImpl.make`, one of two shapes keyed by the\n * spec's provenance.\n */\nexport type AnyWithProps =\n | ConfectFunctionRegistryItem\n | ConvexFunctionRegistryItem;\n\nexport interface ConfectFunctionRegistryItem {\n readonly [TypeId]: TypeId;\n readonly _tag: \"Confect\";\n readonly name: string;\n readonly reservedArgument?: string;\n readonly functionVisibility: FunctionVisibility;\n readonly functionType: FunctionType;\n readonly args: Schema.Codec<any, any>;\n readonly returns: Schema.Codec<any, any>;\n readonly error?: Schema.Codec<any, any>;\n readonly middlewareAttachments: ReadonlyArray<MiddlewareAttachment.MiddlewareAttachment>;\n readonly handler: Handler.AnyConfectProvenance;\n}\n\nexport interface ConvexFunctionRegistryItem {\n readonly [TypeId]: TypeId;\n readonly _tag: \"Convex\";\n readonly handler: Handler.AnyConvexProvenance;\n}\n\nexport const make = ({\n functionSpec,\n groupMiddlewareAttachments,\n handler,\n}: {\n functionSpec: FunctionSpec.AnyWithProps;\n groupMiddlewareAttachments: ReadonlyArray<MiddlewareAttachment.MiddlewareAttachment>;\n handler: Handler.Any;\n}): AnyWithProps =>\n Match.value(functionSpec.functionProvenance).pipe(\n Match.tag(\"Convex\", (): AnyWithProps =>\n Object.assign(Object.create(FunctionRegistryItemProto), {\n _tag: \"Convex\" as const,\n handler: handler as Handler.AnyConvexProvenance,\n }),\n ),\n Match.tag(\"Confect\", (provenance): AnyWithProps => {\n const item = Object.assign(Object.create(FunctionRegistryItemProto), {\n _tag: \"Confect\" as const,\n name: functionSpec.name,\n ...(functionSpec.reservedArgument === undefined\n ? {}\n : { reservedArgument: functionSpec.reservedArgument }),\n functionVisibility: functionSpec.functionVisibility,\n functionType: functionSpec.runtimeAndFunctionType.functionType,\n middlewareAttachments: [\n ...groupMiddlewareAttachments,\n ...functionSpec.middlewareAttachments,\n ],\n handler: handler as Handler.AnyConfectProvenance,\n });\n\n Lazy.defineProperty(item, \"args\", () => provenance.args);\n Lazy.defineProperty(item, \"returns\", () => provenance.returns);\n if (\"error\" in provenance) {\n Lazy.defineProperty(item, \"error\", () => provenance.error);\n }\n\n return item as AnyWithProps;\n }),\n Match.exhaustive,\n );\n"],"mappings":";;;;;;;;;;AASA,MAAa,SAAS;AAGtB,MAAa,0BAA0B,UACrC,UAAU,YAAY,OAAO,MAAM;AAErC,MAAM,4BAA4B,GAC/B,SAAS,OACZ;AA8BA,MAAa,QAAQ,EACnB,cACA,4BACA,cAMA,MAAM,MAAM,aAAa,kBAAkB,CAAC,CAAC,KAC3C,MAAM,IAAI,gBACR,OAAO,OAAO,OAAO,OAAO,yBAAyB,GAAG;CACtD,MAAM;CACG;AACX,CAAC,CACH,GACA,MAAM,IAAI,YAAY,eAA6B;CACjD,MAAM,OAAO,OAAO,OAAO,OAAO,OAAO,yBAAyB,GAAG;EACnE,MAAM;EACN,MAAM,aAAa;EACnB,GAAI,aAAa,qBAAqB,KAAA,IAClC,CAAC,IACD,EAAE,kBAAkB,aAAa,iBAAiB;EACtD,oBAAoB,aAAa;EACjC,cAAc,aAAa,uBAAuB;EAClD,uBAAuB,CACrB,GAAG,4BACH,GAAG,aAAa,qBAClB;EACS;CACX,CAAC;CAED,KAAK,eAAe,MAAM,cAAc,WAAW,IAAI;CACvD,KAAK,eAAe,MAAM,iBAAiB,WAAW,OAAO;CAC7D,IAAI,WAAW,YACb,KAAK,eAAe,MAAM,eAAe,WAAW,KAAK;CAG3D,OAAO;AACT,CAAC,GACD,MAAM,UACR"}
|
package/dist/GroupImpl.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type * as GroupSpec from "@confect/core/GroupSpec";
|
|
2
2
|
import type * as MiddlewareSpec from "@confect/core/MiddlewareSpec";
|
|
3
|
+
import * as RegistryItems from "./RegistryItems.js";
|
|
3
4
|
import * as Context from "effect/Context";
|
|
4
5
|
import * as Layer from "effect/Layer";
|
|
5
6
|
import type * as DatabaseSchema from "./DatabaseSchema.js";
|
|
@@ -59,6 +60,15 @@ export declare const GroupImpl: <FinalizationStatus_ extends FinalizationStatus>
|
|
|
59
60
|
* runtime.
|
|
60
61
|
*/
|
|
61
62
|
export declare const make: <DatabaseSchema_ extends DatabaseSchema.AnyWithProps, Group extends GroupSpec.AnyWithProps>(_databaseSchema: DatabaseSchema_, _group: Group & MiddlewareSpec.ValidateImplRequires<GroupSpec.Functions<Group>, GroupSpec.MiddlewareSpecs<Group>>) => Layer.Layer<GroupImpl<"Unfinalized">, never, FunctionImpl.FromGroupSpec<Group> | MiddlewareImpl.FromGroupSpec<Group>>;
|
|
63
|
+
declare const MissingRequiredMiddlewareError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
64
|
+
readonly _tag: "MissingRequiredMiddlewareError";
|
|
65
|
+
} & Readonly<A>;
|
|
66
|
+
export declare class MissingRequiredMiddlewareError extends MissingRequiredMiddlewareError_base<{
|
|
67
|
+
readonly missing: ReadonlyArray<RegistryItems.MissingMiddleware>;
|
|
68
|
+
}> {
|
|
69
|
+
get message(): string;
|
|
70
|
+
}
|
|
71
|
+
type Finalizable = Layer.Layer<AnyUnfinalized> | Layer.Layer<AnyFinalized>;
|
|
62
72
|
/**
|
|
63
73
|
* Mark a `GroupImpl` layer as fully implemented. The parameter type defaults
|
|
64
74
|
* `RIn = never`, so passing a layer that still requires any `FunctionImpl`
|
|
@@ -70,8 +80,17 @@ export declare const make: <DatabaseSchema_ extends DatabaseSchema.AnyWithProps,
|
|
|
70
80
|
* registered into this group's scope are snapshotted onto the produced service
|
|
71
81
|
* value's `registeredFunctionNames` field, so consumers can verify impl
|
|
72
82
|
* completeness against a `GroupSpec`'s expected functions without having to
|
|
73
|
-
* inspect the `Registry` themselves.
|
|
83
|
+
* inspect the `Registry` themselves. Pass `{ required }` to check every
|
|
84
|
+
* registered function's middleware at layer build, including internal
|
|
85
|
+
* functions. This form also accepts a finalized layer so generated registration
|
|
86
|
+
* can enforce the backend declaration without changing authored impls. Pass
|
|
87
|
+
* `groupPath` to qualify uncovered function names in the diagnostic.
|
|
74
88
|
*/
|
|
75
|
-
export declare
|
|
89
|
+
export declare function finalize(options: {
|
|
90
|
+
readonly groupPath?: string;
|
|
91
|
+
readonly required: ReadonlyArray<Pick<MiddlewareSpec.AnyMiddlewareSpec, "key">>;
|
|
92
|
+
}): (group: Finalizable) => Layer.Layer<GroupImpl<"Finalized">>;
|
|
93
|
+
export declare function finalize(group: Layer.Layer<GroupImpl<"Unfinalized">>): Layer.Layer<GroupImpl<"Finalized">>;
|
|
76
94
|
export type FromGroupSpec<Group extends GroupSpec.AnyWithProps> = FunctionImpl.FromGroupSpec<Group> | MiddlewareImpl.FromGroupSpec<Group>;
|
|
95
|
+
export {};
|
|
77
96
|
//# sourceMappingURL=GroupImpl.d.ts.map
|
package/dist/GroupImpl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GroupImpl.d.ts","sourceRoot":"","sources":["../src/GroupImpl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,SAAS,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,KAAK,cAAc,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"GroupImpl.d.ts","sourceRoot":"","sources":["../src/GroupImpl.ts"],"names":[],"mappings":"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"}
|
package/dist/GroupImpl.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { Registry } from "./Registry.js";
|
|
3
|
-
import { functionNames, middlewareKeys } from "./RegistryItems.js";
|
|
3
|
+
import { functionNames, middlewareKeys, missingRequired } from "./RegistryItems.js";
|
|
4
4
|
import * as Context from "effect/Context";
|
|
5
|
-
import * as Layer from "effect/Layer";
|
|
6
5
|
import * as Effect from "effect/Effect";
|
|
7
|
-
import * as
|
|
8
|
-
import * as
|
|
9
|
-
import * as Predicate from "effect/Predicate";
|
|
6
|
+
import * as Data from "effect/Data";
|
|
7
|
+
import * as Layer from "effect/Layer";
|
|
10
8
|
import * as Ref from "effect/Ref";
|
|
9
|
+
import * as Predicate from "effect/Predicate";
|
|
10
|
+
import * as Array from "effect/Array";
|
|
11
|
+
import * as Option from "effect/Option";
|
|
11
12
|
//#region src/GroupImpl.ts
|
|
12
13
|
var GroupImpl_exports = /* @__PURE__ */ __exportAll({
|
|
13
14
|
GroupImpl: () => GroupImpl,
|
|
15
|
+
MissingRequiredMiddlewareError: () => MissingRequiredMiddlewareError,
|
|
14
16
|
TypeId: () => TypeId,
|
|
15
17
|
finalize: () => finalize,
|
|
16
18
|
isFinalizedGroupImpl: () => isFinalizedGroupImpl,
|
|
@@ -48,25 +50,22 @@ const make = (_databaseSchema, _group) => Layer.succeed(GroupImpl({ finalization
|
|
|
48
50
|
registeredFunctionNames: [],
|
|
49
51
|
registeredMiddlewareKeys: []
|
|
50
52
|
});
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
* completeness against a `GroupSpec`'s expected functions without having to
|
|
63
|
-
* inspect the `Registry` themselves.
|
|
64
|
-
*/
|
|
65
|
-
const finalize = (group) => Layer.flatMap(group, (context) => findUnfinalizedGroupImpl(context).pipe(Option.match({
|
|
66
|
-
onNone: () => Layer.effect(GroupImpl({ finalizationStatus: "Finalized" }), Effect.die(/* @__PURE__ */ new Error("GroupImpl.finalize: no Unfinalized GroupImpl service was found in the layer's context."))),
|
|
53
|
+
const findGroupImpl = (context) => Array.findFirst(context.mapUnsafe.values(), isGroupImpl);
|
|
54
|
+
var MissingRequiredMiddlewareError = class extends Data.TaggedError("MissingRequiredMiddlewareError") {
|
|
55
|
+
get message() {
|
|
56
|
+
return `GroupImpl.finalize: ${this.missing.map(({ functionName, middlewareKey }) => `${functionName} requires middleware "${middlewareKey}"`).join("\n")}`;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
function finalize(input) {
|
|
60
|
+
return "required" in input ? (group) => finalizeWith(group, input.required, input.groupPath) : finalizeWith(input, []);
|
|
61
|
+
}
|
|
62
|
+
const finalizeWith = (group, required, groupPath = "") => Layer.flatMap(group, (context) => findGroupImpl(context).pipe(Option.match({
|
|
63
|
+
onNone: () => Layer.effect(GroupImpl({ finalizationStatus: "Finalized" }), Effect.die(/* @__PURE__ */ new Error("GroupImpl.finalize: no GroupImpl service was found in the layer's context."))),
|
|
67
64
|
onSome: () => Layer.effect(GroupImpl({ finalizationStatus: "Finalized" }), Effect.gen(function* () {
|
|
68
65
|
const registry = yield* Registry;
|
|
69
66
|
const items = yield* Ref.get(registry);
|
|
67
|
+
const missing = missingRequired(items, required, groupPath);
|
|
68
|
+
if (missing.length > 0) return yield* Effect.die(new MissingRequiredMiddlewareError({ missing }));
|
|
70
69
|
return {
|
|
71
70
|
[TypeId]: TypeId,
|
|
72
71
|
finalizationStatus: "Finalized",
|
|
@@ -76,6 +75,6 @@ const finalize = (group) => Layer.flatMap(group, (context) => findUnfinalizedGro
|
|
|
76
75
|
}))
|
|
77
76
|
})));
|
|
78
77
|
//#endregion
|
|
79
|
-
export { GroupImpl, GroupImpl_exports, TypeId, finalize, isFinalizedGroupImpl, isGroupImpl, isUnfinalizedGroupImpl, make };
|
|
78
|
+
export { GroupImpl, GroupImpl_exports, MissingRequiredMiddlewareError, TypeId, finalize, isFinalizedGroupImpl, isGroupImpl, isUnfinalizedGroupImpl, make };
|
|
80
79
|
|
|
81
80
|
//# sourceMappingURL=GroupImpl.js.map
|
package/dist/GroupImpl.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GroupImpl.js","names":["Registry.Registry","RegistryItems.functionNames","RegistryItems.middlewareKeys"],"sources":["../src/GroupImpl.ts"],"sourcesContent":["import type * as GroupSpec from \"@confect/core/GroupSpec\";\nimport type * as MiddlewareSpec from \"@confect/core/MiddlewareSpec\";\nimport * as Registry from \"./Registry.js\";\nimport * as RegistryItems from \"./RegistryItems.js\";\nimport * as Array from \"effect/Array\";\nimport * as Context from \"effect/Context\";\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Option from \"effect/Option\";\nimport * as Predicate from \"effect/Predicate\";\nimport * as Ref from \"effect/Ref\";\nimport type * as DatabaseSchema from \"./DatabaseSchema.js\";\nimport type * as FunctionImpl from \"./FunctionImpl.js\";\nimport type * as MiddlewareImpl from \"./MiddlewareImpl.js\";\n\nexport const TypeId = \"~@confect/server/GroupImpl\";\nexport type TypeId = typeof TypeId;\n\nexport type FinalizationStatus = \"Unfinalized\" | \"Finalized\";\n\nexport interface GroupImpl<\n FinalizationStatus_ extends FinalizationStatus = \"Unfinalized\",\n> {\n readonly [TypeId]: TypeId;\n readonly finalizationStatus: FinalizationStatus_;\n /**\n * Names of every function registered into this group's layer scope by\n * `FunctionImpl.make`. Authoritative only when `finalizationStatus` is\n * `\"Finalized\"`; the `\"Unfinalized\"` value is set to `[]` at `make`-time\n * since the list is only known once `finalize` snapshots the registry.\n */\n readonly registeredFunctionNames: ReadonlyArray<string>;\n /**\n * Keys of every middleware whose implementation registered into this group's\n * layer scope via `MiddlewareImpl.make` (and friends). Same authoritativeness\n * caveat as `registeredFunctionNames`. Lets consumers (the CLI's\n * `validateImpl`) verify middleware-impl completeness against a `GroupSpec`'s\n * attached middleware without inspecting the `Registry`.\n */\n readonly registeredMiddlewareKeys: ReadonlyArray<string>;\n}\n\nexport interface Any extends GroupImpl<FinalizationStatus> {}\n\nexport const isGroupImpl = (u: unknown): u is Any =>\n Predicate.hasProperty(u, TypeId);\n\nexport interface AnyFinalized extends GroupImpl<\"Finalized\"> {}\nexport interface AnyUnfinalized extends GroupImpl<\"Unfinalized\"> {}\n\nexport const isFinalizedGroupImpl = (u: unknown): u is AnyFinalized =>\n isGroupImpl(u) && u.finalizationStatus === \"Finalized\";\n\nexport const isUnfinalizedGroupImpl = (u: unknown): u is AnyUnfinalized =>\n isGroupImpl(u) && u.finalizationStatus === \"Unfinalized\";\n\n/**\n * Build the runtime tag for a `GroupImpl` service. The finalization status is\n * embedded in the tag string so that `Unfinalized` and `Finalized` are distinct\n * services at runtime; consumers of a finalized layer (the server's\n * `RegisteredFunctions.buildForGroup` and the CLI's `validateImpl`) retrieve\n * the typed `Finalized` service directly rather than scanning the context.\n *\n * The tag is keyed only by finalization status—no group path—because each\n * group's impl layer is built in its own isolated scope\n * (`buildForGroup`/`validateImpl` each provide a fresh `Registry`), so at most\n * one `GroupImpl` service of each status exists per build.\n */\nexport const GroupImpl = <FinalizationStatus_ extends FinalizationStatus>({\n finalizationStatus,\n}: {\n finalizationStatus: FinalizationStatus_;\n}) =>\n Context.Service<GroupImpl<FinalizationStatus_>>(\n `@confect/server/GroupImpl/${finalizationStatus}`,\n );\n\n/**\n * Begin a group's impl layer. `databaseSchema` and `group` are retained only as\n * type-level carriers (`group` drives the required `FunctionImpl` services via\n * `FromGroupSpec<Group>`; `databaseSchema` keeps the impl's dependency on\n * `_generated/schema` symmetric with `FunctionImpl.make`). Neither is read at\n * runtime.\n */\nexport const make = <\n DatabaseSchema_ extends DatabaseSchema.AnyWithProps,\n Group extends GroupSpec.AnyWithProps,\n>(\n _databaseSchema: DatabaseSchema_,\n _group: Group &\n MiddlewareSpec.ValidateImplRequires<\n GroupSpec.Functions<Group>,\n GroupSpec.MiddlewareSpecs<Group>\n >,\n): Layer.Layer<\n GroupImpl<\"Unfinalized\">,\n never,\n FunctionImpl.FromGroupSpec<Group> | MiddlewareImpl.FromGroupSpec<Group>\n> =>\n Layer.succeed(\n GroupImpl<\"Unfinalized\">({ finalizationStatus: \"Unfinalized\" }),\n {\n [TypeId]: TypeId,\n finalizationStatus: \"Unfinalized\" as const,\n registeredFunctionNames: [],\n registeredMiddlewareKeys: [],\n },\n ) as Layer.Layer<\n GroupImpl<\"Unfinalized\">,\n never,\n FunctionImpl.FromGroupSpec<Group> | MiddlewareImpl.FromGroupSpec<Group>\n >;\n\nconst findUnfinalizedGroupImpl = <S>(\n context: Context.Context<S>,\n): Option.Option<AnyUnfinalized> =>\n Array.findFirst(context.mapUnsafe.values(), isUnfinalizedGroupImpl);\n\n/**\n * Mark a `GroupImpl` layer as fully implemented. The parameter type defaults\n * `RIn = never`, so passing a layer that still requires any `FunctionImpl`\n * service produces a type error at the impl author's site. The codegen boundary\n * requires the resulting `\"Finalized\"` brand, so omitting this call is also\n * rejected downstream.\n *\n * As a side effect of finalization, the names of every `FunctionImpl` that\n * registered into this group's scope are snapshotted onto the produced service\n * value's `registeredFunctionNames` field, so consumers can verify impl\n * completeness against a `GroupSpec`'s expected functions without having to\n * inspect the `Registry` themselves.\n */\nexport const finalize = (\n group: Layer.Layer<GroupImpl<\"Unfinalized\">>,\n): Layer.Layer<GroupImpl<\"Finalized\">> =>\n Layer.flatMap(group, (context): Layer.Layer<GroupImpl<\"Finalized\">> =>\n findUnfinalizedGroupImpl(context).pipe(\n Option.match({\n onNone: () =>\n Layer.effect(\n GroupImpl<\"Finalized\">({ finalizationStatus: \"Finalized\" }),\n Effect.die(\n new Error(\n \"GroupImpl.finalize: no Unfinalized GroupImpl service was found in the layer's context.\",\n ),\n ),\n ),\n onSome: () =>\n Layer.effect(\n GroupImpl<\"Finalized\">({ finalizationStatus: \"Finalized\" }),\n Effect.gen(function* () {\n const registry = yield* Registry.Registry;\n const items = yield* Ref.get(registry);\n return {\n [TypeId]: TypeId,\n finalizationStatus: \"Finalized\" as const,\n registeredFunctionNames: RegistryItems.functionNames(items),\n registeredMiddlewareKeys: RegistryItems.middlewareKeys(items),\n };\n }),\n ),\n }),\n ),\n );\n\nexport type FromGroupSpec<Group extends GroupSpec.AnyWithProps> =\n | FunctionImpl.FromGroupSpec<Group>\n | MiddlewareImpl.FromGroupSpec<Group>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAeA,MAAa,SAAS;AA6BtB,MAAa,eAAe,MAC1B,UAAU,YAAY,GAAG,MAAM;AAKjC,MAAa,wBAAwB,MACnC,YAAY,CAAC,KAAK,EAAE,uBAAuB;AAE7C,MAAa,0BAA0B,MACrC,YAAY,CAAC,KAAK,EAAE,uBAAuB;;;;;;;;;;;;;AAc7C,MAAa,aAA6D,EACxE,yBAIA,QAAQ,QACN,6BAA6B,oBAC/B;;;;;;;;AASF,MAAa,QAIX,iBACA,WAUA,MAAM,QACJ,UAAyB,EAAE,oBAAoB,cAAc,CAAC,GAC9D;EACG,SAAS;CACV,oBAAoB;CACpB,yBAAyB,CAAC;CAC1B,0BAA0B,CAAC;AAC7B,CACF;AAMF,MAAM,4BACJ,YAEA,MAAM,UAAU,QAAQ,UAAU,OAAO,GAAG,sBAAsB;;;;;;;;;;;;;;AAepE,MAAa,YACX,UAEA,MAAM,QAAQ,QAAQ,YACpB,yBAAyB,OAAO,CAAC,CAAC,KAChC,OAAO,MAAM;CACX,cACE,MAAM,OACJ,UAAuB,EAAE,oBAAoB,YAAY,CAAC,GAC1D,OAAO,oBACL,IAAI,MACF,wFACF,CACF,CACF;CACF,cACE,MAAM,OACJ,UAAuB,EAAE,oBAAoB,YAAY,CAAC,GAC1D,OAAO,IAAI,aAAa;EACtB,MAAM,WAAW,OAAOA;EACxB,MAAM,QAAQ,OAAO,IAAI,IAAI,QAAQ;EACrC,OAAO;IACJ,SAAS;GACV,oBAAoB;GACpB,yBAAyBC,cAA4B,KAAK;GAC1D,0BAA0BC,eAA6B,KAAK;EAC9D;CACF,CAAC,CACH;AACJ,CAAC,CACH,CACF"}
|
|
1
|
+
{"version":3,"file":"GroupImpl.js","names":["Registry.Registry","RegistryItems.missingRequired","RegistryItems.functionNames","RegistryItems.middlewareKeys"],"sources":["../src/GroupImpl.ts"],"sourcesContent":["import type * as GroupSpec from \"@confect/core/GroupSpec\";\nimport type * as MiddlewareSpec from \"@confect/core/MiddlewareSpec\";\nimport * as Registry from \"./Registry.js\";\nimport * as RegistryItems from \"./RegistryItems.js\";\nimport * as Array from \"effect/Array\";\nimport * as Context from \"effect/Context\";\nimport * as Effect from \"effect/Effect\";\nimport * as Data from \"effect/Data\";\nimport * as Layer from \"effect/Layer\";\nimport * as Option from \"effect/Option\";\nimport * as Predicate from \"effect/Predicate\";\nimport * as Ref from \"effect/Ref\";\nimport type * as DatabaseSchema from \"./DatabaseSchema.js\";\nimport type * as FunctionImpl from \"./FunctionImpl.js\";\nimport type * as MiddlewareImpl from \"./MiddlewareImpl.js\";\n\nexport const TypeId = \"~@confect/server/GroupImpl\";\nexport type TypeId = typeof TypeId;\n\nexport type FinalizationStatus = \"Unfinalized\" | \"Finalized\";\n\nexport interface GroupImpl<\n FinalizationStatus_ extends FinalizationStatus = \"Unfinalized\",\n> {\n readonly [TypeId]: TypeId;\n readonly finalizationStatus: FinalizationStatus_;\n /**\n * Names of every function registered into this group's layer scope by\n * `FunctionImpl.make`. Authoritative only when `finalizationStatus` is\n * `\"Finalized\"`; the `\"Unfinalized\"` value is set to `[]` at `make`-time\n * since the list is only known once `finalize` snapshots the registry.\n */\n readonly registeredFunctionNames: ReadonlyArray<string>;\n /**\n * Keys of every middleware whose implementation registered into this group's\n * layer scope via `MiddlewareImpl.make` (and friends). Same authoritativeness\n * caveat as `registeredFunctionNames`. Lets consumers (the CLI's\n * `validateImpl`) verify middleware-impl completeness against a `GroupSpec`'s\n * attached middleware without inspecting the `Registry`.\n */\n readonly registeredMiddlewareKeys: ReadonlyArray<string>;\n}\n\nexport interface Any extends GroupImpl<FinalizationStatus> {}\n\nexport const isGroupImpl = (u: unknown): u is Any =>\n Predicate.hasProperty(u, TypeId);\n\nexport interface AnyFinalized extends GroupImpl<\"Finalized\"> {}\nexport interface AnyUnfinalized extends GroupImpl<\"Unfinalized\"> {}\n\nexport const isFinalizedGroupImpl = (u: unknown): u is AnyFinalized =>\n isGroupImpl(u) && u.finalizationStatus === \"Finalized\";\n\nexport const isUnfinalizedGroupImpl = (u: unknown): u is AnyUnfinalized =>\n isGroupImpl(u) && u.finalizationStatus === \"Unfinalized\";\n\n/**\n * Build the runtime tag for a `GroupImpl` service. The finalization status is\n * embedded in the tag string so that `Unfinalized` and `Finalized` are distinct\n * services at runtime; consumers of a finalized layer (the server's\n * `RegisteredFunctions.buildForGroup` and the CLI's `validateImpl`) retrieve\n * the typed `Finalized` service directly rather than scanning the context.\n *\n * The tag is keyed only by finalization status—no group path—because each\n * group's impl layer is built in its own isolated scope\n * (`buildForGroup`/`validateImpl` each provide a fresh `Registry`), so at most\n * one `GroupImpl` service of each status exists per build.\n */\nexport const GroupImpl = <FinalizationStatus_ extends FinalizationStatus>({\n finalizationStatus,\n}: {\n finalizationStatus: FinalizationStatus_;\n}) =>\n Context.Service<GroupImpl<FinalizationStatus_>>(\n `@confect/server/GroupImpl/${finalizationStatus}`,\n );\n\n/**\n * Begin a group's impl layer. `databaseSchema` and `group` are retained only as\n * type-level carriers (`group` drives the required `FunctionImpl` services via\n * `FromGroupSpec<Group>`; `databaseSchema` keeps the impl's dependency on\n * `_generated/schema` symmetric with `FunctionImpl.make`). Neither is read at\n * runtime.\n */\nexport const make = <\n DatabaseSchema_ extends DatabaseSchema.AnyWithProps,\n Group extends GroupSpec.AnyWithProps,\n>(\n _databaseSchema: DatabaseSchema_,\n _group: Group &\n MiddlewareSpec.ValidateImplRequires<\n GroupSpec.Functions<Group>,\n GroupSpec.MiddlewareSpecs<Group>\n >,\n): Layer.Layer<\n GroupImpl<\"Unfinalized\">,\n never,\n FunctionImpl.FromGroupSpec<Group> | MiddlewareImpl.FromGroupSpec<Group>\n> =>\n Layer.succeed(\n GroupImpl<\"Unfinalized\">({ finalizationStatus: \"Unfinalized\" }),\n {\n [TypeId]: TypeId,\n finalizationStatus: \"Unfinalized\" as const,\n registeredFunctionNames: [],\n registeredMiddlewareKeys: [],\n },\n ) as Layer.Layer<\n GroupImpl<\"Unfinalized\">,\n never,\n FunctionImpl.FromGroupSpec<Group> | MiddlewareImpl.FromGroupSpec<Group>\n >;\n\nconst findGroupImpl = <S>(context: Context.Context<S>): Option.Option<Any> =>\n Array.findFirst(context.mapUnsafe.values(), isGroupImpl);\n\nexport class MissingRequiredMiddlewareError extends Data.TaggedError(\n \"MissingRequiredMiddlewareError\",\n)<{\n readonly missing: ReadonlyArray<RegistryItems.MissingMiddleware>;\n}> {\n override get message(): string {\n return `GroupImpl.finalize: ${this.missing.map(({ functionName, middlewareKey }) => `${functionName} requires middleware \"${middlewareKey}\"`).join(\"\\n\")}`;\n }\n}\n\ntype Finalizable = Layer.Layer<AnyUnfinalized> | Layer.Layer<AnyFinalized>;\n\n/**\n * Mark a `GroupImpl` layer as fully implemented. The parameter type defaults\n * `RIn = never`, so passing a layer that still requires any `FunctionImpl`\n * service produces a type error at the impl author's site. The codegen boundary\n * requires the resulting `\"Finalized\"` brand, so omitting this call is also\n * rejected downstream.\n *\n * As a side effect of finalization, the names of every `FunctionImpl` that\n * registered into this group's scope are snapshotted onto the produced service\n * value's `registeredFunctionNames` field, so consumers can verify impl\n * completeness against a `GroupSpec`'s expected functions without having to\n * inspect the `Registry` themselves. Pass `{ required }` to check every\n * registered function's middleware at layer build, including internal\n * functions. This form also accepts a finalized layer so generated registration\n * can enforce the backend declaration without changing authored impls. Pass\n * `groupPath` to qualify uncovered function names in the diagnostic.\n */\nexport function finalize(options: {\n readonly groupPath?: string;\n readonly required: ReadonlyArray<\n Pick<MiddlewareSpec.AnyMiddlewareSpec, \"key\">\n >;\n}): (group: Finalizable) => Layer.Layer<GroupImpl<\"Finalized\">>;\nexport function finalize(\n group: Layer.Layer<GroupImpl<\"Unfinalized\">>,\n): Layer.Layer<GroupImpl<\"Finalized\">>;\nexport function finalize(\n input:\n | Finalizable\n | {\n readonly groupPath?: string;\n readonly required: ReadonlyArray<\n Pick<MiddlewareSpec.AnyMiddlewareSpec, \"key\">\n >;\n },\n):\n | Layer.Layer<GroupImpl<\"Finalized\">>\n | ((group: Finalizable) => Layer.Layer<GroupImpl<\"Finalized\">>) {\n return \"required\" in input\n ? (group) => finalizeWith(group, input.required, input.groupPath)\n : finalizeWith(input, []);\n}\n\nconst finalizeWith = (\n group: Layer.Layer<never>,\n required: ReadonlyArray<Pick<MiddlewareSpec.AnyMiddlewareSpec, \"key\">>,\n groupPath = \"\",\n): Layer.Layer<GroupImpl<\"Finalized\">> =>\n Layer.flatMap(group, (context): Layer.Layer<GroupImpl<\"Finalized\">> =>\n findGroupImpl(context).pipe(\n Option.match({\n onNone: () =>\n Layer.effect(\n GroupImpl<\"Finalized\">({ finalizationStatus: \"Finalized\" }),\n Effect.die(\n new Error(\n \"GroupImpl.finalize: no GroupImpl service was found in the layer's context.\",\n ),\n ),\n ),\n onSome: () =>\n Layer.effect(\n GroupImpl<\"Finalized\">({ finalizationStatus: \"Finalized\" }),\n Effect.gen(function* () {\n const registry = yield* Registry.Registry;\n const items = yield* Ref.get(registry);\n const missing = RegistryItems.missingRequired(\n items,\n required,\n groupPath,\n );\n if (missing.length > 0) {\n return yield* Effect.die(\n new MissingRequiredMiddlewareError({ missing }),\n );\n }\n return {\n [TypeId]: TypeId,\n finalizationStatus: \"Finalized\" as const,\n registeredFunctionNames: RegistryItems.functionNames(items),\n registeredMiddlewareKeys: RegistryItems.middlewareKeys(items),\n };\n }),\n ),\n }),\n ),\n );\n\nexport type FromGroupSpec<Group extends GroupSpec.AnyWithProps> =\n | FunctionImpl.FromGroupSpec<Group>\n | MiddlewareImpl.FromGroupSpec<Group>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAgBA,MAAa,SAAS;AA6BtB,MAAa,eAAe,MAC1B,UAAU,YAAY,GAAG,MAAM;AAKjC,MAAa,wBAAwB,MACnC,YAAY,CAAC,KAAK,EAAE,uBAAuB;AAE7C,MAAa,0BAA0B,MACrC,YAAY,CAAC,KAAK,EAAE,uBAAuB;;;;;;;;;;;;;AAc7C,MAAa,aAA6D,EACxE,yBAIA,QAAQ,QACN,6BAA6B,oBAC/B;;;;;;;;AASF,MAAa,QAIX,iBACA,WAUA,MAAM,QACJ,UAAyB,EAAE,oBAAoB,cAAc,CAAC,GAC9D;EACG,SAAS;CACV,oBAAoB;CACpB,yBAAyB,CAAC;CAC1B,0BAA0B,CAAC;AAC7B,CACF;AAMF,MAAM,iBAAoB,YACxB,MAAM,UAAU,QAAQ,UAAU,OAAO,GAAG,WAAW;AAEzD,IAAa,iCAAb,cAAoD,KAAK,YACvD,gCACF,CAAC,CAEE;CACD,IAAa,UAAkB;EAC7B,OAAO,uBAAuB,KAAK,QAAQ,KAAK,EAAE,cAAc,oBAAoB,GAAG,aAAa,wBAAwB,cAAc,EAAE,CAAC,CAAC,KAAK,IAAI;CACzJ;AACF;AA8BA,SAAgB,SACd,OAUgE;CAChE,OAAO,cAAc,SAChB,UAAU,aAAa,OAAO,MAAM,UAAU,MAAM,SAAS,IAC9D,aAAa,OAAO,CAAC,CAAC;AAC5B;AAEA,MAAM,gBACJ,OACA,UACA,YAAY,OAEZ,MAAM,QAAQ,QAAQ,YACpB,cAAc,OAAO,CAAC,CAAC,KACrB,OAAO,MAAM;CACX,cACE,MAAM,OACJ,UAAuB,EAAE,oBAAoB,YAAY,CAAC,GAC1D,OAAO,oBACL,IAAI,MACF,4EACF,CACF,CACF;CACF,cACE,MAAM,OACJ,UAAuB,EAAE,oBAAoB,YAAY,CAAC,GAC1D,OAAO,IAAI,aAAa;EACtB,MAAM,WAAW,OAAOA;EACxB,MAAM,QAAQ,OAAO,IAAI,IAAI,QAAQ;EACrC,MAAM,UAAUC,gBACd,OACA,UACA,SACF;EACA,IAAI,QAAQ,SAAS,GACnB,OAAO,OAAO,OAAO,IACnB,IAAI,+BAA+B,EAAE,QAAQ,CAAC,CAChD;EAEF,OAAO;IACJ,SAAS;GACV,oBAAoB;GACpB,yBAAyBC,cAA4B,KAAK;GAC1D,0BAA0BC,eAA6B,KAAK;EAC9D;CACF,CAAC,CACH;AACJ,CAAC,CACH,CACF"}
|
package/dist/GroupRegistry.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type * as Layer from "effect/Layer";
|
|
|
2
2
|
import type * as GroupImpl from "./GroupImpl.js";
|
|
3
3
|
import * as MiddlewareRegistryItem from "./MiddlewareRegistryItem.js";
|
|
4
4
|
export declare const make: (groupLayer: Layer.Layer<GroupImpl.GroupImpl<"Finalized">>) => {
|
|
5
|
+
observability: Layer.Layer<never, never, never> | undefined;
|
|
5
6
|
functionRegistryItems: Record<string, unknown>;
|
|
6
7
|
middlewareRegistryItems: Map<string, MiddlewareRegistryItem.MiddlewareRegistryItem>;
|
|
7
8
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GroupRegistry.d.ts","sourceRoot":"","sources":["../src/GroupRegistry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GroupRegistry.d.ts","sourceRoot":"","sources":["../src/GroupRegistry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC;AAI3C,OAAO,KAAK,KAAK,SAAS,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,sBAAsB,MAAM,6BAA6B,CAAC;AAEtE,eAAO,MAAM,IAAI,eACH,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;;;;CAkB1D,CAAC"}
|
package/dist/GroupRegistry.js
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import { Registry } from "./Registry.js";
|
|
2
2
|
import { isMiddlewareRegistryItem } from "./MiddlewareRegistryItem.js";
|
|
3
|
+
import { Observability } from "./RegisteredFunction.js";
|
|
3
4
|
import * as Effect from "effect/Effect";
|
|
4
5
|
import * as Ref from "effect/Ref";
|
|
5
6
|
//#region src/GroupRegistry.ts
|
|
6
7
|
const make = (groupLayer) => {
|
|
7
|
-
const registryItems = Effect.gen(function* () {
|
|
8
|
+
const { registryItems, observability } = Effect.gen(function* () {
|
|
8
9
|
const registry = yield* Registry;
|
|
9
|
-
return
|
|
10
|
+
return {
|
|
11
|
+
registryItems: yield* Ref.get(registry),
|
|
12
|
+
observability: yield* Observability
|
|
13
|
+
};
|
|
10
14
|
}).pipe(Effect.provide(groupLayer), Effect.provideService(Registry, Ref.makeUnsafe({})), Effect.runSync);
|
|
11
|
-
return
|
|
15
|
+
return {
|
|
16
|
+
...partitionRegistryItems(registryItems),
|
|
17
|
+
observability
|
|
18
|
+
};
|
|
12
19
|
};
|
|
13
20
|
const partitionRegistryItems = (registryItems) => {
|
|
14
21
|
const middlewareRegistryItems = /* @__PURE__ */ new Map();
|