equipped 5.2.9 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +95 -0
- package/README.md +362 -34
- package/dist/cjs/cache/adapters/in-memory/index.cjs +824 -0
- package/dist/cjs/cache/adapters/in-memory/index.cjs.map +1 -0
- package/dist/cjs/cache/adapters/in-memory/index.min.cjs +4 -0
- package/dist/cjs/cache/adapters/in-memory/index.min.cjs.map +1 -0
- package/dist/cjs/cache/adapters/redis/index.cjs +844 -0
- package/dist/cjs/cache/adapters/redis/index.cjs.map +1 -0
- package/dist/cjs/cache/adapters/redis/index.min.cjs +4 -0
- package/dist/cjs/cache/adapters/redis/index.min.cjs.map +1 -0
- package/dist/cjs/cache/index.cjs +602 -4
- package/dist/cjs/cache/index.cjs.map +1 -1
- package/dist/cjs/cache/index.min.cjs +3 -1
- package/dist/cjs/cache/index.min.cjs.map +1 -1
- package/dist/cjs/dbs/adapters/mongodb/index.cjs +1314 -0
- package/dist/cjs/dbs/adapters/mongodb/index.cjs.map +1 -0
- package/dist/cjs/dbs/adapters/mongodb/index.min.cjs +4 -0
- package/dist/cjs/dbs/adapters/mongodb/index.min.cjs.map +1 -0
- package/dist/cjs/dbs/index.cjs +965 -6
- package/dist/cjs/dbs/index.cjs.map +1 -1
- package/dist/cjs/dbs/index.min.cjs +3 -1
- package/dist/cjs/dbs/index.min.cjs.map +1 -1
- package/dist/cjs/errors/index.cjs +127 -8
- package/dist/cjs/errors/index.cjs.map +1 -1
- package/dist/cjs/errors/index.min.cjs +1 -1
- package/dist/cjs/errors/index.min.cjs.map +1 -1
- package/dist/cjs/events/adapters/kafka/index.cjs +845 -0
- package/dist/cjs/events/adapters/kafka/index.cjs.map +1 -0
- package/dist/cjs/events/adapters/kafka/index.min.cjs +4 -0
- package/dist/cjs/events/adapters/kafka/index.min.cjs.map +1 -0
- package/dist/cjs/events/adapters/rabbitmq/index.cjs +836 -0
- package/dist/cjs/events/adapters/rabbitmq/index.cjs.map +1 -0
- package/dist/cjs/events/adapters/rabbitmq/index.min.cjs +4 -0
- package/dist/cjs/events/adapters/rabbitmq/index.min.cjs.map +1 -0
- package/dist/cjs/events/index.cjs +33 -4
- package/dist/cjs/events/index.cjs.map +1 -1
- package/dist/cjs/events/index.min.cjs +1 -1
- package/dist/cjs/events/index.min.cjs.map +1 -1
- package/dist/cjs/index.cjs +588 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.min.cjs +3 -1
- package/dist/cjs/index.min.cjs.map +1 -1
- package/dist/cjs/instance/index.cjs +514 -64
- package/dist/cjs/instance/index.cjs.map +1 -1
- package/dist/cjs/instance/index.min.cjs +3 -3
- package/dist/cjs/instance/index.min.cjs.map +1 -1
- package/dist/cjs/jobs/adapters/redis/index.cjs +979 -0
- package/dist/cjs/jobs/adapters/redis/index.cjs.map +1 -0
- package/dist/cjs/jobs/adapters/redis/index.min.cjs +4 -0
- package/dist/cjs/jobs/adapters/redis/index.min.cjs.map +1 -0
- package/dist/cjs/jobs/index.cjs +55 -2
- package/dist/cjs/jobs/index.cjs.map +1 -1
- package/dist/cjs/jobs/index.min.cjs +1 -1
- package/dist/cjs/jobs/index.min.cjs.map +1 -1
- package/dist/cjs/orm/adapters/in-memory/index.cjs +2551 -0
- package/dist/cjs/orm/adapters/in-memory/index.cjs.map +1 -0
- package/dist/cjs/orm/adapters/in-memory/index.min.cjs +4 -0
- package/dist/cjs/orm/adapters/in-memory/index.min.cjs.map +1 -0
- package/dist/cjs/orm/adapters/json/index.cjs +3518 -0
- package/dist/cjs/orm/adapters/json/index.cjs.map +1 -0
- package/dist/cjs/orm/adapters/json/index.min.cjs +4 -0
- package/dist/cjs/orm/adapters/json/index.min.cjs.map +1 -0
- package/dist/cjs/orm/adapters/mongodb/index.cjs +3299 -0
- package/dist/cjs/orm/adapters/mongodb/index.cjs.map +1 -0
- package/dist/cjs/orm/adapters/mongodb/index.min.cjs +4 -0
- package/dist/cjs/orm/adapters/mongodb/index.min.cjs.map +1 -0
- package/dist/cjs/orm/adapters/postgresql/index.cjs +4114 -0
- package/dist/cjs/orm/adapters/postgresql/index.cjs.map +1 -0
- package/dist/cjs/orm/adapters/postgresql/index.min.cjs +49 -0
- package/dist/cjs/orm/adapters/postgresql/index.min.cjs.map +1 -0
- package/dist/cjs/orm/index.cjs +9216 -0
- package/dist/cjs/orm/index.cjs.map +1 -0
- package/dist/cjs/orm/index.min.cjs +4 -0
- package/dist/cjs/orm/index.min.cjs.map +1 -0
- package/dist/cjs/server/adapters/express/index.cjs +1967 -0
- package/dist/cjs/server/adapters/express/index.cjs.map +1 -0
- package/dist/cjs/server/adapters/express/index.min.cjs +32 -0
- package/dist/cjs/server/adapters/express/index.min.cjs.map +1 -0
- package/dist/cjs/server/adapters/fastify/index.cjs +1974 -0
- package/dist/cjs/server/adapters/fastify/index.cjs.map +1 -0
- package/dist/cjs/server/adapters/fastify/index.min.cjs +32 -0
- package/dist/cjs/server/adapters/fastify/index.min.cjs.map +1 -0
- package/dist/cjs/server/index.cjs +1811 -9
- package/dist/cjs/server/index.cjs.map +1 -1
- package/dist/cjs/server/index.min.cjs +31 -1
- package/dist/cjs/server/index.min.cjs.map +1 -1
- package/dist/cjs/types/index.cjs +18 -1
- package/dist/cjs/types/index.cjs.map +1 -1
- package/dist/cjs/types/index.min.cjs +1 -1
- package/dist/cjs/types/index.min.cjs.map +1 -1
- package/dist/cjs/utilities/index.cjs +862 -7
- package/dist/cjs/utilities/index.cjs.map +1 -1
- package/dist/cjs/utilities/index.min.cjs +3 -1
- package/dist/cjs/utilities/index.min.cjs.map +1 -1
- package/dist/cjs/validations/index.cjs +679 -10
- package/dist/cjs/validations/index.cjs.map +1 -1
- package/dist/cjs/validations/index.min.cjs +3 -1
- package/dist/cjs/validations/index.min.cjs.map +1 -1
- package/dist/esm/cache/adapters/in-memory/index.min.mjs +2 -0
- package/dist/esm/cache/adapters/in-memory/index.min.mjs.map +1 -0
- package/dist/esm/cache/adapters/in-memory/index.mjs +93 -0
- package/dist/esm/cache/adapters/in-memory/index.mjs.map +1 -0
- package/dist/esm/cache/adapters/redis/index.min.mjs +2 -0
- package/dist/esm/cache/adapters/redis/index.mjs +13 -0
- package/dist/esm/cache/index.min.mjs +1 -1
- package/dist/esm/cache/index.min.mjs.map +1 -1
- package/dist/esm/cache/index.mjs +9 -4
- package/dist/esm/cache/index.mjs.map +1 -1
- package/dist/esm/chunk-4JLDXF7T.min.mjs +2 -0
- package/dist/esm/chunk-4JLDXF7T.min.mjs.map +1 -0
- package/dist/{types/events/types/kafka.js → esm/chunk-4MXYZS5R.mjs} +60 -37
- package/dist/esm/chunk-4MXYZS5R.mjs.map +1 -0
- package/dist/esm/chunk-5VW3JAFR.min.mjs +2 -0
- package/dist/esm/chunk-5VW3JAFR.min.mjs.map +1 -0
- package/dist/esm/chunk-AKQBDYUO.mjs +126 -0
- package/dist/esm/chunk-AKQBDYUO.mjs.map +1 -0
- package/dist/esm/chunk-AQY7QVYI.min.mjs +2 -0
- package/dist/esm/chunk-B5QQ32YY.min.mjs +2 -0
- package/dist/esm/chunk-B5QQ32YY.min.mjs.map +1 -0
- package/dist/esm/chunk-BJNIUCPT.min.mjs +2 -0
- package/dist/esm/chunk-BJNIUCPT.min.mjs.map +1 -0
- package/dist/esm/chunk-DKPZJIIR.mjs +29 -0
- package/dist/esm/chunk-DKPZJIIR.mjs.map +1 -0
- package/dist/esm/chunk-DSUJ5FUL.min.mjs +2 -0
- package/dist/esm/chunk-DSUJ5FUL.min.mjs.map +1 -0
- package/dist/esm/chunk-FLAPYQUT.min.mjs +32 -0
- package/dist/esm/chunk-FLAPYQUT.min.mjs.map +1 -0
- package/dist/esm/chunk-J5LGTIGS.mjs +10 -0
- package/dist/esm/chunk-JH6EBXY4.mjs +53 -0
- package/dist/esm/chunk-JH6EBXY4.mjs.map +1 -0
- package/dist/esm/chunk-MDQKODYQ.mjs +2035 -0
- package/dist/esm/chunk-MDQKODYQ.mjs.map +1 -0
- package/dist/esm/chunk-PCAUXBAG.min.mjs +2 -0
- package/dist/esm/chunk-PCAUXBAG.min.mjs.map +1 -0
- package/dist/esm/chunk-PNZNNUMN.mjs +113 -0
- package/dist/esm/chunk-PNZNNUMN.mjs.map +1 -0
- package/dist/esm/chunk-PQCBVQL6.mjs +1280 -0
- package/dist/esm/chunk-PQCBVQL6.mjs.map +1 -0
- package/dist/esm/chunk-QHLKB47N.min.mjs +2 -0
- package/dist/esm/chunk-QHLKB47N.min.mjs.map +1 -0
- package/dist/esm/chunk-SGZNOYC3.min.mjs +2 -0
- package/dist/esm/chunk-SGZNOYC3.min.mjs.map +1 -0
- package/dist/esm/chunk-TVTYDU2D.mjs +795 -0
- package/dist/esm/chunk-TVTYDU2D.mjs.map +1 -0
- package/dist/esm/chunk-VCCS7CAI.mjs +8 -0
- package/dist/esm/chunk-VCCS7CAI.mjs.map +1 -0
- package/dist/esm/chunk-Z2TZ3KR7.mjs +22 -0
- package/dist/esm/chunk-Z2TZ3KR7.mjs.map +1 -0
- package/dist/esm/chunk-ZGMFFK6Y.min.mjs +2 -0
- package/dist/esm/chunk-ZGMFFK6Y.min.mjs.map +1 -0
- package/dist/esm/dbs/adapters/mongodb/index.min.mjs +2 -0
- package/dist/esm/dbs/adapters/mongodb/index.min.mjs.map +1 -0
- package/dist/esm/dbs/adapters/mongodb/index.mjs +419 -0
- package/dist/esm/dbs/adapters/mongodb/index.mjs.map +1 -0
- package/dist/esm/dbs/index.min.mjs +1 -1
- package/dist/esm/dbs/index.min.mjs.map +1 -1
- package/dist/esm/dbs/index.mjs +22 -6
- package/dist/esm/dbs/index.mjs.map +1 -1
- package/dist/esm/errors/index.min.mjs +1 -1
- package/dist/esm/errors/index.min.mjs.map +1 -1
- package/dist/esm/errors/index.mjs +22 -8
- package/dist/esm/errors/index.mjs.map +1 -1
- package/dist/esm/events/adapters/kafka/index.min.mjs +2 -0
- package/dist/esm/events/adapters/kafka/index.min.mjs.map +1 -0
- package/dist/esm/events/adapters/kafka/index.mjs +12 -0
- package/dist/esm/events/adapters/kafka/index.mjs.map +1 -0
- package/dist/esm/events/adapters/rabbitmq/index.min.mjs +2 -0
- package/dist/esm/events/adapters/rabbitmq/index.min.mjs.map +1 -0
- package/dist/esm/events/adapters/rabbitmq/index.mjs +92 -0
- package/dist/esm/events/adapters/rabbitmq/index.mjs.map +1 -0
- package/dist/esm/events/index.min.mjs +1 -1
- package/dist/esm/events/index.min.mjs.map +1 -1
- package/dist/esm/events/index.mjs +7 -4
- package/dist/esm/events/index.mjs.map +1 -1
- package/dist/esm/index.min.mjs +1 -1
- package/dist/esm/index.min.mjs.map +1 -1
- package/dist/esm/index.mjs +8 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/instance/index.min.mjs +1 -3
- package/dist/esm/instance/index.min.mjs.map +1 -1
- package/dist/esm/instance/index.mjs +4 -132
- package/dist/esm/instance/index.mjs.map +1 -1
- package/dist/esm/introspection-32BRYKYY.mjs +10 -0
- package/dist/esm/introspection-32BRYKYY.mjs.map +1 -0
- package/dist/esm/introspection-A72WMWE3.min.mjs +2 -0
- package/dist/esm/introspection-A72WMWE3.min.mjs.map +1 -0
- package/dist/esm/jobs/adapters/redis/index.min.mjs +2 -0
- package/dist/esm/jobs/adapters/redis/index.min.mjs.map +1 -0
- package/dist/esm/jobs/{types/redis.mjs → adapters/redis/index.mjs} +71 -56
- package/dist/esm/jobs/adapters/redis/index.mjs.map +1 -0
- package/dist/esm/jobs/index.min.mjs +1 -1
- package/dist/esm/jobs/index.min.mjs.map +1 -1
- package/dist/esm/jobs/index.mjs +9 -2
- package/dist/esm/jobs/index.mjs.map +1 -1
- package/dist/esm/orm/adapters/in-memory/index.min.mjs +2 -0
- package/dist/esm/orm/adapters/in-memory/index.min.mjs.map +1 -0
- package/dist/esm/orm/adapters/in-memory/index.mjs +11 -0
- package/dist/esm/orm/adapters/in-memory/index.mjs.map +1 -0
- package/dist/esm/orm/adapters/json/index.min.mjs +2 -0
- package/dist/esm/orm/adapters/json/index.min.mjs.map +1 -0
- package/dist/esm/orm/adapters/json/index.mjs +980 -0
- package/dist/esm/orm/adapters/json/index.mjs.map +1 -0
- package/dist/esm/orm/adapters/mongodb/index.min.mjs +2 -0
- package/dist/esm/orm/adapters/mongodb/index.min.mjs.map +1 -0
- package/dist/esm/orm/adapters/mongodb/index.mjs +1539 -0
- package/dist/esm/orm/adapters/mongodb/index.mjs.map +1 -0
- package/dist/esm/orm/adapters/postgresql/index.min.mjs +47 -0
- package/dist/esm/orm/adapters/postgresql/index.min.mjs.map +1 -0
- package/dist/esm/orm/adapters/postgresql/index.mjs +2070 -0
- package/dist/esm/orm/adapters/postgresql/index.mjs.map +1 -0
- package/dist/esm/orm/index.min.mjs +2 -0
- package/dist/esm/orm/index.min.mjs.map +1 -0
- package/dist/esm/orm/index.mjs +7326 -0
- package/dist/esm/orm/index.mjs.map +1 -0
- package/dist/esm/server/adapters/express/index.min.mjs +2 -0
- package/dist/esm/server/adapters/express/index.min.mjs.map +1 -0
- package/dist/esm/server/adapters/express/index.mjs +177 -0
- package/dist/esm/server/adapters/express/index.mjs.map +1 -0
- package/dist/esm/server/adapters/fastify/index.min.mjs +2 -0
- package/dist/esm/server/adapters/fastify/index.min.mjs.map +1 -0
- package/dist/esm/server/adapters/fastify/index.mjs +185 -0
- package/dist/esm/server/adapters/fastify/index.mjs.map +1 -0
- package/dist/esm/server/index.min.mjs +1 -1
- package/dist/esm/server/index.min.mjs.map +1 -1
- package/dist/esm/server/index.mjs +38 -9
- package/dist/esm/server/index.mjs.map +1 -1
- package/dist/esm/types/index.min.mjs +0 -1
- package/dist/esm/types/index.min.mjs.map +1 -1
- package/dist/esm/types/index.mjs +0 -1
- package/dist/esm/types/index.mjs.map +1 -1
- package/dist/esm/utilities/index.min.mjs +1 -1
- package/dist/esm/utilities/index.min.mjs.map +1 -1
- package/dist/esm/utilities/index.mjs +22 -9
- package/dist/esm/utilities/index.mjs.map +1 -1
- package/dist/esm/validations/index.min.mjs +1 -1
- package/dist/esm/validations/index.min.mjs.map +1 -1
- package/dist/esm/validations/index.mjs +8 -18
- package/dist/esm/validations/index.mjs.map +1 -1
- package/dist/types/adapter-Coap9ISX.d.ts +1435 -0
- package/dist/types/{fastify-DLPUK3vD.d.ts → base-DVr0fHil.d.ts} +76 -143
- package/dist/types/cache/adapters/in-memory/index.d.ts +21 -0
- package/dist/types/cache/adapters/in-memory/index.js +92 -0
- package/dist/types/cache/adapters/redis/index.d.ts +73 -0
- package/dist/types/cache/adapters/redis/index.js +12 -0
- package/dist/types/cache/index.d.ts +2 -42
- package/dist/types/cache/index.js +9 -4
- package/dist/types/chunk-3M4PBZAQ.js +125 -0
- package/dist/types/chunk-3TKJGSCZ.js +21 -0
- package/dist/types/chunk-65EHKCDZ.js +112 -0
- package/dist/types/chunk-JQ2FWX4W.js +1279 -0
- package/dist/types/chunk-KZKFYO4V.js +7 -0
- package/dist/types/chunk-LN3A6R4Y.js +28 -0
- package/dist/types/chunk-MLKGABMK.js +9 -0
- package/dist/types/chunk-NJ2FHI3U.js +794 -0
- package/dist/types/chunk-OHFTQGQG.js +52 -0
- package/dist/{esm/events/types/kafka.mjs → types/chunk-XGGGAEET.js} +59 -38
- package/dist/types/chunk-YTY3EFNB.js +2034 -0
- package/dist/types/{core-BrkNSwvc.d.ts → core-tNlIMH9Y.d.ts} +48 -38
- package/dist/types/dbs/adapters/mongodb/index.d.ts +43 -0
- package/dist/types/dbs/adapters/mongodb/index.js +418 -0
- package/dist/types/dbs/index.d.ts +14 -12
- package/dist/types/dbs/index.js +22 -6
- package/dist/types/equippedError-Cmo60Kn-.d.ts +8 -0
- package/dist/types/errors/index.d.ts +3 -3
- package/dist/types/errors/index.js +22 -8
- package/dist/types/events/adapters/kafka/index.d.ts +83 -0
- package/dist/types/events/adapters/kafka/index.js +11 -0
- package/dist/types/events/adapters/rabbitmq/index.d.ts +41 -0
- package/dist/types/events/adapters/rabbitmq/index.js +91 -0
- package/dist/types/events/index.d.ts +11 -11
- package/dist/types/events/index.js +7 -4
- package/dist/types/index.d.ts +2 -25
- package/dist/types/index.js +8 -1
- package/dist/types/instance/index.d.ts +12 -179
- package/dist/types/instance/index.js +4 -132
- package/dist/types/introspection-VOIU3XE6.js +9 -0
- package/dist/types/jobs/adapters/redis/index.d.ts +93 -0
- package/dist/types/jobs/{types/redis.js → adapters/redis/index.js} +70 -55
- package/dist/types/jobs/index.d.ts +19 -35
- package/dist/types/jobs/index.js +9 -2
- package/dist/types/orm/adapters/in-memory/index.d.ts +92 -0
- package/dist/types/orm/adapters/in-memory/index.js +10 -0
- package/dist/types/orm/adapters/json/index.d.ts +72 -0
- package/dist/types/orm/adapters/json/index.js +979 -0
- package/dist/types/orm/adapters/mongodb/index.d.ts +74 -0
- package/dist/types/orm/adapters/mongodb/index.js +1538 -0
- package/dist/types/orm/adapters/postgresql/index.d.ts +112 -0
- package/dist/types/orm/adapters/postgresql/index.js +2069 -0
- package/dist/types/orm/index.d.ts +160 -0
- package/dist/types/orm/index.js +7325 -0
- package/dist/types/{requestError-C2PNWUrt.d.ts → requestError-DdaL8hc3.d.ts} +2 -8
- package/dist/types/server/adapters/express/index.d.ts +196 -0
- package/dist/types/server/adapters/express/index.js +176 -0
- package/dist/types/server/adapters/fastify/index.d.ts +221 -0
- package/dist/types/server/adapters/fastify/index.js +184 -0
- package/dist/types/server/index.d.ts +10 -11
- package/dist/types/server/index.js +38 -9
- package/dist/types/types/index.js +0 -1
- package/dist/types/utilities/index.d.ts +22 -9
- package/dist/types/utilities/index.js +22 -9
- package/dist/types/{validationError-Bw8OYv5s.d.ts → validationError-oigtHqBi.d.ts} +1 -1
- package/dist/types/validations/index.d.ts +3 -2
- package/dist/types/validations/index.js +8 -18
- package/package.json +155 -18
- package/dist/cjs/audit/events.cjs +0 -101
- package/dist/cjs/audit/events.cjs.map +0 -1
- package/dist/cjs/audit/events.min.cjs +0 -2
- package/dist/cjs/audit/events.min.cjs.map +0 -1
- package/dist/cjs/audit/index.cjs +0 -2
- package/dist/cjs/audit/index.cjs.map +0 -1
- package/dist/cjs/audit/index.min.cjs +0 -2
- package/dist/cjs/audit/index.min.cjs.map +0 -1
- package/dist/cjs/cache/base.cjs +0 -6
- package/dist/cjs/cache/base.cjs.map +0 -1
- package/dist/cjs/cache/base.min.cjs +0 -2
- package/dist/cjs/cache/base.min.cjs.map +0 -1
- package/dist/cjs/cache/pipes.cjs +0 -16
- package/dist/cjs/cache/pipes.cjs.map +0 -1
- package/dist/cjs/cache/pipes.min.cjs +0 -2
- package/dist/cjs/cache/pipes.min.cjs.map +0 -1
- package/dist/cjs/cache/types/in-memory.cjs +0 -47
- package/dist/cjs/cache/types/in-memory.cjs.map +0 -1
- package/dist/cjs/cache/types/in-memory.min.cjs +0 -2
- package/dist/cjs/cache/types/in-memory.min.cjs.map +0 -1
- package/dist/cjs/cache/types/redis.cjs +0 -55
- package/dist/cjs/cache/types/redis.cjs.map +0 -1
- package/dist/cjs/cache/types/redis.min.cjs +0 -2
- package/dist/cjs/cache/types/redis.min.cjs.map +0 -1
- package/dist/cjs/dbs/base/changes.cjs +0 -36
- package/dist/cjs/dbs/base/changes.cjs.map +0 -1
- package/dist/cjs/dbs/base/changes.min.cjs +0 -2
- package/dist/cjs/dbs/base/changes.min.cjs.map +0 -1
- package/dist/cjs/dbs/base/core.cjs +0 -1
- package/dist/cjs/dbs/base/core.cjs.map +0 -1
- package/dist/cjs/dbs/base/core.min.cjs +0 -1
- package/dist/cjs/dbs/base/core.min.cjs.map +0 -1
- package/dist/cjs/dbs/base/db.cjs +0 -14
- package/dist/cjs/dbs/base/db.cjs.map +0 -1
- package/dist/cjs/dbs/base/db.min.cjs +0 -2
- package/dist/cjs/dbs/base/db.min.cjs.map +0 -1
- package/dist/cjs/dbs/base/types.cjs +0 -2
- package/dist/cjs/dbs/base/types.cjs.map +0 -1
- package/dist/cjs/dbs/base/types.min.cjs +0 -2
- package/dist/cjs/dbs/base/types.min.cjs.map +0 -1
- package/dist/cjs/dbs/mongo/changes.cjs +0 -81
- package/dist/cjs/dbs/mongo/changes.cjs.map +0 -1
- package/dist/cjs/dbs/mongo/changes.min.cjs +0 -2
- package/dist/cjs/dbs/mongo/changes.min.cjs.map +0 -1
- package/dist/cjs/dbs/mongo/db.cjs +0 -225
- package/dist/cjs/dbs/mongo/db.cjs.map +0 -1
- package/dist/cjs/dbs/mongo/db.min.cjs +0 -2
- package/dist/cjs/dbs/mongo/db.min.cjs.map +0 -1
- package/dist/cjs/dbs/mongo/query.cjs +0 -66
- package/dist/cjs/dbs/mongo/query.cjs.map +0 -1
- package/dist/cjs/dbs/mongo/query.min.cjs +0 -2
- package/dist/cjs/dbs/mongo/query.min.cjs.map +0 -1
- package/dist/cjs/dbs/pipes.cjs +0 -104
- package/dist/cjs/dbs/pipes.cjs.map +0 -1
- package/dist/cjs/dbs/pipes.min.cjs +0 -2
- package/dist/cjs/dbs/pipes.min.cjs.map +0 -1
- package/dist/cjs/errors/equippedError.cjs +0 -12
- package/dist/cjs/errors/equippedError.cjs.map +0 -1
- package/dist/cjs/errors/equippedError.min.cjs +0 -2
- package/dist/cjs/errors/equippedError.min.cjs.map +0 -1
- package/dist/cjs/errors/requestError.cjs +0 -12
- package/dist/cjs/errors/requestError.cjs.map +0 -1
- package/dist/cjs/errors/requestError.min.cjs +0 -2
- package/dist/cjs/errors/requestError.min.cjs.map +0 -1
- package/dist/cjs/errors/types/badRequestError.cjs +0 -12
- package/dist/cjs/errors/types/badRequestError.cjs.map +0 -1
- package/dist/cjs/errors/types/badRequestError.min.cjs +0 -2
- package/dist/cjs/errors/types/badRequestError.min.cjs.map +0 -1
- package/dist/cjs/errors/types/notAuthenticatedError.cjs +0 -12
- package/dist/cjs/errors/types/notAuthenticatedError.cjs.map +0 -1
- package/dist/cjs/errors/types/notAuthenticatedError.min.cjs +0 -2
- package/dist/cjs/errors/types/notAuthenticatedError.min.cjs.map +0 -1
- package/dist/cjs/errors/types/notAuthorizedError.cjs +0 -12
- package/dist/cjs/errors/types/notAuthorizedError.cjs.map +0 -1
- package/dist/cjs/errors/types/notAuthorizedError.min.cjs +0 -2
- package/dist/cjs/errors/types/notAuthorizedError.min.cjs.map +0 -1
- package/dist/cjs/errors/types/notFoundError.cjs +0 -12
- package/dist/cjs/errors/types/notFoundError.cjs.map +0 -1
- package/dist/cjs/errors/types/notFoundError.min.cjs +0 -2
- package/dist/cjs/errors/types/notFoundError.min.cjs.map +0 -1
- package/dist/cjs/errors/types/tokenExpired.cjs +0 -12
- package/dist/cjs/errors/types/tokenExpired.cjs.map +0 -1
- package/dist/cjs/errors/types/tokenExpired.min.cjs +0 -2
- package/dist/cjs/errors/types/tokenExpired.min.cjs.map +0 -1
- package/dist/cjs/errors/types/validationError.cjs +0 -16
- package/dist/cjs/errors/types/validationError.cjs.map +0 -1
- package/dist/cjs/errors/types/validationError.min.cjs +0 -2
- package/dist/cjs/errors/types/validationError.min.cjs.map +0 -1
- package/dist/cjs/events/base.cjs +0 -6
- package/dist/cjs/events/base.cjs.map +0 -1
- package/dist/cjs/events/base.min.cjs +0 -2
- package/dist/cjs/events/base.min.cjs.map +0 -1
- package/dist/cjs/events/pipes.cjs +0 -28
- package/dist/cjs/events/pipes.cjs.map +0 -1
- package/dist/cjs/events/pipes.min.cjs +0 -2
- package/dist/cjs/events/pipes.min.cjs.map +0 -1
- package/dist/cjs/events/types/kafka.cjs +0 -80
- package/dist/cjs/events/types/kafka.cjs.map +0 -1
- package/dist/cjs/events/types/kafka.min.cjs +0 -2
- package/dist/cjs/events/types/kafka.min.cjs.map +0 -1
- package/dist/cjs/events/types/rabbitmq.cjs +0 -54
- package/dist/cjs/events/types/rabbitmq.cjs.map +0 -1
- package/dist/cjs/events/types/rabbitmq.min.cjs +0 -2
- package/dist/cjs/events/types/rabbitmq.min.cjs.map +0 -1
- package/dist/cjs/instance/hooks.cjs +0 -26
- package/dist/cjs/instance/hooks.cjs.map +0 -1
- package/dist/cjs/instance/hooks.min.cjs +0 -2
- package/dist/cjs/instance/hooks.min.cjs.map +0 -1
- package/dist/cjs/instance/settings.cjs +0 -57
- package/dist/cjs/instance/settings.cjs.map +0 -1
- package/dist/cjs/instance/settings.min.cjs +0 -2
- package/dist/cjs/instance/settings.min.cjs.map +0 -1
- package/dist/cjs/jobs/pipes.cjs +0 -13
- package/dist/cjs/jobs/pipes.cjs.map +0 -1
- package/dist/cjs/jobs/pipes.min.cjs +0 -2
- package/dist/cjs/jobs/pipes.min.cjs.map +0 -1
- package/dist/cjs/jobs/types/redis.cjs +0 -106
- package/dist/cjs/jobs/types/redis.cjs.map +0 -1
- package/dist/cjs/jobs/types/redis.min.cjs +0 -2
- package/dist/cjs/jobs/types/redis.min.cjs.map +0 -1
- package/dist/cjs/server/impls/base.cjs +0 -211
- package/dist/cjs/server/impls/base.cjs.map +0 -1
- package/dist/cjs/server/impls/base.min.cjs +0 -2
- package/dist/cjs/server/impls/base.min.cjs.map +0 -1
- package/dist/cjs/server/impls/express.cjs +0 -111
- package/dist/cjs/server/impls/express.cjs.map +0 -1
- package/dist/cjs/server/impls/express.min.cjs +0 -2
- package/dist/cjs/server/impls/express.min.cjs.map +0 -1
- package/dist/cjs/server/impls/fastify.cjs +0 -121
- package/dist/cjs/server/impls/fastify.cjs.map +0 -1
- package/dist/cjs/server/impls/fastify.min.cjs +0 -2
- package/dist/cjs/server/impls/fastify.min.cjs.map +0 -1
- package/dist/cjs/server/middlewares/index.cjs +0 -2
- package/dist/cjs/server/middlewares/index.cjs.map +0 -1
- package/dist/cjs/server/middlewares/index.min.cjs +0 -2
- package/dist/cjs/server/middlewares/index.min.cjs.map +0 -1
- package/dist/cjs/server/middlewares/requireAuthUser.cjs +0 -22
- package/dist/cjs/server/middlewares/requireAuthUser.cjs.map +0 -1
- package/dist/cjs/server/middlewares/requireAuthUser.min.cjs +0 -2
- package/dist/cjs/server/middlewares/requireAuthUser.min.cjs.map +0 -1
- package/dist/cjs/server/openapi.cjs +0 -191
- package/dist/cjs/server/openapi.cjs.map +0 -1
- package/dist/cjs/server/openapi.min.cjs +0 -30
- package/dist/cjs/server/openapi.min.cjs.map +0 -1
- package/dist/cjs/server/pipes.cjs +0 -67
- package/dist/cjs/server/pipes.cjs.map +0 -1
- package/dist/cjs/server/pipes.min.cjs +0 -2
- package/dist/cjs/server/pipes.min.cjs.map +0 -1
- package/dist/cjs/server/requests-auth-methods/apiKeys.cjs +0 -21
- package/dist/cjs/server/requests-auth-methods/apiKeys.cjs.map +0 -1
- package/dist/cjs/server/requests-auth-methods/apiKeys.min.cjs +0 -2
- package/dist/cjs/server/requests-auth-methods/apiKeys.min.cjs.map +0 -1
- package/dist/cjs/server/requests-auth-methods/base.cjs +0 -20
- package/dist/cjs/server/requests-auth-methods/base.cjs.map +0 -1
- package/dist/cjs/server/requests-auth-methods/base.min.cjs +0 -2
- package/dist/cjs/server/requests-auth-methods/base.min.cjs.map +0 -1
- package/dist/cjs/server/requests-auth-methods/index.cjs +0 -4
- package/dist/cjs/server/requests-auth-methods/index.cjs.map +0 -1
- package/dist/cjs/server/requests-auth-methods/index.min.cjs +0 -2
- package/dist/cjs/server/requests-auth-methods/index.min.cjs.map +0 -1
- package/dist/cjs/server/requests-auth-methods/jwt.cjs +0 -78
- package/dist/cjs/server/requests-auth-methods/jwt.cjs.map +0 -1
- package/dist/cjs/server/requests-auth-methods/jwt.min.cjs +0 -2
- package/dist/cjs/server/requests-auth-methods/jwt.min.cjs.map +0 -1
- package/dist/cjs/server/requests.cjs +0 -80
- package/dist/cjs/server/requests.cjs.map +0 -1
- package/dist/cjs/server/requests.min.cjs +0 -2
- package/dist/cjs/server/requests.min.cjs.map +0 -1
- package/dist/cjs/server/routes.cjs +0 -74
- package/dist/cjs/server/routes.cjs.map +0 -1
- package/dist/cjs/server/routes.min.cjs +0 -2
- package/dist/cjs/server/routes.min.cjs.map +0 -1
- package/dist/cjs/server/sockets.cjs +0 -126
- package/dist/cjs/server/sockets.cjs.map +0 -1
- package/dist/cjs/server/sockets.min.cjs +0 -2
- package/dist/cjs/server/sockets.min.cjs.map +0 -1
- package/dist/cjs/server/types.cjs +0 -34
- package/dist/cjs/server/types.cjs.map +0 -1
- package/dist/cjs/server/types.min.cjs +0 -2
- package/dist/cjs/server/types.min.cjs.map +0 -1
- package/dist/cjs/types/overrides.cjs +0 -1
- package/dist/cjs/types/overrides.cjs.map +0 -1
- package/dist/cjs/types/overrides.min.cjs +0 -1
- package/dist/cjs/types/overrides.min.cjs.map +0 -1
- package/dist/cjs/utilities/authProviders.cjs +0 -53
- package/dist/cjs/utilities/authProviders.cjs.map +0 -1
- package/dist/cjs/utilities/authProviders.min.cjs +0 -2
- package/dist/cjs/utilities/authProviders.min.cjs.map +0 -1
- package/dist/cjs/utilities/hash.cjs +0 -17
- package/dist/cjs/utilities/hash.cjs.map +0 -1
- package/dist/cjs/utilities/hash.min.cjs +0 -2
- package/dist/cjs/utilities/hash.min.cjs.map +0 -1
- package/dist/cjs/utilities/json.cjs +0 -16
- package/dist/cjs/utilities/json.cjs.map +0 -1
- package/dist/cjs/utilities/json.min.cjs +0 -2
- package/dist/cjs/utilities/json.min.cjs.map +0 -1
- package/dist/cjs/utilities/media.cjs +0 -13
- package/dist/cjs/utilities/media.cjs.map +0 -1
- package/dist/cjs/utilities/media.min.cjs +0 -2
- package/dist/cjs/utilities/media.min.cjs.map +0 -1
- package/dist/cjs/utilities/random.cjs +0 -12
- package/dist/cjs/utilities/random.cjs.map +0 -1
- package/dist/cjs/utilities/random.min.cjs +0 -2
- package/dist/cjs/utilities/random.min.cjs.map +0 -1
- package/dist/cjs/utilities/retry.cjs +0 -14
- package/dist/cjs/utilities/retry.cjs.map +0 -1
- package/dist/cjs/utilities/retry.min.cjs +0 -2
- package/dist/cjs/utilities/retry.min.cjs.map +0 -1
- package/dist/cjs/validations/valleyed.cjs +0 -43
- package/dist/cjs/validations/valleyed.cjs.map +0 -1
- package/dist/cjs/validations/valleyed.min.cjs +0 -2
- package/dist/cjs/validations/valleyed.min.cjs.map +0 -1
- package/dist/esm/audit/events.min.mjs +0 -2
- package/dist/esm/audit/events.min.mjs.map +0 -1
- package/dist/esm/audit/events.mjs +0 -101
- package/dist/esm/audit/events.mjs.map +0 -1
- package/dist/esm/audit/index.min.mjs +0 -2
- package/dist/esm/audit/index.min.mjs.map +0 -1
- package/dist/esm/audit/index.mjs +0 -2
- package/dist/esm/audit/index.mjs.map +0 -1
- package/dist/esm/cache/base.min.mjs +0 -2
- package/dist/esm/cache/base.min.mjs.map +0 -1
- package/dist/esm/cache/base.mjs +0 -6
- package/dist/esm/cache/base.mjs.map +0 -1
- package/dist/esm/cache/pipes.min.mjs +0 -2
- package/dist/esm/cache/pipes.min.mjs.map +0 -1
- package/dist/esm/cache/pipes.mjs +0 -16
- package/dist/esm/cache/pipes.mjs.map +0 -1
- package/dist/esm/cache/types/in-memory.min.mjs +0 -2
- package/dist/esm/cache/types/in-memory.min.mjs.map +0 -1
- package/dist/esm/cache/types/in-memory.mjs +0 -47
- package/dist/esm/cache/types/in-memory.mjs.map +0 -1
- package/dist/esm/cache/types/redis.min.mjs +0 -2
- package/dist/esm/cache/types/redis.min.mjs.map +0 -1
- package/dist/esm/cache/types/redis.mjs +0 -55
- package/dist/esm/cache/types/redis.mjs.map +0 -1
- package/dist/esm/dbs/base/changes.min.mjs +0 -2
- package/dist/esm/dbs/base/changes.min.mjs.map +0 -1
- package/dist/esm/dbs/base/changes.mjs +0 -36
- package/dist/esm/dbs/base/changes.mjs.map +0 -1
- package/dist/esm/dbs/base/core.min.mjs +0 -1
- package/dist/esm/dbs/base/core.mjs +0 -1
- package/dist/esm/dbs/base/db.min.mjs +0 -2
- package/dist/esm/dbs/base/db.min.mjs.map +0 -1
- package/dist/esm/dbs/base/db.mjs +0 -14
- package/dist/esm/dbs/base/db.mjs.map +0 -1
- package/dist/esm/dbs/base/types.min.mjs +0 -2
- package/dist/esm/dbs/base/types.min.mjs.map +0 -1
- package/dist/esm/dbs/base/types.mjs +0 -2
- package/dist/esm/dbs/base/types.mjs.map +0 -1
- package/dist/esm/dbs/mongo/changes.min.mjs +0 -2
- package/dist/esm/dbs/mongo/changes.min.mjs.map +0 -1
- package/dist/esm/dbs/mongo/changes.mjs +0 -81
- package/dist/esm/dbs/mongo/changes.mjs.map +0 -1
- package/dist/esm/dbs/mongo/db.min.mjs +0 -2
- package/dist/esm/dbs/mongo/db.min.mjs.map +0 -1
- package/dist/esm/dbs/mongo/db.mjs +0 -225
- package/dist/esm/dbs/mongo/db.mjs.map +0 -1
- package/dist/esm/dbs/mongo/query.min.mjs +0 -2
- package/dist/esm/dbs/mongo/query.min.mjs.map +0 -1
- package/dist/esm/dbs/mongo/query.mjs +0 -66
- package/dist/esm/dbs/mongo/query.mjs.map +0 -1
- package/dist/esm/dbs/pipes.min.mjs +0 -2
- package/dist/esm/dbs/pipes.min.mjs.map +0 -1
- package/dist/esm/dbs/pipes.mjs +0 -104
- package/dist/esm/dbs/pipes.mjs.map +0 -1
- package/dist/esm/errors/equippedError.min.mjs +0 -2
- package/dist/esm/errors/equippedError.min.mjs.map +0 -1
- package/dist/esm/errors/equippedError.mjs +0 -12
- package/dist/esm/errors/equippedError.mjs.map +0 -1
- package/dist/esm/errors/requestError.min.mjs +0 -2
- package/dist/esm/errors/requestError.min.mjs.map +0 -1
- package/dist/esm/errors/requestError.mjs +0 -12
- package/dist/esm/errors/requestError.mjs.map +0 -1
- package/dist/esm/errors/types/badRequestError.min.mjs +0 -2
- package/dist/esm/errors/types/badRequestError.min.mjs.map +0 -1
- package/dist/esm/errors/types/badRequestError.mjs +0 -12
- package/dist/esm/errors/types/badRequestError.mjs.map +0 -1
- package/dist/esm/errors/types/notAuthenticatedError.min.mjs +0 -2
- package/dist/esm/errors/types/notAuthenticatedError.min.mjs.map +0 -1
- package/dist/esm/errors/types/notAuthenticatedError.mjs +0 -12
- package/dist/esm/errors/types/notAuthenticatedError.mjs.map +0 -1
- package/dist/esm/errors/types/notAuthorizedError.min.mjs +0 -2
- package/dist/esm/errors/types/notAuthorizedError.min.mjs.map +0 -1
- package/dist/esm/errors/types/notAuthorizedError.mjs +0 -12
- package/dist/esm/errors/types/notAuthorizedError.mjs.map +0 -1
- package/dist/esm/errors/types/notFoundError.min.mjs +0 -2
- package/dist/esm/errors/types/notFoundError.min.mjs.map +0 -1
- package/dist/esm/errors/types/notFoundError.mjs +0 -12
- package/dist/esm/errors/types/notFoundError.mjs.map +0 -1
- package/dist/esm/errors/types/tokenExpired.min.mjs +0 -2
- package/dist/esm/errors/types/tokenExpired.min.mjs.map +0 -1
- package/dist/esm/errors/types/tokenExpired.mjs +0 -12
- package/dist/esm/errors/types/tokenExpired.mjs.map +0 -1
- package/dist/esm/errors/types/validationError.min.mjs +0 -2
- package/dist/esm/errors/types/validationError.min.mjs.map +0 -1
- package/dist/esm/errors/types/validationError.mjs +0 -16
- package/dist/esm/errors/types/validationError.mjs.map +0 -1
- package/dist/esm/events/base.min.mjs +0 -2
- package/dist/esm/events/base.min.mjs.map +0 -1
- package/dist/esm/events/base.mjs +0 -6
- package/dist/esm/events/base.mjs.map +0 -1
- package/dist/esm/events/pipes.min.mjs +0 -2
- package/dist/esm/events/pipes.min.mjs.map +0 -1
- package/dist/esm/events/pipes.mjs +0 -28
- package/dist/esm/events/pipes.mjs.map +0 -1
- package/dist/esm/events/types/kafka.min.mjs +0 -2
- package/dist/esm/events/types/kafka.min.mjs.map +0 -1
- package/dist/esm/events/types/kafka.mjs.map +0 -1
- package/dist/esm/events/types/rabbitmq.min.mjs +0 -2
- package/dist/esm/events/types/rabbitmq.min.mjs.map +0 -1
- package/dist/esm/events/types/rabbitmq.mjs +0 -54
- package/dist/esm/events/types/rabbitmq.mjs.map +0 -1
- package/dist/esm/instance/hooks.min.mjs +0 -2
- package/dist/esm/instance/hooks.min.mjs.map +0 -1
- package/dist/esm/instance/hooks.mjs +0 -26
- package/dist/esm/instance/hooks.mjs.map +0 -1
- package/dist/esm/instance/settings.min.mjs +0 -2
- package/dist/esm/instance/settings.min.mjs.map +0 -1
- package/dist/esm/instance/settings.mjs +0 -57
- package/dist/esm/instance/settings.mjs.map +0 -1
- package/dist/esm/jobs/pipes.min.mjs +0 -2
- package/dist/esm/jobs/pipes.min.mjs.map +0 -1
- package/dist/esm/jobs/pipes.mjs +0 -13
- package/dist/esm/jobs/pipes.mjs.map +0 -1
- package/dist/esm/jobs/types/redis.min.mjs +0 -2
- package/dist/esm/jobs/types/redis.min.mjs.map +0 -1
- package/dist/esm/jobs/types/redis.mjs.map +0 -1
- package/dist/esm/server/impls/base.min.mjs +0 -2
- package/dist/esm/server/impls/base.min.mjs.map +0 -1
- package/dist/esm/server/impls/base.mjs +0 -211
- package/dist/esm/server/impls/base.mjs.map +0 -1
- package/dist/esm/server/impls/express.min.mjs +0 -2
- package/dist/esm/server/impls/express.min.mjs.map +0 -1
- package/dist/esm/server/impls/express.mjs +0 -111
- package/dist/esm/server/impls/express.mjs.map +0 -1
- package/dist/esm/server/impls/fastify.min.mjs +0 -2
- package/dist/esm/server/impls/fastify.min.mjs.map +0 -1
- package/dist/esm/server/impls/fastify.mjs +0 -121
- package/dist/esm/server/impls/fastify.mjs.map +0 -1
- package/dist/esm/server/middlewares/index.min.mjs +0 -2
- package/dist/esm/server/middlewares/index.min.mjs.map +0 -1
- package/dist/esm/server/middlewares/index.mjs +0 -2
- package/dist/esm/server/middlewares/index.mjs.map +0 -1
- package/dist/esm/server/middlewares/requireAuthUser.min.mjs +0 -2
- package/dist/esm/server/middlewares/requireAuthUser.min.mjs.map +0 -1
- package/dist/esm/server/middlewares/requireAuthUser.mjs +0 -22
- package/dist/esm/server/middlewares/requireAuthUser.mjs.map +0 -1
- package/dist/esm/server/openapi.min.mjs +0 -30
- package/dist/esm/server/openapi.min.mjs.map +0 -1
- package/dist/esm/server/openapi.mjs +0 -191
- package/dist/esm/server/openapi.mjs.map +0 -1
- package/dist/esm/server/pipes.min.mjs +0 -2
- package/dist/esm/server/pipes.min.mjs.map +0 -1
- package/dist/esm/server/pipes.mjs +0 -67
- package/dist/esm/server/pipes.mjs.map +0 -1
- package/dist/esm/server/requests-auth-methods/apiKeys.min.mjs +0 -2
- package/dist/esm/server/requests-auth-methods/apiKeys.min.mjs.map +0 -1
- package/dist/esm/server/requests-auth-methods/apiKeys.mjs +0 -21
- package/dist/esm/server/requests-auth-methods/apiKeys.mjs.map +0 -1
- package/dist/esm/server/requests-auth-methods/base.min.mjs +0 -2
- package/dist/esm/server/requests-auth-methods/base.min.mjs.map +0 -1
- package/dist/esm/server/requests-auth-methods/base.mjs +0 -20
- package/dist/esm/server/requests-auth-methods/base.mjs.map +0 -1
- package/dist/esm/server/requests-auth-methods/index.min.mjs +0 -2
- package/dist/esm/server/requests-auth-methods/index.min.mjs.map +0 -1
- package/dist/esm/server/requests-auth-methods/index.mjs +0 -4
- package/dist/esm/server/requests-auth-methods/index.mjs.map +0 -1
- package/dist/esm/server/requests-auth-methods/jwt.min.mjs +0 -2
- package/dist/esm/server/requests-auth-methods/jwt.min.mjs.map +0 -1
- package/dist/esm/server/requests-auth-methods/jwt.mjs +0 -78
- package/dist/esm/server/requests-auth-methods/jwt.mjs.map +0 -1
- package/dist/esm/server/requests.min.mjs +0 -2
- package/dist/esm/server/requests.min.mjs.map +0 -1
- package/dist/esm/server/requests.mjs +0 -80
- package/dist/esm/server/requests.mjs.map +0 -1
- package/dist/esm/server/routes.min.mjs +0 -2
- package/dist/esm/server/routes.min.mjs.map +0 -1
- package/dist/esm/server/routes.mjs +0 -74
- package/dist/esm/server/routes.mjs.map +0 -1
- package/dist/esm/server/sockets.min.mjs +0 -2
- package/dist/esm/server/sockets.min.mjs.map +0 -1
- package/dist/esm/server/sockets.mjs +0 -126
- package/dist/esm/server/sockets.mjs.map +0 -1
- package/dist/esm/server/types.min.mjs +0 -2
- package/dist/esm/server/types.min.mjs.map +0 -1
- package/dist/esm/server/types.mjs +0 -34
- package/dist/esm/server/types.mjs.map +0 -1
- package/dist/esm/types/overrides.min.mjs +0 -1
- package/dist/esm/types/overrides.mjs +0 -1
- package/dist/esm/utilities/authProviders.min.mjs +0 -2
- package/dist/esm/utilities/authProviders.min.mjs.map +0 -1
- package/dist/esm/utilities/authProviders.mjs +0 -53
- package/dist/esm/utilities/authProviders.mjs.map +0 -1
- package/dist/esm/utilities/hash.min.mjs +0 -2
- package/dist/esm/utilities/hash.min.mjs.map +0 -1
- package/dist/esm/utilities/hash.mjs +0 -17
- package/dist/esm/utilities/hash.mjs.map +0 -1
- package/dist/esm/utilities/json.min.mjs +0 -2
- package/dist/esm/utilities/json.min.mjs.map +0 -1
- package/dist/esm/utilities/json.mjs +0 -16
- package/dist/esm/utilities/json.mjs.map +0 -1
- package/dist/esm/utilities/media.min.mjs +0 -2
- package/dist/esm/utilities/media.min.mjs.map +0 -1
- package/dist/esm/utilities/media.mjs +0 -13
- package/dist/esm/utilities/media.mjs.map +0 -1
- package/dist/esm/utilities/random.min.mjs +0 -2
- package/dist/esm/utilities/random.min.mjs.map +0 -1
- package/dist/esm/utilities/random.mjs +0 -12
- package/dist/esm/utilities/random.mjs.map +0 -1
- package/dist/esm/utilities/retry.min.mjs +0 -2
- package/dist/esm/utilities/retry.min.mjs.map +0 -1
- package/dist/esm/utilities/retry.mjs +0 -14
- package/dist/esm/utilities/retry.mjs.map +0 -1
- package/dist/esm/validations/valleyed.min.mjs +0 -2
- package/dist/esm/validations/valleyed.min.mjs.map +0 -1
- package/dist/esm/validations/valleyed.mjs +0 -43
- package/dist/esm/validations/valleyed.mjs.map +0 -1
- package/dist/types/audit/events.js +0 -100
- package/dist/types/audit/index.d.ts +0 -44
- package/dist/types/audit/index.js +0 -1
- package/dist/types/cache/base.js +0 -5
- package/dist/types/cache/pipes.js +0 -15
- package/dist/types/cache/types/in-memory.js +0 -46
- package/dist/types/cache/types/redis.js +0 -54
- package/dist/types/db-C8YY1yTO.d.ts +0 -14
- package/dist/types/db-Dj1SGto0.d.ts +0 -24
- package/dist/types/dbs/base/changes.js +0 -35
- package/dist/types/dbs/base/core.js +0 -0
- package/dist/types/dbs/base/db.js +0 -13
- package/dist/types/dbs/base/types.js +0 -1
- package/dist/types/dbs/mongo/changes.js +0 -80
- package/dist/types/dbs/mongo/db.js +0 -224
- package/dist/types/dbs/mongo/query.js +0 -65
- package/dist/types/dbs/pipes.js +0 -103
- package/dist/types/errors/equippedError.js +0 -11
- package/dist/types/errors/requestError.js +0 -11
- package/dist/types/errors/types/badRequestError.js +0 -11
- package/dist/types/errors/types/notAuthenticatedError.js +0 -11
- package/dist/types/errors/types/notAuthorizedError.js +0 -11
- package/dist/types/errors/types/notFoundError.js +0 -11
- package/dist/types/errors/types/tokenExpired.js +0 -11
- package/dist/types/errors/types/validationError.js +0 -15
- package/dist/types/events/base.js +0 -5
- package/dist/types/events/pipes.js +0 -27
- package/dist/types/events/types/rabbitmq.js +0 -53
- package/dist/types/instance/hooks.js +0 -25
- package/dist/types/instance/settings.js +0 -56
- package/dist/types/jobs/pipes.js +0 -12
- package/dist/types/kafka-Cf-TUJgv.d.ts +0 -54
- package/dist/types/server/impls/base.js +0 -210
- package/dist/types/server/impls/express.js +0 -110
- package/dist/types/server/impls/fastify.js +0 -120
- package/dist/types/server/middlewares/index.js +0 -1
- package/dist/types/server/middlewares/requireAuthUser.js +0 -21
- package/dist/types/server/openapi.js +0 -190
- package/dist/types/server/pipes.js +0 -66
- package/dist/types/server/requests-auth-methods/apiKeys.js +0 -20
- package/dist/types/server/requests-auth-methods/base.js +0 -19
- package/dist/types/server/requests-auth-methods/index.js +0 -3
- package/dist/types/server/requests-auth-methods/jwt.js +0 -77
- package/dist/types/server/requests.js +0 -79
- package/dist/types/server/routes.js +0 -73
- package/dist/types/server/sockets.js +0 -125
- package/dist/types/server/types.js +0 -33
- package/dist/types/types/overrides.js +0 -0
- package/dist/types/utilities/authProviders.js +0 -52
- package/dist/types/utilities/hash.js +0 -16
- package/dist/types/utilities/json.js +0 -15
- package/dist/types/utilities/media.js +0 -12
- package/dist/types/utilities/random.js +0 -11
- package/dist/types/utilities/retry.js +0 -13
- package/dist/types/validations/valleyed.js +0 -42
- /package/dist/esm/{dbs/base/core.min.mjs.map → cache/adapters/redis/index.min.mjs.map} +0 -0
- /package/dist/esm/{dbs/base/core.mjs.map → cache/adapters/redis/index.mjs.map} +0 -0
- /package/dist/esm/{types/overrides.min.mjs.map → chunk-AQY7QVYI.min.mjs.map} +0 -0
- /package/dist/esm/{types/overrides.mjs.map → chunk-J5LGTIGS.mjs.map} +0 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
"use strict";var ce=Object.create;var C=Object.defineProperty;var le=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var de=Object.getPrototypeOf,ue=Object.prototype.hasOwnProperty;var me=(n,e)=>{for(var t in e)C(n,t,{get:e[t],enumerable:!0})},Q=(n,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of pe(e))!ue.call(n,s)&&s!==t&&C(n,s,{get:()=>e[s],enumerable:!(a=le(e,s))||a.enumerable});return n};var ge=(n,e,t)=>(t=n!=null?ce(de(n)):{},Q(e||!n||!n.__esModule?C(t,"default",{value:n,enumerable:!0}):t,n)),fe=n=>Q(C({},"__esModule",{value:!0}),n);var Ae={};me(Ae,{JsonAdapter:()=>$});module.exports=fe(Ae);var x=require("fs/promises"),P=require("valleyed");var _=require("valleyed");function B(n,e){let t=n();_.v.compile(t);class a extends e{constructor(i,...r){super(...r);this.config=i}static create(i,...r){let c=_.v.validate(t,i);if(!c.valid)throw c.error;return new this(c.value,...r)}}return a}var y=class extends Error{constructor(t,a,s){super(t,{cause:s});this.message=t;this.context=a;this.cause=s}};var A=ge(require("pino"),1),Z=require("ulid"),K=require("valleyed");function X(n,e){for(let t of e.after)if(!n.some(a=>a.class===t)){let a=t.name||"unknown",s=e.class?.name||"anonymous";throw new Error(`Missing dependency: ${s} declares after: [${a}], but ${a} is not registered`)}if(e.class){let t=[...n,e];ye(t)}n.push(e)}function ye(n){let e=new Map;for(let o of n){if(!o.class)continue;let i=e.get(o.class);if(i)for(let r of o.after)i.includes(r)||i.push(r);else e.set(o.class,[...o.after])}let t=new Set,a=new Set;function s(o,i){if(a.has(o)){let r=i.indexOf(o),l=[...i.slice(r),o].map(p=>p.name||"unknown");throw new Error(`Cycle detected: ${l.join(" \u2192 ")}`)}if(!t.has(o)){a.add(o),i.push(o);for(let r of e.get(o)??[])s(r,i);i.pop(),a.delete(o),t.add(o)}}for(let o of e.keys())s(o,[])}function he(n,e=!1){if(n.length===0)return[];let t=new Map,a=[];for(let l of n)if(l.class){let p=t.get(l.class);p?p.push(l):t.set(l.class,[l])}else a.push(l);let s=[...t.keys()],o=new Map,i=new Map;for(let l of s)o.set(l,0),i.set(l,[]);for(let l of n)if(l.class)for(let p of l.after){let[d,u]=e?[l.class,p]:[p,l.class],f=i.get(d);f.includes(u)||(f.push(u),o.set(u,o.get(u)+1))}let r=[],c=s.filter(l=>o.get(l)===0);for(;c.length>0;){let l=[],p=[];for(let d of c)l.push(...t.get(d)??[]);r.push(l);for(let d of c)for(let u of i.get(d)??[]){let f=o.get(u)-1;o.set(u,f),f===0&&p.push(u)}c=p}if(a.length>0){let l=a.filter(d=>d.after.length>0),p=a.filter(d=>d.after.length===0);if(l.length>0){let d=-1;for(let f of l)for(let re of f.after){let z=r.findIndex(oe=>oe.some(ie=>ie.class===re));z>d&&(d=z)}let u=d+1;u<r.length?r[u].push(...l):r.push(l)}p.length>0&&(r.length>0?r[r.length-1].push(...p):r.push(p))}return r}async function T(n,e=a=>{throw a},t=!1){let a=he(n,t);for(let s of a)await Promise.all(s.map(async o=>{try{return typeof o.cb=="function"?await o.cb():await o.cb}catch(i){return e(i instanceof Error?i:new Error(`${i}`))}}))}var h=require("valleyed"),Y=()=>h.v.object({app:h.v.object({name:h.v.string()}),log:h.v.defaults(h.v.object({level:h.v.defaults(h.v.in(["fatal","error","warn","info","debug","trace","silent"]),"info")}),{}),utils:h.v.defaults(h.v.object({hashSaltRounds:h.v.defaults(h.v.number(),10),paginationDefaultLimit:h.v.defaults(h.v.number(),100),maxFileUploadSizeInMb:h.v.defaults(h.v.number(),500)}),{})});var O=class n{static#e;static#n;static#a={};settings;log;constructor(e){n.#n=this,this.settings=Object.freeze(e),this.log=(0,A.default)({level:this.settings.log.level,serializers:{err:A.default.stdSerializers.err,error:A.default.stdSerializers.err,req:A.default.stdSerializers.req,res:A.default.stdSerializers.res},mixin:()=>({instanceId:n.#e})}),n.#s()}alias(e){if(n.#e!==void 0)return n.crash(new y("Instance already has an alias",{}));n.#e=e}get id(){return n.#e===void 0?n.crash(new y("Instance doesnt have an alias yet",{})):n.#e}getScopedName(e,t="."){return[this.settings.app.name,e].join(t)}async start(){try{await T(n.#a.setup??[]),await T(n.#a.start??[])}catch(e){n.crash(new y("Error starting instance",{},e))}}static envs(e){let t=K.v.validate(e,process.env);return t.valid||n.crash(new y(`Environment variables are not valid
|
|
2
|
+
${t.error.toString()}`,{messages:t.error.messages})),t.value}static create(e){if(n.#n)return n.crash(new y("Instance has been initialized already",{}));let t=K.v.validate(Y(),e);return t.valid||n.crash(new y(`Settings are not valid
|
|
3
|
+
${t.error.toString()}`,{messages:t.error.messages})),new n(t.value)}static get(){return n.#n?n.#n:n.crash(new y("Has not been initialized. Make sure an instance has been created before you get an instance",{}))}static maybeGet(){return n.#n}static on(e,t,a){n.#a[e]??=[];let s={cb:t,class:a?.class,after:a?.after??[]};X(n.#a[e],s)}static#s(){Object.entries({SIGHUP:1,SIGINT:2,SIGTERM:15}).forEach(([t,a])=>{process.on(t,async()=>{await T(n.#a.close??[],()=>{},!0),process.exit(128+a)})})}static resolveBeforeCrash(e){let t=e();return n.on("close",async()=>await t),t}static crash(e){console.error(e),process.exit(1)}static createId(e){return`${e?.prefix??""}${(0,Z.ulid)(e?.time?.getTime())}`}};var Ie=require("valleyed"),L=class{name;path;constructor(e,t){this.name=e,this.path=t??[e]}};function ee(n){return n instanceof L?n.path.join("."):n}var g=class{constructor(e,t,a){this.op=t;this.value=a;this.field=ee(e)}field},v=class n{constructor(e="and",t){this.op=e;this.children=t??[]}children;#e(e){return new n(this.op,[...this.children,e])}eq(e,t){return this.#e(new g(e,"eq",t))}ne(e,t){return this.#e(new g(e,"ne",t))}gt(e,t){return this.#e(new g(e,"gt",t))}gte(e,t){return this.#e(new g(e,"gte",t))}lt(e,t){return this.#e(new g(e,"lt",t))}lte(e,t){return this.#e(new g(e,"lte",t))}in(e,t){return this.#e(new g(e,"in",t))}notIn(e,t){return this.#e(new g(e,"notIn",t))}like(e,t){return this.#e(new g(e,"like",t))}exists(e){return this.#e(new g(e,"exists",!0))}notExists(e){return this.#e(new g(e,"notExists",!0))}contains(e,t){return this.#e(new g(e,"contains",t))}notContains(e,t){return this.#e(new g(e,"notContains",t))}and(e){if(e.length===0)throw new y("and() requires at least one filter factory",{op:"and"});let t=new n("and",e.map(a=>a(n.create())));return this.#e(t)}or(e){if(e.length===0)throw new y("or() requires at least one filter factory",{op:"or"});let t=new n("or",e.map(a=>a(n.create())));return this.#e(t)}clone(){return new n(this.op,this.children.map(e=>e instanceof g?new g(e.field,e.op,structuredClone(e.value)):e.clone()))}static create(){return new n}};var F=class{queryableOps=[];updateOps=[];aggregateOps=[];supportedFieldTypes=[];onFatalError(e){let t=e instanceof y?e:new y("OrmAdapter fatal error",{},e);O.crash(t)}constructor(){let e=this;typeof e.connect=="function"&&O.on("start",()=>e.connect(),{class:this.constructor}),typeof e.disconnect=="function"&&O.on("close",()=>e.disconnect(),{class:this.constructor})}use(e,t){let a=this,s=async function*(){},o={findMany:(i,r)=>a.findMany?.(e,t,i,r)??Promise.resolve([]),iterateMany:(i,r)=>a.iterateMany?.(e,t,i,r)??s(),findOne:async i=>(await o.findMany(i,{limit:1}))[0]??null,count:i=>a.count?.(e,t,i)??Promise.reject(new Error("count not implemented")),createOne:async i=>(await o.createMany([i]))[0],createMany:i=>a.createMany?.(e,t,i)??Promise.resolve([]),updateMany:(i,r)=>a.updateMany?.(e,t,i,r)??Promise.resolve([]),updateOne:async(i,r)=>{let c=await o.findOne(i);if(!c)return null;let l=e.pkField.name,p=v.create().eq(l,c[l]);return(await o.updateMany(p,r))[0]??null},upsertOne:(i,r,c)=>a.upsertOne?.(e,t,i,r,c)??Promise.reject(new Error("upsertOne not implemented")),deleteOne:async i=>{let r=await o.findOne(i);if(!r)return null;let c=e.pkField.name;if(a.deleteByPk)await a.deleteByPk(e,t,r[c]);else if(a.deleteMany){let l=v.create().eq(c,r[c]);await a.deleteMany(e,t,l)}return r},deleteMany:i=>a.deleteMany?.(e,t,i)??Promise.resolve([]),raw:(...i)=>a.raw?.(e,t,...i)??Promise.reject(new Error("raw not implemented")),aggregate:i=>a.aggregate?.(e,t,i)??Promise.reject(new Error("aggregate not implemented")),aggregateOps:a.aggregateOps??[]};return o}};var ne=require("async_hooks"),w=require("valleyed");var M=class{constructor(e){this.values=e}kind="set"},q=class{constructor(e,t){this.field=e;this.value=t}kind="inc"},I=class{constructor(e,t){this.field=e;this.value=t}kind="mul"},E=class{constructor(e,t){this.field=e;this.value=t}kind="min"},R=class{constructor(e,t){this.field=e;this.value=t}kind="max"},G=class{constructor(e){this.field=e}kind="unset"},H=class{constructor(e,t){this.field=e;this.value=t}kind="push"},U=class{constructor(e,t){this.field=e;this.value=t}kind="pull"},D=class{constructor(e,t){this.field=e;this.value=t}kind="patch"};var we=()=>w.v.object({});function m(n){return structuredClone(n)}var S=(n,e)=>{n.clear();for(let[t,a]of e.entries())n.set(t,a)};function j(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function V(n,e){return Array.isArray(n)?(Array.isArray(e)?e:[e]).every(a=>n.some(s=>w.differ.equal(s,a))):j(n)&&j(e)?Object.entries(e).every(([t,a])=>V(n[t],a)):w.differ.equal(n,e)}function b(n,e){if(n===e)return 0;if(n==null)return-1;if(e==null)return 1;if(typeof n=="number"&&typeof e=="number"||typeof n=="string"&&typeof e=="string")return n<e?-1:1;if(typeof n=="boolean"&&typeof e=="boolean")return n===!1?-1:1;let t=JSON.stringify(n),a=JSON.stringify(e);return t===a?0:t<a?-1:1}function xe(n,e){return`${e.prefix??""}${e.table}`}function be(n,e){let t=n[e.field],a=e.value;switch(e.op){case"eq":return w.differ.equal(t,a);case"ne":return!w.differ.equal(t,a);case"gt":return b(t,a)>0;case"gte":return b(t,a)>=0;case"lt":return b(t,a)<0;case"lte":return b(t,a)<=0;case"in":return Array.isArray(a)?a.some(s=>w.differ.equal(t,s)):!1;case"notIn":return Array.isArray(a)?!a.some(s=>w.differ.equal(t,s)):!0;case"like":return String(t??"").toLowerCase().includes(String(a??"").toLowerCase());case"exists":return t!=null;case"notExists":return t==null;case"contains":return V(t,a);case"notContains":return!V(t,a);default:return!1}}function W(n,e){if(e instanceof g)return be(n,e);if(e instanceof v){if(e.op==="and")return e.children.every(t=>W(n,t));if(e.op==="or")return e.children.some(t=>W(n,t))}return!0}function k(n,e){for(let t of e.children)if(!W(n,t))return!1;return!0}function te(n,e){let t=n;if(e?.orderBy?.length&&(t=[...t].sort((a,s)=>{for(let o of e.orderBy??[]){let i=b(a[o.field],s[o.field]);if(i!==0)return o.direction==="asc"?i:-i}return 0})),e?.offset!=null&&(t=t.slice(Math.max(0,e.offset))),e?.limit!=null&&(t=t.slice(0,e.limit)),e?.select?.length){let a=new Set(e.select);t=t.map(s=>{let o={};for(let i of a)o[i]=s[i];return o})}return t}function se(n,e,t){if(t instanceof q){let a=Number(n[e]??0);n[e]=a+t.value;return}if(t instanceof I){let a=Number(n[e]??0);n[e]=a*t.value;return}if(t instanceof E){let a=n[e];n[e]=a==null||b(t.value,a)<0?t.value:a;return}if(t instanceof R){let a=n[e];n[e]=a==null||b(t.value,a)>0?t.value:a;return}if(t instanceof G){n[e]=null;return}if(t instanceof H){let a=Array.isArray(n[e])?[...n[e]]:[];a.push(m(t.value)),n[e]=a;return}if(t instanceof U){let a=Array.isArray(n[e])?n[e]:[];n[e]=a.filter(s=>!w.differ.equal(s,t.value));return}if(t instanceof D){let a=j(n[e])?m(n[e]):{};if(j(t.value))for(let[s,o]of Object.entries(t.value))a[s]=m(o);n[e]=a;return}n[e]=m(t)}function ke(n,e){let t=m(n);for(let[a,s]of Object.entries(e))se(t,a,s);return t}function J(n,e){let t=m(n);for(let a of e)if(a instanceof M)for(let[s,o]of Object.entries(a.values))t[s]=m(o);else se(t,a.field,a);return t}var ae=new ne.AsyncLocalStorage,N=class extends B(we,F){schemaConfigPipe=w.v.object({table:w.v.string()});supportedFieldTypes=["string","number","boolean","null","object","array","date"];queryableOps=["eq","ne","gt","gte","lt","lte","in","notIn","like","exists","notExists","contains","notContains"];updateOps=["set","inc","mul","min","max","unset","push","pull","patch"];aggregateOps=["count","countDistinct","sum","avg","min","max"];stores=new Map;migrations=new Map;indexes=new Map;tables=new Map;foreignKeys=new Map;#e=Promise.resolve();constructor(e){super(e)}#n(e){return this.stores.has(e)||this.stores.set(e,new Map),this.stores.get(e)}#a(e,t){return this.#n(xe(e,t))}#s(){let e=new Map;for(let[i,r]of this.stores.entries()){let c=new Map;for(let[l,p]of r.entries())c.set(l,m(p));e.set(i,c)}let t=new Map(this.migrations),a=new Map(this.indexes),s=new Map;for(let[i,r]of this.tables.entries())s.set(i,{pk:{...r.pk},fields:new Map(r.fields)});let o=new Map(this.foreignKeys);return{stores:e,migrations:t,indexes:a,tables:s,foreignKeys:o}}#t(e){S(this.stores,e.stores),S(this.migrations,e.migrations),S(this.indexes,e.indexes),S(this.tables,e.tables),S(this.foreignKeys,e.foreignKeys)}async findByPk(e,t,a){let o=this.#a(e,t).get(String(a));return o?m(o):null}async createMany(e,t,a){let s=e.pkField.name,o=this.#a(e,t);return a.map(i=>{let r=m(i);return o.set(String(r[s]),r),m(r)})}async deleteByPk(e,t,a){let s=this.#a(e,t),o=String(a),i=s.get(o);return i?(s.delete(o),m(i)):null}async updateByPk(e,t,a,s){let o=this.#a(e,t),i=String(a),r=o.get(i);if(!r)return null;let c=J(r,s);return o.set(i,c),m(c)}async findMany(e,t,a,s){let i=[...this.#a(e,t).values()].filter(r=>k(r,a)).map(r=>m(r));return te(i,s)}async count(e,t,a){return[...this.#a(e,t).values()].filter(o=>k(o,a)).length}async*iterateMany(e,t,a,s){let o=this.#a(e,t),i=te([...o.values()].filter(c=>k(c,a)).map(c=>m(c)),s),r=typeof s?.batchSize=="number"&&Number.isSafeInteger(s.batchSize)&&s.batchSize>0?s.batchSize:1;for(let c=0;c<i.length;c+=r)for(let l of i.slice(c,c+r))yield l}async updateMany(e,t,a,s){let o=this.#a(e,t),i=[...o.entries()].filter(([,c])=>k(c,a)).map(([c])=>c),r=[];for(let c of i){let l=o.get(c);if(!l)continue;let p=ke(l,s);o.set(c,p),r.push(m(p))}return r}async deleteMany(e,t,a){let s=this.#a(e,t),o=e.pkField.name,i=[...s.values()].filter(r=>k(r,a)).map(r=>m(r));for(let r of i)s.delete(String(r[o]));return i}async upsertOne(e,t,a,s,o){let i=this.#a(e,t),r=e.pkField.name,l=[...i.values()].filter(u=>k(u,a))[0];if(l){let u=o.length>0?J(l,o):m(l);return i.set(String(u[r]),u),m(u)}let p=m(s),d=o.length>0?J(p,o):p;return i.set(String(d[r]),d),m(d)}async aggregate(e,t,a){let o=[...this.#a(e,t).values()];if(a.where){let c=a.where;o=o.filter(l=>k(l,c))}let i=new Map;if(a.groupBy.length>0)for(let c of o){let l=JSON.stringify(a.groupBy.map(p=>c[p]));i.has(l)||i.set(l,[]),i.get(l).push(c)}else i.set("__all__",o);let r=[];for(let[,c]of i){let l={};if(a.groupBy.length>0)for(let p of a.groupBy)l[p]=c[0][p];for(let p of a.aggregates)switch(p.fn){case"count":l[p.alias]=c.length;break;case"countDistinct":{let d=new Set(c.map(u=>JSON.stringify(u[p.field])));l[p.alias]=d.size;break}case"sum":l[p.alias]=c.reduce((d,u)=>d+Number(u[p.field]??0),0);break;case"avg":{let d=c.reduce((u,f)=>u+Number(f[p.field]??0),0);l[p.alias]=c.length>0?d/c.length:0;break}case"min":{let d=null;for(let u of c){let f=u[p.field];f!=null&&(d===null||b(f,d)<0)&&(d=f)}l[p.alias]=d;break}case"max":{let d=null;for(let u of c){let f=u[p.field];f!=null&&(d===null||b(f,d)>0)&&(d=f)}l[p.alias]=d;break}}r.push(l)}if(a.having){let c=a.having;return r.filter(l=>k(l,c))}return r}async loadMigrations(){return[...this.migrations.values()].map(e=>({id:e.id,appliedAt:e.appliedAt}))}async recordMigration(e,t){this.migrations.set(e,{id:e,appliedAt:t})}async applyCreateTable(e){let t=new Map;for(let a of e.fields)t.set(a.name,{...a});this.tables.set(e.name,{pk:{name:e.pk.name,type:e.pk.type},fields:t})}async applyDropTable(e){this.tables.delete(e.name)}async applyAddField(e){let t=this.tables.get(e.table);t&&t.fields.set(e.field.name,{...e.field})}async applyDropField(e){let t=this.tables.get(e.table);t&&t.fields.delete(e.name)}async applyModifyField(e){let t=this.tables.get(e.table);t&&(t.fields.delete(e.name),t.fields.set(e.to.name,{...e.to}))}async applyRenameTable(e){let t=this.tables.get(e.from);t&&(this.tables.delete(e.from),this.tables.set(e.to,t))}async applyRenameField(e){let t=this.tables.get(e.table);if(t){let a=t.fields.get(e.from);a&&(t.fields.delete(e.from),t.fields.set(e.to,{...a,name:e.to}))}}async applyAddIndex(e){let t=e.name??`${e.table}_${e.on.join("_")}_idx`;this.indexes.set(t,{table:e.table,on:e.on,unique:e.unique??!1})}async applyDropIndex(e){this.indexes.delete(e.name)}async applyAddForeignKey(e){let t=e.name??`${e.table}_${e.on}_fk`;this.foreignKeys.set(t,{table:e.table,on:e.on,references:{table:e.references.table,column:e.references.column},onDelete:e.onDelete,onUpdate:e.onUpdate})}async applyDropForeignKey(e){this.foreignKeys.delete(e.name)}async introspect(){let e=[];for(let[t,a]of this.tables.entries()){let s=[...a.fields.values()].map(r=>({name:r.name,type:r.type,nullable:r.nullable??!1,...r.default!==void 0?{default:r.default}:{},...r.unique?{unique:!0}:{}})),o=[...this.indexes.entries()].filter(([,r])=>r.table===t).map(([r,c])=>({name:r,on:c.on,unique:c.unique})),i=[...this.foreignKeys.entries()].filter(([,r])=>r.table===t).map(([r,c])=>({name:r,on:c.on,references:{table:c.references.table,column:c.references.column},...c.onDelete?{onDelete:c.onDelete}:{},...c.onUpdate?{onUpdate:c.onUpdate}:{}}));e.push({name:t,pk:{name:a.pk.name,type:a.pk.type},fields:s,indexes:o,foreignKeys:i})}return e}async acquireMigrationLock(e){let t,a=new Promise(o=>{t=o}),s=this.#e;this.#e=a,await s;try{return await e()}finally{t()}}async session(e){if(ae.getStore())return e();let t=this.#s();try{return await ae.run(!0,e)}catch(a){throw this.#t(t),a}}};var ve=()=>P.v.object({filePath:P.v.string()}),$=class extends B(ve,F){schemaConfigPipe=P.v.object({table:P.v.string()});#e=N.create({});supportedFieldTypes=this.#e.supportedFieldTypes;queryableOps=this.#e.queryableOps;updateOps=this.#e.updateOps;aggregateOps=this.#e.aggregateOps;#n=Promise.resolve();constructor(e){super(e)}get stores(){return this.#e.stores}#a(){let e={},t=[...this.#e.migrations.values()];t.length>0&&(e.__migrations=t);let a={};for(let[i,r]of this.#e.tables.entries())a[i]={pk:r.pk,fields:Object.fromEntries(r.fields.entries())};Object.keys(a).length>0&&(e.__tables=a);let s={};for(let[i,r]of this.#e.indexes.entries())s[i]={table:r.table,on:[...r.on],unique:r.unique};Object.keys(s).length>0&&(e.__indexes=s);let o={};for(let[i,r]of this.#e.foreignKeys.entries())o[i]={table:r.table,on:r.on,references:r.references,...r.onDelete?{onDelete:r.onDelete}:{},...r.onUpdate?{onUpdate:r.onUpdate}:{}};Object.keys(o).length>0&&(e.__foreignKeys=o);for(let[i,r]of this.stores.entries()){let c={};for(let[l,p]of r.entries())c[l]=p;e[i]=c}return JSON.stringify(e)}async#s(){let e=this.#a(),t=this.config.filePath+".tmp."+process.pid+"."+Date.now();await(0,x.writeFile)(t,e,"utf-8"),await(0,x.rename)(t,this.config.filePath)}#t(){let e=this.#n.then(()=>this.#s());return this.#n=e.catch(()=>{}),e}async connect(){let e;try{e=await(0,x.readFile)(this.config.filePath,"utf-8")}catch{return}let t=JSON.parse(e);if(this.#e.migrations.clear(),Array.isArray(t.__migrations))for(let a of t.__migrations)this.#e.migrations.set(a.id,{id:a.id,appliedAt:a.appliedAt});if(this.#e.tables.clear(),t.__tables&&typeof t.__tables=="object")for(let[a,s]of Object.entries(t.__tables)){let o=new Map;if(s.fields)for(let[i,r]of Object.entries(s.fields))o.set(i,r);this.#e.tables.set(a,{pk:s.pk,fields:o})}if(this.#e.indexes.clear(),t.__indexes&&typeof t.__indexes=="object")for(let[a,s]of Object.entries(t.__indexes))this.#e.indexes.set(a,{table:s.table,on:s.on,unique:s.unique});if(this.#e.foreignKeys.clear(),t.__foreignKeys&&typeof t.__foreignKeys=="object")for(let[a,s]of Object.entries(t.__foreignKeys))this.#e.foreignKeys.set(a,s);this.stores.clear();for(let[a,s]of Object.entries(t)){if(a.startsWith("__"))continue;let o=new Map;for(let[i,r]of Object.entries(s))o.set(i,r);this.stores.set(a,o)}}async disconnect(){await this.#t()}async findByPk(e,t,a){return this.#e.findByPk(e,t,a)}async createMany(e,t,a){let s=await this.#e.createMany(e,t,a);return await this.#t(),s}async updateByPk(e,t,a,s){let o=await this.#e.updateByPk(e,t,a,s);return o&&await this.#t(),o}async deleteByPk(e,t,a){let s=await this.#e.deleteByPk(e,t,a);return s&&await this.#t(),s}async findMany(e,t,a,s){return this.#e.findMany(e,t,a,s)}async count(e,t,a){return this.#e.count(e,t,a)}iterateMany(e,t,a,s){return this.#e.iterateMany(e,t,a,s)}async updateMany(e,t,a,s){let o=await this.#e.updateMany(e,t,a,s);return o.length&&await this.#t(),o}async deleteMany(e,t,a){let s=await this.#e.deleteMany(e,t,a);return s.length&&await this.#t(),s}async upsertOne(e,t,a,s,o){let i=await this.#e.upsertOne(e,t,a,s,o);return await this.#t(),i}async aggregate(e,t,a){return this.#e.aggregate(e,t,a)}async session(e){return this.#e.session(async()=>{let t=await e();return await this.#t(),t})}async loadMigrations(){return await this.connect(),this.#e.loadMigrations()}async recordMigration(e,t){await this.#e.recordMigration(e,t),await this.#t()}async acquireMigrationLock(e){let t=this.config.filePath+".lock",a=Date.now()+3e4;for(;;)try{await(await(0,x.open)(t,"wx")).close();break}catch(s){if(s.code!=="EEXIST")throw s;if(Date.now()>a)throw new Error("Timed out waiting for migration lock");await new Promise(o=>setTimeout(o,50))}try{return await e()}finally{await(0,x.unlink)(t).catch(()=>{})}}async applyCreateTable(e){await this.#e.applyCreateTable(e),await this.#t()}async applyDropTable(e){await this.#e.applyDropTable(e),await this.#t()}async applyAddField(e){await this.#e.applyAddField(e),await this.#t()}async applyDropField(e){await this.#e.applyDropField(e),await this.#t()}async applyModifyField(e){await this.#e.applyModifyField(e),await this.#t()}async applyRenameTable(e){await this.#e.applyRenameTable(e),await this.#t()}async applyRenameField(e){await this.#e.applyRenameField(e),await this.#t()}async applyAddIndex(e){await this.#e.applyAddIndex(e),await this.#t()}async applyDropIndex(e){await this.#e.applyDropIndex(e),await this.#t()}async applyAddForeignKey(e){await this.#e.applyAddForeignKey(e),await this.#t()}async applyDropForeignKey(e){await this.#e.applyDropForeignKey(e),await this.#t()}async introspect(){return this.#e.introspect()}};0&&(module.exports={JsonAdapter});
|
|
4
|
+
//# sourceMappingURL=index.min.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../src/orm/adapters/json/index.ts","../../../../../src/utilities/configurable.ts","../../../../../src/errors/equippedError.ts","../../../../../src/instance/index.ts","../../../../../src/instance/hooks.ts","../../../../../src/instance/settings.ts","../../../../../src/orm/fields.ts","../../../../../src/orm/filter.ts","../../../../../src/orm/orm-adapter.ts","../../../../../src/orm/adapters/in-memory/index.ts","../../../../../src/orm/updates.ts"],"sourcesContent":["import { open, readFile, rename, unlink, writeFile } from 'node:fs/promises'\n\nimport { v } from 'valleyed'\n\nimport { configurable } from '../../../utilities/configurable'\nimport type { FilterGroup } from '../../filter'\nimport type { DiscoveredSchema } from '../../migrations/introspection-types'\nimport type { AddFieldChange, AddForeignKeyChange, AddIndexChange, AnyFieldSpec, CreateTableChange, DropFieldChange, DropForeignKeyChange, DropIndexChange, DropTableChange, ModifyFieldChange, RenameFieldChange, RenameTableChange } from '../../migrations/types'\nimport { OrmAdapter, type AggregateSpec } from '../../orm-adapter'\nimport type { IterationQueryOptions, QueryOptions } from '../../query-options'\nimport type { AnySchema } from '../../schema'\nimport type { AnyUpdateOp } from '../../updates'\nimport { InMemoryAdapter, type InMemoryRepoConfig } from '../in-memory'\n\nexport type JsonAdapterConfig = InMemoryRepoConfig\n\nconst jsonConnectionPipe = () =>\n\tv.object({\n\t\tfilePath: v.string(),\n\t})\n\nexport class JsonAdapter extends configurable(jsonConnectionPipe, OrmAdapter) {\n\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\n\treadonly #inMemory = InMemoryAdapter.create({})\n\n\treadonly supportedFieldTypes = this.#inMemory.supportedFieldTypes\n\treadonly queryableOps = this.#inMemory.queryableOps\n\treadonly updateOps = this.#inMemory.updateOps\n\treadonly aggregateOps = this.#inMemory.aggregateOps\n\n\t#writeQueue: Promise<void> = Promise.resolve()\n\n\tprotected constructor(config: typeof JsonAdapter.Config) {\n\t\tsuper(config)\n\t}\n\n\tget stores() {\n\t\treturn this.#inMemory.stores\n\t}\n\n\t#serialize(): string {\n\t\tconst obj: Record<string, unknown> = {}\n\n\t\tconst migrations = [...this.#inMemory.migrations.values()]\n\t\tif (migrations.length > 0) obj['__migrations'] = migrations\n\n\t\tconst tables: Record<string, unknown> = {}\n\t\tfor (const [name, meta] of this.#inMemory.tables.entries()) {\n\t\t\ttables[name] = { pk: meta.pk, fields: Object.fromEntries(meta.fields.entries()) }\n\t\t}\n\t\tif (Object.keys(tables).length > 0) obj['__tables'] = tables\n\n\t\tconst indexes: Record<string, unknown> = {}\n\t\tfor (const [name, meta] of this.#inMemory.indexes.entries()) {\n\t\t\tindexes[name] = { table: meta.table, on: [...meta.on], unique: meta.unique }\n\t\t}\n\t\tif (Object.keys(indexes).length > 0) obj['__indexes'] = indexes\n\n\t\tconst foreignKeys: Record<string, unknown> = {}\n\t\tfor (const [name, meta] of this.#inMemory.foreignKeys.entries()) {\n\t\t\tforeignKeys[name] = {\n\t\t\t\ttable: meta.table,\n\t\t\t\ton: meta.on,\n\t\t\t\treferences: meta.references,\n\t\t\t\t...(meta.onDelete ? { onDelete: meta.onDelete } : {}),\n\t\t\t\t...(meta.onUpdate ? { onUpdate: meta.onUpdate } : {}),\n\t\t\t}\n\t\t}\n\t\tif (Object.keys(foreignKeys).length > 0) obj['__foreignKeys'] = foreignKeys\n\n\t\tfor (const [name, store] of this.stores.entries()) {\n\t\t\tconst records: Record<string, Record<string, unknown>> = {}\n\t\t\tfor (const [pk, doc] of store.entries()) {\n\t\t\t\trecords[pk] = doc\n\t\t\t}\n\t\t\tobj[name] = records\n\t\t}\n\n\t\treturn JSON.stringify(obj)\n\t}\n\n\tasync #atomicWrite(): Promise<void> {\n\t\tconst data = this.#serialize()\n\t\tconst tmpPath = this.config.filePath + '.tmp.' + process.pid + '.' + Date.now()\n\t\tawait writeFile(tmpPath, data, 'utf-8')\n\t\tawait rename(tmpPath, this.config.filePath)\n\t}\n\n\t#persistToDisk(): Promise<void> {\n\t\tconst next = this.#writeQueue.then(() => this.#atomicWrite())\n\t\tthis.#writeQueue = next.catch(() => {})\n\t\treturn next\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tlet raw: string\n\t\ttry {\n\t\t\traw = await readFile(this.config.filePath, 'utf-8')\n\t\t} catch {\n\t\t\treturn\n\t\t}\n\t\tconst data = JSON.parse(raw) as Record<string, unknown>\n\n\t\tthis.#inMemory.migrations.clear()\n\t\tif (Array.isArray(data['__migrations'])) {\n\t\t\tfor (const m of data['__migrations'] as Array<{ id: string; appliedAt: number }>) {\n\t\t\t\tthis.#inMemory.migrations.set(m.id, { id: m.id, appliedAt: m.appliedAt })\n\t\t\t}\n\t\t}\n\n\t\tthis.#inMemory.tables.clear()\n\t\tif (data['__tables'] && typeof data['__tables'] === 'object') {\n\t\t\tfor (const [name, meta] of Object.entries(data['__tables'] as Record<string, any>)) {\n\t\t\t\tconst fields = new Map<string, AnyFieldSpec>()\n\t\t\t\tif (meta.fields) {\n\t\t\t\t\tfor (const [fieldName, fspec] of Object.entries(meta.fields as Record<string, AnyFieldSpec>)) {\n\t\t\t\t\t\tfields.set(fieldName, fspec)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.#inMemory.tables.set(name, { pk: meta.pk, fields })\n\t\t\t}\n\t\t}\n\n\t\tthis.#inMemory.indexes.clear()\n\t\tif (data['__indexes'] && typeof data['__indexes'] === 'object') {\n\t\t\tfor (const [name, meta] of Object.entries(data['__indexes'] as Record<string, any>)) {\n\t\t\t\tthis.#inMemory.indexes.set(name, { table: meta.table, on: meta.on, unique: meta.unique })\n\t\t\t}\n\t\t}\n\n\t\tthis.#inMemory.foreignKeys.clear()\n\t\tif (data['__foreignKeys'] && typeof data['__foreignKeys'] === 'object') {\n\t\t\tfor (const [name, meta] of Object.entries(data['__foreignKeys'] as Record<string, any>)) {\n\t\t\t\tthis.#inMemory.foreignKeys.set(name, meta)\n\t\t\t}\n\t\t}\n\n\t\tthis.stores.clear()\n\t\tfor (const [name, records] of Object.entries(data)) {\n\t\t\tif (name.startsWith('__')) continue\n\t\t\tconst store = new Map<string, Record<string, unknown>>()\n\t\t\tfor (const [pk, doc] of Object.entries(records as Record<string, Record<string, unknown>>)) {\n\t\t\t\tstore.set(pk, doc)\n\t\t\t}\n\t\t\tthis.stores.set(name, store)\n\t\t}\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tawait this.#persistToDisk()\n\t}\n\n\tasync findByPk(schema: AnySchema, config: unknown, pk: unknown) {\n\t\treturn this.#inMemory.findByPk(schema, config, pk)\n\t}\n\n\tasync createMany(schema: AnySchema, config: unknown, data: Record<string, unknown>[]) {\n\t\tconst result = await this.#inMemory.createMany(schema, config, data)\n\t\tawait this.#persistToDisk()\n\t\treturn result\n\t}\n\n\tasync updateByPk(schema: AnySchema, config: unknown, pk: unknown, ops: AnyUpdateOp[]) {\n\t\tconst result = await this.#inMemory.updateByPk(schema, config, pk, ops)\n\t\tif (result) await this.#persistToDisk()\n\t\treturn result\n\t}\n\n\tasync deleteByPk(schema: AnySchema, config: unknown, pk: unknown) {\n\t\tconst result = await this.#inMemory.deleteByPk(schema, config, pk)\n\t\tif (result) await this.#persistToDisk()\n\t\treturn result\n\t}\n\n\tasync findMany(schema: AnySchema, config: unknown, group: FilterGroup, options?: QueryOptions) {\n\t\treturn this.#inMemory.findMany(schema, config, group, options)\n\t}\n\n\tasync count(schema: AnySchema, config: unknown, group: FilterGroup) {\n\t\treturn this.#inMemory.count(schema, config, group)\n\t}\n\n\titerateMany(schema: AnySchema, config: unknown, group: FilterGroup, options?: IterationQueryOptions) {\n\t\treturn this.#inMemory.iterateMany(schema, config, group, options)\n\t}\n\n\tasync updateMany(schema: AnySchema, config: unknown, group: FilterGroup, data: Record<string, unknown>) {\n\t\tconst result = await this.#inMemory.updateMany(schema, config, group, data)\n\t\tif (result.length) await this.#persistToDisk()\n\t\treturn result\n\t}\n\n\tasync deleteMany(schema: AnySchema, config: unknown, filter: FilterGroup) {\n\t\tconst result = await this.#inMemory.deleteMany(schema, config, filter)\n\t\tif (result.length) await this.#persistToDisk()\n\t\treturn result\n\t}\n\n\tasync upsertOne(schema: AnySchema, config: unknown, filter: FilterGroup, create: Record<string, unknown>, ops: AnyUpdateOp[]) {\n\t\tconst result = await this.#inMemory.upsertOne(schema, config, filter, create, ops)\n\t\tawait this.#persistToDisk()\n\t\treturn result\n\t}\n\n\tasync aggregate(schema: AnySchema, config: unknown, spec: AggregateSpec) {\n\t\treturn this.#inMemory.aggregate(schema, config, spec)\n\t}\n\n\tasync session<T>(fn: () => Promise<T>): Promise<T> {\n\t\treturn this.#inMemory.session(async () => {\n\t\t\tconst result = await fn()\n\t\t\tawait this.#persistToDisk()\n\t\t\treturn result\n\t\t})\n\t}\n\n\tasync loadMigrations(): Promise<{ id: string; appliedAt: number }[]> {\n\t\tawait this.connect()\n\t\treturn this.#inMemory.loadMigrations()\n\t}\n\n\tasync recordMigration(id: string, appliedAt: number): Promise<void> {\n\t\tawait this.#inMemory.recordMigration(id, appliedAt)\n\t\tawait this.#persistToDisk()\n\t}\n\n\tasync acquireMigrationLock<T>(fn: () => Promise<T>): Promise<T> {\n\t\tconst lockPath = this.config.filePath + '.lock'\n\t\tconst deadline = Date.now() + 30_000\n\t\twhile (true) {\n\t\t\ttry {\n\t\t\t\tconst handle = await open(lockPath, 'wx')\n\t\t\t\tawait handle.close()\n\t\t\t\tbreak\n\t\t\t} catch (err: any) {\n\t\t\t\tif (err.code !== 'EEXIST') throw err\n\t\t\t\tif (Date.now() > deadline) throw new Error('Timed out waiting for migration lock')\n\t\t\t\tawait new Promise((r) => setTimeout(r, 50))\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\treturn await fn()\n\t\t} finally {\n\t\t\tawait unlink(lockPath).catch(() => {})\n\t\t}\n\t}\n\n\tasync applyCreateTable(change: CreateTableChange<any>): Promise<void> {\n\t\tawait this.#inMemory.applyCreateTable(change)\n\t\tawait this.#persistToDisk()\n\t}\n\n\tasync applyDropTable(change: DropTableChange): Promise<void> {\n\t\tawait this.#inMemory.applyDropTable(change)\n\t\tawait this.#persistToDisk()\n\t}\n\n\tasync applyAddField(change: AddFieldChange<any>): Promise<void> {\n\t\tawait this.#inMemory.applyAddField(change)\n\t\tawait this.#persistToDisk()\n\t}\n\n\tasync applyDropField(change: DropFieldChange): Promise<void> {\n\t\tawait this.#inMemory.applyDropField(change)\n\t\tawait this.#persistToDisk()\n\t}\n\n\tasync applyModifyField(change: ModifyFieldChange<any>): Promise<void> {\n\t\tawait this.#inMemory.applyModifyField(change)\n\t\tawait this.#persistToDisk()\n\t}\n\n\tasync applyRenameTable(change: RenameTableChange): Promise<void> {\n\t\tawait this.#inMemory.applyRenameTable(change)\n\t\tawait this.#persistToDisk()\n\t}\n\n\tasync applyRenameField(change: RenameFieldChange): Promise<void> {\n\t\tawait this.#inMemory.applyRenameField(change)\n\t\tawait this.#persistToDisk()\n\t}\n\n\tasync applyAddIndex(change: AddIndexChange): Promise<void> {\n\t\tawait this.#inMemory.applyAddIndex(change)\n\t\tawait this.#persistToDisk()\n\t}\n\n\tasync applyDropIndex(change: DropIndexChange): Promise<void> {\n\t\tawait this.#inMemory.applyDropIndex(change)\n\t\tawait this.#persistToDisk()\n\t}\n\n\tasync applyAddForeignKey(change: AddForeignKeyChange): Promise<void> {\n\t\tawait this.#inMemory.applyAddForeignKey(change)\n\t\tawait this.#persistToDisk()\n\t}\n\n\tasync applyDropForeignKey(change: DropForeignKeyChange): Promise<void> {\n\t\tawait this.#inMemory.applyDropForeignKey(change)\n\t\tawait this.#persistToDisk()\n\t}\n\n\tasync introspect(): Promise<DiscoveredSchema[]> {\n\t\treturn this.#inMemory.introspect()\n\t}\n}\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect, beforeEach, afterEach } = import.meta.vitest\n\tconst { FilterGroup } = await import('../../filter')\n\tconst { OrderBy } = await import('../../query-options')\n\tconst { Schema } = await import('../../schema')\n\tconst { IncOp, PatchOp, PullOp, PushOp } = await import('../../updates')\n\tconst { v } = await import('valleyed')\n\tconst { mkdtemp, rm } = await import('node:fs/promises')\n\tconst { tmpdir } = await import('node:os')\n\tconst { join } = await import('node:path')\n\tconst { Migrator } = await import('../../migrations/migrator')\n\tconst { Repo } = await import('../../repo/repo')\n\tconst { OrmMigrationError } = await import('../../errors/migration')\n\ttype Migration<A extends import('../base').OrmAdapterLike<any>> = import('../../migrations/types').Migration<A>\n\n\tlet tmpDir: string\n\tlet filePath: string\n\n\tbeforeEach(async () => {\n\t\ttmpDir = await mkdtemp(join(tmpdir(), 'json-adapter-'))\n\t\tfilePath = join(tmpDir, 'test.json')\n\t})\n\n\tafterEach(async () => {\n\t\tawait rm(tmpDir, { recursive: true, force: true })\n\t})\n\n\tdescribe('json adapter — class construction', () => {\n\t\ttest('JsonAdapter.create({ filePath }) produces a working adapter', () => {\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\texpect(adapter).toBeInstanceOf(JsonAdapter)\n\t\t\texpect(adapter.schemaConfigPipe).toBeDefined()\n\t\t\texpect(adapter.supportedFieldTypes).toEqual(['string', 'number', 'boolean', 'null', 'object', 'array', 'date'])\n\t\t})\n\n\t\ttest('auto-wired Instance hooks register connect/disconnect keyed by class', async () => {\n\t\t\tconst { Instance: Inst } = await import('../../../instance')\n\t\t\tconst onSpy = (await import('vitest')).vi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tJsonAdapter.create({ filePath })\n\n\t\t\texpect(onSpy).toHaveBeenCalledWith('start', expect.any(Function), expect.objectContaining({ class: JsonAdapter }))\n\t\t\texpect(onSpy).toHaveBeenCalledWith('close', expect.any(Function), expect.objectContaining({ class: JsonAdapter }))\n\n\t\t\tonSpy.mockRestore()\n\t\t})\n\t})\n\n\tdescribe('json adapter — surface parity with in-memory', () => {\n\t\ttest('CRUD: create, find, update, delete round-trip', async () => {\n\t\t\tconst schema = Schema.from('users')\n\t\t\t\t.pk('id', v.string(), () => 'u')\n\t\t\t\t.field('name', v.string())\n\t\t\t\t.field('age', v.number())\n\t\t\t\t.build()\n\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\n\t\t\tconst use = adapter.use(schema, { table: 'users' })\n\n\t\t\tconst created = await use.createMany([\n\t\t\t\t{ id: 'u1', name: 'Alice', age: 30 },\n\t\t\t\t{ id: 'u2', name: 'Bob', age: 20 },\n\t\t\t])\n\t\t\texpect(created).toHaveLength(2)\n\n\t\t\tconst found = await use.findOne(FilterGroup.create().eq('id', 'u1'))\n\t\t\texpect(found).toEqual({ id: 'u1', name: 'Alice', age: 30 })\n\n\t\t\tconst many = await use.findMany(FilterGroup.create().gt('age', 19), {\n\t\t\t\torderBy: [new OrderBy('age', 'asc')],\n\t\t\t})\n\t\t\texpect(many).toEqual([\n\t\t\t\t{ id: 'u2', name: 'Bob', age: 20 },\n\t\t\t\t{ id: 'u1', name: 'Alice', age: 30 },\n\t\t\t])\n\n\t\t\tawait use.updateOne(FilterGroup.create().eq('id', 'u1'), { age: 31 })\n\t\t\tconst updated = await use.findOne(FilterGroup.create().eq('id', 'u1'))\n\t\t\texpect(updated?.age).toBe(31)\n\n\t\t\tconst deleted = await use.deleteOne(FilterGroup.create().eq('id', 'u2'))\n\t\t\texpect(deleted).toEqual({ id: 'u2', name: 'Bob', age: 20 })\n\n\t\t\tconst remaining = await use.findMany(FilterGroup.create())\n\t\t\texpect(remaining).toHaveLength(1)\n\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('supports nested filters, ordering, select, offset and limit', async () => {\n\t\t\tconst schema = Schema.from('users')\n\t\t\t\t.pk('id', v.string(), () => 'u')\n\t\t\t\t.field('name', v.string())\n\t\t\t\t.field('age', v.number())\n\t\t\t\t.build()\n\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\t\t\tconst use = adapter.use(schema, { table: 'users' })\n\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'u1', name: 'Alice', age: 30 },\n\t\t\t\t{ id: 'u2', name: 'Bob', age: 20 },\n\t\t\t\t{ id: 'u3', name: 'Carol', age: 40 },\n\t\t\t])\n\n\t\t\tconst builtGroup = FilterGroup.create().and([\n\t\t\t\t(q) => q.gt('age', 19),\n\t\t\t\t(q) => q.or([(g) => g.eq('name', 'Alice'), (g) => g.eq('name', 'Carol')]),\n\t\t\t])\n\t\t\tconst options = { orderBy: [new OrderBy('age', 'desc')], offset: 1, limit: 1, select: ['id', 'name'] as const }\n\t\t\tconst rows = await use.findMany(builtGroup, options)\n\t\t\texpect(rows).toEqual([{ id: 'u1', name: 'Alice' }])\n\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('count delegates to the in-memory store and persists separately from query options', async () => {\n\t\t\tconst schema = Schema.from('count_users')\n\t\t\t\t.pk('id', v.string(), () => 'u')\n\t\t\t\t.field('name', v.string())\n\t\t\t\t.build()\n\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\t\t\tconst use = adapter.use(schema, { table: 'count_users' })\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'u1', name: 'Alice' },\n\t\t\t\t{ id: 'u2', name: 'Bob' },\n\t\t\t\t{ id: 'u3', name: 'Alice' },\n\t\t\t])\n\n\t\t\tawait expect(use.count(FilterGroup.create().eq('name', 'Alice'))).resolves.toBe(2)\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('iterateMany with batchSize matches findMany through in-memory delegation', async () => {\n\t\t\tconst schema = Schema.from('json_iter_users')\n\t\t\t\t.pk('id', v.string(), () => 'u')\n\t\t\t\t.field('name', v.string())\n\t\t\t\t.field('age', v.number())\n\t\t\t\t.build()\n\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\t\t\tconst use = adapter.use(schema, { table: 'json_iter_users' })\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'u1', name: 'Alice', age: 30 },\n\t\t\t\t{ id: 'u2', name: 'Bob', age: 20 },\n\t\t\t\t{ id: 'u3', name: 'Carol', age: 40 },\n\t\t\t\t{ id: 'u4', name: 'Dan', age: 50 },\n\t\t\t])\n\n\t\t\tconst filter = FilterGroup.create().gt('age', 19)\n\t\t\tconst options = {\n\t\t\t\torderBy: [new OrderBy('age', 'desc')],\n\t\t\t\toffset: 1,\n\t\t\t\tlimit: 2,\n\t\t\t\tselect: ['id', 'name'],\n\t\t\t}\n\t\t\tconst expected = await use.findMany(filter, options)\n\t\t\tconst rows: Record<string, unknown>[] = []\n\t\t\tfor await (const row of use.iterateMany(filter, { ...options, batchSize: 2 })) {\n\t\t\t\trows.push(row)\n\t\t\t}\n\t\t\texpect(rows).toEqual(expected)\n\t\t\texpect(rows).toEqual([\n\t\t\t\t{ id: 'u3', name: 'Carol' },\n\t\t\t\t{ id: 'u1', name: 'Alice' },\n\t\t\t])\n\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('supports update operators and rollback on failed session', async () => {\n\t\t\tconst schema = Schema.from('docs')\n\t\t\t\t.pk('id', v.string(), () => 'd1')\n\t\t\t\t.field('count', v.number())\n\t\t\t\t.field('tags', v.array(v.string()))\n\t\t\t\t.field('meta', v.object({ a: v.number() }))\n\t\t\t\t.build()\n\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\t\t\tconst use = adapter.use(schema, { table: 'docs' })\n\n\t\t\tawait use.createOne({ id: 'd1', count: 1, tags: ['x'], meta: { a: 1 } })\n\n\t\t\tawait adapter.session(async () => {\n\t\t\t\tawait use.updateOne(FilterGroup.create().eq('id', 'd1'), {\n\t\t\t\t\tcount: new IncOp('count', 2),\n\t\t\t\t\ttags: new PushOp('tags', 'y'),\n\t\t\t\t\tmeta: new PatchOp('meta', { a: 9 }),\n\t\t\t\t})\n\t\t\t})\n\n\t\t\tawait expect(\n\t\t\t\tadapter.session(async () => {\n\t\t\t\t\tawait use.updateOne(FilterGroup.create().eq('id', 'd1'), { tags: new PullOp('tags', 'x') })\n\t\t\t\t\tthrow new Error('boom')\n\t\t\t\t}),\n\t\t\t).rejects.toThrow('boom')\n\n\t\t\tconst row = await use.findOne(FilterGroup.create().eq('id', 'd1'))\n\t\t\texpect(row).toEqual({ id: 'd1', count: 3, tags: ['x', 'y'], meta: { a: 9 } })\n\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('upsertOne inserts when missing and updates when existing', async () => {\n\t\t\tconst schema = Schema.from('items')\n\t\t\t\t.pk('id', v.string(), () => 'i')\n\t\t\t\t.field('val', v.number())\n\t\t\t\t.build()\n\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\t\t\tconst use = adapter.use(schema, { table: 'items' })\n\n\t\t\tconst inserted = await use.upsertOne(FilterGroup.create().eq('id', 'i1'), { id: 'i1', val: 10 }, [])\n\t\t\texpect(inserted).toEqual({ id: 'i1', val: 10 })\n\n\t\t\tconst updated = await use.upsertOne(FilterGroup.create().eq('id', 'i1'), { id: 'i1', val: 10 }, [new IncOp('val', 5)])\n\t\t\texpect(updated).toEqual({ id: 'i1', val: 15 })\n\n\t\t\tawait adapter.disconnect()\n\t\t})\n\t})\n\n\tdescribe('json adapter — persistence', () => {\n\t\ttest('state persists across adapter restarts', async () => {\n\t\t\tconst schema = Schema.from('users')\n\t\t\t\t.pk('id', v.string(), () => 'u')\n\t\t\t\t.field('name', v.string())\n\t\t\t\t.build()\n\n\t\t\tconst a1 = JsonAdapter.create({ filePath })\n\t\t\tawait a1.connect()\n\t\t\tconst use1 = a1.use(schema, { table: 'users' })\n\t\t\tawait use1.createMany([\n\t\t\t\t{ id: 'u1', name: 'Alice' },\n\t\t\t\t{ id: 'u2', name: 'Bob' },\n\t\t\t])\n\t\t\tawait a1.disconnect()\n\n\t\t\tconst a2 = JsonAdapter.create({ filePath })\n\t\t\tawait a2.connect()\n\t\t\tconst use2 = a2.use(schema, { table: 'users' })\n\t\t\tconst rows = await use2.findMany(FilterGroup.create())\n\t\t\texpect(rows).toHaveLength(2)\n\t\t\texpect(rows.map((r) => r.name).sort()).toEqual(['Alice', 'Bob'])\n\t\t\tawait a2.disconnect()\n\t\t})\n\n\t\ttest('failed session does not persist rolled-back state to disk', async () => {\n\t\t\tconst schema = Schema.from('docs')\n\t\t\t\t.pk('id', v.string(), () => 'd')\n\t\t\t\t.field('val', v.number())\n\t\t\t\t.build()\n\n\t\t\tconst a1 = JsonAdapter.create({ filePath })\n\t\t\tawait a1.connect()\n\t\t\tconst use1 = a1.use(schema, { table: 'docs' })\n\t\t\tawait use1.createOne({ id: 'd1', val: 1 })\n\t\t\tawait a1.disconnect()\n\n\t\t\tconst a2 = JsonAdapter.create({ filePath })\n\t\t\tawait a2.connect()\n\t\t\tconst use2 = a2.use(schema, { table: 'docs' })\n\t\t\tawait expect(\n\t\t\t\ta2.session(async () => {\n\t\t\t\t\tawait use2.updateOne(FilterGroup.create().eq('id', 'd1'), { val: 999 })\n\t\t\t\t\tthrow new Error('rollback')\n\t\t\t\t}),\n\t\t\t).rejects.toThrow('rollback')\n\t\t\tawait a2.disconnect()\n\n\t\t\tconst a3 = JsonAdapter.create({ filePath })\n\t\t\tawait a3.connect()\n\t\t\tconst use3 = a3.use(schema, { table: 'docs' })\n\t\t\tconst row = await use3.findOne(FilterGroup.create().eq('id', 'd1'))\n\t\t\texpect(row?.val).toBe(1)\n\t\t\tawait a3.disconnect()\n\t\t})\n\t})\n\n\tdescribe('json adapter — atomic writes', () => {\n\t\ttest('file is valid JSON after every write', async () => {\n\t\t\tconst { readFile: rf } = await import('node:fs/promises')\n\t\t\tconst schema = Schema.from('items')\n\t\t\t\t.pk('id', v.string(), () => 'i')\n\t\t\t\t.field('val', v.number())\n\t\t\t\t.build()\n\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\t\t\tconst use = adapter.use(schema, { table: 'items' })\n\n\t\t\tfor (let i = 0; i < 10; i++) {\n\t\t\t\tawait use.createOne({ id: `i${i}`, val: i })\n\t\t\t\tconst raw = await rf(filePath, 'utf-8')\n\t\t\t\texpect(() => JSON.parse(raw)).not.toThrow()\n\t\t\t}\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('no .tmp files remain after writes complete', async () => {\n\t\t\tconst { readdir } = await import('node:fs/promises')\n\t\t\tconst schema = Schema.from('items')\n\t\t\t\t.pk('id', v.string(), () => 'i')\n\t\t\t\t.field('val', v.number())\n\t\t\t\t.build()\n\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\t\t\tconst use = adapter.use(schema, { table: 'items' })\n\n\t\t\tfor (let i = 0; i < 5; i++) {\n\t\t\t\tawait use.createOne({ id: `i${i}`, val: i })\n\t\t\t}\n\t\t\tawait adapter.disconnect()\n\n\t\t\tconst files = await readdir(tmpDir)\n\t\t\tconst tmpFiles = files.filter((f) => f.includes('.tmp.'))\n\t\t\texpect(tmpFiles).toHaveLength(0)\n\t\t})\n\t})\n\n\tdescribe('json adapter — aggregate delegation', () => {\n\t\tconst orderSchema = Schema.from('orders')\n\t\t\t.pk('id', v.string(), () => 'o')\n\t\t\t.field('amount', v.number())\n\t\t\t.field('region', v.string())\n\t\t\t.build()\n\n\t\tconst orderSeed = [\n\t\t\t{ id: 'o1', amount: 100, region: 'us' },\n\t\t\t{ id: 'o2', amount: 200, region: 'eu' },\n\t\t\t{ id: 'o3', amount: 150, region: 'us' },\n\t\t]\n\n\t\tasync function makeSeededAdapter() {\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\t\t\tconst use = adapter.use(orderSchema, { table: 'orders' })\n\t\t\tawait use.createMany(orderSeed)\n\t\t\treturn adapter\n\t\t}\n\n\t\ttest('aggregateOps matches in-memory adapter', () => {\n\t\t\tconst json = JsonAdapter.create({ filePath })\n\t\t\tconst inMem = InMemoryAdapter.create({})\n\t\t\texpect(json.aggregateOps).toEqual(inMem.aggregateOps)\n\t\t\texpect(json.aggregateOps).toEqual(['count', 'countDistinct', 'sum', 'avg', 'min', 'max'])\n\t\t})\n\n\t\ttest('count returns identical result to in-memory', async () => {\n\t\t\tconst adapter = await makeSeededAdapter()\n\t\t\tconst result = await adapter.aggregate(orderSchema, { table: 'orders' }, {\n\t\t\t\taggregates: [{ fn: 'count', alias: 'total' }],\n\t\t\t\tgroupBy: [],\n\t\t\t})\n\t\t\texpect(result).toEqual([{ total: 3 }])\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('countDistinct returns identical result to in-memory', async () => {\n\t\t\tconst adapter = await makeSeededAdapter()\n\t\t\tconst result = await adapter.aggregate(orderSchema, { table: 'orders' }, {\n\t\t\t\taggregates: [{ fn: 'countDistinct', field: 'region', alias: 'uniqueRegions' }],\n\t\t\t\tgroupBy: [],\n\t\t\t})\n\t\t\texpect(result).toEqual([{ uniqueRegions: 2 }])\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('sum, avg, min, max return identical results to in-memory', async () => {\n\t\t\tconst adapter = await makeSeededAdapter()\n\t\t\tconst result = await adapter.aggregate(orderSchema, { table: 'orders' }, {\n\t\t\t\taggregates: [\n\t\t\t\t\t{ fn: 'sum', field: 'amount', alias: 'totalAmount' },\n\t\t\t\t\t{ fn: 'avg', field: 'amount', alias: 'avgAmount' },\n\t\t\t\t\t{ fn: 'min', field: 'amount', alias: 'minAmount' },\n\t\t\t\t\t{ fn: 'max', field: 'amount', alias: 'maxAmount' },\n\t\t\t\t],\n\t\t\t\tgroupBy: [],\n\t\t\t})\n\t\t\texpect(result).toEqual([{ totalAmount: 450, avgAmount: 150, minAmount: 100, maxAmount: 200 }])\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('groupBy returns identical results to in-memory', async () => {\n\t\t\tconst adapter = await makeSeededAdapter()\n\t\t\tconst result = await adapter.aggregate(orderSchema, { table: 'orders' }, {\n\t\t\t\taggregates: [\n\t\t\t\t\t{ fn: 'count', alias: 'cnt' },\n\t\t\t\t\t{ fn: 'sum', field: 'amount', alias: 'total' },\n\t\t\t\t],\n\t\t\t\tgroupBy: ['region'],\n\t\t\t})\n\t\t\tconst sorted = result.sort((a, b) => String(a.region).localeCompare(String(b.region)))\n\t\t\texpect(sorted).toEqual([\n\t\t\t\t{ region: 'eu', cnt: 1, total: 200 },\n\t\t\t\t{ region: 'us', cnt: 2, total: 250 },\n\t\t\t])\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('where pre-filter returns identical results to in-memory', async () => {\n\t\t\tconst adapter = await makeSeededAdapter()\n\t\t\tconst result = await adapter.aggregate(orderSchema, { table: 'orders' }, {\n\t\t\t\twhere: FilterGroup.create().gt('amount', 100),\n\t\t\t\taggregates: [{ fn: 'count', alias: 'cnt' }],\n\t\t\t\tgroupBy: [],\n\t\t\t})\n\t\t\texpect(result).toEqual([{ cnt: 2 }])\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('having post-filter returns identical results to in-memory', async () => {\n\t\t\tconst adapter = await makeSeededAdapter()\n\t\t\tconst result = await adapter.aggregate(orderSchema, { table: 'orders' }, {\n\t\t\t\taggregates: [{ fn: 'count', alias: 'cnt' }],\n\t\t\t\tgroupBy: ['region'],\n\t\t\t\thaving: FilterGroup.create().gt('cnt', 1),\n\t\t\t})\n\t\t\texpect(result).toEqual([{ region: 'us', cnt: 2 }])\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('aggregate delegates to same in-memory instance used by CRUD', async () => {\n\t\t\tconst schema = Schema.from('items')\n\t\t\t\t.pk('id', v.string(), () => 'i')\n\t\t\t\t.field('val', v.number())\n\t\t\t\t.build()\n\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\t\t\tconst use = adapter.use(schema, { table: 'items' })\n\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'i1', val: 10 },\n\t\t\t\t{ id: 'i2', val: 20 },\n\t\t\t])\n\n\t\t\tconst spec: AggregateSpec = {\n\t\t\t\taggregates: [{ fn: 'sum', field: 'val', alias: 'total' }],\n\t\t\t\tgroupBy: [],\n\t\t\t}\n\t\t\tconst result = await adapter.aggregate(schema, { table: 'items' }, spec)\n\t\t\texpect(result).toEqual([{ total: 30 }])\n\n\t\t\tawait use.createOne({ id: 'i3', val: 30 })\n\t\t\tconst result2 = await adapter.aggregate(schema, { table: 'items' }, spec)\n\t\t\texpect(result2).toEqual([{ total: 60 }])\n\n\t\t\tawait adapter.disconnect()\n\t\t})\n\t})\n\n\tdescribe('json adapter — concurrent writes serialize', () => {\n\t\ttest('parallel writes from same process all persist', async () => {\n\t\t\tconst schema = Schema.from('items')\n\t\t\t\t.pk('id', v.string(), () => 'i')\n\t\t\t\t.field('val', v.number())\n\t\t\t\t.build()\n\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\t\t\tconst use = adapter.use(schema, { table: 'items' })\n\n\t\t\tawait Promise.all(Array.from({ length: 20 }, (_, i) => use.createOne({ id: `i${i}`, val: i })))\n\n\t\t\tconst rows = await use.findMany(FilterGroup.create())\n\t\t\texpect(rows).toHaveLength(20)\n\t\t\tawait adapter.disconnect()\n\n\t\t\tconst a2 = JsonAdapter.create({ filePath })\n\t\t\tawait a2.connect()\n\t\t\tconst use2 = a2.use(schema, { table: 'items' })\n\t\t\tconst reloaded = await use2.findMany(FilterGroup.create())\n\t\t\texpect(reloaded).toHaveLength(20)\n\t\t\tawait a2.disconnect()\n\t\t})\n\t})\n\n\tdescribe('json adapter — migration storage', () => {\n\t\ttest('recordMigration + loadMigrations round-trip', async () => {\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\n\t\t\tawait adapter.recordMigration('m-001', 1000)\n\t\t\tawait adapter.recordMigration('m-002', 2000)\n\n\t\t\tconst loaded = await adapter.loadMigrations()\n\t\t\texpect(loaded).toHaveLength(2)\n\t\t\texpect(loaded).toEqual([\n\t\t\t\t{ id: 'm-001', appliedAt: 1000 },\n\t\t\t\t{ id: 'm-002', appliedAt: 2000 },\n\t\t\t])\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('migration tracker persists across adapter restarts', async () => {\n\t\t\tconst a1 = JsonAdapter.create({ filePath })\n\t\t\tawait a1.connect()\n\t\t\tawait a1.recordMigration('m-001', 1000)\n\t\t\tawait a1.disconnect()\n\n\t\t\tconst a2 = JsonAdapter.create({ filePath })\n\t\t\tawait a2.connect()\n\t\t\tconst loaded = await a2.loadMigrations()\n\t\t\texpect(loaded).toEqual([{ id: 'm-001', appliedAt: 1000 }])\n\t\t\tawait a2.disconnect()\n\t\t})\n\n\t\ttest('__migrations key in JSON file stores tracker data', async () => {\n\t\t\tconst { readFile: rf } = await import('node:fs/promises')\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\t\t\tawait adapter.recordMigration('m-001', 1000)\n\t\t\tawait adapter.disconnect()\n\n\t\t\tconst raw = JSON.parse(await rf(filePath, 'utf-8'))\n\t\t\texpect(raw['__migrations']).toEqual([{ id: 'm-001', appliedAt: 1000 }])\n\t\t})\n\t})\n\n\tdescribe('json adapter — apply* methods', () => {\n\t\ttest('applyCreateTable persists table metadata', async () => {\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\t\t\tawait adapter.applyCreateTable({\n\t\t\t\tkind: 'createTable',\n\t\t\t\tname: 'users',\n\t\t\t\tpk: { name: 'id', type: 'string' },\n\t\t\t\tfields: [{ name: 'email', type: 'string', unique: true }],\n\t\t\t})\n\t\t\tawait adapter.disconnect()\n\n\t\t\tconst a2 = JsonAdapter.create({ filePath })\n\t\t\tawait a2.connect()\n\t\t\tconst schemas = await a2.introspect()\n\t\t\texpect(schemas).toHaveLength(1)\n\t\t\texpect(schemas[0].name).toBe('users')\n\t\t\texpect(schemas[0].pk).toEqual({ name: 'id', type: 'string' })\n\t\t\texpect(schemas[0].fields).toEqual([{ name: 'email', type: 'string', nullable: false, unique: true }])\n\t\t\tawait a2.disconnect()\n\t\t})\n\n\t\ttest('applyAddIndex and applyDropIndex persist across restarts', async () => {\n\t\t\tconst a1 = JsonAdapter.create({ filePath })\n\t\t\tawait a1.connect()\n\t\t\tawait a1.applyCreateTable({ kind: 'createTable', name: 'users', pk: { name: 'id', type: 'string' }, fields: [] })\n\t\t\tawait a1.applyAddIndex({ kind: 'addIndex', table: 'users', on: ['email'], unique: true })\n\t\t\tawait a1.disconnect()\n\n\t\t\tconst a2 = JsonAdapter.create({ filePath })\n\t\t\tawait a2.connect()\n\t\t\tconst schemas = await a2.introspect()\n\t\t\texpect(schemas[0].indexes).toEqual([{ name: 'users_email_idx', on: ['email'], unique: true }])\n\t\t\tawait a2.applyDropIndex({ kind: 'dropIndex', name: 'users_email_idx' })\n\t\t\tawait a2.disconnect()\n\n\t\t\tconst a3 = JsonAdapter.create({ filePath })\n\t\t\tawait a3.connect()\n\t\t\tconst schemas2 = await a3.introspect()\n\t\t\texpect(schemas2[0].indexes).toEqual([])\n\t\t\tawait a3.disconnect()\n\t\t})\n\n\t\ttest('applyAddForeignKey and applyDropForeignKey persist across restarts', async () => {\n\t\t\tconst a1 = JsonAdapter.create({ filePath })\n\t\t\tawait a1.connect()\n\t\t\tawait a1.applyCreateTable({ kind: 'createTable', name: 'users', pk: { name: 'id', type: 'string' }, fields: [] })\n\t\t\tawait a1.applyCreateTable({ kind: 'createTable', name: 'posts', pk: { name: 'id', type: 'string' }, fields: [] })\n\t\t\tawait a1.applyAddForeignKey({ kind: 'addForeignKey', table: 'posts', on: 'authorId', references: { table: 'users', column: 'id' }, onDelete: 'cascade' })\n\t\t\tawait a1.disconnect()\n\n\t\t\tconst a2 = JsonAdapter.create({ filePath })\n\t\t\tawait a2.connect()\n\t\t\tconst schemas = await a2.introspect()\n\t\t\tconst posts = schemas.find((s) => s.name === 'posts')!\n\t\t\texpect(posts.foreignKeys).toEqual([{\n\t\t\t\tname: 'posts_authorId_fk',\n\t\t\t\ton: 'authorId',\n\t\t\t\treferences: { table: 'users', column: 'id' },\n\t\t\t\tonDelete: 'cascade',\n\t\t\t}])\n\t\t\tawait a2.applyDropForeignKey({ kind: 'dropForeignKey', table: 'posts', name: 'posts_authorId_fk' })\n\t\t\tawait a2.disconnect()\n\n\t\t\tconst a3 = JsonAdapter.create({ filePath })\n\t\t\tawait a3.connect()\n\t\t\tconst schemas2 = await a3.introspect()\n\t\t\tconst posts2 = schemas2.find((s) => s.name === 'posts')!\n\t\t\texpect(posts2.foreignKeys).toEqual([])\n\t\t\tawait a3.disconnect()\n\t\t})\n\t})\n\n\tdescribe('json adapter — acquireMigrationLock', () => {\n\t\ttest('file lock serialises concurrent calls', async () => {\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\n\t\t\tconst order: string[] = []\n\t\t\tlet resolveGate!: () => void\n\t\t\tconst gate = new Promise<void>((r) => { resolveGate = r })\n\n\t\t\tconst p1 = adapter.acquireMigrationLock(async () => {\n\t\t\t\torder.push('p1-start')\n\t\t\t\tawait gate\n\t\t\t\torder.push('p1-end')\n\t\t\t})\n\t\t\tawait new Promise((r) => setTimeout(r, 100))\n\t\t\tconst p2 = adapter.acquireMigrationLock(async () => {\n\t\t\t\torder.push('p2')\n\t\t\t})\n\n\t\t\tawait new Promise((r) => setTimeout(r, 100))\n\t\t\texpect(order).toEqual(['p1-start'])\n\n\t\t\tresolveGate()\n\t\t\tawait Promise.all([p1, p2])\n\t\t\texpect(order).toEqual(['p1-start', 'p1-end', 'p2'])\n\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('lock file is cleaned up after successful execution', async () => {\n\t\t\tconst { access } = await import('node:fs/promises')\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\n\t\t\tawait adapter.acquireMigrationLock(async () => { /* no-op */ })\n\n\t\t\tawait expect(access(filePath + '.lock')).rejects.toThrow()\n\t\t\tawait adapter.disconnect()\n\t\t})\n\n\t\ttest('lock file is cleaned up after failed execution', async () => {\n\t\t\tconst { access } = await import('node:fs/promises')\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\n\t\t\tawait expect(\n\t\t\t\tadapter.acquireMigrationLock(async () => { throw new Error('boom') }),\n\t\t\t).rejects.toThrow('boom')\n\n\t\t\tawait expect(access(filePath + '.lock')).rejects.toThrow()\n\t\t\tawait adapter.disconnect()\n\t\t})\n\t})\n\n\tdescribe('json adapter — end-to-end migrations via Migrator', () => {\n\t\tconst UserSchema = Schema.from('users')\n\t\t\t.pk('id', v.string(), () => `u-${Math.random().toString(36).slice(2)}`)\n\t\t\t.field('email', v.string())\n\t\t\t.build()\n\n\t\tfunction makeEnv() {\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tconst repo = new Repo({ adapter, resolve: (s) => ({ table: s.name }) })\n\t\t\treturn { adapter, repo }\n\t\t}\n\n\t\ttest('end-to-end migration run covering every declarative variant + execute', async () => {\n\t\t\tconst { adapter, repo } = makeEnv()\n\t\t\tawait adapter.connect()\n\n\t\t\tconst migrations: Migration<typeof adapter>[] = [\n\t\t\t\t{\n\t\t\t\t\tid: '0001-create',\n\t\t\t\t\tchanges: [\n\t\t\t\t\t\t{ kind: 'createTable', name: 'users', pk: { name: 'id', type: 'string' }, fields: [{ name: 'email', type: 'string' }] },\n\t\t\t\t\t\t{ kind: 'createTable', name: 'posts', pk: { name: 'id', type: 'string' }, fields: [{ name: 'title', type: 'string' }, { name: 'authorId', type: 'string' }] },\n\t\t\t\t\t\t{ kind: 'addIndex', table: 'users', on: ['email'], unique: true },\n\t\t\t\t\t\t{ kind: 'addForeignKey', table: 'posts', on: 'authorId', references: { table: 'users', column: 'id' } },\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '0002-evolve',\n\t\t\t\t\tchanges: [\n\t\t\t\t\t\t{ kind: 'addField', table: 'users', field: { name: 'age', type: 'number', nullable: true } },\n\t\t\t\t\t\t{ kind: 'modifyField', table: 'users', name: 'email', to: { name: 'email', type: 'string', unique: true, nullable: true } },\n\t\t\t\t\t\t{ kind: 'renameField', table: 'posts', from: 'title', to: 'headline' },\n\t\t\t\t\t\t{ kind: 'renameTable', from: 'posts', to: 'articles' },\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '0003-cleanup',\n\t\t\t\t\tchanges: [\n\t\t\t\t\t\t{ kind: 'dropField', table: 'users', name: 'age' },\n\t\t\t\t\t\t{ kind: 'dropForeignKey', table: 'posts', name: 'posts_authorId_fk' },\n\t\t\t\t\t\t{ kind: 'dropIndex', name: 'users_email_idx' },\n\t\t\t\t\t\t{ kind: 'dropTable', name: 'articles' },\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '0004-seed',\n\t\t\t\t\tchanges: [{\n\t\t\t\t\t\tkind: 'execute',\n\t\t\t\t\t\tup: async (r) => {\n\t\t\t\t\t\t\tawait r.on(UserSchema).one().create({ id: 'seed-1', email: 'test@example.com' })\n\t\t\t\t\t\t},\n\t\t\t\t\t}],\n\t\t\t\t},\n\t\t\t]\n\n\t\t\tconst migrator = Migrator.from(repo, adapter).migrations(migrations).build()\n\t\t\tconst result = await migrator.up()\n\t\t\texpect(result.ran).toEqual(['0001-create', '0002-evolve', '0003-cleanup', '0004-seed'])\n\n\t\t\tconst recorded = await adapter.loadMigrations()\n\t\t\texpect(recorded).toHaveLength(4)\n\n\t\t\tconst row = await repo.on(UserSchema).one().id('seed-1').find()\n\t\t\texpect(row).not.toBeNull()\n\t\t\texpect(row!.email).toBe('test@example.com')\n\n\t\t\t// Verify via re-reading the file\n\t\t\tawait adapter.disconnect()\n\t\t\tconst { adapter: a2, repo: r2 } = makeEnv()\n\t\t\tawait a2.connect()\n\t\t\tconst recorded2 = await a2.loadMigrations()\n\t\t\texpect(recorded2).toHaveLength(4)\n\n\t\t\tconst row2 = await r2.on(UserSchema).one().id('seed-1').find()\n\t\t\texpect(row2!.email).toBe('test@example.com')\n\t\t\tawait a2.disconnect()\n\t\t})\n\n\t\ttest('file lock serialises concurrent migrator.up() runs', async () => {\n\t\t\tconst order: string[] = []\n\t\t\tlet resolveGate!: () => void\n\t\t\tconst gate = new Promise<void>((r) => { resolveGate = r })\n\n\t\t\tconst migrations: Migration<JsonAdapter>[] = [\n\t\t\t\t{\n\t\t\t\t\tid: '0001',\n\t\t\t\t\tchanges: [{\n\t\t\t\t\t\tkind: 'execute',\n\t\t\t\t\t\tup: async () => {\n\t\t\t\t\t\t\torder.push('0001-start')\n\t\t\t\t\t\t\tawait gate\n\t\t\t\t\t\t\torder.push('0001-end')\n\t\t\t\t\t\t},\n\t\t\t\t\t}],\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '0002',\n\t\t\t\t\tchanges: [{ kind: 'execute', up: async () => { order.push('0002') } }],\n\t\t\t\t},\n\t\t\t]\n\n\t\t\tconst adapter1 = JsonAdapter.create({ filePath })\n\t\t\tawait adapter1.connect()\n\t\t\tconst repo1 = new Repo({ adapter: adapter1, resolve: (s) => ({ table: s.name }) })\n\t\t\tconst migrator1 = Migrator.from(repo1, adapter1).migrations(migrations).build()\n\n\t\t\tconst adapter2 = JsonAdapter.create({ filePath })\n\t\t\tawait adapter2.connect()\n\t\t\tconst repo2 = new Repo({ adapter: adapter2, resolve: (s) => ({ table: s.name }) })\n\t\t\tconst migrator2 = Migrator.from(repo2, adapter2).migrations(migrations).build()\n\n\t\t\tconst p1 = migrator1.up()\n\t\t\tconst p2 = migrator2.up()\n\n\t\t\tawait new Promise((r) => setTimeout(r, 200))\n\t\t\texpect(order).toEqual(['0001-start'])\n\n\t\t\tresolveGate()\n\t\t\tawait Promise.all([p1, p2])\n\n\t\t\texpect(order).toEqual(['0001-start', '0001-end', '0002'])\n\n\t\t\tawait adapter1.disconnect()\n\t\t\tawait adapter2.disconnect()\n\t\t})\n\n\t\ttest('tx:true rollback leaves file unchanged on failure', async () => {\n\t\t\tconst { adapter } = makeEnv()\n\t\t\tawait adapter.connect()\n\n\t\t\tawait adapter.applyCreateTable({ kind: 'createTable', name: 'users', pk: { name: 'id', type: 'string' }, fields: [] })\n\t\t\tawait adapter.disconnect()\n\n\t\t\tconst { adapter: a2, repo: r2 } = makeEnv()\n\t\t\tawait a2.connect()\n\n\t\t\tconst m: Migration<typeof a2> = {\n\t\t\t\tid: '0001-will-fail',\n\t\t\t\tchanges: [\n\t\t\t\t\t{ kind: 'addIndex', table: 'users', on: ['email'] },\n\t\t\t\t\t{\n\t\t\t\t\t\tkind: 'execute',\n\t\t\t\t\t\tup: async (r) => {\n\t\t\t\t\t\t\tawait r.on(UserSchema).one().create({ id: 'partial', email: 'fail@test.com' })\n\t\t\t\t\t\t\tthrow new Error('mid-migration boom')\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t}\n\t\t\tconst migrator = Migrator.from(r2, a2).migrations([m]).build()\n\t\t\tawait expect(migrator.up()).rejects.toThrow(OrmMigrationError)\n\t\t\tawait a2.disconnect()\n\n\t\t\tconst { adapter: a3, repo: r3 } = makeEnv()\n\t\t\tawait a3.connect()\n\t\t\tconst recorded = await a3.loadMigrations()\n\t\t\texpect(recorded).toHaveLength(0)\n\t\t\tconst schemas = await a3.introspect()\n\t\t\tconst users = schemas.find((s) => s.name === 'users')!\n\t\t\texpect(users.indexes).toEqual([])\n\t\t\tconst row = await r3.on(UserSchema).one().id('partial').find()\n\t\t\texpect(row).toBeNull()\n\t\t\tawait a3.disconnect()\n\t\t})\n\n\t\ttest('introspect() round-trip: apply* then introspect returns matching descriptors', async () => {\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\n\t\t\tawait adapter.applyCreateTable({\n\t\t\t\tkind: 'createTable',\n\t\t\t\tname: 'users',\n\t\t\t\tpk: { name: 'id', type: 'string' },\n\t\t\t\tfields: [\n\t\t\t\t\t{ name: 'email', type: 'string', unique: true },\n\t\t\t\t\t{ name: 'age', type: 'number', nullable: true },\n\t\t\t\t],\n\t\t\t})\n\t\t\tawait adapter.applyAddIndex({ kind: 'addIndex', table: 'users', on: ['email'], unique: true })\n\t\t\tawait adapter.applyCreateTable({\n\t\t\t\tkind: 'createTable',\n\t\t\t\tname: 'posts',\n\t\t\t\tpk: { name: 'id', type: 'string' },\n\t\t\t\tfields: [{ name: 'authorId', type: 'string' }],\n\t\t\t})\n\t\t\tawait adapter.applyAddForeignKey({\n\t\t\t\tkind: 'addForeignKey',\n\t\t\t\ttable: 'posts',\n\t\t\t\ton: 'authorId',\n\t\t\t\treferences: { table: 'users', column: 'id' },\n\t\t\t\tonDelete: 'cascade',\n\t\t\t})\n\t\t\tawait adapter.disconnect()\n\n\t\t\tconst a2 = JsonAdapter.create({ filePath })\n\t\t\tawait a2.connect()\n\t\t\tconst schemas = await a2.introspect()\n\n\t\t\tconst users = schemas.find((s) => s.name === 'users')!\n\t\t\texpect(users.pk).toEqual({ name: 'id', type: 'string' })\n\t\t\texpect(users.fields).toEqual([\n\t\t\t\t{ name: 'email', type: 'string', nullable: false, unique: true },\n\t\t\t\t{ name: 'age', type: 'number', nullable: true },\n\t\t\t])\n\t\t\texpect(users.indexes).toEqual([{ name: 'users_email_idx', on: ['email'], unique: true }])\n\n\t\t\tconst posts = schemas.find((s) => s.name === 'posts')!\n\t\t\texpect(posts.pk).toEqual({ name: 'id', type: 'string' })\n\t\t\texpect(posts.fields).toEqual([{ name: 'authorId', type: 'string', nullable: false }])\n\t\t\texpect(posts.foreignKeys).toEqual([{\n\t\t\t\tname: 'posts_authorId_fk',\n\t\t\t\ton: 'authorId',\n\t\t\t\treferences: { table: 'users', column: 'id' },\n\t\t\t\tonDelete: 'cascade',\n\t\t\t}])\n\n\t\t\tawait a2.disconnect()\n\t\t})\n\n\t\ttest('metadata keys do not leak into data stores', async () => {\n\t\t\tconst adapter = JsonAdapter.create({ filePath })\n\t\t\tawait adapter.connect()\n\t\t\tawait adapter.recordMigration('m-001', 1000)\n\t\t\tawait adapter.applyCreateTable({ kind: 'createTable', name: 'users', pk: { name: 'id', type: 'string' }, fields: [] })\n\n\t\t\texpect(adapter.stores.has('__migrations')).toBe(false)\n\t\t\texpect(adapter.stores.has('__tables')).toBe(false)\n\t\t\tawait adapter.disconnect()\n\n\t\t\tconst a2 = JsonAdapter.create({ filePath })\n\t\t\tawait a2.connect()\n\t\t\texpect(a2.stores.has('__migrations')).toBe(false)\n\t\t\texpect(a2.stores.has('__tables')).toBe(false)\n\t\t\tawait a2.disconnect()\n\t\t})\n\t})\n}\n","import { v, type ConditionalObjectKeys, type Pipe, type PipeInput, type PipeOutput } from 'valleyed'\n\ntype CtorParams<T> = ConstructorParameters<T & (abstract new (...args: any[]) => any)>\ntype BaseCtorParams<T> = T extends abstract new (...args: infer A) => any ? A : never\n\nexport function configurable<P extends Pipe<any, any>, Base extends abstract new (...args: any[]) => any>(pipeFn: () => P, base: Base) {\n\tconst pipe = pipeFn()\n\tv.compile(pipe)\n\n\tabstract class Configurable extends (base as unknown as new (...args: any[]) => any) {\n\t\tdeclare static readonly Config: PipeOutput<P>\n\n\t\tprotected constructor (protected readonly config: PipeOutput<P>, ...baseArgs: BaseCtorParams<Base>) {\n\t\t\t// eslint-disable-next-line constructor-super\n\t\t\tsuper(...baseArgs)\n\t\t}\n\n\t\tstatic create<This extends Function & { prototype: any }>(\n\t\t\tthis: This,\n\t\t\tinput: ConditionalObjectKeys<PipeInput<P>>,\n\t\t\t...args: CtorParams<This> extends [PipeOutput<P>, ...infer R] ? R : never\n\t\t): This['prototype'] {\n\t\t\tconst r = v.validate(pipe, input)\n\t\t\tif (!r.valid) throw r.error\n\t\t\treturn new (this as any)(r.value, ...args) as This['prototype']\n\t\t}\n\t}\n\n\treturn Configurable as unknown as (abstract new (validated: PipeOutput<P>, ...baseArgs: BaseCtorParams<Base>) => InstanceType<Base> & { readonly config: PipeOutput<P> }) & {\n\t\treadonly Config: PipeOutput<P>\n\t\tcreate<This extends Function & { prototype: any }>(\n\t\t\tthis: This,\n\t\t\tinput: ConditionalObjectKeys<PipeInput<P>>,\n\t\t\t...args: CtorParams<This> extends [PipeOutput<P>, ...infer R] ? R : never\n\t\t): This['prototype']\n\t}\n}\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect, expectTypeOf } = import.meta.vitest\n\tconst { v } = await import('valleyed')\n\n\tconst testPipe = () =>\n\t\tv.object({\n\t\t\thost: v.string(),\n\t\t\tport: v.number(),\n\t\t})\n\n\ttype TestConfig = PipeOutput<ReturnType<typeof testPipe>>\n\n\tclass TestBase {\n\t\tbaseValue: string\n\t\tconstructor() {\n\t\t\tthis.baseValue = 'base'\n\t\t}\n\t}\n\n\tclass TestBaseWithArgs {\n\t\tlabel: string\n\t\tconstructor(label: string) {\n\t\t\tthis.label = label\n\t\t}\n\t}\n\n\tdescribe('configurable', () => {\n\t\ttest('validation runs in static create before constructor body executes', () => {\n\t\t\tlet constructorRan = false\n\n\t\t\tconst Wrapped = configurable(testPipe, TestBase)\n\t\t\tclass MyClass extends Wrapped {\n\t\t\t\tprotected constructor(config: typeof MyClass.Config) {\n\t\t\t\t\tsuper(config)\n\t\t\t\t\tconstructorRan = true\n\t\t\t\t}\n\t\t\t}\n\n\t\t\texpect(() => MyClass.create({ host: 123, port: 'bad' } as any)).toThrow()\n\t\t\texpect(constructorRan).toBe(false)\n\n\t\t\tMyClass.create({ host: 'localhost', port: 3000 })\n\t\t\texpect(constructorRan).toBe(true)\n\t\t})\n\n\t\ttest('constructor receives validated value', () => {\n\t\t\tconst Wrapped = configurable(testPipe, TestBase)\n\t\t\tlet receivedConfig: unknown\n\n\t\t\tclass MyClass extends Wrapped {\n\t\t\t\tprotected constructor(config: typeof MyClass.Config) {\n\t\t\t\t\tsuper(config)\n\t\t\t\t\treceivedConfig = this.config\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tMyClass.create({ host: 'localhost', port: 3000 })\n\n\t\t\texpect(receivedConfig).toEqual({ host: 'localhost', port: 3000 })\n\t\t})\n\n\t\ttest('external new is a compile error', () => {\n\t\t\tconst Wrapped = configurable(testPipe, TestBase)\n\t\t\tclass MyClass extends Wrapped {\n\t\t\t\tprotected constructor(config: typeof MyClass.Config) {\n\t\t\t\t\tsuper(config)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// @ts-expect-error — external `new` on a class with protected constructor is a compile error\n\t\t\tvoid (() => new MyClass({ host: 'localhost', port: 3000 }))\n\t\t})\n\n\t\ttest('static Config resolves to PipeOutput<P> at the type level', () => {\n\t\t\tconst Wrapped = configurable(testPipe, TestBase)\n\t\t\tclass MyClass extends Wrapped {\n\t\t\t\tprotected constructor(config: typeof MyClass.Config) {\n\t\t\t\t\tsuper(config)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\texpectTypeOf<typeof MyClass.Config>().toEqualTypeOf<TestConfig>()\n\t\t\texpect(MyClass.create).toBeTypeOf('function')\n\t\t})\n\n\t\ttest('ConstructorParameters<This>-based extras inference works for non-zero-arg leaf signatures', () => {\n\t\t\tconst Wrapped = configurable(testPipe, TestBase)\n\t\t\tclass MyClass extends Wrapped {\n\t\t\t\textra: number\n\t\t\t\tprotected constructor(config: typeof MyClass.Config, extra: number) {\n\t\t\t\t\tsuper(config)\n\t\t\t\t\tthis.extra = extra\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst instance = MyClass.create({ host: 'localhost', port: 3000 }, 42)\n\n\t\t\texpect(instance.extra).toBe(42)\n\t\t\texpectTypeOf(instance).toHaveProperty('extra')\n\t\t\texpectTypeOf(instance.extra).toEqualTypeOf<number>()\n\n\t\t\t// @ts-expect-error — wrong extra type\n\t\t\tvoid (() => MyClass.create({ host: 'localhost', port: 3000 }, 'not-a-number'))\n\t\t})\n\n\t\ttest('base-args forwarding works for non-zero-arg bases', () => {\n\t\t\tconst Wrapped = configurable(testPipe, TestBaseWithArgs)\n\t\t\tclass MyClass extends Wrapped {\n\t\t\t\tprotected constructor(config: typeof MyClass.Config, label: string) {\n\t\t\t\t\tsuper(config, label)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst instance = MyClass.create({ host: 'localhost', port: 3000 }, 'test-label')\n\n\t\t\texpect(instance.label).toBe('test-label')\n\t\t})\n\n\t\ttest('config is accessible as protected readonly on instances', () => {\n\t\t\tconst Wrapped = configurable(testPipe, TestBase)\n\t\t\tclass MyClass extends Wrapped {\n\t\t\t\tprotected constructor(config: typeof MyClass.Config) {\n\t\t\t\t\tsuper(config)\n\t\t\t\t}\n\n\t\t\t\tgetHost() {\n\t\t\t\t\treturn this.config.host\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst instance = MyClass.create({ host: 'localhost', port: 3000 })\n\t\t\texpect(instance.getHost()).toBe('localhost')\n\t\t})\n\n\t\ttest('accepts an abstract base class', () => {\n\t\t\tabstract class AbstractBase {\n\t\t\t\tabstract greet(): string\n\t\t\t}\n\n\t\t\tconst Wrapped = configurable(testPipe, AbstractBase)\n\t\t\tclass Concrete extends Wrapped {\n\t\t\t\tprotected constructor(config: typeof Concrete.Config) {\n\t\t\t\t\tsuper(config)\n\t\t\t\t}\n\t\t\t\tgreet() {\n\t\t\t\t\treturn `hello from ${this.config.host}`\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst instance = Concrete.create({ host: 'localhost', port: 3000 })\n\t\t\texpect(instance.greet()).toBe('hello from localhost')\n\t\t\texpectTypeOf(instance).toHaveProperty('config')\n\t\t})\n\t})\n}\n","export class EquippedError extends Error {\n\tconstructor(\n\t\tpublic readonly message: string,\n\t\tpublic readonly context: Record<string, unknown>,\n\t\tpublic readonly cause?: unknown,\n\t) {\n\t\tsuper(message, { cause })\n\t}\n}\n","import pino, { type Logger } from 'pino'\nimport { ulid } from 'ulid'\nimport { type Pipe, v } from 'valleyed'\n\nimport { EquippedError } from '../errors'\nimport { type ClassRef, type HookCb, type HookEvent, type HookOptions, type HookRecord, registerHook, runHooks } from './hooks'\nimport { instanceSettingsPipe, type Settings, type SettingsInput } from './settings'\n\nexport type { ClassRef, HookCb, HookEvent, HookOptions }\n\nexport class Instance {\n\tstatic #id: string | undefined\n\tstatic #instance: Instance | undefined\n\tstatic #hooks: Partial<Record<HookEvent, HookRecord[]>> = {}\n\treadonly settings: Readonly<Settings>\n\treadonly log: Logger<never>\n\n\tprivate constructor(settings: Settings) {\n\t\tInstance.#instance = this\n\t\tthis.settings = Object.freeze(settings)\n\t\tthis.log = pino<never>({\n\t\t\tlevel: this.settings.log.level,\n\t\t\tserializers: {\n\t\t\t\terr: pino.stdSerializers.err,\n\t\t\t\terror: pino.stdSerializers.err,\n\t\t\t\treq: pino.stdSerializers.req,\n\t\t\t\tres: pino.stdSerializers.res,\n\t\t\t},\n\t\t\tmixin: () => ({\n\t\t\t\tinstanceId: Instance.#id,\n\t\t\t}),\n\t\t})\n\t\tInstance.#registerOnExitHandler()\n\t}\n\n\talias(id: string) {\n\t\tif (Instance.#id !== undefined) return Instance.crash(new EquippedError('Instance already has an alias', {}))\n\t\tInstance.#id = id\n\t}\n\n\tget id() {\n\t\tif (Instance.#id === undefined) return Instance.crash(new EquippedError('Instance doesnt have an alias yet', {}))\n\t\treturn Instance.#id\n\t}\n\n\tgetScopedName(name: string, key = '.') {\n\t\treturn [this.settings.app.name, name].join(key)\n\t}\n\n\tasync start() {\n\t\ttry {\n\t\t\tawait runHooks(Instance.#hooks['setup'] ?? [])\n\t\t\tawait runHooks(Instance.#hooks['start'] ?? [])\n\t\t} catch (error) {\n\t\t\tInstance.crash(new EquippedError(`Error starting instance`, {}, error))\n\t\t}\n\t}\n\n\tstatic envs<E extends object>(envsPipe: Pipe<unknown, E>): E {\n\t\tconst envValidity = v.validate(envsPipe, process.env)\n\t\tif (!envValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Environment variables are not valid\\n${envValidity.error.toString()}`, {\n\t\t\t\t\tmessages: envValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn envValidity.value\n\t}\n\n\tstatic create(settings: SettingsInput) {\n\t\tif (Instance.#instance) return Instance.crash(new EquippedError('Instance has been initialized already', {}))\n\t\tconst settingsValidity = v.validate(instanceSettingsPipe(), settings)\n\t\tif (!settingsValidity.valid) {\n\t\t\tInstance.crash(\n\t\t\t\tnew EquippedError(`Settings are not valid\\n${settingsValidity.error.toString()}`, {\n\t\t\t\t\tmessages: settingsValidity.error.messages,\n\t\t\t\t}),\n\t\t\t)\n\t\t}\n\t\treturn new Instance(settingsValidity.value)\n\t}\n\n\tstatic get() {\n\t\tif (!Instance.#instance)\n\t\t\treturn Instance.crash(\n\t\t\t\tnew EquippedError('Has not been initialized. Make sure an instance has been created before you get an instance', {}),\n\t\t\t)\n\t\treturn Instance.#instance\n\t}\n\n\tstatic maybeGet() {\n\t\treturn Instance.#instance\n\t}\n\n\tstatic on(event: HookEvent, cb: HookCb, options?: HookOptions) {\n\t\tInstance.#hooks[event] ??= []\n\t\tconst record: HookRecord = { cb, class: options?.class, after: options?.after ?? [] }\n\t\tregisterHook(Instance.#hooks[event], record)\n\t}\n\n\tstatic #registerOnExitHandler() {\n\t\tconst signals = {\n\t\t\tSIGHUP: 1,\n\t\t\tSIGINT: 2,\n\t\t\tSIGTERM: 15,\n\t\t}\n\n\t\tObject.entries(signals).forEach(([signal, code]) => {\n\t\t\tprocess.on(signal, async () => {\n\t\t\t\tawait runHooks(Instance.#hooks['close'] ?? [], () => {}, true)\n\t\t\t\tprocess.exit(128 + code)\n\t\t\t})\n\t\t})\n\t}\n\n\tstatic resolveBeforeCrash<T>(cb: () => Promise<T>) {\n\t\tconst value = cb()\n\t\tInstance.on('close', async () => await value)\n\t\treturn value\n\t}\n\n\tstatic crash(error: EquippedError): never {\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.error(error)\n\t\tprocess.exit(1)\n\t}\n\n\tstatic createId(opts?: { prefix?: string; time?: Date }) {\n\t\treturn `${opts?.prefix ?? ''}${ulid(opts?.time?.getTime())}`\n\t}\n}\n","export type HookEvent = 'setup' | 'start' | 'close'\nexport type HookCb = Promise<unknown | void> | (() => void | unknown | Promise<void | unknown>)\n\nexport type ClassRef = Function & { prototype: unknown; name: string }\nexport type HookOptions = {\n\tclass?: ClassRef\n\tafter?: ClassRef[]\n}\nexport type HookRecord = { cb: HookCb; class?: ClassRef; after: ClassRef[] }\n\nexport function registerHook(hooks: HookRecord[], record: HookRecord): void {\n\tfor (const dep of record.after) {\n\t\tif (!hooks.some((h) => h.class === dep)) {\n\t\t\tconst depName = dep.name || 'unknown'\n\t\t\tconst ownerName = record.class?.name || 'anonymous'\n\t\t\tthrow new Error(`Missing dependency: ${ownerName} declares after: [${depName}], but ${depName} is not registered`)\n\t\t}\n\t}\n\n\tif (record.class) {\n\t\tconst tentative = [...hooks, record]\n\t\tdetectCycle(tentative)\n\t}\n\n\thooks.push(record)\n}\n\nfunction detectCycle(hooks: HookRecord[]): void {\n\tconst classToAfter = new Map<ClassRef, ClassRef[]>()\n\tfor (const h of hooks) {\n\t\tif (!h.class) continue\n\t\tconst existing = classToAfter.get(h.class)\n\t\tif (existing) {\n\t\t\tfor (const dep of h.after) {\n\t\t\t\tif (!existing.includes(dep)) existing.push(dep)\n\t\t\t}\n\t\t} else {\n\t\t\tclassToAfter.set(h.class, [...h.after])\n\t\t}\n\t}\n\n\tconst visited = new Set<ClassRef>()\n\tconst stack = new Set<ClassRef>()\n\n\tfunction visit(cls: ClassRef, path: ClassRef[]): void {\n\t\tif (stack.has(cls)) {\n\t\t\tconst cycleStart = path.indexOf(cls)\n\t\t\tconst cycle = [...path.slice(cycleStart), cls]\n\t\t\tconst names = cycle.map((c) => c.name || 'unknown')\n\t\t\tthrow new Error(`Cycle detected: ${names.join(' → ')}`)\n\t\t}\n\t\tif (visited.has(cls)) return\n\t\tstack.add(cls)\n\t\tpath.push(cls)\n\t\tfor (const dep of classToAfter.get(cls) ?? []) {\n\t\t\tvisit(dep, path)\n\t\t}\n\t\tpath.pop()\n\t\tstack.delete(cls)\n\t\tvisited.add(cls)\n\t}\n\n\tfor (const cls of classToAfter.keys()) {\n\t\tvisit(cls, [])\n\t}\n}\n\nexport type HookLayer = HookRecord[]\n\nexport function resolveHookDAG(hooks: HookRecord[], invert: boolean = false): HookLayer[] {\n\tif (hooks.length === 0) return []\n\n\tconst classToHooks = new Map<ClassRef, HookRecord[]>()\n\tconst anonymous: HookRecord[] = []\n\n\tfor (const h of hooks) {\n\t\tif (h.class) {\n\t\t\tconst list = classToHooks.get(h.class)\n\t\t\tif (list) list.push(h)\n\t\t\telse classToHooks.set(h.class, [h])\n\t\t} else {\n\t\t\tanonymous.push(h)\n\t\t}\n\t}\n\n\tconst classes = [...classToHooks.keys()]\n\n\tconst inDegree = new Map<ClassRef, number>()\n\tconst graph = new Map<ClassRef, ClassRef[]>()\n\n\tfor (const cls of classes) {\n\t\tinDegree.set(cls, 0)\n\t\tgraph.set(cls, [])\n\t}\n\n\tfor (const h of hooks) {\n\t\tif (!h.class) continue\n\t\tfor (const dep of h.after) {\n\t\t\tconst [from, to] = invert ? [h.class, dep] : [dep, h.class]\n\t\t\tconst edges = graph.get(from)!\n\t\t\tif (!edges.includes(to)) {\n\t\t\t\tedges.push(to)\n\t\t\t\tinDegree.set(to, inDegree.get(to)! + 1)\n\t\t\t}\n\t\t}\n\t}\n\n\tconst layers: HookLayer[] = []\n\tlet queue = classes.filter((c) => inDegree.get(c) === 0)\n\n\twhile (queue.length > 0) {\n\t\tconst layer: HookRecord[] = []\n\t\tconst next: ClassRef[] = []\n\n\t\tfor (const cls of queue) {\n\t\t\tlayer.push(...(classToHooks.get(cls) ?? []))\n\t\t}\n\t\tlayers.push(layer)\n\n\t\tfor (const cls of queue) {\n\t\t\tfor (const neighbor of graph.get(cls) ?? []) {\n\t\t\t\tconst d = inDegree.get(neighbor)! - 1\n\t\t\t\tinDegree.set(neighbor, d)\n\t\t\t\tif (d === 0) next.push(neighbor)\n\t\t\t}\n\t\t}\n\n\t\tqueue = next\n\t}\n\n\tif (anonymous.length > 0) {\n\t\tconst anonWithDeps = anonymous.filter((h) => h.after.length > 0)\n\t\tconst anonWithoutDeps = anonymous.filter((h) => h.after.length === 0)\n\n\t\tif (anonWithDeps.length > 0) {\n\t\t\tlet maxLayer = -1\n\t\t\tfor (const h of anonWithDeps) {\n\t\t\t\tfor (const dep of h.after) {\n\t\t\t\t\tconst depLayer = layers.findIndex((l) => l.some((r) => r.class === dep))\n\t\t\t\t\tif (depLayer > maxLayer) maxLayer = depLayer\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst insertAt = maxLayer + 1\n\t\t\tif (insertAt < layers.length) {\n\t\t\t\tlayers[insertAt].push(...anonWithDeps)\n\t\t\t} else {\n\t\t\t\tlayers.push(anonWithDeps)\n\t\t\t}\n\t\t}\n\n\t\tif (anonWithoutDeps.length > 0) {\n\t\t\tif (layers.length > 0) {\n\t\t\t\tlayers[layers.length - 1].push(...anonWithoutDeps)\n\t\t\t} else {\n\t\t\t\tlayers.push(anonWithoutDeps)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn layers\n}\n\nexport async function runHooks(\n\thooks: HookRecord[],\n\tonError: (error: Error) => void = (error) => {\n\t\tthrow error\n\t},\n\tinvert: boolean = false,\n) {\n\tconst layers = resolveHookDAG(hooks, invert)\n\tfor (const layer of layers)\n\t\tawait Promise.all(\n\t\t\tlayer.map(async (h) => {\n\t\t\t\ttry {\n\t\t\t\t\tif (typeof h.cb === 'function') return await h.cb()\n\t\t\t\t\treturn await h.cb\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn onError(error instanceof Error ? error : new Error(`${error}`))\n\t\t\t\t}\n\t\t\t}),\n\t\t)\n}\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect } = import.meta.vitest\n\n\tclass A {}\n\tclass B {}\n\tclass C {}\n\tclass D {}\n\n\tconst noop = () => {}\n\n\tdescribe('registerHook', () => {\n\t\ttest('registers a hook with no dependencies', () => {\n\t\t\tconst hooks: HookRecord[] = []\n\t\t\tregisterHook(hooks, { cb: noop, class: A, after: [] })\n\t\t\texpect(hooks).toHaveLength(1)\n\t\t})\n\n\t\ttest('throws on missing dependency', () => {\n\t\t\tconst hooks: HookRecord[] = []\n\t\t\texpect(() => registerHook(hooks, { cb: noop, class: B, after: [A] })).toThrow(/Missing dependency.*B.*A/)\n\t\t})\n\n\t\ttest('throws on cycle: A→B→A', () => {\n\t\t\tconst hooks: HookRecord[] = []\n\t\t\tregisterHook(hooks, { cb: noop, class: A, after: [] })\n\t\t\tregisterHook(hooks, { cb: noop, class: B, after: [A] })\n\t\t\texpect(() => registerHook(hooks, { cb: noop, class: A, after: [B] })).toThrow(/Cycle detected/)\n\t\t})\n\n\t\ttest('throws on transitive cycle: A→B→C→A', () => {\n\t\t\tconst hooks: HookRecord[] = []\n\t\t\tregisterHook(hooks, { cb: noop, class: A, after: [] })\n\t\t\tregisterHook(hooks, { cb: noop, class: B, after: [A] })\n\t\t\tregisterHook(hooks, { cb: noop, class: C, after: [B] })\n\t\t\texpect(() => registerHook(hooks, { cb: noop, class: A, after: [C] })).toThrow(/Cycle detected/)\n\t\t})\n\n\t\ttest('allows anonymous hooks with dependencies', () => {\n\t\t\tconst hooks: HookRecord[] = []\n\t\t\tregisterHook(hooks, { cb: noop, class: A, after: [] })\n\t\t\tregisterHook(hooks, { cb: noop, after: [A] })\n\t\t\texpect(hooks).toHaveLength(2)\n\t\t})\n\n\t\ttest('anonymous hook throws on missing dependency', () => {\n\t\t\tconst hooks: HookRecord[] = []\n\t\t\texpect(() => registerHook(hooks, { cb: noop, after: [A] })).toThrow(/Missing dependency.*anonymous.*A/)\n\t\t})\n\t})\n\n\tdescribe('resolveHookDAG', () => {\n\t\ttest('linear chain: A → B → C', () => {\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{ cb: noop, class: A, after: [] },\n\t\t\t\t{ cb: noop, class: B, after: [A] },\n\t\t\t\t{ cb: noop, class: C, after: [B] },\n\t\t\t]\n\t\t\tconst layers = resolveHookDAG(hooks)\n\t\t\texpect(layers).toHaveLength(3)\n\t\t\texpect(layers[0].every((h) => h.class === A)).toBe(true)\n\t\t\texpect(layers[1].every((h) => h.class === B)).toBe(true)\n\t\t\texpect(layers[2].every((h) => h.class === C)).toBe(true)\n\t\t})\n\n\t\ttest('fan-out: A → B, A → C (B and C are parallel)', () => {\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{ cb: noop, class: A, after: [] },\n\t\t\t\t{ cb: noop, class: B, after: [A] },\n\t\t\t\t{ cb: noop, class: C, after: [A] },\n\t\t\t]\n\t\t\tconst layers = resolveHookDAG(hooks)\n\t\t\texpect(layers).toHaveLength(2)\n\t\t\texpect(layers[0].every((h) => h.class === A)).toBe(true)\n\t\t\tconst secondClasses = layers[1].map((h) => h.class)\n\t\t\texpect(secondClasses).toContain(B)\n\t\t\texpect(secondClasses).toContain(C)\n\t\t})\n\n\t\ttest('fan-in: B → D, C → D', () => {\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{ cb: noop, class: B, after: [] },\n\t\t\t\t{ cb: noop, class: C, after: [] },\n\t\t\t\t{ cb: noop, class: D, after: [B, C] },\n\t\t\t]\n\t\t\tconst layers = resolveHookDAG(hooks)\n\t\t\texpect(layers).toHaveLength(2)\n\t\t\tconst firstClasses = layers[0].map((h) => h.class)\n\t\t\texpect(firstClasses).toContain(B)\n\t\t\texpect(firstClasses).toContain(C)\n\t\t\texpect(layers[1].every((h) => h.class === D)).toBe(true)\n\t\t})\n\n\t\ttest('diamond: A → B, A → C, B → D, C → D', () => {\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{ cb: noop, class: A, after: [] },\n\t\t\t\t{ cb: noop, class: B, after: [A] },\n\t\t\t\t{ cb: noop, class: C, after: [A] },\n\t\t\t\t{ cb: noop, class: D, after: [B, C] },\n\t\t\t]\n\t\t\tconst layers = resolveHookDAG(hooks)\n\t\t\texpect(layers).toHaveLength(3)\n\t\t\texpect(layers[0][0].class).toBe(A)\n\t\t\tconst midClasses = layers[1].map((h) => h.class)\n\t\t\texpect(midClasses).toContain(B)\n\t\t\texpect(midClasses).toContain(C)\n\t\t\texpect(layers[2][0].class).toBe(D)\n\t\t})\n\n\t\ttest('close-event inversion reverses the graph', () => {\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{ cb: noop, class: A, after: [] },\n\t\t\t\t{ cb: noop, class: B, after: [A] },\n\t\t\t\t{ cb: noop, class: C, after: [B] },\n\t\t\t]\n\t\t\tconst layers = resolveHookDAG(hooks, true)\n\t\t\texpect(layers).toHaveLength(3)\n\t\t\texpect(layers[0].every((h) => h.class === C)).toBe(true)\n\t\t\texpect(layers[1].every((h) => h.class === B)).toBe(true)\n\t\t\texpect(layers[2].every((h) => h.class === A)).toBe(true)\n\t\t})\n\n\t\ttest('close inversion: fan-out becomes fan-in', () => {\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{ cb: noop, class: A, after: [] },\n\t\t\t\t{ cb: noop, class: B, after: [A] },\n\t\t\t\t{ cb: noop, class: C, after: [A] },\n\t\t\t]\n\t\t\tconst layers = resolveHookDAG(hooks, true)\n\t\t\texpect(layers).toHaveLength(2)\n\t\t\tconst firstClasses = layers[0].map((h) => h.class)\n\t\t\texpect(firstClasses).toContain(B)\n\t\t\texpect(firstClasses).toContain(C)\n\t\t\texpect(layers[1].every((h) => h.class === A)).toBe(true)\n\t\t})\n\n\t\ttest('multiple hooks per class are all in the same layer', () => {\n\t\t\tconst cb1 = () => {}\n\t\t\tconst cb2 = () => {}\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{ cb: cb1, class: A, after: [] },\n\t\t\t\t{ cb: cb2, class: A, after: [] },\n\t\t\t\t{ cb: noop, class: B, after: [A] },\n\t\t\t]\n\t\t\tconst layers = resolveHookDAG(hooks)\n\t\t\texpect(layers).toHaveLength(2)\n\t\t\texpect(layers[0]).toHaveLength(2)\n\t\t\texpect(layers[0].every((h) => h.class === A)).toBe(true)\n\t\t})\n\n\t\ttest('anonymous hooks without deps run at deepest level', () => {\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{ cb: noop, class: A, after: [] },\n\t\t\t\t{ cb: noop, class: B, after: [A] },\n\t\t\t\t{ cb: noop, after: [] },\n\t\t\t]\n\t\t\tconst layers = resolveHookDAG(hooks)\n\t\t\texpect(layers).toHaveLength(2)\n\t\t\tconst lastLayer = layers[layers.length - 1]\n\t\t\texpect(lastLayer.some((h) => h.class === undefined)).toBe(true)\n\t\t})\n\n\t\ttest('anonymous hooks with deps run after their dependencies', () => {\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{ cb: noop, class: A, after: [] },\n\t\t\t\t{ cb: noop, class: B, after: [A] },\n\t\t\t\t{ cb: noop, class: C, after: [B] },\n\t\t\t\t{ cb: noop, after: [A] },\n\t\t\t]\n\t\t\tconst layers = resolveHookDAG(hooks)\n\t\t\tconst anonLayer = layers.findIndex((l) => l.some((h) => h.class === undefined))\n\t\t\tconst aLayer = layers.findIndex((l) => l.some((h) => h.class === A))\n\t\t\texpect(anonLayer).toBeGreaterThan(aLayer)\n\t\t})\n\n\t\ttest('empty hooks returns empty layers', () => {\n\t\t\texpect(resolveHookDAG([])).toEqual([])\n\t\t})\n\t})\n\n\tdescribe('runHooks', () => {\n\t\ttest('same-depth siblings observably overlap', async () => {\n\t\t\tconst log: string[] = []\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{\n\t\t\t\t\tcb: async () => {\n\t\t\t\t\t\tlog.push('B-start')\n\t\t\t\t\t\tawait new Promise((r) => setTimeout(r, 20))\n\t\t\t\t\t\tlog.push('B-end')\n\t\t\t\t\t},\n\t\t\t\t\tclass: B,\n\t\t\t\t\tafter: [],\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcb: async () => {\n\t\t\t\t\t\tlog.push('C-start')\n\t\t\t\t\t\tawait new Promise((r) => setTimeout(r, 20))\n\t\t\t\t\t\tlog.push('C-end')\n\t\t\t\t\t},\n\t\t\t\t\tclass: C,\n\t\t\t\t\tafter: [],\n\t\t\t\t},\n\t\t\t]\n\t\t\tawait runHooks(hooks)\n\t\t\texpect(log[0]).toBe('B-start')\n\t\t\texpect(log[1]).toBe('C-start')\n\t\t})\n\n\t\ttest('different depths run sequentially', async () => {\n\t\t\tconst log: string[] = []\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{\n\t\t\t\t\tcb: async () => {\n\t\t\t\t\t\tlog.push('A')\n\t\t\t\t\t},\n\t\t\t\t\tclass: A,\n\t\t\t\t\tafter: [],\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcb: async () => {\n\t\t\t\t\t\tlog.push('B')\n\t\t\t\t\t},\n\t\t\t\t\tclass: B,\n\t\t\t\t\tafter: [A],\n\t\t\t\t},\n\t\t\t]\n\t\t\tawait runHooks(hooks)\n\t\t\texpect(log).toEqual(['A', 'B'])\n\t\t})\n\n\t\ttest('close inversion runs hooks in reverse dependency order', async () => {\n\t\t\tconst log: string[] = []\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{ cb: async () => log.push('A'), class: A, after: [] },\n\t\t\t\t{ cb: async () => log.push('B'), class: B, after: [A] },\n\t\t\t\t{ cb: async () => log.push('C'), class: C, after: [B] },\n\t\t\t]\n\t\t\tawait runHooks(hooks, undefined, true)\n\t\t\texpect(log).toEqual(['C', 'B', 'A'])\n\t\t})\n\n\t\ttest('errors are routed to onError handler', async () => {\n\t\t\tconst errors: Error[] = []\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{\n\t\t\t\t\tcb: () => {\n\t\t\t\t\t\tthrow new Error('boom')\n\t\t\t\t\t},\n\t\t\t\t\tclass: A,\n\t\t\t\t\tafter: [],\n\t\t\t\t},\n\t\t\t]\n\t\t\tawait runHooks(hooks, (e) => {\n\t\t\t\terrors.push(e)\n\t\t\t})\n\t\t\texpect(errors).toHaveLength(1)\n\t\t\texpect(errors[0].message).toBe('boom')\n\t\t})\n\n\t\ttest('raw promise callbacks are awaited', async () => {\n\t\t\tconst log: string[] = []\n\t\t\tconst hooks: HookRecord[] = [\n\t\t\t\t{\n\t\t\t\t\tcb: Promise.resolve().then(() => log.push('resolved')),\n\t\t\t\t\tclass: A,\n\t\t\t\t\tafter: [],\n\t\t\t\t},\n\t\t\t]\n\t\t\tawait runHooks(hooks)\n\t\t\texpect(log).toContain('resolved')\n\t\t})\n\t})\n}\n","import { type ConditionalObjectKeys, type PipeInput, type PipeOutput, v } from 'valleyed'\n\nexport const instanceSettingsPipe = () =>\n\tv.object({\n\t\tapp: v.object({\n\t\t\tname: v.string(),\n\t\t}),\n\t\tlog: v.defaults(\n\t\t\tv.object({\n\t\t\t\tlevel: v.defaults(v.in(['fatal', 'error', 'warn', 'info', 'debug', 'trace', 'silent'] as const), 'info'),\n\t\t\t}),\n\t\t\t{},\n\t\t),\n\t\tutils: v.defaults(\n\t\t\tv.object({\n\t\t\t\thashSaltRounds: v.defaults(v.number(), 10),\n\t\t\t\tpaginationDefaultLimit: v.defaults(v.number(), 100),\n\t\t\t\tmaxFileUploadSizeInMb: v.defaults(v.number(), 500),\n\t\t\t}),\n\t\t\t{},\n\t\t),\n\t})\n\nexport type Settings = PipeOutput<ReturnType<typeof instanceSettingsPipe>>\nexport type SettingsInput = ConditionalObjectKeys<PipeInput<ReturnType<typeof instanceSettingsPipe>>>\n","import { v, type Pipe, type PipeOutput } from 'valleyed'\n\nexport class Field<T = unknown, Name extends string = string, S = unknown> {\n\tdeclare readonly __valueType?: T\n\tdeclare readonly __schema?: S\n\treadonly name: Name\n\treadonly path: readonly string[]\n\n\tconstructor(name: Name, path?: readonly string[]) {\n\t\tthis.name = name\n\t\tthis.path = path ?? [name]\n\t}\n}\n\nexport type AnyField = Field<unknown, string, any>\n\nexport function toFieldName(field: string | AnyField): string {\n\tif (field instanceof Field) return field.path.join('.')\n\treturn field\n}\n\nexport class SchemaField<\n\tName extends string = string,\n\tP extends Pipe<any, any> = Pipe<any, any>,\n\tHasOnCreate extends boolean = false,\n> extends Field<PipeOutput<P>, Name> {\n\tdeclare readonly __hasOnCreate?: HasOnCreate\n\treadonly pipe: P\n\treadonly onCreate?: () => PipeOutput<P>\n\treadonly onUpdate?: () => PipeOutput<P>\n\n\tconstructor(name: Name, pipe: P, opts?: { onCreate?: () => PipeOutput<P>; onUpdate?: () => PipeOutput<P> }) {\n\t\tsuper(name)\n\t\tthis.pipe = pipe\n\t\tthis.onCreate = opts?.onCreate\n\t\tthis.onUpdate = opts?.onUpdate\n\t}\n}\n\nexport type AnySchemaField = SchemaField<string, Pipe<any, any>, boolean>\n\nexport class ComputedField<\n\tName extends string = string,\n\tP extends Pipe<any, any> = Pipe<any, any>,\n\tDeps extends readonly string[] = readonly string[],\n> {\n\tconstructor(\n\t\treadonly name: Name,\n\t\treadonly pipe: P,\n\t\treadonly deps: Deps,\n\t\treadonly compute: (data: Record<Deps[number], unknown>) => PipeOutput<P>,\n\t) {}\n}\n\nexport type AnyComputedField = ComputedField<string, Pipe<any, any>, readonly string[]>\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect } = import.meta.vitest\n\n\tdescribe('Fields', () => {\n\t\tdescribe('Field', () => {\n\t\t\ttest('stores name and defaults path to [name]', () => {\n\t\t\t\tconst f = new Field('email')\n\t\t\t\texpect(f.name).toBe('email')\n\t\t\t\texpect(f.path).toEqual(['email'])\n\t\t\t})\n\n\t\t\ttest('stores provided custom path', () => {\n\t\t\t\tconst f = new Field('profile', ['profile', 'displayName'])\n\t\t\t\texpect(f.name).toBe('profile')\n\t\t\t\texpect(f.path).toEqual(['profile', 'displayName'])\n\t\t\t})\n\t\t})\n\n\t\tdescribe('toFieldName()', () => {\n\t\t\ttest('returns string input unchanged', () => {\n\t\t\t\texpect(toFieldName('createdAt')).toBe('createdAt')\n\t\t\t})\n\n\t\t\ttest('converts Field path into dot notation', () => {\n\t\t\t\tconst f = new Field('profile', ['profile', 'displayName'])\n\t\t\t\texpect(toFieldName(f)).toBe('profile.displayName')\n\t\t\t})\n\t\t})\n\n\t\tdescribe('SchemaField', () => {\n\t\t\ttest('extends Field and stores pipe', () => {\n\t\t\t\tconst mockPipe = v.string()\n\t\t\t\tconst f = new SchemaField('email', mockPipe)\n\t\t\t\texpect(f).toBeInstanceOf(Field)\n\t\t\t\texpect(f.name).toBe('email')\n\t\t\t\texpect(f.path).toEqual(['email'])\n\t\t\t\texpect(f.pipe).toBe(mockPipe)\n\t\t\t})\n\n\t\t\ttest('stores lifecycle hooks when provided', () => {\n\t\t\t\tconst mockPipe = v.number()\n\t\t\t\tconst f = new SchemaField('updatedAt', mockPipe, {\n\t\t\t\t\tonCreate: () => 1000,\n\t\t\t\t\tonUpdate: () => 2000,\n\t\t\t\t})\n\t\t\t\texpect(f.onCreate?.()).toBe(1000)\n\t\t\t\texpect(f.onUpdate?.()).toBe(2000)\n\t\t\t})\n\n\t\t\ttest('keeps lifecycle hooks undefined when omitted', () => {\n\t\t\t\tconst mockPipe = v.string()\n\t\t\t\tconst f = new SchemaField('name', mockPipe)\n\t\t\t\texpect(f.onCreate).toBeUndefined()\n\t\t\t\texpect(f.onUpdate).toBeUndefined()\n\t\t\t})\n\t\t})\n\t})\n}\n","import type { FilterOpName } from './adapter'\nimport { EquippedError } from '../errors'\nimport { OrmValidationError, type OrmValidationFailure } from './errors'\nimport { toFieldName, type AnyField, type Field } from './fields'\nimport type { AggregateSpec } from './orm-adapter'\nimport type { AnySchema } from './schema'\n\nexport class Filter {\n\treadonly field: string\n\tconstructor(\n\t\tfield: string | AnyField,\n\t\treadonly op: FilterOpName,\n\t\treadonly value: unknown,\n\t) {\n\t\tthis.field = toFieldName(field)\n\t}\n}\n\nexport type FilterChild = Filter | FilterGroup\n\nexport type FilterFactory = (q: FilterGroup) => FilterGroup\n\nexport type FilterGroupOp = 'and' | 'or'\n\nexport class FilterGroup {\n\treadonly children: readonly FilterChild[]\n\n\tprivate constructor(\n\t\treadonly op: FilterGroupOp = 'and',\n\t\tchildren?: readonly FilterChild[],\n\t) {\n\t\tthis.children = children ?? []\n\t}\n\n\t#withChild(child: FilterChild): FilterGroup {\n\t\treturn new FilterGroup(this.op, [...this.children, child])\n\t}\n\n\teq<T>(field: string | Field<T>, value: T): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'eq', value))\n\t}\n\n\tne<T>(field: string | Field<T>, value: T): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'ne', value))\n\t}\n\n\tgt<T>(field: string | Field<T>, value: T): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'gt', value))\n\t}\n\n\tgte<T>(field: string | Field<T>, value: T): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'gte', value))\n\t}\n\n\tlt<T>(field: string | Field<T>, value: T): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'lt', value))\n\t}\n\n\tlte<T>(field: string | Field<T>, value: T): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'lte', value))\n\t}\n\n\tin<T>(field: string | Field<T>, value: T[]): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'in', value))\n\t}\n\n\tnotIn<T>(field: string | Field<T>, value: T[]): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'notIn', value))\n\t}\n\n\tlike(field: string | Field<string>, value: string): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'like', value))\n\t}\n\n\texists(field: string | Field<unknown>): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'exists', true))\n\t}\n\n\tnotExists(field: string | Field<unknown>): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'notExists', true))\n\t}\n\n\tcontains<T>(field: string | Field<T>, value: T[]): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'contains', value))\n\t}\n\n\tnotContains<T>(field: string | Field<T>, value: T[]): FilterGroup {\n\t\treturn this.#withChild(new Filter(field, 'notContains', value))\n\t}\n\n\tand(facFns: FilterFactory[]): FilterGroup {\n\t\tif (facFns.length === 0) throw new EquippedError('and() requires at least one filter factory', { op: 'and' })\n\t\tconst group = new FilterGroup('and', facFns.map((fn) => fn(FilterGroup.create())))\n\t\treturn this.#withChild(group)\n\t}\n\n\tor(facFns: FilterFactory[]): FilterGroup {\n\t\tif (facFns.length === 0) throw new EquippedError('or() requires at least one filter factory', { op: 'or' })\n\t\tconst group = new FilterGroup('or', facFns.map((fn) => fn(FilterGroup.create())))\n\t\treturn this.#withChild(group)\n\t}\n\n\tclone(): FilterGroup {\n\t\treturn new FilterGroup(\n\t\t\tthis.op,\n\t\t\tthis.children.map((c) => {\n\t\t\t\tif (c instanceof Filter) return new Filter(c.field, c.op, structuredClone(c.value))\n\t\t\t\treturn c.clone()\n\t\t\t}),\n\t\t)\n\t}\n\n\tstatic create(): FilterGroup {\n\t\treturn new FilterGroup()\n\t}\n}\n\n\nexport type GatedFilterGroup<DeclaredOps extends readonly FilterOpName[]> = {\n\t[K in FilterOpName]: K extends DeclaredOps[number] ? FilterGroup[K] : never\n} & Pick<FilterGroup, 'and' | 'or' | 'clone' | 'children' | 'op'>\n\nexport type GatedFilterFactory<DeclaredOps extends readonly FilterOpName[]> = (\n\tq: GatedFilterGroup<DeclaredOps>,\n) => GatedFilterGroup<DeclaredOps>\n\nexport function assertNormalisedAggregate(schema: AnySchema, adapter: { aggregateOps: readonly string[] }, spec: AggregateSpec): void {\n\tconst failures: OrmValidationFailure[] = []\n\n\tif (spec.aggregates.length === 0) {\n\t\tfailures.push({ cause: 'At least one aggregator step is required' })\n\t}\n\n\tconst seenAliases = new Set<string>()\n\tfor (const agg of spec.aggregates) {\n\t\tif (seenAliases.has(agg.alias)) {\n\t\t\tfailures.push({ alias: agg.alias, cause: `Duplicate alias \"${agg.alias}\"` })\n\t\t}\n\t\tseenAliases.add(agg.alias)\n\n\t\tif (!adapter.aggregateOps.includes(agg.fn)) {\n\t\t\tfailures.push({ alias: agg.alias, cause: `Undeclared aggregate op \"${agg.fn}\"` })\n\t\t}\n\t}\n\n\tconst allFields = schema.fields as Record<string, unknown>\n\tconst fieldNames = new Set(Object.keys(allFields))\n\tfor (const field of spec.groupBy) {\n\t\tif (!fieldNames.has(field)) {\n\t\t\tfailures.push({ field, cause: `Unknown groupBy field \"${field}\" on schema \"${schema.name}\"` })\n\t\t}\n\t\tif (seenAliases.has(field)) {\n\t\t\tfailures.push({ alias: field, cause: `Alias \"${field}\" collides with groupBy field name` })\n\t\t}\n\t}\n\n\tif (failures.length > 0) {\n\t\tthrow new OrmValidationError('aggregate', schema.name, 'aggregate', failures)\n\t}\n\n\tif (spec.where) {\n\t\tassertNormalisedFilter(schema, spec.where)\n\t}\n\n\tif (spec.having) {\n\t\tconst validHavingFields = new Set([...seenAliases, ...spec.groupBy])\n\t\tconst havingErrors: OrmValidationFailure[] = []\n\n\t\tfunction walkHaving(node: FilterChild): void {\n\t\t\tif (node instanceof Filter) {\n\t\t\t\tif (!validHavingFields.has(node.field)) {\n\t\t\t\t\thavingErrors.push({ field: node.field, cause: `Unknown having field \"${node.field}\" — must be an aggregator alias or groupBy field` })\n\t\t\t\t}\n\t\t\t} else if (node instanceof FilterGroup) {\n\t\t\t\tfor (const child of node.children) walkHaving(child)\n\t\t\t}\n\t\t}\n\n\t\tfor (const child of spec.having.children) walkHaving(child)\n\n\t\tif (havingErrors.length > 0) {\n\t\t\tthrow new OrmValidationError('aggregate', schema.name, 'aggregate', havingErrors)\n\t\t}\n\t}\n}\n\nexport function assertNormalisedFilter(schema: AnySchema, group: FilterGroup): void {\n\tconst allFields = schema.fields as Record<string, unknown>\n\tconst fieldNames = new Set(Object.keys(allFields))\n\tconst errors: Array<{ field: string; cause: string }> = []\n\n\tfunction walk(node: FilterChild): void {\n\t\tif (node instanceof Filter) {\n\t\t\tif (!fieldNames.has(node.field)) {\n\t\t\t\terrors.push({ field: node.field, cause: `Unknown field \"${node.field}\" on schema \"${schema.name}\"` })\n\t\t\t}\n\t\t} else if (node instanceof FilterGroup) {\n\t\t\tfor (const child of node.children) walk(child)\n\t\t}\n\t}\n\n\tfor (const child of group.children) walk(child)\n\n\tif (errors.length > 0) {\n\t\tthrow new OrmValidationError(\n\t\t\t'validation',\n\t\t\tschema.name,\n\t\t\t'filter',\n\t\t\terrors.map((e) => ({ field: e.field, cause: e.cause })),\n\t\t)\n\t}\n}\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect } = import.meta.vitest\n\tconst { v } = await import('valleyed')\n\tconst { Schema } = await import('./schema')\n\n\tconst UserSchema = Schema.from('users')\n\t\t.pk('id', v.string(), () => 'u1')\n\t\t.field('email', v.string())\n\t\t.field('age', v.number())\n\t\t.field('name', v.string())\n\t\t.field('tags', v.array(v.string()))\n\t\t.build()\n\n\tdescribe('FilterGroup', () => {\n\t\tdescribe('filter-op methods', () => {\n\t\t\ttest('eq adds a filter clause with op eq', () => {\n\t\t\t\tconst g = FilterGroup.create().eq(UserSchema.fields.age, 25)\n\t\t\t\texpect(g.children).toHaveLength(1)\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.field).toBe('age')\n\t\t\t\texpect(f.op).toBe('eq')\n\t\t\t\texpect(f.value).toBe(25)\n\t\t\t})\n\n\t\t\ttest('ne adds a filter clause with op ne', () => {\n\t\t\t\tconst g = FilterGroup.create().ne('name', 'Bob')\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.op).toBe('ne')\n\t\t\t\texpect(f.value).toBe('Bob')\n\t\t\t})\n\n\t\t\ttest('gt/gte/lt/lte produce correct ops', () => {\n\t\t\t\tconst g = FilterGroup.create()\n\t\t\t\t\t.gt(UserSchema.fields.age, 10)\n\t\t\t\t\t.gte(UserSchema.fields.age, 20)\n\t\t\t\t\t.lt(UserSchema.fields.age, 30)\n\t\t\t\t\t.lte(UserSchema.fields.age, 40)\n\t\t\t\texpect(g.children.map((c) => (c as Filter).op)).toEqual(['gt', 'gte', 'lt', 'lte'])\n\t\t\t})\n\n\t\t\ttest('in adds a filter clause with array value', () => {\n\t\t\t\tconst g = FilterGroup.create().in(UserSchema.fields.age, [1, 2, 3])\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.op).toBe('in')\n\t\t\t\texpect(f.value).toEqual([1, 2, 3])\n\t\t\t})\n\n\t\t\ttest('notIn adds a filter clause with op notIn', () => {\n\t\t\t\tconst g = FilterGroup.create().notIn(UserSchema.fields.age, [4, 5])\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.op).toBe('notIn')\n\t\t\t\texpect(f.value).toEqual([4, 5])\n\t\t\t})\n\n\t\t\ttest('like adds a filter clause with op like', () => {\n\t\t\t\tconst g = FilterGroup.create().like(UserSchema.fields.email, 'alice')\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.op).toBe('like')\n\t\t\t\texpect(f.value).toBe('alice')\n\t\t\t})\n\n\t\t\ttest('exists adds a filter clause with op exists', () => {\n\t\t\t\tconst g = FilterGroup.create().exists(UserSchema.fields.name)\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.op).toBe('exists')\n\t\t\t})\n\n\t\t\ttest('notExists is its own op, not a boolean form of exists', () => {\n\t\t\t\tconst g = FilterGroup.create().notExists(UserSchema.fields.name)\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.op).toBe('notExists')\n\t\t\t\texpect(f.op).not.toBe('exists')\n\t\t\t})\n\n\t\t\ttest('contains/notContains produce correct ops', () => {\n\t\t\t\tconst g = FilterGroup.create()\n\t\t\t\t\t.contains('tags', ['a'])\n\t\t\t\t\t.notContains('tags', ['b'])\n\t\t\t\texpect((g.children[0] as Filter).op).toBe('contains')\n\t\t\t\texpect((g.children[1] as Filter).op).toBe('notContains')\n\t\t\t})\n\n\t\t\ttest('all 13 filter ops produce matching Filter.op values (name-parity)', () => {\n\t\t\t\tconst g = FilterGroup.create()\n\t\t\t\t\t.eq('f', 1)\n\t\t\t\t\t.ne('f', 1)\n\t\t\t\t\t.gt('f', 1)\n\t\t\t\t\t.gte('f', 1)\n\t\t\t\t\t.lt('f', 1)\n\t\t\t\t\t.lte('f', 1)\n\t\t\t\t\t.in('f', [1])\n\t\t\t\t\t.notIn('f', [1])\n\t\t\t\t\t.like('f', 'x')\n\t\t\t\t\t.exists('f')\n\t\t\t\t\t.notExists('f')\n\t\t\t\t\t.contains('f', [1])\n\t\t\t\t\t.notContains('f', [1])\n\t\t\t\tconst ops = g.children.map((c) => (c as Filter).op)\n\t\t\t\texpect(ops).toEqual([\n\t\t\t\t\t'eq', 'ne', 'gt', 'gte', 'lt', 'lte',\n\t\t\t\t\t'in', 'notIn', 'like', 'exists', 'notExists',\n\t\t\t\t\t'contains', 'notContains',\n\t\t\t\t])\n\t\t\t})\n\t\t})\n\n\t\tdescribe('raw-string field overload', () => {\n\t\t\ttest('accepts raw string field name', () => {\n\t\t\t\tconst g = FilterGroup.create().eq('age', 18)\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.field).toBe('age')\n\t\t\t})\n\n\t\t\ttest('accepts typed Field ref and extracts field name', () => {\n\t\t\t\tconst g = FilterGroup.create().eq(UserSchema.fields.age, 18)\n\t\t\t\tconst f = g.children[0] as Filter\n\t\t\t\texpect(f.field).toBe('age')\n\t\t\t})\n\t\t})\n\n\t\tdescribe('structural combinators', () => {\n\t\t\ttest('and() creates a nested and-group', () => {\n\t\t\t\tconst g = FilterGroup.create().and([\n\t\t\t\t\t(q) => q.eq('age', 10),\n\t\t\t\t\t(q) => q.eq('name', 'Alice'),\n\t\t\t\t])\n\t\t\t\texpect(g.children).toHaveLength(1)\n\t\t\t\tconst nested = g.children[0] as FilterGroup\n\t\t\t\texpect(nested.op).toBe('and')\n\t\t\t\texpect(nested.children).toHaveLength(2)\n\t\t\t})\n\n\t\t\ttest('or() creates a nested or-group', () => {\n\t\t\t\tconst g = FilterGroup.create().or([\n\t\t\t\t\t(q) => q.eq('name', 'Alice'),\n\t\t\t\t\t(q) => q.eq('name', 'Bob'),\n\t\t\t\t])\n\t\t\t\tconst nested = g.children[0] as FilterGroup\n\t\t\t\texpect(nested.op).toBe('or')\n\t\t\t})\n\t\t})\n\n\t\tdescribe('empty-combinator rejection', () => {\n\t\t\ttest('and([]) throws at builder time', () => {\n\t\t\t\texpect(() => FilterGroup.create().and([])).toThrow()\n\t\t\t})\n\n\t\t\ttest('or([]) throws at builder time', () => {\n\t\t\t\texpect(() => FilterGroup.create().or([])).toThrow()\n\t\t\t})\n\n\t\t\ttest('thrown error has stack pointing at offending call', () => {\n\t\t\t\ttry {\n\t\t\t\t\tFilterGroup.create().and([])\n\t\t\t\t\texpect.unreachable()\n\t\t\t\t} catch (e) {\n\t\t\t\t\texpect((e as Error).stack).toContain('filter.ts')\n\t\t\t\t}\n\t\t\t})\n\t\t})\n\n\t\tdescribe('clone()', () => {\n\t\t\ttest('deep-clones the tree', () => {\n\t\t\t\tconst original = FilterGroup.create()\n\t\t\t\t\t.eq('name', 'Alice')\n\t\t\t\t\t.and([(q) => q.gt('age', 20)])\n\t\t\t\tconst cloned = original.clone()\n\n\t\t\t\texpect(cloned.children).toHaveLength(2)\n\t\t\t\texpect(cloned).not.toBe(original)\n\t\t\t\texpect(cloned.children[0]).not.toBe(original.children[0])\n\t\t\t})\n\n\t\t\ttest('structuredClone of values — mutations on clone do not leak', () => {\n\t\t\t\tconst arr = [1, 2, 3]\n\t\t\t\tconst original = FilterGroup.create().in('ids', arr)\n\t\t\t\tconst cloned = original.clone()\n\n\t\t\t\tconst clonedValue = (cloned.children[0] as Filter).value as number[]\n\t\t\t\tclonedValue.push(4)\n\n\t\t\t\texpect((original.children[0] as Filter).value).toEqual([1, 2, 3])\n\t\t\t\texpect(clonedValue).toEqual([1, 2, 3, 4])\n\t\t\t})\n\t\t})\n\t})\n\n\tdescribe('clone-on-step: fan-out independence', () => {\n\t\ttest('.eq() returns a new FilterGroup, not the same instance', () => {\n\t\t\tconst base = FilterGroup.create()\n\t\t\tconst a = base.eq('name', 'Alice')\n\t\t\texpect(a).not.toBe(base)\n\t\t})\n\n\t\ttest('fan-out from shared base does not pollute either branch', () => {\n\t\t\tconst base = FilterGroup.create().eq('name', 'Alice')\n\t\t\tconst branchA = base.gt('age', 20)\n\t\t\tconst branchB = base.lt('age', 40)\n\n\t\t\texpect(branchA.children).toHaveLength(2)\n\t\t\texpect(branchB.children).toHaveLength(2)\n\t\t\texpect(base.children).toHaveLength(1)\n\t\t\texpect((branchA.children[1] as Filter).op).toBe('gt')\n\t\t\texpect((branchB.children[1] as Filter).op).toBe('lt')\n\t\t})\n\n\t\ttest('.and() returns a new FilterGroup', () => {\n\t\t\tconst base = FilterGroup.create().eq('name', 'Alice')\n\t\t\tconst withAnd = base.and([(q) => q.gt('age', 20)])\n\t\t\texpect(withAnd).not.toBe(base)\n\t\t\texpect(base.children).toHaveLength(1)\n\t\t\texpect(withAnd.children).toHaveLength(2)\n\t\t})\n\n\t\ttest('.or() returns a new FilterGroup', () => {\n\t\t\tconst base = FilterGroup.create().eq('name', 'Alice')\n\t\t\tconst withOr = base.or([(q) => q.gt('age', 20)])\n\t\t\texpect(withOr).not.toBe(base)\n\t\t\texpect(base.children).toHaveLength(1)\n\t\t\texpect(withOr.children).toHaveLength(2)\n\t\t})\n\t})\n\n\tdescribe('assertNormalisedFilter', () => {\n\t\ttest('passes for valid filter referencing known fields', () => {\n\t\t\tconst g = FilterGroup.create().eq(UserSchema.fields.age, 25)\n\t\t\texpect(() => assertNormalisedFilter(UserSchema, g)).not.toThrow()\n\t\t})\n\n\t\ttest('passes for raw string field that exists on schema', () => {\n\t\t\tconst g = FilterGroup.create().eq('email', 'test@test.com')\n\t\t\texpect(() => assertNormalisedFilter(UserSchema, g)).not.toThrow()\n\t\t})\n\n\t\ttest('rejects unknown field name with OrmValidationError', () => {\n\t\t\tconst g = FilterGroup.create().eq('unknownField', 42)\n\t\t\texpect(() => assertNormalisedFilter(UserSchema, g)).toThrow(OrmValidationError)\n\t\t})\n\n\t\ttest('rejected error has kind validation', () => {\n\t\t\tconst g = FilterGroup.create().eq('badField', 42)\n\t\t\ttry {\n\t\t\t\tassertNormalisedFilter(UserSchema, g)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\texpect(e).toBeInstanceOf(OrmValidationError)\n\t\t\t\texpect((e as OrmValidationError).kind).toBe('validation')\n\t\t\t\texpect((e as OrmValidationError).failures).toHaveLength(1)\n\t\t\t\texpect((e as OrmValidationError).failures[0].field).toBe('badField')\n\t\t\t}\n\t\t})\n\n\t\ttest('preserves logical field names verbatim for Field refs', () => {\n\t\t\tconst g = FilterGroup.create().eq(UserSchema.fields.email, 'a@b.com')\n\t\t\tconst f = g.children[0] as Filter\n\t\t\texpect(f.field).toBe('email')\n\t\t\tassertNormalisedFilter(UserSchema, g)\n\t\t})\n\n\t\ttest('preserves logical field names verbatim for raw-string overloads', () => {\n\t\t\tconst g = FilterGroup.create().eq('age', 18)\n\t\t\tconst f = g.children[0] as Filter\n\t\t\texpect(f.field).toBe('age')\n\t\t\tassertNormalisedFilter(UserSchema, g)\n\t\t})\n\n\t\ttest('walks nested groups to detect unknown fields', () => {\n\t\t\tconst g = FilterGroup.create().and([\n\t\t\t\t(q) => q.eq('name', 'Alice'),\n\t\t\t\t(q) => q.or([(inner) => inner.eq('nonexistent', 'val')]),\n\t\t\t])\n\t\t\texpect(() => assertNormalisedFilter(UserSchema, g)).toThrow(OrmValidationError)\n\t\t})\n\t})\n\n\tdescribe('assertNormalisedAggregate', () => {\n\t\tconst adapter = { aggregateOps: ['count'] as readonly string[] }\n\n\t\ttest('passes for valid count aggregate', () => {\n\t\t\tconst spec = { aggregates: [{ fn: 'count' as const, alias: 'total' }], groupBy: [] }\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, adapter, spec)).not.toThrow()\n\t\t})\n\n\t\ttest('rejects empty aggregator list', () => {\n\t\t\tconst spec = { aggregates: [], groupBy: [] }\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, adapter, spec)).toThrow(OrmValidationError)\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, adapter, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\texpect((e as OrmValidationError).kind).toBe('aggregate')\n\t\t\t}\n\t\t})\n\n\t\ttest('rejects undeclared aggregate op', () => {\n\t\t\tconst spec = { aggregates: [{ fn: 'sum' as const, alias: 'total', field: 'age' }], groupBy: [] }\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, adapter, spec)).toThrow(OrmValidationError)\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, adapter, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\tconst err = e as OrmValidationError\n\t\t\t\texpect(err.kind).toBe('aggregate')\n\t\t\t\texpect(err.failures[0].alias).toBe('total')\n\t\t\t\texpect(err.failures[0].cause).toContain('Undeclared')\n\t\t\t}\n\t\t})\n\n\t\ttest('rejects duplicate aliases', () => {\n\t\t\tconst spec = {\n\t\t\t\taggregates: [\n\t\t\t\t\t{ fn: 'count' as const, alias: 'total' },\n\t\t\t\t\t{ fn: 'count' as const, alias: 'total' },\n\t\t\t\t],\n\t\t\t\tgroupBy: [],\n\t\t\t}\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, adapter, spec)).toThrow(OrmValidationError)\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, adapter, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\tconst err = e as OrmValidationError\n\t\t\t\texpect(err.failures.some((f) => f.alias === 'total')).toBe(true)\n\t\t\t}\n\t\t})\n\n\t\ttest('validates where filter against schema', () => {\n\t\t\tconst spec = {\n\t\t\t\taggregates: [{ fn: 'count' as const, alias: 'total' }],\n\t\t\t\tgroupBy: [],\n\t\t\t\twhere: FilterGroup.create().eq('unknownField', 42),\n\t\t\t}\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, adapter, spec)).toThrow(OrmValidationError)\n\t\t})\n\n\t\ttest('collects multiple failures', () => {\n\t\t\tconst spec = {\n\t\t\t\taggregates: [\n\t\t\t\t\t{ fn: 'sum' as const, alias: 'x', field: 'age' },\n\t\t\t\t\t{ fn: 'avg' as const, alias: 'x', field: 'age' },\n\t\t\t\t],\n\t\t\t\tgroupBy: [],\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, adapter, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\tconst err = e as OrmValidationError\n\t\t\t\texpect(err.failures.length).toBeGreaterThanOrEqual(2)\n\t\t\t}\n\t\t})\n\n\t\ttest('rejects unknown groupBy field', () => {\n\t\t\tconst allOps = { aggregateOps: ['count', 'sum'] as readonly string[] }\n\t\t\tconst spec = {\n\t\t\t\taggregates: [{ fn: 'count' as const, alias: 'total' }],\n\t\t\t\tgroupBy: ['nonexistent'],\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, allOps, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\tconst err = e as OrmValidationError\n\t\t\t\texpect(err.kind).toBe('aggregate')\n\t\t\t\texpect(err.failures[0].cause).toContain('groupBy')\n\t\t\t\texpect(err.failures[0].field).toBe('nonexistent')\n\t\t\t}\n\t\t})\n\n\t\ttest('rejects alias colliding with groupBy field name', () => {\n\t\t\tconst allOps = { aggregateOps: ['count'] as readonly string[] }\n\t\t\tconst spec = {\n\t\t\t\taggregates: [{ fn: 'count' as const, alias: 'name' }],\n\t\t\t\tgroupBy: ['name'],\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, allOps, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\tconst err = e as OrmValidationError\n\t\t\t\texpect(err.kind).toBe('aggregate')\n\t\t\t\texpect(err.failures.some((f) => String(f.cause).includes('collides'))).toBe(true)\n\t\t\t}\n\t\t})\n\n\t\ttest('rejects unknown having field', () => {\n\t\t\tconst allOps = { aggregateOps: ['count'] as readonly string[] }\n\t\t\tconst spec = {\n\t\t\t\taggregates: [{ fn: 'count' as const, alias: 'total' }],\n\t\t\t\tgroupBy: ['name'],\n\t\t\t\thaving: FilterGroup.create().gt('nonexistent', 0),\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tassertNormalisedAggregate(UserSchema, allOps, spec)\n\t\t\t\texpect.unreachable()\n\t\t\t} catch (e) {\n\t\t\t\tconst err = e as OrmValidationError\n\t\t\t\texpect(err.kind).toBe('aggregate')\n\t\t\t\texpect(err.failures[0].cause).toContain('having')\n\t\t\t}\n\t\t})\n\n\t\ttest('having accepts alias and groupBy field names', () => {\n\t\t\tconst allOps = { aggregateOps: ['count'] as readonly string[] }\n\t\t\tconst spec = {\n\t\t\t\taggregates: [{ fn: 'count' as const, alias: 'total' }],\n\t\t\t\tgroupBy: ['name'],\n\t\t\t\thaving: FilterGroup.create().gt('total', 0).eq('name', 'Alice'),\n\t\t\t}\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, allOps, spec)).not.toThrow()\n\t\t})\n\n\t\ttest('passes valid groupBy with known schema fields', () => {\n\t\t\tconst allOps = { aggregateOps: ['count'] as readonly string[] }\n\t\t\tconst spec = {\n\t\t\t\taggregates: [{ fn: 'count' as const, alias: 'total' }],\n\t\t\t\tgroupBy: ['name', 'age'],\n\t\t\t}\n\t\t\texpect(() => assertNormalisedAggregate(UserSchema, allOps, spec)).not.toThrow()\n\t\t})\n\t})\n}\n","import type { Pipe } from 'valleyed'\n\nimport { EquippedError } from '../errors'\nimport { Instance, type ClassRef } from '../instance'\nimport type { AggregateOpName, FieldTypeName, FilterOpName, UpdateOpName } from './adapter'\nimport type { OrmUse } from './adapters/base'\nimport { FilterGroup } from './filter'\nimport type { DiscoveredSchema } from './migrations/introspection-types'\nimport type { AddFieldChange, AddForeignKeyChange, AddIndexChange, CreateTableChange, DropFieldChange, DropForeignKeyChange, DropIndexChange, DropTableChange, ModifyFieldChange, RenameFieldChange, RenameTableChange } from './migrations/types'\nimport type { IterationQueryOptions, QueryOptions } from './query-options'\nimport type { AnySchema } from './schema'\nimport type { AnyUpdateOp } from './updates'\n\nexport type AggregateSpec = {\n\twhere?: FilterGroup\n\taggregates: ReadonlyArray<{\n\t\tfn: AggregateOpName\n\t\tfield?: string\n\t\talias: string\n\t}>\n\tgroupBy: readonly string[]\n\thaving?: FilterGroup\n}\n\nexport abstract class OrmAdapter {\n\treadonly queryableOps: readonly FilterOpName[] = []\n\treadonly updateOps: readonly UpdateOpName[] = []\n\treadonly aggregateOps: readonly AggregateOpName[] = []\n\treadonly supportedFieldTypes: readonly FieldTypeName[] = []\n\n\tabstract readonly schemaConfigPipe: Pipe<any, any>\n\n\tconnect?(): Promise<void>\n\tdisconnect?(): Promise<void>\n\tfindByPk?(schema: AnySchema, config: unknown, pk: unknown): Promise<Record<string, unknown> | null>\n\tcreateMany?(schema: AnySchema, config: unknown, data: Record<string, unknown>[]): Promise<Record<string, unknown>[]>\n\tupdateByPk?(schema: AnySchema, config: unknown, pk: unknown, ops: AnyUpdateOp[]): Promise<Record<string, unknown> | null>\n\tdeleteByPk?(schema: AnySchema, config: unknown, pk: unknown): Promise<Record<string, unknown> | null>\n\traw?(schema: AnySchema, config: unknown, ...args: any[]): Promise<any>\n\tfindMany?(schema: AnySchema, config: unknown, filter: FilterGroup, options?: QueryOptions): Promise<Record<string, unknown>[]>\n\tcount?(schema: AnySchema, config: unknown, filter: FilterGroup): Promise<number>\n\titerateMany?(schema: AnySchema, config: unknown, filter: FilterGroup, options?: IterationQueryOptions): AsyncGenerator<Record<string, unknown>, void, void>\n\tupdateMany?(schema: AnySchema, config: unknown, filter: FilterGroup, data: Record<string, unknown>): Promise<Record<string, unknown>[]>\n\tdeleteMany?(schema: AnySchema, config: unknown, filter: FilterGroup): Promise<Record<string, unknown>[]>\n\tupsertOne?(\n\t\tschema: AnySchema,\n\t\tconfig: unknown,\n\t\tfilter: FilterGroup,\n\t\tcreate: Record<string, unknown>,\n\t\tops: AnyUpdateOp[],\n\t): Promise<Record<string, unknown>>\n\taggregate?(schema: AnySchema, config: unknown, spec: AggregateSpec): Promise<Array<Record<string, unknown>>>\n\tsession?<T>(fn: () => Promise<T>): Promise<T>\n\n\tloadMigrations?(): Promise<{ id: string; appliedAt: number }[]>\n\trecordMigration?(id: string, appliedAt: number): Promise<void>\n\tacquireMigrationLock?<T>(fn: () => Promise<T>): Promise<T>\n\tapplyCreateTable?(change: CreateTableChange<any>): Promise<void>\n\tapplyDropTable?(change: DropTableChange): Promise<void>\n\tapplyAddField?(change: AddFieldChange<any>): Promise<void>\n\tapplyDropField?(change: DropFieldChange): Promise<void>\n\tapplyModifyField?(change: ModifyFieldChange<any>): Promise<void>\n\tapplyRenameTable?(change: RenameTableChange): Promise<void>\n\tapplyRenameField?(change: RenameFieldChange): Promise<void>\n\tapplyAddIndex?(change: AddIndexChange): Promise<void>\n\tapplyDropIndex?(change: DropIndexChange): Promise<void>\n\tapplyAddForeignKey?(change: AddForeignKeyChange): Promise<void>\n\tapplyDropForeignKey?(change: DropForeignKeyChange): Promise<void>\n\tintrospect?(): Promise<DiscoveredSchema[]>\n\n\tprotected onFatalError(err: unknown): never {\n\t\tconst wrapped = err instanceof EquippedError ? err : new EquippedError('OrmAdapter fatal error', {}, err)\n\t\tInstance.crash(wrapped)\n\t}\n\n\tconstructor() {\n\t\tconst self = this as any\n\t\tif (typeof self.connect === 'function') {\n\t\t\tInstance.on('start', () => self.connect(), { class: this.constructor as ClassRef })\n\t\t}\n\t\tif (typeof self.disconnect === 'function') {\n\t\t\tInstance.on('close', () => self.disconnect(), { class: this.constructor as ClassRef })\n\t\t}\n\t}\n\n\tuse(schema: AnySchema, config: unknown): OrmUse {\n\t\tconst self = this as any\n\t\tconst emptyIterator = async function* (): AsyncGenerator<Record<string, unknown>, void, void> {}\n\t\tconst use: OrmUse = {\n\t\t\tfindMany: (filter, opts) => self.findMany?.(schema, config, filter, opts) ?? Promise.resolve([]),\n\t\t\titerateMany: (filter, opts) => self.iterateMany?.(schema, config, filter, opts) ?? emptyIterator(),\n\t\t\tfindOne: async (filter) => {\n\t\t\t\tconst rows = await use.findMany(filter, { limit: 1 })\n\t\t\t\treturn rows[0] ?? null\n\t\t\t},\n\t\t\tcount: (filter) => self.count?.(schema, config, filter) ?? Promise.reject(new Error('count not implemented')),\n\t\t\tcreateOne: async (d) => {\n\t\t\t\tconst rows = await use.createMany([d])\n\t\t\t\treturn rows[0]\n\t\t\t},\n\t\t\tcreateMany: (d) => self.createMany?.(schema, config, d) ?? Promise.resolve([]),\n\t\t\tupdateMany: (filter, d) => self.updateMany?.(schema, config, filter, d) ?? Promise.resolve([]),\n\t\t\tupdateOne: async (filter, d) => {\n\t\t\t\tconst match = await use.findOne(filter)\n\t\t\t\tif (!match) return null\n\t\t\t\tconst pk = schema.pkField.name\n\t\t\t\tconst pkFilter = FilterGroup.create().eq(pk, match[pk])\n\t\t\t\tconst rows = await use.updateMany(pkFilter, d)\n\t\t\t\treturn rows[0] ?? null\n\t\t\t},\n\t\t\tupsertOne: (filter, create, ops) =>\n\t\t\t\tself.upsertOne?.(schema, config, filter, create, ops) ?? Promise.reject(new Error('upsertOne not implemented')),\n\t\t\tdeleteOne: async (filter) => {\n\t\t\t\tconst row = await use.findOne(filter)\n\t\t\t\tif (!row) return null\n\t\t\t\tconst pk = schema.pkField.name\n\t\t\t\tif (self.deleteByPk) {\n\t\t\t\t\tawait self.deleteByPk(schema, config, row[pk])\n\t\t\t\t} else if (self.deleteMany) {\n\t\t\t\t\tconst pkFilter = FilterGroup.create().eq(pk, row[pk])\n\t\t\t\t\tawait self.deleteMany(schema, config, pkFilter)\n\t\t\t\t}\n\t\t\t\treturn row\n\t\t\t},\n\t\t\tdeleteMany: (filter) => self.deleteMany?.(schema, config, filter) ?? Promise.resolve([]),\n\t\t\traw: (...args: any[]) => self.raw?.(schema, config, ...args) ?? Promise.reject(new Error('raw not implemented')),\n\t\t\taggregate: (spec) => self.aggregate?.(schema, config, spec) ?? Promise.reject(new Error('aggregate not implemented')),\n\t\t\taggregateOps: self.aggregateOps ?? [],\n\t\t}\n\t\treturn use\n\t}\n}\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect, vi } = import.meta.vitest\n\tconst { v } = await import('valleyed')\n\n\tdescribe('OrmAdapter', () => {\n\t\ttest('subclass with connect/disconnect auto-registers Instance hooks', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tconst onSpy = vi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tclass TestAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\treadonly supportedFieldTypes = ['string'] as const\n\t\t\t\tasync connect() {}\n\t\t\t\tasync disconnect() {}\n\t\t\t}\n\n\t\t\tnew (TestAdapter as any)()\n\n\t\t\texpect(onSpy).toHaveBeenCalledWith('start', expect.any(Function), expect.objectContaining({ class: TestAdapter }))\n\t\t\texpect(onSpy).toHaveBeenCalledWith('close', expect.any(Function), expect.objectContaining({ class: TestAdapter }))\n\n\t\t\tonSpy.mockRestore()\n\t\t})\n\n\t\ttest('subclass without connect/disconnect does not register hooks', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tconst onSpy = vi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tclass MinimalAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t}\n\n\t\t\tnew (MinimalAdapter as any)()\n\t\t\texpect(onSpy).not.toHaveBeenCalled()\n\n\t\t\tonSpy.mockRestore()\n\t\t})\n\n\t\ttest('capability declarations default to empty arrays', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tclass DefaultAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t}\n\t\t\tconst adapter = new (DefaultAdapter as any)() as DefaultAdapter\n\t\t\texpect(adapter.queryableOps).toEqual([])\n\t\t\texpect(adapter.updateOps).toEqual([])\n\t\t\texpect(adapter.aggregateOps).toEqual([])\n\t\t\texpect(adapter.supportedFieldTypes).toEqual([])\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('onFatalError wraps non-EquippedError and calls Instance.crash', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\t\t\tconst crashSpy = vi.spyOn(Inst, 'crash').mockImplementation((() => {\n\t\t\t\tthrow new Error('crash')\n\t\t\t}) as any)\n\n\t\t\tclass FatalAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\ttriggerFatal() {\n\t\t\t\t\tthis.onFatalError(new Error('something broke'))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adapter = new (FatalAdapter as any)() as FatalAdapter\n\t\t\texpect(() => adapter.triggerFatal()).toThrow('crash')\n\t\t\texpect(crashSpy).toHaveBeenCalled()\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('onFatalError passes through EquippedError directly', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\t\t\tlet crashedWith: unknown\n\t\t\tvi.spyOn(Inst, 'crash').mockImplementation(((err: any) => {\n\t\t\t\tcrashedWith = err\n\t\t\t\tthrow err\n\t\t\t}) as any)\n\n\t\t\tclass FatalAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\ttriggerFatal() {\n\t\t\t\t\tthis.onFatalError(new EquippedError('equipped error', { detail: 'test' }))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adapter = new (FatalAdapter as any)() as FatalAdapter\n\t\t\texpect(() => adapter.triggerFatal()).toThrow()\n\t\t\texpect(crashedWith).toBeInstanceOf(EquippedError)\n\t\t\texpect((crashedWith as EquippedError).message).toBe('equipped error')\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('use() creates OrmUse bridge that delegates to flat methods', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tconst { Schema } = await import('./schema')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tclass BridgeAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\treadonly supportedFieldTypes = ['string'] as const\n\t\t\t\treadonly queryableOps = ['eq'] as const\n\n\t\t\t\tasync findMany(_s: AnySchema, _c: unknown, _f: any, _o?: any) {\n\t\t\t\t\treturn [{ id: 'found' }]\n\t\t\t\t}\n\t\t\t\tasync count(_s: AnySchema, _c: unknown, _f: any) {\n\t\t\t\t\treturn 1\n\t\t\t\t}\n\t\t\t\tasync *iterateMany(_s: AnySchema, _c: unknown, _f: any, _o?: any) {\n\t\t\t\t\tyield { id: 'iterated' }\n\t\t\t\t}\n\t\t\t\tasync createMany(_s: AnySchema, _c: unknown, data: Record<string, unknown>[]) {\n\t\t\t\t\treturn data\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst TestSchema = Schema.from('bridge_test')\n\t\t\t\t.pk('id', v.string(), () => 'x')\n\t\t\t\t.build()\n\t\t\tconst adapter = new (BridgeAdapter as any)() as BridgeAdapter\n\t\t\tconst ormUse = adapter.use(TestSchema, { table: 'bridge_test' })\n\n\t\t\tconst rows = await ormUse.findMany(FilterGroup.create())\n\t\t\texpect(rows).toEqual([{ id: 'found' }])\n\t\t\tawait expect(ormUse.count(FilterGroup.create())).resolves.toBe(1)\n\n\t\t\tconst iterated: Record<string, unknown>[] = []\n\t\t\tfor await (const row of ormUse.iterateMany(FilterGroup.create())) iterated.push(row)\n\t\t\texpect(iterated).toEqual([{ id: 'iterated' }])\n\n\t\t\tconst created = await ormUse.createOne({ id: 'new' })\n\t\t\texpect(created).toEqual({ id: 'new' })\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('use() bridge delegates updateMany to flat method', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tconst { Schema } = await import('./schema')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tclass UpdateAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\treadonly supportedFieldTypes = ['string', 'number'] as const\n\t\t\t\treadonly updateOps = ['set'] as const\n\n\t\t\t\tasync findMany(_s: AnySchema, _c: unknown, _f: any) {\n\t\t\t\t\treturn [{ id: 'u1', name: 'old' }]\n\t\t\t\t}\n\t\t\t\tasync updateMany(_s: AnySchema, _c: unknown, _f: any, data: Record<string, unknown>) {\n\t\t\t\t\treturn [{ id: 'u1', ...data }]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst TestSchema = Schema.from('upd_test')\n\t\t\t\t.pk('id', v.string(), () => 'x')\n\t\t\t\t.field('name', v.string())\n\t\t\t\t.build()\n\t\t\tconst adapter = new (UpdateAdapter as any)() as UpdateAdapter\n\t\t\tconst ormUse = adapter.use(TestSchema, { table: 'upd_test' })\n\n\t\t\tconst updated = await ormUse.updateOne(FilterGroup.create().eq('id', 'u1'), { name: 'new' })\n\t\t\texpect(updated).not.toBeNull()\n\t\t\texpect(updated!.name).toBe('new')\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('use().iterateMany does not fall back to findMany when adapter omits iterateMany', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tconst { Schema } = await import('./schema')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tlet findManyCalls = 0\n\t\t\tclass FindOnlyAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\treadonly supportedFieldTypes = ['string'] as const\n\t\t\t\tasync findMany() {\n\t\t\t\t\tfindManyCalls += 1\n\t\t\t\t\treturn [{ id: 'found' }]\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst TestSchema = Schema.from('iter_no_fallback')\n\t\t\t\t.pk('id', v.string(), () => 'x')\n\t\t\t\t.build()\n\t\t\tconst adapter = new (FindOnlyAdapter as any)() as FindOnlyAdapter\n\t\t\tconst rows: Record<string, unknown>[] = []\n\t\t\tfor await (const row of adapter.use(TestSchema, { table: 'iter_no_fallback' }).iterateMany(FilterGroup.create())) rows.push(row)\n\n\t\t\texpect(rows).toEqual([])\n\t\t\texpect(findManyCalls).toBe(0)\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('use() bridge delegates deleteByPk via deleteOne', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tconst { Schema } = await import('./schema')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tlet deletedPk: unknown = null\n\t\t\tclass DeleteAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\treadonly supportedFieldTypes = ['string'] as const\n\n\t\t\t\tasync findMany(_s: AnySchema, _c: unknown, _f: any) {\n\t\t\t\t\treturn [{ id: 'd1' }]\n\t\t\t\t}\n\t\t\t\tasync deleteByPk(_s: AnySchema, _c: unknown, pk: unknown) {\n\t\t\t\t\tdeletedPk = pk\n\t\t\t\t\treturn { id: String(pk) }\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst TestSchema = Schema.from('del_test')\n\t\t\t\t.pk('id', v.string(), () => 'x')\n\t\t\t\t.build()\n\t\t\tconst adapter = new (DeleteAdapter as any)() as DeleteAdapter\n\t\t\tconst ormUse = adapter.use(TestSchema, { table: 'del_test' })\n\n\t\t\tconst deleted = await ormUse.deleteOne(FilterGroup.create().eq('id', 'd1'))\n\t\t\texpect(deleted).toEqual({ id: 'd1' })\n\t\t\texpect(deletedPk).toBe('d1')\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('use() bridge delegates session to flat method', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tlet sessionRan = false\n\t\t\tclass SessionAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\tasync session<T>(fn: () => Promise<T>): Promise<T> {\n\t\t\t\t\tsessionRan = true\n\t\t\t\t\treturn fn()\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adapter = new (SessionAdapter as any)() as SessionAdapter\n\t\t\tconst result = await adapter.session!(async () => 42)\n\t\t\texpect(result).toBe(42)\n\t\t\texpect(sessionRan).toBe(true)\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\n\t\ttest('type-level: subclass method override enforces canonical signature', async () => {\n\t\t\tconst { Instance: Inst } = await import('../instance')\n\t\t\tvi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tclass CorrectAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\t\t\t\tasync findByPk(_s: AnySchema, _c: unknown, _pk: unknown) {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\tasync createMany(_s: AnySchema, _c: unknown, _d: Record<string, unknown>[]) {\n\t\t\t\t\treturn []\n\t\t\t\t}\n\t\t\t\tasync raw(_s: AnySchema, _c: unknown, ..._args: any[]) {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst adapter = new (CorrectAdapter as any)() as CorrectAdapter\n\t\t\texpect(adapter.findByPk).toBeTypeOf('function')\n\t\t\texpect(adapter.createMany).toBeTypeOf('function')\n\t\t\texpect(adapter.raw).toBeTypeOf('function')\n\n\t\t\tvi.restoreAllMocks()\n\t\t})\n\t})\n}\n","import { AsyncLocalStorage } from 'node:async_hooks'\n\nimport { v, differ } from 'valleyed'\n\nimport { configurable } from '../../../utilities/configurable'\nimport type { FieldTypeName } from '../../adapter'\nimport { Filter, FilterGroup, type FilterChild } from '../../filter'\nimport type { DiscoveredSchema, ForeignKeyAction } from '../../migrations/introspection-types'\nimport type { AddFieldChange, AddForeignKeyChange, AddIndexChange, AnyFieldSpec, CreateTableChange, DropFieldChange, DropForeignKeyChange, DropIndexChange, DropTableChange, ModifyFieldChange, RenameFieldChange, RenameTableChange } from '../../migrations/types'\nimport { OrmAdapter, type AggregateSpec } from '../../orm-adapter'\nimport type { IterationQueryOptions, QueryOptions } from '../../query-options'\nimport type { AnySchema } from '../../schema'\nimport { IncOp, MaxOp, MinOp, MulOp, PatchOp, PullOp, PushOp, SetOp, UnsetOp, type AnyUpdateOp } from '../../updates'\n\nconst inMemoryConnectionPipe = () => v.object({})\n\nexport type InMemoryRepoConfig = {\n\ttable: string\n\tprefix?: string\n}\n\ntype MigrationRecord = { id: string; appliedAt: number }\ntype TableMeta = { pk: { name: string; type: string }; fields: Map<string, AnyFieldSpec> }\ntype IndexMeta = { table: string; on: readonly string[]; unique: boolean }\ntype ForeignKeyMeta = { table: string; on: string; references: { table: string; column: string }; onDelete?: ForeignKeyAction; onUpdate?: ForeignKeyAction }\n\ntype Snapshot = {\n\tstores: Map<string, Map<string, Record<string, unknown>>>\n\tmigrations: Map<string, MigrationRecord>\n\tindexes: Map<string, IndexMeta>\n\ttables: Map<string, TableMeta>\n\tforeignKeys: Map<string, ForeignKeyMeta>\n}\n\nfunction clone<T>(value: T): T {\n\treturn structuredClone(value)\n}\n\nconst replaceMap = <K, V>(target: Map<K, V>, source: Map<K, V>) => {\n\ttarget.clear()\n\tfor (const [k, val] of source.entries()) target.set(k, val)\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction containsSubset(source: unknown, needle: unknown): boolean {\n\tif (Array.isArray(source)) {\n\t\tconst wanted = Array.isArray(needle) ? needle : [needle]\n\t\treturn wanted.every((item) => source.some((existing) => differ.equal(existing, item)))\n\t}\n\n\tif (isPlainObject(source) && isPlainObject(needle)) {\n\t\treturn Object.entries(needle).every(([k, v]) => containsSubset(source[k], v))\n\t}\n\n\treturn differ.equal(source, needle)\n}\n\nfunction compareValues(a: unknown, b: unknown): number {\n\tif (a === b) return 0\n\tif (a == null) return -1\n\tif (b == null) return 1\n\tif (typeof a === 'number' && typeof b === 'number') return a < b ? -1 : 1\n\tif (typeof a === 'string' && typeof b === 'string') return a < b ? -1 : 1\n\tif (typeof a === 'boolean' && typeof b === 'boolean') return a === false ? -1 : 1\n\tconst sa = JSON.stringify(a)\n\tconst sb = JSON.stringify(b)\n\tif (sa === sb) return 0\n\treturn sa < sb ? -1 : 1\n}\n\nfunction resolveConfigName(_: AnySchema, config: InMemoryRepoConfig): string {\n\treturn `${config.prefix ?? ''}${config.table}`\n}\n\nfunction evaluateFilter(doc: Record<string, unknown>, filter: Filter): boolean {\n\tconst fieldValue = doc[filter.field]\n\tconst value = filter.value\n\n\tswitch (filter.op) {\n\t\tcase 'eq':\n\t\t\treturn differ.equal(fieldValue, value)\n\t\tcase 'ne':\n\t\t\treturn !differ.equal(fieldValue, value)\n\t\tcase 'gt':\n\t\t\treturn compareValues(fieldValue, value) > 0\n\t\tcase 'gte':\n\t\t\treturn compareValues(fieldValue, value) >= 0\n\t\tcase 'lt':\n\t\t\treturn compareValues(fieldValue, value) < 0\n\t\tcase 'lte':\n\t\t\treturn compareValues(fieldValue, value) <= 0\n\t\tcase 'in': {\n\t\t\tif (!Array.isArray(value)) return false\n\t\t\treturn value.some((v) => differ.equal(fieldValue, v))\n\t\t}\n\t\tcase 'notIn': {\n\t\t\tif (!Array.isArray(value)) return true\n\t\t\treturn !value.some((v) => differ.equal(fieldValue, v))\n\t\t}\n\t\tcase 'like':\n\t\t\treturn String(fieldValue ?? '')\n\t\t\t\t.toLowerCase()\n\t\t\t\t.includes(String(value ?? '').toLowerCase())\n\t\tcase 'exists':\n\t\t\treturn fieldValue != null\n\t\tcase 'notExists':\n\t\t\treturn fieldValue == null\n\t\tcase 'contains':\n\t\t\treturn containsSubset(fieldValue, value)\n\t\tcase 'notContains':\n\t\t\treturn !containsSubset(fieldValue, value)\n\t\tdefault:\n\t\t\treturn false\n\t}\n}\n\nfunction evaluateChild(doc: Record<string, unknown>, child: FilterChild): boolean {\n\tif (child instanceof Filter) return evaluateFilter(doc, child)\n\tif (child instanceof FilterGroup) {\n\t\tif (child.op === 'and') return child.children.every((c) => evaluateChild(doc, c))\n\t\tif (child.op === 'or') return child.children.some((c) => evaluateChild(doc, c))\n\t}\n\treturn true\n}\n\nfunction matchesFilter(doc: Record<string, unknown>, group: FilterGroup): boolean {\n\tfor (const clause of group.children) {\n\t\tif (!evaluateChild(doc, clause)) return false\n\t}\n\treturn true\n}\n\nfunction applyOptions(rows: Record<string, unknown>[], options?: QueryOptions): Record<string, unknown>[] {\n\tlet results = rows\n\n\tif (options?.orderBy?.length) {\n\t\tresults = [...results].sort((a, b) => {\n\t\t\tfor (const ord of options.orderBy ?? []) {\n\t\t\t\tconst cmp = compareValues(a[ord.field], b[ord.field])\n\t\t\t\tif (cmp !== 0) return ord.direction === 'asc' ? cmp : -cmp\n\t\t\t}\n\t\t\treturn 0\n\t\t})\n\t}\n\n\tif (options?.offset != null) {\n\t\tresults = results.slice(Math.max(0, options.offset))\n\t}\n\n\tif (options?.limit != null) {\n\t\tresults = results.slice(0, options.limit)\n\t}\n\n\tif (options?.select?.length) {\n\t\tconst fields = new Set<string>(options.select)\n\t\tresults = results.map((row) => {\n\t\t\tconst out: Record<string, unknown> = {}\n\t\t\tfor (const key of fields) out[key] = row[key]\n\t\t\treturn out\n\t\t})\n\t}\n\n\treturn results\n}\n\nfunction applyUpdateOp(current: Record<string, unknown>, key: string, value: unknown) {\n\tif (value instanceof IncOp) {\n\t\tconst base = Number(current[key] ?? 0)\n\t\tcurrent[key] = base + value.value\n\t\treturn\n\t}\n\tif (value instanceof MulOp) {\n\t\tconst base = Number(current[key] ?? 0)\n\t\tcurrent[key] = base * value.value\n\t\treturn\n\t}\n\tif (value instanceof MinOp) {\n\t\tconst base = current[key]\n\t\tcurrent[key] = base == null || compareValues(value.value, base) < 0 ? value.value : base\n\t\treturn\n\t}\n\tif (value instanceof MaxOp) {\n\t\tconst base = current[key]\n\t\tcurrent[key] = base == null || compareValues(value.value, base) > 0 ? value.value : base\n\t\treturn\n\t}\n\tif (value instanceof UnsetOp) {\n\t\tcurrent[key] = null\n\t\treturn\n\t}\n\tif (value instanceof PushOp) {\n\t\tconst arr = Array.isArray(current[key]) ? [...(current[key] as unknown[])] : []\n\t\tarr.push(clone(value.value))\n\t\tcurrent[key] = arr\n\t\treturn\n\t}\n\tif (value instanceof PullOp) {\n\t\tconst arr = Array.isArray(current[key]) ? (current[key] as unknown[]) : []\n\t\tcurrent[key] = arr.filter((entry) => !differ.equal(entry, value.value))\n\t\treturn\n\t}\n\tif (value instanceof PatchOp) {\n\t\tconst target = isPlainObject(current[key]) ? clone(current[key] as Record<string, unknown>) : {}\n\t\tif (isPlainObject(value.value)) {\n\t\t\tfor (const [k, v] of Object.entries(value.value as Record<string, unknown>)) {\n\t\t\t\ttarget[k] = clone(v)\n\t\t\t}\n\t\t}\n\t\tcurrent[key] = target\n\t\treturn\n\t}\n\tcurrent[key] = clone(value)\n}\n\nfunction applyUpdateData(doc: Record<string, unknown>, data: Record<string, unknown>): Record<string, unknown> {\n\tconst updated = clone(doc)\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tapplyUpdateOp(updated, key, value)\n\t}\n\treturn updated\n}\n\nfunction applyOps(doc: Record<string, unknown>, ops: AnyUpdateOp[]): Record<string, unknown> {\n\tconst updated = clone(doc)\n\tfor (const op of ops) {\n\t\tif (op instanceof SetOp) {\n\t\t\tfor (const [key, value] of Object.entries(op.values)) {\n\t\t\t\tupdated[key] = clone(value)\n\t\t\t}\n\t\t} else {\n\t\t\tapplyUpdateOp(updated, op.field, op)\n\t\t}\n\t}\n\treturn updated\n}\n\nconst sessionActiveStore = new AsyncLocalStorage<boolean>()\n\nexport class InMemoryAdapter extends configurable(inMemoryConnectionPipe, OrmAdapter) {\n\treadonly schemaConfigPipe = v.object({ table: v.string() })\n\n\treadonly supportedFieldTypes = ['string', 'number', 'boolean', 'null', 'object', 'array', 'date'] as const\n\treadonly queryableOps = ['eq', 'ne', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn', 'like', 'exists', 'notExists', 'contains', 'notContains'] as const\n\treadonly updateOps = ['set', 'inc', 'mul', 'min', 'max', 'unset', 'push', 'pull', 'patch'] as const\n\treadonly aggregateOps = ['count', 'countDistinct', 'sum', 'avg', 'min', 'max'] as const\n\n\treadonly stores = new Map<string, Map<string, Record<string, unknown>>>()\n\treadonly migrations = new Map<string, MigrationRecord>()\n\treadonly indexes = new Map<string, IndexMeta>()\n\treadonly tables = new Map<string, TableMeta>()\n\treadonly foreignKeys = new Map<string, ForeignKeyMeta>()\n\n\t#migrationLock: Promise<void> = Promise.resolve()\n\n\tprotected constructor(config: typeof InMemoryAdapter.Config) {\n\t\tsuper(config)\n\t}\n\n\t#getStore(name: string) {\n\t\tif (!this.stores.has(name)) this.stores.set(name, new Map())\n\t\treturn this.stores.get(name)!\n\t}\n\n\t#resolveStore(schema: AnySchema, config: unknown) {\n\t\treturn this.#getStore(resolveConfigName(schema, config as InMemoryRepoConfig))\n\t}\n\n\t#snapshot(): Snapshot {\n\t\tconst stores = new Map<string, Map<string, Record<string, unknown>>>()\n\t\tfor (const [name, store] of this.stores.entries()) {\n\t\t\tconst storeCopy = new Map<string, Record<string, unknown>>()\n\t\t\tfor (const [id, doc] of store.entries()) {\n\t\t\t\tstoreCopy.set(id, clone(doc))\n\t\t\t}\n\t\t\tstores.set(name, storeCopy)\n\t\t}\n\t\tconst migrations = new Map(this.migrations)\n\t\tconst indexes = new Map(this.indexes)\n\t\tconst tables = new Map<string, TableMeta>()\n\t\tfor (const [name, meta] of this.tables.entries()) {\n\t\t\ttables.set(name, { pk: { ...meta.pk }, fields: new Map(meta.fields) })\n\t\t}\n\t\tconst foreignKeys = new Map(this.foreignKeys)\n\t\treturn { stores, migrations, indexes, tables, foreignKeys }\n\t}\n\n\t#restore(snap: Snapshot) {\n\t\treplaceMap(this.stores, snap.stores)\n\t\treplaceMap(this.migrations, snap.migrations)\n\t\treplaceMap(this.indexes, snap.indexes)\n\t\treplaceMap(this.tables, snap.tables)\n\t\treplaceMap(this.foreignKeys, snap.foreignKeys)\n\t}\n\n\tasync findByPk(schema: AnySchema, config: unknown, pk: unknown) {\n\t\tconst store = this.#resolveStore(schema, config)\n\t\tconst doc = store.get(String(pk))\n\t\treturn doc ? clone(doc) : null\n\t}\n\n\tasync createMany(schema: AnySchema, config: unknown, data: Record<string, unknown>[]) {\n\t\tconst pk = schema.pkField.name\n\t\tconst store = this.#resolveStore(schema, config)\n\t\treturn data.map((d) => {\n\t\t\tconst row = clone(d)\n\t\t\tstore.set(String(row[pk]), row)\n\t\t\treturn clone(row)\n\t\t})\n\t}\n\n\tasync deleteByPk(schema: AnySchema, config: unknown, pk: unknown) {\n\t\tconst store = this.#resolveStore(schema, config)\n\t\tconst pkStr = String(pk)\n\t\tconst doc = store.get(pkStr)\n\t\tif (!doc) return null\n\t\tstore.delete(pkStr)\n\t\treturn clone(doc)\n\t}\n\n\tasync updateByPk(schema: AnySchema, config: unknown, pk: unknown, ops: AnyUpdateOp[]) {\n\t\tconst store = this.#resolveStore(schema, config)\n\t\tconst pkStr = String(pk)\n\t\tconst doc = store.get(pkStr)\n\t\tif (!doc) return null\n\t\tconst updated = applyOps(doc, ops)\n\t\tstore.set(pkStr, updated)\n\t\treturn clone(updated)\n\t}\n\n\tasync findMany(schema: AnySchema, config: unknown, group: FilterGroup, options?: QueryOptions) {\n\t\tconst store = this.#resolveStore(schema, config)\n\t\tconst rows = [...store.values()].filter((doc) => matchesFilter(doc, group)).map((doc) => clone(doc))\n\t\treturn applyOptions(rows, options)\n\t}\n\n\tasync count(schema: AnySchema, config: unknown, group: FilterGroup) {\n\t\tconst store = this.#resolveStore(schema, config)\n\t\treturn [...store.values()].filter((doc) => matchesFilter(doc, group)).length\n\t}\n\n\tasync *iterateMany(schema: AnySchema, config: unknown, group: FilterGroup, options?: IterationQueryOptions) {\n\t\tconst store = this.#resolveStore(schema, config)\n\t\tconst rows = applyOptions([...store.values()].filter((doc) => matchesFilter(doc, group)).map((doc) => clone(doc)), options)\n\t\tconst batchSize = typeof options?.batchSize === 'number' && Number.isSafeInteger(options.batchSize) && options.batchSize > 0 ? options.batchSize : 1\n\t\tfor (let start = 0; start < rows.length; start += batchSize) {\n\t\t\tfor (const row of rows.slice(start, start + batchSize)) {\n\t\t\t\tyield row\n\t\t\t}\n\t\t}\n\t}\n\n\tasync updateMany(schema: AnySchema, config: unknown, group: FilterGroup, data: Record<string, unknown>) {\n\t\tconst store = this.#resolveStore(schema, config)\n\t\tconst ids = [...store.entries()].filter(([, doc]) => matchesFilter(doc, group)).map(([id]) => id)\n\n\t\tconst updated: Record<string, unknown>[] = []\n\t\tfor (const id of ids) {\n\t\t\tconst current = store.get(id)\n\t\t\tif (!current) continue\n\t\t\tconst next = applyUpdateData(current, data)\n\t\t\tstore.set(id, next)\n\t\t\tupdated.push(clone(next))\n\t\t}\n\t\treturn updated\n\t}\n\n\tasync deleteMany(schema: AnySchema, config: unknown, filter: FilterGroup) {\n\t\tconst store = this.#resolveStore(schema, config)\n\t\tconst pk = schema.pkField.name\n\t\tconst rows = [...store.values()].filter((doc) => matchesFilter(doc, filter)).map((doc) => clone(doc))\n\t\tfor (const row of rows) store.delete(String(row[pk]))\n\t\treturn rows\n\t}\n\n\tasync upsertOne(schema: AnySchema, config: unknown, filter: FilterGroup, create: Record<string, unknown>, ops: AnyUpdateOp[]) {\n\t\tconst store = this.#resolveStore(schema, config)\n\t\tconst pk = schema.pkField.name\n\t\tconst rows = [...store.values()].filter((doc) => matchesFilter(doc, filter))\n\t\tconst current = rows[0]\n\t\tif (current) {\n\t\t\tconst next = ops.length > 0 ? applyOps(current, ops) : clone(current)\n\t\t\tstore.set(String(next[pk]), next)\n\t\t\treturn clone(next)\n\t\t}\n\t\tconst base = clone(create)\n\t\tconst result = ops.length > 0 ? applyOps(base, ops) : base\n\t\tstore.set(String(result[pk]), result)\n\t\treturn clone(result)\n\t}\n\n\tasync aggregate(schema: AnySchema, config: unknown, spec: AggregateSpec): Promise<Array<Record<string, unknown>>> {\n\t\tconst store = this.#resolveStore(schema, config)\n\t\tlet rows = [...store.values()]\n\t\tif (spec.where) {\n\t\t\tconst where = spec.where\n\t\t\trows = rows.filter((doc) => matchesFilter(doc, where))\n\t\t}\n\n\t\tconst groups = new Map<string, Record<string, unknown>[]>()\n\t\tif (spec.groupBy.length > 0) {\n\t\t\tfor (const row of rows) {\n\t\t\t\tconst key = JSON.stringify(spec.groupBy.map((f) => row[f]))\n\t\t\t\tif (!groups.has(key)) groups.set(key, [])\n\t\t\t\tgroups.get(key)!.push(row)\n\t\t\t}\n\t\t} else {\n\t\t\tgroups.set('__all__', rows)\n\t\t}\n\n\t\tconst results: Record<string, unknown>[] = []\n\t\tfor (const [, groupRows] of groups) {\n\t\t\tconst result: Record<string, unknown> = {}\n\t\t\tif (spec.groupBy.length > 0) {\n\t\t\t\tfor (const field of spec.groupBy) {\n\t\t\t\t\tresult[field] = groupRows[0][field]\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const agg of spec.aggregates) {\n\t\t\t\tswitch (agg.fn) {\n\t\t\t\t\tcase 'count':\n\t\t\t\t\t\tresult[agg.alias] = groupRows.length\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase 'countDistinct': {\n\t\t\t\t\t\tconst vals = new Set(groupRows.map((r) => JSON.stringify(r[agg.field!])))\n\t\t\t\t\t\tresult[agg.alias] = vals.size\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'sum':\n\t\t\t\t\t\tresult[agg.alias] = groupRows.reduce((acc, r) => acc + Number(r[agg.field!] ?? 0), 0)\n\t\t\t\t\t\tbreak\n\t\t\t\t\tcase 'avg': {\n\t\t\t\t\t\tconst sum = groupRows.reduce((acc, r) => acc + Number(r[agg.field!] ?? 0), 0)\n\t\t\t\t\t\tresult[agg.alias] = groupRows.length > 0 ? sum / groupRows.length : 0\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'min': {\n\t\t\t\t\t\tlet minVal: unknown = null\n\t\t\t\t\t\tfor (const r of groupRows) {\n\t\t\t\t\t\t\tconst val = r[agg.field!]\n\t\t\t\t\t\t\tif (val != null && (minVal === null || compareValues(val, minVal) < 0)) minVal = val\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresult[agg.alias] = minVal\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'max': {\n\t\t\t\t\t\tlet maxVal: unknown = null\n\t\t\t\t\t\tfor (const r of groupRows) {\n\t\t\t\t\t\t\tconst val = r[agg.field!]\n\t\t\t\t\t\t\tif (val != null && (maxVal === null || compareValues(val, maxVal) > 0)) maxVal = val\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresult[agg.alias] = maxVal\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tresults.push(result)\n\t\t}\n\n\t\tif (spec.having) {\n\t\t\tconst having = spec.having\n\t\t\treturn results.filter((r) => matchesFilter(r, having))\n\t\t}\n\t\treturn results\n\t}\n\n\tasync loadMigrations(): Promise<{ id: string; appliedAt: number }[]> {\n\t\treturn [...this.migrations.values()].map((m) => ({ id: m.id, appliedAt: m.appliedAt }))\n\t}\n\n\tasync recordMigration(id: string, appliedAt: number): Promise<void> {\n\t\tthis.migrations.set(id, { id, appliedAt })\n\t}\n\n\tasync applyCreateTable(change: CreateTableChange<any>): Promise<void> {\n\t\tconst fields = new Map<string, AnyFieldSpec>()\n\t\tfor (const f of change.fields) {\n\t\t\tfields.set(f.name, { ...f })\n\t\t}\n\t\tthis.tables.set(change.name, { pk: { name: change.pk.name, type: change.pk.type }, fields })\n\t}\n\n\tasync applyDropTable(change: DropTableChange): Promise<void> {\n\t\tthis.tables.delete(change.name)\n\t}\n\n\tasync applyAddField(change: AddFieldChange<any>): Promise<void> {\n\t\tconst table = this.tables.get(change.table)\n\t\tif (table) {\n\t\t\ttable.fields.set(change.field.name, { ...change.field })\n\t\t}\n\t}\n\n\tasync applyDropField(change: DropFieldChange): Promise<void> {\n\t\tconst table = this.tables.get(change.table)\n\t\tif (table) {\n\t\t\ttable.fields.delete(change.name)\n\t\t}\n\t}\n\n\tasync applyModifyField(change: ModifyFieldChange<any>): Promise<void> {\n\t\tconst table = this.tables.get(change.table)\n\t\tif (table) {\n\t\t\ttable.fields.delete(change.name)\n\t\t\ttable.fields.set(change.to.name, { ...change.to })\n\t\t}\n\t}\n\n\tasync applyRenameTable(change: RenameTableChange): Promise<void> {\n\t\tconst table = this.tables.get(change.from)\n\t\tif (table) {\n\t\t\tthis.tables.delete(change.from)\n\t\t\tthis.tables.set(change.to, table)\n\t\t}\n\t}\n\n\tasync applyRenameField(change: RenameFieldChange): Promise<void> {\n\t\tconst table = this.tables.get(change.table)\n\t\tif (table) {\n\t\t\tconst field = table.fields.get(change.from)\n\t\t\tif (field) {\n\t\t\t\ttable.fields.delete(change.from)\n\t\t\t\ttable.fields.set(change.to, { ...field, name: change.to })\n\t\t\t}\n\t\t}\n\t}\n\n\tasync applyAddIndex(change: AddIndexChange): Promise<void> {\n\t\tconst indexName = change.name ?? `${change.table}_${change.on.join('_')}_idx`\n\t\tthis.indexes.set(indexName, { table: change.table, on: change.on, unique: change.unique ?? false })\n\t}\n\n\tasync applyDropIndex(change: DropIndexChange): Promise<void> {\n\t\tthis.indexes.delete(change.name)\n\t}\n\n\tasync applyAddForeignKey(change: AddForeignKeyChange): Promise<void> {\n\t\tconst fkName = change.name ?? `${change.table}_${change.on}_fk`\n\t\tthis.foreignKeys.set(fkName, {\n\t\t\ttable: change.table,\n\t\t\ton: change.on,\n\t\t\treferences: { table: change.references.table, column: change.references.column },\n\t\t\tonDelete: change.onDelete as ForeignKeyAction | undefined,\n\t\t\tonUpdate: change.onUpdate as ForeignKeyAction | undefined,\n\t\t})\n\t}\n\n\tasync applyDropForeignKey(change: DropForeignKeyChange): Promise<void> {\n\t\tthis.foreignKeys.delete(change.name)\n\t}\n\n\tasync introspect(): Promise<DiscoveredSchema[]> {\n\t\tconst schemas: DiscoveredSchema[] = []\n\t\tfor (const [name, meta] of this.tables.entries()) {\n\t\t\tconst fields = [...meta.fields.values()].map((f) => ({\n\t\t\t\tname: f.name,\n\t\t\t\ttype: f.type as FieldTypeName,\n\t\t\t\tnullable: f.nullable ?? false,\n\t\t\t\t...(f.default !== undefined ? { default: f.default } : {}),\n\t\t\t\t...(f.unique ? { unique: true } : {}),\n\t\t\t}))\n\t\t\tconst indexes = [...this.indexes.entries()]\n\t\t\t\t.filter(([, idx]) => idx.table === name)\n\t\t\t\t.map(([idxName, idx]) => ({ name: idxName, on: idx.on, unique: idx.unique }))\n\t\t\tconst foreignKeys = [...this.foreignKeys.entries()]\n\t\t\t\t.filter(([, fk]) => fk.table === name)\n\t\t\t\t.map(([fkName, fk]) => ({\n\t\t\t\t\tname: fkName,\n\t\t\t\t\ton: fk.on,\n\t\t\t\t\treferences: { table: fk.references.table, column: fk.references.column },\n\t\t\t\t\t...(fk.onDelete ? { onDelete: fk.onDelete } : {}),\n\t\t\t\t\t...(fk.onUpdate ? { onUpdate: fk.onUpdate } : {}),\n\t\t\t\t}))\n\t\t\tschemas.push({\n\t\t\t\tname,\n\t\t\t\tpk: { name: meta.pk.name, type: meta.pk.type as FieldTypeName },\n\t\t\t\tfields,\n\t\t\t\tindexes,\n\t\t\t\tforeignKeys,\n\t\t\t})\n\t\t}\n\t\treturn schemas\n\t}\n\n\tasync acquireMigrationLock<T>(fn: () => Promise<T>): Promise<T> {\n\t\tlet release!: () => void\n\t\tconst next = new Promise<void>((r) => { release = r })\n\t\tconst prev = this.#migrationLock\n\t\tthis.#migrationLock = next\n\t\tawait prev\n\t\ttry {\n\t\t\treturn await fn()\n\t\t} finally {\n\t\t\trelease()\n\t\t}\n\t}\n\n\tasync session<T>(fn: () => Promise<T>): Promise<T> {\n\t\tif (sessionActiveStore.getStore()) return fn()\n\t\tconst snap = this.#snapshot()\n\t\ttry {\n\t\t\treturn await sessionActiveStore.run(true, fn)\n\t\t} catch (error) {\n\t\t\tthis.#restore(snap)\n\t\t\tthrow error\n\t\t}\n\t}\n}\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect } = import.meta.vitest\n\tconst { FilterGroup } = await import('../../filter')\n\tconst { OrderBy } = await import('../../query-options')\n\tconst { Schema } = await import('../../schema')\n\tconst { IncOp, PatchOp, PullOp, PushOp } = await import('../../updates')\n\n\tconst { v } = await import('valleyed')\n\n\tdescribe('in-memory adapter', () => {\n\t\ttest('InMemoryAdapter.create({}) produces a working adapter', () => {\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\texpect(adapter).toBeInstanceOf(InMemoryAdapter)\n\t\t\texpect(adapter.schemaConfigPipe).toBeDefined()\n\t\t\texpect(adapter.supportedFieldTypes).toEqual(['string', 'number', 'boolean', 'null', 'object', 'array', 'date'])\n\t\t})\n\n\t\ttest('supports nested filters, ordering, select, offset and limit', async () => {\n\t\t\tconst schema = Schema.from('users')\n\t\t\t\t.pk('id', v.string(), () => 'u')\n\t\t\t\t.field('name', v.string())\n\t\t\t\t.field('age', v.number())\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\tconst use = adapter.use(schema, { table: 'users' })\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'u1', name: 'Alice', age: 30 },\n\t\t\t\t{ id: 'u2', name: 'Bob', age: 20 },\n\t\t\t\t{ id: 'u3', name: 'Carol', age: 40 },\n\t\t\t])\n\t\t\tconst builtGroup = FilterGroup.create().and([\n\t\t\t\t(q) => q.gt('age', 19),\n\t\t\t\t(q) => q.or([(g) => g.eq('name', 'Alice'), (g) => g.eq('name', 'Carol')]),\n\t\t\t])\n\t\t\tconst options = { orderBy: [new OrderBy('age', 'desc')], offset: 1, limit: 1, select: ['id', 'name'] }\n\t\t\tconst rows = await use.findMany(builtGroup, options)\n\t\t\texpect(rows).toEqual([{ id: 'u1', name: 'Alice' }])\n\t\t})\n\n\t\ttest('count returns the number of matching rows without query options', async () => {\n\t\t\tconst schema = Schema.from('count_users')\n\t\t\t\t.pk('id', v.string(), () => 'u')\n\t\t\t\t.field('name', v.string())\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\tconst use = adapter.use(schema, { table: 'count_users' })\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'u1', name: 'Alice' },\n\t\t\t\t{ id: 'u2', name: 'Bob' },\n\t\t\t\t{ id: 'u3', name: 'Alice' },\n\t\t\t])\n\n\t\t\tawait expect(use.count(FilterGroup.create().eq('name', 'Alice'))).resolves.toBe(2)\n\t\t})\n\n\t\ttest('iterateMany with batchSize matches findMany filtering ordering offset limit and selection', async () => {\n\t\t\tconst schema = Schema.from('iter_users')\n\t\t\t\t.pk('id', v.string(), () => 'u')\n\t\t\t\t.field('name', v.string())\n\t\t\t\t.field('age', v.number())\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\tconst use = adapter.use(schema, { table: 'iter_users' })\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'u1', name: 'Alice', age: 30 },\n\t\t\t\t{ id: 'u2', name: 'Bob', age: 20 },\n\t\t\t\t{ id: 'u3', name: 'Carol', age: 40 },\n\t\t\t\t{ id: 'u4', name: 'Dan', age: 50 },\n\t\t\t])\n\n\t\t\tconst filter = FilterGroup.create().gt('age', 19)\n\t\t\tconst options = {\n\t\t\t\torderBy: [new OrderBy('age', 'desc')],\n\t\t\t\toffset: 1,\n\t\t\t\tlimit: 2,\n\t\t\t\tselect: ['id', 'name'],\n\t\t\t}\n\t\t\tconst expected = await use.findMany(filter, options)\n\t\t\tconst rows: Record<string, unknown>[] = []\n\t\t\tfor await (const row of use.iterateMany(filter, { ...options, batchSize: 2 })) {\n\t\t\t\trows.push(row)\n\t\t\t}\n\n\t\t\texpect(rows).toEqual(expected)\n\t\t\texpect(rows).toEqual([\n\t\t\t\t{ id: 'u3', name: 'Carol' },\n\t\t\t\t{ id: 'u1', name: 'Alice' },\n\t\t\t])\n\t\t})\n\n\t\ttest('supports update operators and rollback on failed session', async () => {\n\t\t\tconst schema = Schema.from('docs')\n\t\t\t\t.pk('id', v.string(), () => 'd1')\n\t\t\t\t.field('count', v.number())\n\t\t\t\t.field('tags', v.array(v.string()))\n\t\t\t\t.field('meta', v.object({ a: v.number() }))\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\tconst use = adapter.use(schema, { table: 'docs' })\n\t\t\tawait use.createOne({ id: 'd1', count: 1, tags: ['x'], meta: { a: 1 } })\n\n\t\t\tawait adapter.session(async () => {\n\t\t\t\tawait use.updateOne(FilterGroup.create().eq('id', 'd1'), {\n\t\t\t\t\tcount: new IncOp('count', 2),\n\t\t\t\t\ttags: new PushOp('tags', 'y'),\n\t\t\t\t\tmeta: new PatchOp('meta', { a: 9 }),\n\t\t\t\t})\n\t\t\t})\n\n\t\t\tawait expect(\n\t\t\t\tadapter.session(async () => {\n\t\t\t\t\tawait use.updateOne(FilterGroup.create().eq('id', 'd1'), { tags: new PullOp('tags', 'x') })\n\t\t\t\t\tthrow new Error('boom')\n\t\t\t\t}),\n\t\t\t).rejects.toThrow('boom')\n\n\t\t\tconst row = await use.findOne(FilterGroup.create().eq('id', 'd1'))\n\t\t\texpect(row).toEqual({ id: 'd1', count: 3, tags: ['x', 'y'], meta: { a: 9 } })\n\t\t})\n\n\t\ttest('notIn filter excludes matching values', async () => {\n\t\t\tconst schema = Schema.from('users')\n\t\t\t\t.pk('id', v.string(), () => 'u')\n\t\t\t\t.field('name', v.string())\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\tconst use = adapter.use(schema, { table: 'users' })\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'u1', name: 'Alice' },\n\t\t\t\t{ id: 'u2', name: 'Bob' },\n\t\t\t\t{ id: 'u3', name: 'Carol' },\n\t\t\t])\n\t\t\tconst rows = await use.findMany(FilterGroup.create().notIn('name', ['Alice', 'Carol']))\n\t\t\texpect(rows).toHaveLength(1)\n\t\t\texpect(rows[0].name).toBe('Bob')\n\t\t})\n\n\t\ttest('exists / notExists filter ops work correctly', async () => {\n\t\t\tconst schema = Schema.from('items')\n\t\t\t\t.pk('id', v.string(), () => 'i')\n\t\t\t\t.field('val', v.optional(v.string()), { onCreate: () => undefined })\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\tconst use = adapter.use(schema, { table: 'items' })\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'i1', val: 'present' },\n\t\t\t\t{ id: 'i2', val: null },\n\t\t\t\t{ id: 'i3', val: undefined },\n\t\t\t])\n\t\t\tconst existsRows = await use.findMany(FilterGroup.create().exists('val'))\n\t\t\texpect(existsRows).toHaveLength(1)\n\t\t\texpect(existsRows[0].id).toBe('i1')\n\n\t\t\tconst notExistsRows = await use.findMany(FilterGroup.create().notExists('val'))\n\t\t\texpect(notExistsRows).toHaveLength(2)\n\t\t})\n\n\t\ttest('findByPk returns seeded document and null for missing', async () => {\n\t\t\tconst schema = Schema.from('test')\n\t\t\t\t.pk('id', v.string(), () => 'gen')\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\n\t\t\tconst use = adapter.use(schema, { table: 'test' })\n\t\t\tawait use.createOne({ id: 'x' })\n\n\t\t\tconst found = await adapter.findByPk(schema, { table: 'test' }, 'x')\n\t\t\texpect(found).toEqual({ id: 'x' })\n\n\t\t\tconst missing = await adapter.findByPk(schema, { table: 'test' }, 'missing')\n\t\t\texpect(missing).toBeNull()\n\t\t})\n\n\t\ttest('auto-wired Instance hooks register correctly keyed by class', async () => {\n\t\t\tconst { Instance: Inst } = await import('../../../instance')\n\t\t\tconst onSpy = (await import('vitest')).vi.spyOn(Inst, 'on').mockImplementation(() => {})\n\n\t\t\tInMemoryAdapter.create({})\n\n\t\t\texpect(onSpy).not.toHaveBeenCalled()\n\n\t\t\tonSpy.mockRestore()\n\t\t})\n\n\t\ttest('declares aggregateOps with all six canonical ops', () => {\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\texpect(adapter.aggregateOps).toEqual(['count', 'countDistinct', 'sum', 'avg', 'min', 'max'])\n\t\t})\n\n\t\ttest('aggregate count returns correct total', async () => {\n\t\t\tconst schema = Schema.from('items')\n\t\t\t\t.pk('id', v.string(), () => `i-${Math.random().toString(36).slice(2, 8)}`)\n\t\t\t\t.field('category', v.string())\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\tconst use = adapter.use(schema, { table: 'items' })\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'i1', category: 'A' },\n\t\t\t\t{ id: 'i2', category: 'B' },\n\t\t\t\t{ id: 'i3', category: 'A' },\n\t\t\t])\n\t\t\tconst result = await adapter.aggregate(schema, { table: 'items' }, {\n\t\t\t\taggregates: [{ fn: 'count', alias: 'total' }],\n\t\t\t\tgroupBy: [],\n\t\t\t})\n\t\t\texpect(result).toEqual([{ total: 3 }])\n\t\t})\n\n\t\ttest('aggregate count with where filter', async () => {\n\t\t\tconst schema = Schema.from('items')\n\t\t\t\t.pk('id', v.string(), () => `i-${Math.random().toString(36).slice(2, 8)}`)\n\t\t\t\t.field('category', v.string())\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\tconst use = adapter.use(schema, { table: 'items' })\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'i1', category: 'A' },\n\t\t\t\t{ id: 'i2', category: 'B' },\n\t\t\t\t{ id: 'i3', category: 'A' },\n\t\t\t])\n\t\t\tconst result = await adapter.aggregate(schema, { table: 'items' }, {\n\t\t\t\taggregates: [{ fn: 'count', alias: 'total' }],\n\t\t\t\tgroupBy: [],\n\t\t\t\twhere: FilterGroup.create().eq('category', 'A'),\n\t\t\t})\n\t\t\texpect(result).toEqual([{ total: 2 }])\n\t\t})\n\n\t\ttest('aggregate count on empty store returns zero', async () => {\n\t\t\tconst schema = Schema.from('items')\n\t\t\t\t.pk('id', v.string(), () => 'x')\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\tconst result = await adapter.aggregate(schema, { table: 'items' }, {\n\t\t\t\taggregates: [{ fn: 'count', alias: 'total' }],\n\t\t\t\tgroupBy: [],\n\t\t\t})\n\t\t\texpect(result).toEqual([{ total: 0 }])\n\t\t})\n\n\t\ttest('aggregate sum/avg/min/max compute correctly', async () => {\n\t\t\tconst schema = Schema.from('items')\n\t\t\t\t.pk('id', v.string(), () => 'x')\n\t\t\t\t.field('price', v.number())\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\tconst use = adapter.use(schema, { table: 'items' })\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'i1', price: 10 },\n\t\t\t\t{ id: 'i2', price: 20 },\n\t\t\t\t{ id: 'i3', price: 30 },\n\t\t\t])\n\t\t\tconst result = await adapter.aggregate(schema, { table: 'items' }, {\n\t\t\t\taggregates: [\n\t\t\t\t\t{ fn: 'sum', field: 'price', alias: 'total' },\n\t\t\t\t\t{ fn: 'avg', field: 'price', alias: 'avg' },\n\t\t\t\t\t{ fn: 'min', field: 'price', alias: 'low' },\n\t\t\t\t\t{ fn: 'max', field: 'price', alias: 'high' },\n\t\t\t\t],\n\t\t\t\tgroupBy: [],\n\t\t\t})\n\t\t\texpect(result).toEqual([{ total: 60, avg: 20, low: 10, high: 30 }])\n\t\t})\n\n\t\ttest('aggregate countDistinct counts unique values', async () => {\n\t\t\tconst schema = Schema.from('items')\n\t\t\t\t.pk('id', v.string(), () => 'x')\n\t\t\t\t.field('category', v.string())\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\tconst use = adapter.use(schema, { table: 'items' })\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'i1', category: 'A' },\n\t\t\t\t{ id: 'i2', category: 'B' },\n\t\t\t\t{ id: 'i3', category: 'A' },\n\t\t\t])\n\t\t\tconst result = await adapter.aggregate(schema, { table: 'items' }, {\n\t\t\t\taggregates: [{ fn: 'countDistinct', field: 'category', alias: 'unique' }],\n\t\t\t\tgroupBy: [],\n\t\t\t})\n\t\t\texpect(result).toEqual([{ unique: 2 }])\n\t\t})\n\n\t\ttest('aggregate groupBy produces per-group results', async () => {\n\t\t\tconst schema = Schema.from('orders')\n\t\t\t\t.pk('id', v.string(), () => 'x')\n\t\t\t\t.field('region', v.string())\n\t\t\t\t.field('amount', v.number())\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\tconst use = adapter.use(schema, { table: 'orders' })\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'o1', region: 'US', amount: 10 },\n\t\t\t\t{ id: 'o2', region: 'EU', amount: 20 },\n\t\t\t\t{ id: 'o3', region: 'US', amount: 30 },\n\t\t\t])\n\t\t\tconst result = await adapter.aggregate(schema, { table: 'orders' }, {\n\t\t\t\taggregates: [\n\t\t\t\t\t{ fn: 'count', alias: 'cnt' },\n\t\t\t\t\t{ fn: 'sum', field: 'amount', alias: 'total' },\n\t\t\t\t],\n\t\t\t\tgroupBy: ['region'],\n\t\t\t})\n\t\t\texpect(result).toHaveLength(2)\n\t\t\tconst us = result.find((r) => r.region === 'US')\n\t\t\tconst eu = result.find((r) => r.region === 'EU')\n\t\t\texpect(us).toEqual({ region: 'US', cnt: 2, total: 40 })\n\t\t\texpect(eu).toEqual({ region: 'EU', cnt: 1, total: 20 })\n\t\t})\n\n\t\ttest('aggregate having filters post-aggregation', async () => {\n\t\t\tconst schema = Schema.from('orders')\n\t\t\t\t.pk('id', v.string(), () => 'x')\n\t\t\t\t.field('region', v.string())\n\t\t\t\t.field('amount', v.number())\n\t\t\t\t.build()\n\t\t\tconst adapter = InMemoryAdapter.create({})\n\t\t\tconst use = adapter.use(schema, { table: 'orders' })\n\t\t\tawait use.createMany([\n\t\t\t\t{ id: 'o1', region: 'US', amount: 10 },\n\t\t\t\t{ id: 'o2', region: 'EU', amount: 20 },\n\t\t\t\t{ id: 'o3', region: 'US', amount: 30 },\n\t\t\t])\n\t\t\tconst result = await adapter.aggregate(schema, { table: 'orders' }, {\n\t\t\t\taggregates: [{ fn: 'sum', field: 'amount', alias: 'total' }],\n\t\t\t\tgroupBy: ['region'],\n\t\t\t\thaving: FilterGroup.create().gt('total', 25),\n\t\t\t})\n\t\t\texpect(result).toHaveLength(1)\n\t\t\texpect(result[0]).toEqual({ region: 'US', total: 40 })\n\t\t})\n\t})\n}\n","import type { PipeInput, PipeOutput } from 'valleyed'\n\nimport type { AnyField, AnySchemaField, SchemaField } from './fields'\nimport { toFieldName } from './fields'\nimport type { AnySchema, SchemaFields } from './schema'\nimport type { Prettify } from './utils'\n\nexport type NumericFieldOf<S extends AnySchema> = {\n\t[K in keyof SchemaFields<S>]: SchemaFields<S>[K] extends SchemaField<any, infer P, any>\n\t\t? PipeOutput<P> extends number\n\t\t\t? SchemaFields<S>[K]\n\t\t\t: never\n\t\t: never\n}[keyof SchemaFields<S>]\n\nexport type ComparableFieldOf<S extends AnySchema> = {\n\t[K in keyof SchemaFields<S>]: SchemaFields<S>[K] extends SchemaField<any, infer P, any>\n\t\t? PipeOutput<P> extends number | string | Date\n\t\t\t? SchemaFields<S>[K]\n\t\t\t: never\n\t\t: never\n}[keyof SchemaFields<S>]\n\nexport type OptionalFieldOf<S extends AnySchema> = {\n\t[K in keyof SchemaFields<S>]: SchemaFields<S>[K] extends SchemaField<any, infer P, any>\n\t\t? undefined extends PipeOutput<P>\n\t\t\t? SchemaFields<S>[K]\n\t\t\t: never\n\t\t: never\n}[keyof SchemaFields<S>]\n\nexport type ArrayFieldOf<S extends AnySchema> = {\n\t[K in keyof SchemaFields<S>]: SchemaFields<S>[K] extends SchemaField<any, infer P, any>\n\t\t? PipeOutput<P> extends readonly any[]\n\t\t\t? SchemaFields<S>[K]\n\t\t\t: never\n\t\t: never\n}[keyof SchemaFields<S>]\n\nexport type ObjectFieldOf<S extends AnySchema> = {\n\t[K in keyof SchemaFields<S>]: SchemaFields<S>[K] extends SchemaField<any, infer P, any>\n\t\t? PipeOutput<P> extends Record<string, any>\n\t\t\t? PipeOutput<P> extends readonly any[]\n\t\t\t\t? never\n\t\t\t\t: SchemaFields<S>[K]\n\t\t\t: never\n\t\t: never\n}[keyof SchemaFields<S>]\n\nexport type SetValues<S extends AnySchema> = Prettify<\n\tPartial<{\n\t\t[K in keyof SchemaFields<S>]: SchemaFields<S>[K] extends AnySchemaField ? PipeInput<SchemaFields<S>[K]['pipe']> : never\n\t}>\n>\n\nexport class SetOp {\n\treadonly kind = 'set' as const\n\tconstructor(readonly values: Record<string, unknown>) {}\n}\nexport class IncOp {\n\treadonly kind = 'inc' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: number,\n\t) {}\n}\nexport class MulOp {\n\treadonly kind = 'mul' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: number,\n\t) {}\n}\nexport class MinOp<T = unknown> {\n\treadonly kind = 'min' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: T,\n\t) {}\n}\nexport class MaxOp<T = unknown> {\n\treadonly kind = 'max' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: T,\n\t) {}\n}\nexport class UnsetOp {\n\treadonly kind = 'unset' as const\n\tconstructor(readonly field: string) {}\n}\nexport class PushOp<T = unknown> {\n\treadonly kind = 'push' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: T,\n\t) {}\n}\nexport class PullOp<T = unknown> {\n\treadonly kind = 'pull' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: T,\n\t) {}\n}\nexport class PatchOp<T = unknown> {\n\treadonly kind = 'patch' as const\n\tconstructor(\n\t\treadonly field: string,\n\t\treadonly value: T,\n\t) {}\n}\n\nexport type AnyUpdateOp = SetOp | IncOp | MulOp | MinOp | MaxOp | UnsetOp | PushOp | PullOp | PatchOp\n\nexport function isUpdateOp(v: unknown): v is AnyUpdateOp {\n\treturn (\n\t\tv instanceof SetOp ||\n\t\tv instanceof IncOp ||\n\t\tv instanceof MulOp ||\n\t\tv instanceof MinOp ||\n\t\tv instanceof MaxOp ||\n\t\tv instanceof UnsetOp ||\n\t\tv instanceof PushOp ||\n\t\tv instanceof PullOp ||\n\t\tv instanceof PatchOp\n\t)\n}\n\nexport type HasOp<A, Op extends string> = A extends { updateOps: readonly (infer U)[] } ? (Op extends U ? true : false) : false\n\nexport type UpdateOp<_S extends AnySchema, A> =\n\t| (HasOp<A, 'set'> extends true ? SetOp : never)\n\t| (HasOp<A, 'inc'> extends true ? IncOp : never)\n\t| (HasOp<A, 'mul'> extends true ? MulOp : never)\n\t| (HasOp<A, 'min'> extends true ? MinOp : never)\n\t| (HasOp<A, 'max'> extends true ? MaxOp : never)\n\t| (HasOp<A, 'unset'> extends true ? UnsetOp : never)\n\t| (HasOp<A, 'push'> extends true ? PushOp : never)\n\t| (HasOp<A, 'pull'> extends true ? PullOp : never)\n\t| (HasOp<A, 'patch'> extends true ? PatchOp : never)\n\nexport function set<S extends AnySchema>(values: SetValues<S>): SetOp {\n\treturn new SetOp(values as Record<string, unknown>)\n}\n\nexport function inc<S extends AnySchema>(field: NumericFieldOf<S>, value: number): IncOp {\n\treturn new IncOp(toFieldName(field as AnyField), value)\n}\n\nexport function mul<S extends AnySchema>(field: NumericFieldOf<S>, value: number): MulOp {\n\treturn new MulOp(toFieldName(field as AnyField), value)\n}\n\nexport function min<S extends AnySchema>(field: ComparableFieldOf<S>, value: unknown): MinOp {\n\treturn new MinOp(toFieldName(field as AnyField), value)\n}\n\nexport function max<S extends AnySchema>(field: ComparableFieldOf<S>, value: unknown): MaxOp {\n\treturn new MaxOp(toFieldName(field as AnyField), value)\n}\n\nexport function unset<S extends AnySchema>(field: OptionalFieldOf<S>): UnsetOp {\n\treturn new UnsetOp(toFieldName(field as AnyField))\n}\n\nexport function push<S extends AnySchema>(field: ArrayFieldOf<S>, value: unknown): PushOp {\n\treturn new PushOp(toFieldName(field as AnyField), value)\n}\n\nexport function pull<S extends AnySchema>(field: ArrayFieldOf<S>, value: unknown): PullOp {\n\treturn new PullOp(toFieldName(field as AnyField), value)\n}\n\nexport function patch<S extends AnySchema>(field: ObjectFieldOf<S>, value: Record<string, unknown>): PatchOp {\n\treturn new PatchOp(toFieldName(field as AnyField), value)\n}\n\nexport function opTouchedFields(op: AnyUpdateOp): string[] {\n\tif (op instanceof SetOp) return Object.keys(op.values)\n\treturn [op.field]\n}\n\nexport function flattenOps(ops: AnyUpdateOp[]): Record<string, unknown> {\n\tconst data: Record<string, unknown> = {}\n\tfor (const op of ops) {\n\t\tif (op instanceof SetOp) Object.assign(data, op.values)\n\t\telse data[op.field] = op\n\t}\n\treturn data\n}\n\nif (import.meta.vitest) {\n\tconst { describe, test, expect, expectTypeOf } = import.meta.vitest\n\tconst { v } = await import('valleyed')\n\tconst { Schema } = await import('./schema')\n\n\tconst TestSchema = Schema.from('test')\n\t\t.pk('id', v.string(), () => 'x')\n\t\t.field('name', v.string())\n\t\t.field('age', v.number())\n\t\t.field('score', v.optional(v.number()))\n\t\t.field('tags', v.array(v.string()))\n\t\t.field('meta', v.object({ a: v.number() }))\n\t\t.field('createdAt', v.number(), { onCreate: () => 1000 })\n\t\t.field('updatedAt', v.number(), { onCreate: () => 1000, onUpdate: () => 2000 })\n\t\t.build()\n\n\tdescribe('op classes', () => {\n\t\ttest('SetOp has kind \"set\" and stores values', () => {\n\t\t\tconst op = new SetOp({ name: 'Alice' })\n\t\t\texpect(op.kind).toBe('set')\n\t\t\texpect(op.values).toEqual({ name: 'Alice' })\n\t\t})\n\t\ttest('IncOp has kind \"inc\" and stores field + value', () => {\n\t\t\tconst op = new IncOp('age', 5)\n\t\t\texpect(op.kind).toBe('inc')\n\t\t\texpect(op.field).toBe('age')\n\t\t\texpect(op.value).toBe(5)\n\t\t})\n\t\ttest('MulOp has kind \"mul\" and stores field + value', () => {\n\t\t\tconst op = new MulOp('score', 3)\n\t\t\texpect(op.kind).toBe('mul')\n\t\t\texpect(op.field).toBe('score')\n\t\t\texpect(op.value).toBe(3)\n\t\t})\n\t\ttest('MinOp has kind \"min\"', () => {\n\t\t\texpect(new MinOp('age', 10).kind).toBe('min')\n\t\t})\n\t\ttest('MaxOp has kind \"max\"', () => {\n\t\t\texpect(new MaxOp('age', 99).kind).toBe('max')\n\t\t})\n\t\ttest('UnsetOp has kind \"unset\"', () => {\n\t\t\texpect(new UnsetOp('score').kind).toBe('unset')\n\t\t})\n\t\ttest('PushOp has kind \"push\"', () => {\n\t\t\texpect(new PushOp('tags', 'x').kind).toBe('push')\n\t\t})\n\t\ttest('PullOp has kind \"pull\"', () => {\n\t\t\texpect(new PullOp('tags', 'x').kind).toBe('pull')\n\t\t})\n\t\ttest('PatchOp has kind \"patch\"', () => {\n\t\t\texpect(new PatchOp('meta', { a: 9 }).kind).toBe('patch')\n\t\t})\n\t})\n\n\tdescribe('isUpdateOp', () => {\n\t\ttest('returns true for every op class', () => {\n\t\t\texpect(isUpdateOp(new SetOp({}))).toBe(true)\n\t\t\texpect(isUpdateOp(new IncOp('f', 1))).toBe(true)\n\t\t\texpect(isUpdateOp(new MulOp('f', 2))).toBe(true)\n\t\t\texpect(isUpdateOp(new MinOp('f', 0))).toBe(true)\n\t\t\texpect(isUpdateOp(new MaxOp('f', 10))).toBe(true)\n\t\t\texpect(isUpdateOp(new UnsetOp('f'))).toBe(true)\n\t\t\texpect(isUpdateOp(new PushOp('f', 'v'))).toBe(true)\n\t\t\texpect(isUpdateOp(new PullOp('f', 'v'))).toBe(true)\n\t\t\texpect(isUpdateOp(new PatchOp('f', {}))).toBe(true)\n\t\t})\n\t\ttest('returns false for non-op values', () => {\n\t\t\texpect(isUpdateOp('string')).toBe(false)\n\t\t\texpect(isUpdateOp(42)).toBe(false)\n\t\t\texpect(isUpdateOp(null)).toBe(false)\n\t\t\texpect(isUpdateOp({})).toBe(false)\n\t\t})\n\t})\n\n\tdescribe('op helper functions', () => {\n\t\ttest('set() creates SetOp with values', () => {\n\t\t\tconst op = set<typeof TestSchema>({ name: 'Alice', age: 30 })\n\t\t\texpect(op).toBeInstanceOf(SetOp)\n\t\t\texpect(op.kind).toBe('set')\n\t\t\texpect(op.values).toEqual({ name: 'Alice', age: 30 })\n\t\t})\n\t\ttest('inc() creates IncOp from field ref', () => {\n\t\t\tconst op = inc<typeof TestSchema>(TestSchema.fields.age, 5)\n\t\t\texpect(op).toBeInstanceOf(IncOp)\n\t\t\texpect(op.field).toBe('age')\n\t\t\texpect(op.value).toBe(5)\n\t\t})\n\t\ttest('mul() creates MulOp from field ref', () => {\n\t\t\tconst op = mul<typeof TestSchema>(TestSchema.fields.age, 3)\n\t\t\texpect(op).toBeInstanceOf(MulOp)\n\t\t\texpect(op.field).toBe('age')\n\t\t\texpect(op.value).toBe(3)\n\t\t})\n\t\ttest('min() creates MinOp from field ref', () => {\n\t\t\tconst op = min<typeof TestSchema>(TestSchema.fields.age, 10)\n\t\t\texpect(op).toBeInstanceOf(MinOp)\n\t\t\texpect(op.field).toBe('age')\n\t\t})\n\t\ttest('max() creates MaxOp from field ref', () => {\n\t\t\tconst op = max<typeof TestSchema>(TestSchema.fields.age, 99)\n\t\t\texpect(op).toBeInstanceOf(MaxOp)\n\t\t\texpect(op.field).toBe('age')\n\t\t})\n\t\ttest('unset() creates UnsetOp from field ref', () => {\n\t\t\tconst op = unset<typeof TestSchema>(TestSchema.fields.score)\n\t\t\texpect(op).toBeInstanceOf(UnsetOp)\n\t\t\texpect(op.field).toBe('score')\n\t\t})\n\t\ttest('push() creates PushOp from field ref', () => {\n\t\t\tconst op = push<typeof TestSchema>(TestSchema.fields.tags, 'new-tag')\n\t\t\texpect(op).toBeInstanceOf(PushOp)\n\t\t\texpect(op.field).toBe('tags')\n\t\t\texpect(op.value).toBe('new-tag')\n\t\t})\n\t\ttest('pull() creates PullOp from field ref', () => {\n\t\t\tconst op = pull<typeof TestSchema>(TestSchema.fields.tags, 'old-tag')\n\t\t\texpect(op).toBeInstanceOf(PullOp)\n\t\t\texpect(op.field).toBe('tags')\n\t\t})\n\t\ttest('patch() creates PatchOp from field ref', () => {\n\t\t\tconst op = patch<typeof TestSchema>(TestSchema.fields.meta, { a: 9 })\n\t\t\texpect(op).toBeInstanceOf(PatchOp)\n\t\t\texpect(op.field).toBe('meta')\n\t\t\texpect(op.value).toEqual({ a: 9 })\n\t\t})\n\t})\n\n\tdescribe('opTouchedFields', () => {\n\t\ttest('SetOp returns all keys from values', () => {\n\t\t\texpect(opTouchedFields(new SetOp({ name: 'A', age: 1 }))).toEqual(['name', 'age'])\n\t\t})\n\t\ttest('IncOp returns the field', () => {\n\t\t\texpect(opTouchedFields(new IncOp('age', 1))).toEqual(['age'])\n\t\t})\n\t\ttest('UnsetOp returns the field', () => {\n\t\t\texpect(opTouchedFields(new UnsetOp('score'))).toEqual(['score'])\n\t\t})\n\t})\n\n\tdescribe('type-level: field-category helpers', () => {\n\t\ttest('NumericFieldOf only matches numeric fields (excludes optional numeric)', () => {\n\t\t\ttype Numeric = NumericFieldOf<typeof TestSchema>\n\t\t\texpectTypeOf<Numeric['name']>().toEqualTypeOf<'age' | 'createdAt' | 'updatedAt'>()\n\t\t})\n\t\ttest('ComparableFieldOf matches numeric and string fields (excludes optional)', () => {\n\t\t\ttype Comparable = ComparableFieldOf<typeof TestSchema>\n\t\t\texpectTypeOf<Comparable['name']>().toEqualTypeOf<'id' | 'name' | 'age' | 'createdAt' | 'updatedAt'>()\n\t\t})\n\t\ttest('OptionalFieldOf only matches optional fields', () => {\n\t\t\ttype Optional = OptionalFieldOf<typeof TestSchema>\n\t\t\texpectTypeOf<Optional['name']>().toEqualTypeOf<'score'>()\n\t\t})\n\t\ttest('ArrayFieldOf only matches array fields', () => {\n\t\t\ttype Arr = ArrayFieldOf<typeof TestSchema>\n\t\t\texpectTypeOf<Arr['name']>().toEqualTypeOf<'tags'>()\n\t\t})\n\t\ttest('ObjectFieldOf only matches object fields (not arrays)', () => {\n\t\t\ttype Obj = ObjectFieldOf<typeof TestSchema>\n\t\t\texpectTypeOf<Obj['name']>().toEqualTypeOf<'meta'>()\n\t\t})\n\t})\n\n\tdescribe('type-level: inc on a string field is a TS error', () => {\n\t\ttest('inc rejects non-numeric fields', () => {\n\t\t\t// @ts-expect-error — name is a string field, not numeric\n\t\t\tinc<typeof TestSchema>(TestSchema.fields.name, 1)\n\t\t})\n\t})\n\n\tdescribe('type-level: push on a non-array field is a TS error', () => {\n\t\ttest('push rejects non-array fields', () => {\n\t\t\t// @ts-expect-error — name is a string field, not array\n\t\t\tpush<typeof TestSchema>(TestSchema.fields.name, 'val')\n\t\t})\n\t})\n\n\tdescribe('type-level: per-op gating via UpdateOp<S, A>', () => {\n\t\ttest('undeclared ops resolve to never', async () => {\n\t\t\tconst { OrmAdapter } = await import('./orm-adapter')\n\t\t\tclass LimitedAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({})\n\t\t\t\treadonly supportedFieldTypes = ['string', 'number'] as const\n\t\t\t\treadonly updateOps = ['set', 'inc'] as const\n\t\t\t}\n\n\t\t\ttype Limited = UpdateOp<typeof TestSchema, LimitedAdapter>\n\t\t\texpectTypeOf<Limited>().toEqualTypeOf<SetOp | IncOp>()\n\t\t})\n\n\t\ttest('adapter with no updateOps resolves all variants to never', async () => {\n\t\t\tconst { OrmAdapter } = await import('./orm-adapter')\n\t\t\tclass NoOpsAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({})\n\t\t\t\treadonly supportedFieldTypes = ['string'] as const\n\t\t\t\treadonly updateOps = [] as const\n\t\t\t}\n\n\t\t\ttype NoOps = UpdateOp<typeof TestSchema, NoOpsAdapter>\n\t\t\texpectTypeOf<NoOps>().toBeNever()\n\t\t})\n\n\t\ttest('adapter with all updateOps includes all variants', async () => {\n\t\t\tconst { OrmAdapter } = await import('./orm-adapter')\n\t\t\tclass FullAdapter extends OrmAdapter {\n\t\t\t\treadonly schemaConfigPipe = v.object({})\n\t\t\t\treadonly supportedFieldTypes = ['string', 'number'] as const\n\t\t\t\treadonly updateOps = ['set', 'inc', 'mul', 'min', 'max', 'unset', 'push', 'pull', 'patch'] as const\n\t\t\t}\n\n\t\t\ttype Full = UpdateOp<typeof TestSchema, FullAdapter>\n\t\t\ttype Expected =\n\t\t\t\t| SetOp\n\t\t\t\t| IncOp\n\t\t\t\t| MulOp\n\t\t\t\t| MinOp\n\t\t\t\t| MaxOp\n\t\t\t\t| UnsetOp\n\t\t\t\t| PushOp\n\t\t\t\t| PullOp\n\t\t\t\t| PatchOp\n\t\t\texpectTypeOf<Full>().toEqualTypeOf<Expected>()\n\t\t})\n\t})\n}\n"],"mappings":"ukBAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,iBAAAE,IAAA,eAAAC,GAAAH,IAAA,IAAAI,EAA0D,uBAE1DC,EAAkB,oBCFlB,IAAAC,EAA0F,oBAKnF,SAASC,EAA0FC,EAAiBC,EAAY,CACtI,IAAMC,EAAOF,EAAO,EACpB,IAAE,QAAQE,CAAI,EAEd,MAAeC,UAAsBF,CAAgD,CAG1E,YAAgCG,KAA0BC,EAAgC,CAEnG,MAAM,GAAGA,CAAQ,EAFwB,YAAAD,CAG1C,CAEA,OAAO,OAENE,KACGC,EACiB,CACpB,IAAMC,EAAI,IAAE,SAASN,EAAMI,CAAK,EAChC,GAAI,CAACE,EAAE,MAAO,MAAMA,EAAE,MACtB,OAAO,IAAK,KAAaA,EAAE,MAAO,GAAGD,CAAI,CAC1C,CACD,CAEA,OAAOJ,CAQR,CCpCO,IAAMM,EAAN,cAA4B,KAAM,CACxC,YACiBC,EACAC,EACAC,EACf,CACD,MAAMF,EAAS,CAAE,MAAAE,CAAM,CAAC,EAJR,aAAAF,EACA,aAAAC,EACA,WAAAC,CAGjB,CACD,ECRA,IAAAC,EAAkC,sBAClCC,EAAqB,gBACrBC,EAA6B,oBCQtB,SAASC,EAAaC,EAAqBC,EAA0B,CAC3E,QAAWC,KAAOD,EAAO,MACxB,GAAI,CAACD,EAAM,KAAMG,GAAMA,EAAE,QAAUD,CAAG,EAAG,CACxC,IAAME,EAAUF,EAAI,MAAQ,UACtBG,EAAYJ,EAAO,OAAO,MAAQ,YACxC,MAAM,IAAI,MAAM,uBAAuBI,CAAS,qBAAqBD,CAAO,UAAUA,CAAO,oBAAoB,CAClH,CAGD,GAAIH,EAAO,MAAO,CACjB,IAAMK,EAAY,CAAC,GAAGN,EAAOC,CAAM,EACnCM,GAAYD,CAAS,CACtB,CAEAN,EAAM,KAAKC,CAAM,CAClB,CAEA,SAASM,GAAYP,EAA2B,CAC/C,IAAMQ,EAAe,IAAI,IACzB,QAAWL,KAAKH,EAAO,CACtB,GAAI,CAACG,EAAE,MAAO,SACd,IAAMM,EAAWD,EAAa,IAAIL,EAAE,KAAK,EACzC,GAAIM,EACH,QAAWP,KAAOC,EAAE,MACdM,EAAS,SAASP,CAAG,GAAGO,EAAS,KAAKP,CAAG,OAG/CM,EAAa,IAAIL,EAAE,MAAO,CAAC,GAAGA,EAAE,KAAK,CAAC,CAExC,CAEA,IAAMO,EAAU,IAAI,IACdC,EAAQ,IAAI,IAElB,SAASC,EAAMC,EAAeC,EAAwB,CACrD,GAAIH,EAAM,IAAIE,CAAG,EAAG,CACnB,IAAME,EAAaD,EAAK,QAAQD,CAAG,EAE7BG,EADQ,CAAC,GAAGF,EAAK,MAAMC,CAAU,EAAGF,CAAG,EACzB,IAAKI,GAAMA,EAAE,MAAQ,SAAS,EAClD,MAAM,IAAI,MAAM,mBAAmBD,EAAM,KAAK,UAAK,CAAC,EAAE,CACvD,CACA,GAAI,CAAAN,EAAQ,IAAIG,CAAG,EACnB,CAAAF,EAAM,IAAIE,CAAG,EACbC,EAAK,KAAKD,CAAG,EACb,QAAWX,KAAOM,EAAa,IAAIK,CAAG,GAAK,CAAC,EAC3CD,EAAMV,EAAKY,CAAI,EAEhBA,EAAK,IAAI,EACTH,EAAM,OAAOE,CAAG,EAChBH,EAAQ,IAAIG,CAAG,EAChB,CAEA,QAAWA,KAAOL,EAAa,KAAK,EACnCI,EAAMC,EAAK,CAAC,CAAC,CAEf,CAIO,SAASK,GAAelB,EAAqBmB,EAAkB,GAAoB,CACzF,GAAInB,EAAM,SAAW,EAAG,MAAO,CAAC,EAEhC,IAAMoB,EAAe,IAAI,IACnBC,EAA0B,CAAC,EAEjC,QAAWlB,KAAKH,EACf,GAAIG,EAAE,MAAO,CACZ,IAAMmB,EAAOF,EAAa,IAAIjB,EAAE,KAAK,EACjCmB,EAAMA,EAAK,KAAKnB,CAAC,EAChBiB,EAAa,IAAIjB,EAAE,MAAO,CAACA,CAAC,CAAC,CACnC,MACCkB,EAAU,KAAKlB,CAAC,EAIlB,IAAMoB,EAAU,CAAC,GAAGH,EAAa,KAAK,CAAC,EAEjCI,EAAW,IAAI,IACfC,EAAQ,IAAI,IAElB,QAAWZ,KAAOU,EACjBC,EAAS,IAAIX,EAAK,CAAC,EACnBY,EAAM,IAAIZ,EAAK,CAAC,CAAC,EAGlB,QAAWV,KAAKH,EACf,GAAKG,EAAE,MACP,QAAWD,KAAOC,EAAE,MAAO,CAC1B,GAAM,CAACuB,EAAMC,CAAE,EAAIR,EAAS,CAAChB,EAAE,MAAOD,CAAG,EAAI,CAACA,EAAKC,EAAE,KAAK,EACpDyB,EAAQH,EAAM,IAAIC,CAAI,EACvBE,EAAM,SAASD,CAAE,IACrBC,EAAM,KAAKD,CAAE,EACbH,EAAS,IAAIG,EAAIH,EAAS,IAAIG,CAAE,EAAK,CAAC,EAExC,CAGD,IAAME,EAAsB,CAAC,EACzBC,EAAQP,EAAQ,OAAQN,GAAMO,EAAS,IAAIP,CAAC,IAAM,CAAC,EAEvD,KAAOa,EAAM,OAAS,GAAG,CACxB,IAAMC,EAAsB,CAAC,EACvBC,EAAmB,CAAC,EAE1B,QAAWnB,KAAOiB,EACjBC,EAAM,KAAK,GAAIX,EAAa,IAAIP,CAAG,GAAK,CAAC,CAAE,EAE5CgB,EAAO,KAAKE,CAAK,EAEjB,QAAWlB,KAAOiB,EACjB,QAAWG,KAAYR,EAAM,IAAIZ,CAAG,GAAK,CAAC,EAAG,CAC5C,IAAMqB,EAAIV,EAAS,IAAIS,CAAQ,EAAK,EACpCT,EAAS,IAAIS,EAAUC,CAAC,EACpBA,IAAM,GAAGF,EAAK,KAAKC,CAAQ,CAChC,CAGDH,EAAQE,CACT,CAEA,GAAIX,EAAU,OAAS,EAAG,CACzB,IAAMc,EAAed,EAAU,OAAQlB,GAAMA,EAAE,MAAM,OAAS,CAAC,EACzDiC,EAAkBf,EAAU,OAAQlB,GAAMA,EAAE,MAAM,SAAW,CAAC,EAEpE,GAAIgC,EAAa,OAAS,EAAG,CAC5B,IAAIE,EAAW,GACf,QAAWlC,KAAKgC,EACf,QAAWjC,MAAOC,EAAE,MAAO,CAC1B,IAAMmC,EAAWT,EAAO,UAAWU,IAAMA,GAAE,KAAMC,IAAMA,GAAE,QAAUtC,EAAG,CAAC,EACnEoC,EAAWD,IAAUA,EAAWC,EACrC,CAED,IAAMG,EAAWJ,EAAW,EACxBI,EAAWZ,EAAO,OACrBA,EAAOY,CAAQ,EAAE,KAAK,GAAGN,CAAY,EAErCN,EAAO,KAAKM,CAAY,CAE1B,CAEIC,EAAgB,OAAS,IACxBP,EAAO,OAAS,EACnBA,EAAOA,EAAO,OAAS,CAAC,EAAE,KAAK,GAAGO,CAAe,EAEjDP,EAAO,KAAKO,CAAe,EAG9B,CAEA,OAAOP,CACR,CAEA,eAAsBa,EACrB1C,EACA2C,EAAmCC,GAAU,CAC5C,MAAMA,CACP,EACAzB,EAAkB,GACjB,CACD,IAAMU,EAASX,GAAelB,EAAOmB,CAAM,EAC3C,QAAWY,KAASF,EACnB,MAAM,QAAQ,IACbE,EAAM,IAAI,MAAO5B,GAAM,CACtB,GAAI,CACH,OAAI,OAAOA,EAAE,IAAO,WAAmB,MAAMA,EAAE,GAAG,EAC3C,MAAMA,EAAE,EAChB,OAASyC,EAAO,CACf,OAAOD,EAAQC,aAAiB,MAAQA,EAAQ,IAAI,MAAM,GAAGA,CAAK,EAAE,CAAC,CACtE,CACD,CAAC,CACF,CACF,CCrLA,IAAAC,EAA+E,oBAElEC,EAAuB,IACnC,IAAE,OAAO,CACR,IAAK,IAAE,OAAO,CACb,KAAM,IAAE,OAAO,CAChB,CAAC,EACD,IAAK,IAAE,SACN,IAAE,OAAO,CACR,MAAO,IAAE,SAAS,IAAE,GAAG,CAAC,QAAS,QAAS,OAAQ,OAAQ,QAAS,QAAS,QAAQ,CAAU,EAAG,MAAM,CACxG,CAAC,EACD,CAAC,CACF,EACA,MAAO,IAAE,SACR,IAAE,OAAO,CACR,eAAgB,IAAE,SAAS,IAAE,OAAO,EAAG,EAAE,EACzC,uBAAwB,IAAE,SAAS,IAAE,OAAO,EAAG,GAAG,EAClD,sBAAuB,IAAE,SAAS,IAAE,OAAO,EAAG,GAAG,CAClD,CAAC,EACD,CAAC,CACF,CACD,CAAC,EFXK,IAAMC,EAAN,MAAMC,CAAS,CACrB,MAAOC,GACP,MAAOC,GACP,MAAOC,GAAmD,CAAC,EAClD,SACA,IAED,YAAYC,EAAoB,CACvCJ,EAASE,GAAY,KACrB,KAAK,SAAW,OAAO,OAAOE,CAAQ,EACtC,KAAK,OAAM,EAAAC,SAAY,CACtB,MAAO,KAAK,SAAS,IAAI,MACzB,YAAa,CACZ,IAAK,EAAAA,QAAK,eAAe,IACzB,MAAO,EAAAA,QAAK,eAAe,IAC3B,IAAK,EAAAA,QAAK,eAAe,IACzB,IAAK,EAAAA,QAAK,eAAe,GAC1B,EACA,MAAO,KAAO,CACb,WAAYL,EAASC,EACtB,EACD,CAAC,EACDD,EAASM,GAAuB,CACjC,CAEA,MAAMC,EAAY,CACjB,GAAIP,EAASC,KAAQ,OAAW,OAAOD,EAAS,MAAM,IAAIQ,EAAc,gCAAiC,CAAC,CAAC,CAAC,EAC5GR,EAASC,GAAMM,CAChB,CAEA,IAAI,IAAK,CACR,OAAIP,EAASC,KAAQ,OAAkBD,EAAS,MAAM,IAAIQ,EAAc,oCAAqC,CAAC,CAAC,CAAC,EACzGR,EAASC,EACjB,CAEA,cAAcQ,EAAcC,EAAM,IAAK,CACtC,MAAO,CAAC,KAAK,SAAS,IAAI,KAAMD,CAAI,EAAE,KAAKC,CAAG,CAC/C,CAEA,MAAM,OAAQ,CACb,GAAI,CACH,MAAMC,EAASX,EAASG,GAAO,OAAY,CAAC,CAAC,EAC7C,MAAMQ,EAASX,EAASG,GAAO,OAAY,CAAC,CAAC,CAC9C,OAASS,EAAO,CACfZ,EAAS,MAAM,IAAIQ,EAAc,0BAA2B,CAAC,EAAGI,CAAK,CAAC,CACvE,CACD,CAEA,OAAO,KAAuBC,EAA+B,CAC5D,IAAMC,EAAc,IAAE,SAASD,EAAU,QAAQ,GAAG,EACpD,OAAKC,EAAY,OAChBd,EAAS,MACR,IAAIQ,EAAc;AAAA,EAAwCM,EAAY,MAAM,SAAS,CAAC,GAAI,CACzF,SAAUA,EAAY,MAAM,QAC7B,CAAC,CACF,EAEMA,EAAY,KACpB,CAEA,OAAO,OAAOV,EAAyB,CACtC,GAAIJ,EAASE,GAAW,OAAOF,EAAS,MAAM,IAAIQ,EAAc,wCAAyC,CAAC,CAAC,CAAC,EAC5G,IAAMO,EAAmB,IAAE,SAASC,EAAqB,EAAGZ,CAAQ,EACpE,OAAKW,EAAiB,OACrBf,EAAS,MACR,IAAIQ,EAAc;AAAA,EAA2BO,EAAiB,MAAM,SAAS,CAAC,GAAI,CACjF,SAAUA,EAAiB,MAAM,QAClC,CAAC,CACF,EAEM,IAAIf,EAASe,EAAiB,KAAK,CAC3C,CAEA,OAAO,KAAM,CACZ,OAAKf,EAASE,GAIPF,EAASE,GAHRF,EAAS,MACf,IAAIQ,EAAc,8FAA+F,CAAC,CAAC,CACpH,CAEF,CAEA,OAAO,UAAW,CACjB,OAAOR,EAASE,EACjB,CAEA,OAAO,GAAGe,EAAkBC,EAAYC,EAAuB,CAC9DnB,EAASG,GAAOc,CAAK,IAAM,CAAC,EAC5B,IAAMG,EAAqB,CAAE,GAAAF,EAAI,MAAOC,GAAS,MAAO,MAAOA,GAAS,OAAS,CAAC,CAAE,EACpFE,EAAarB,EAASG,GAAOc,CAAK,EAAGG,CAAM,CAC5C,CAEA,MAAOd,IAAyB,CAO/B,OAAO,QANS,CACf,OAAQ,EACR,OAAQ,EACR,QAAS,EACV,CAEsB,EAAE,QAAQ,CAAC,CAACgB,EAAQC,CAAI,IAAM,CACnD,QAAQ,GAAGD,EAAQ,SAAY,CAC9B,MAAMX,EAASX,EAASG,GAAO,OAAY,CAAC,EAAG,IAAM,CAAC,EAAG,EAAI,EAC7D,QAAQ,KAAK,IAAMoB,CAAI,CACxB,CAAC,CACF,CAAC,CACF,CAEA,OAAO,mBAAsBL,EAAsB,CAClD,IAAMM,EAAQN,EAAG,EACjB,OAAAlB,EAAS,GAAG,QAAS,SAAY,MAAMwB,CAAK,EACrCA,CACR,CAEA,OAAO,MAAMZ,EAA6B,CAEzC,QAAQ,MAAMA,CAAK,EACnB,QAAQ,KAAK,CAAC,CACf,CAEA,OAAO,SAASa,EAAyC,CACxD,MAAO,GAAGA,GAAM,QAAU,EAAE,MAAG,QAAKA,GAAM,MAAM,QAAQ,CAAC,CAAC,EAC3D,CACD,EGnIA,IAAAC,GAA8C,oBAEjCC,EAAN,KAAoE,CAGjE,KACA,KAET,YAAYC,EAAYC,EAA0B,CACjD,KAAK,KAAOD,EACZ,KAAK,KAAOC,GAAQ,CAACD,CAAI,CAC1B,CACD,EAIO,SAASE,GAAYC,EAAkC,CAC7D,OAAIA,aAAiBJ,EAAcI,EAAM,KAAK,KAAK,GAAG,EAC/CA,CACR,CCZO,IAAMC,EAAN,KAAa,CAEnB,YACCC,EACSC,EACAC,EACR,CAFQ,QAAAD,EACA,WAAAC,EAET,KAAK,MAAQC,GAAYH,CAAK,CAC/B,CAPS,KAQV,EAQaI,EAAN,MAAMC,CAAY,CAGhB,YACEJ,EAAoB,MAC7BK,EACC,CAFQ,QAAAL,EAGT,KAAK,SAAWK,GAAY,CAAC,CAC9B,CAPS,SASTC,GAAWC,EAAiC,CAC3C,OAAO,IAAIH,EAAY,KAAK,GAAI,CAAC,GAAG,KAAK,SAAUG,CAAK,CAAC,CAC1D,CAEA,GAAMR,EAA0BE,EAAuB,CACtD,OAAO,KAAKK,GAAW,IAAIR,EAAOC,EAAO,KAAME,CAAK,CAAC,CACtD,CAEA,GAAMF,EAA0BE,EAAuB,CACtD,OAAO,KAAKK,GAAW,IAAIR,EAAOC,EAAO,KAAME,CAAK,CAAC,CACtD,CAEA,GAAMF,EAA0BE,EAAuB,CACtD,OAAO,KAAKK,GAAW,IAAIR,EAAOC,EAAO,KAAME,CAAK,CAAC,CACtD,CAEA,IAAOF,EAA0BE,EAAuB,CACvD,OAAO,KAAKK,GAAW,IAAIR,EAAOC,EAAO,MAAOE,CAAK,CAAC,CACvD,CAEA,GAAMF,EAA0BE,EAAuB,CACtD,OAAO,KAAKK,GAAW,IAAIR,EAAOC,EAAO,KAAME,CAAK,CAAC,CACtD,CAEA,IAAOF,EAA0BE,EAAuB,CACvD,OAAO,KAAKK,GAAW,IAAIR,EAAOC,EAAO,MAAOE,CAAK,CAAC,CACvD,CAEA,GAAMF,EAA0BE,EAAyB,CACxD,OAAO,KAAKK,GAAW,IAAIR,EAAOC,EAAO,KAAME,CAAK,CAAC,CACtD,CAEA,MAASF,EAA0BE,EAAyB,CAC3D,OAAO,KAAKK,GAAW,IAAIR,EAAOC,EAAO,QAASE,CAAK,CAAC,CACzD,CAEA,KAAKF,EAA+BE,EAA4B,CAC/D,OAAO,KAAKK,GAAW,IAAIR,EAAOC,EAAO,OAAQE,CAAK,CAAC,CACxD,CAEA,OAAOF,EAA6C,CACnD,OAAO,KAAKO,GAAW,IAAIR,EAAOC,EAAO,SAAU,EAAI,CAAC,CACzD,CAEA,UAAUA,EAA6C,CACtD,OAAO,KAAKO,GAAW,IAAIR,EAAOC,EAAO,YAAa,EAAI,CAAC,CAC5D,CAEA,SAAYA,EAA0BE,EAAyB,CAC9D,OAAO,KAAKK,GAAW,IAAIR,EAAOC,EAAO,WAAYE,CAAK,CAAC,CAC5D,CAEA,YAAeF,EAA0BE,EAAyB,CACjE,OAAO,KAAKK,GAAW,IAAIR,EAAOC,EAAO,cAAeE,CAAK,CAAC,CAC/D,CAEA,IAAIO,EAAsC,CACzC,GAAIA,EAAO,SAAW,EAAG,MAAM,IAAIC,EAAc,6CAA8C,CAAE,GAAI,KAAM,CAAC,EAC5G,IAAMC,EAAQ,IAAIN,EAAY,MAAOI,EAAO,IAAKG,GAAOA,EAAGP,EAAY,OAAO,CAAC,CAAC,CAAC,EACjF,OAAO,KAAKE,GAAWI,CAAK,CAC7B,CAEA,GAAGF,EAAsC,CACxC,GAAIA,EAAO,SAAW,EAAG,MAAM,IAAIC,EAAc,4CAA6C,CAAE,GAAI,IAAK,CAAC,EAC1G,IAAMC,EAAQ,IAAIN,EAAY,KAAMI,EAAO,IAAKG,GAAOA,EAAGP,EAAY,OAAO,CAAC,CAAC,CAAC,EAChF,OAAO,KAAKE,GAAWI,CAAK,CAC7B,CAEA,OAAqB,CACpB,OAAO,IAAIN,EACV,KAAK,GACL,KAAK,SAAS,IAAKQ,GACdA,aAAad,EAAe,IAAIA,EAAOc,EAAE,MAAOA,EAAE,GAAI,gBAAgBA,EAAE,KAAK,CAAC,EAC3EA,EAAE,MAAM,CACf,CACF,CACD,CAEA,OAAO,QAAsB,CAC5B,OAAO,IAAIR,CACZ,CACD,EC3FO,IAAeS,EAAf,KAA0B,CACvB,aAAwC,CAAC,EACzC,UAAqC,CAAC,EACtC,aAA2C,CAAC,EAC5C,oBAAgD,CAAC,EA0ChD,aAAaC,EAAqB,CAC3C,IAAMC,EAAUD,aAAeE,EAAgBF,EAAM,IAAIE,EAAc,yBAA0B,CAAC,EAAGF,CAAG,EACxGG,EAAS,MAAMF,CAAO,CACvB,CAEA,aAAc,CACb,IAAMG,EAAO,KACT,OAAOA,EAAK,SAAY,YAC3BD,EAAS,GAAG,QAAS,IAAMC,EAAK,QAAQ,EAAG,CAAE,MAAO,KAAK,WAAwB,CAAC,EAE/E,OAAOA,EAAK,YAAe,YAC9BD,EAAS,GAAG,QAAS,IAAMC,EAAK,WAAW,EAAG,CAAE,MAAO,KAAK,WAAwB,CAAC,CAEvF,CAEA,IAAIC,EAAmBC,EAAyB,CAC/C,IAAMF,EAAO,KACPG,EAAgB,iBAAwE,CAAC,EACzFC,EAAc,CACnB,SAAU,CAACC,EAAQC,IAASN,EAAK,WAAWC,EAAQC,EAAQG,EAAQC,CAAI,GAAK,QAAQ,QAAQ,CAAC,CAAC,EAC/F,YAAa,CAACD,EAAQC,IAASN,EAAK,cAAcC,EAAQC,EAAQG,EAAQC,CAAI,GAAKH,EAAc,EACjG,QAAS,MAAOE,IACF,MAAMD,EAAI,SAASC,EAAQ,CAAE,MAAO,CAAE,CAAC,GACxC,CAAC,GAAK,KAEnB,MAAQA,GAAWL,EAAK,QAAQC,EAAQC,EAAQG,CAAM,GAAK,QAAQ,OAAO,IAAI,MAAM,uBAAuB,CAAC,EAC5G,UAAW,MAAOE,IACJ,MAAMH,EAAI,WAAW,CAACG,CAAC,CAAC,GACzB,CAAC,EAEd,WAAaA,GAAMP,EAAK,aAAaC,EAAQC,EAAQK,CAAC,GAAK,QAAQ,QAAQ,CAAC,CAAC,EAC7E,WAAY,CAACF,EAAQE,IAAMP,EAAK,aAAaC,EAAQC,EAAQG,EAAQE,CAAC,GAAK,QAAQ,QAAQ,CAAC,CAAC,EAC7F,UAAW,MAAOF,EAAQE,IAAM,CAC/B,IAAMC,EAAQ,MAAMJ,EAAI,QAAQC,CAAM,EACtC,GAAI,CAACG,EAAO,OAAO,KACnB,IAAMC,EAAKR,EAAO,QAAQ,KACpBS,EAAWC,EAAY,OAAO,EAAE,GAAGF,EAAID,EAAMC,CAAE,CAAC,EAEtD,OADa,MAAML,EAAI,WAAWM,EAAUH,CAAC,GACjC,CAAC,GAAK,IACnB,EACA,UAAW,CAACF,EAAQO,EAAQC,IAC3Bb,EAAK,YAAYC,EAAQC,EAAQG,EAAQO,EAAQC,CAAG,GAAK,QAAQ,OAAO,IAAI,MAAM,2BAA2B,CAAC,EAC/G,UAAW,MAAOR,GAAW,CAC5B,IAAMS,EAAM,MAAMV,EAAI,QAAQC,CAAM,EACpC,GAAI,CAACS,EAAK,OAAO,KACjB,IAAML,EAAKR,EAAO,QAAQ,KAC1B,GAAID,EAAK,WACR,MAAMA,EAAK,WAAWC,EAAQC,EAAQY,EAAIL,CAAE,CAAC,UACnCT,EAAK,WAAY,CAC3B,IAAMU,EAAWC,EAAY,OAAO,EAAE,GAAGF,EAAIK,EAAIL,CAAE,CAAC,EACpD,MAAMT,EAAK,WAAWC,EAAQC,EAAQQ,CAAQ,CAC/C,CACA,OAAOI,CACR,EACA,WAAaT,GAAWL,EAAK,aAAaC,EAAQC,EAAQG,CAAM,GAAK,QAAQ,QAAQ,CAAC,CAAC,EACvF,IAAK,IAAIU,IAAgBf,EAAK,MAAMC,EAAQC,EAAQ,GAAGa,CAAI,GAAK,QAAQ,OAAO,IAAI,MAAM,qBAAqB,CAAC,EAC/G,UAAYC,GAAShB,EAAK,YAAYC,EAAQC,EAAQc,CAAI,GAAK,QAAQ,OAAO,IAAI,MAAM,2BAA2B,CAAC,EACpH,aAAchB,EAAK,cAAgB,CAAC,CACrC,EACA,OAAOI,CACR,CACD,ECnIA,IAAAa,GAAkC,uBAElCC,EAA0B,oBCqDnB,IAAMC,EAAN,KAAY,CAElB,YAAqBC,EAAiC,CAAjC,YAAAA,CAAkC,CAD9C,KAAO,KAEjB,EACaC,EAAN,KAAY,CAElB,YACUC,EACAC,EACR,CAFQ,WAAAD,EACA,WAAAC,CACP,CAJM,KAAO,KAKjB,EACaC,EAAN,KAAY,CAElB,YACUF,EACAC,EACR,CAFQ,WAAAD,EACA,WAAAC,CACP,CAJM,KAAO,KAKjB,EACaE,EAAN,KAAyB,CAE/B,YACUH,EACAC,EACR,CAFQ,WAAAD,EACA,WAAAC,CACP,CAJM,KAAO,KAKjB,EACaG,EAAN,KAAyB,CAE/B,YACUJ,EACAC,EACR,CAFQ,WAAAD,EACA,WAAAC,CACP,CAJM,KAAO,KAKjB,EACaI,EAAN,KAAc,CAEpB,YAAqBL,EAAe,CAAf,WAAAA,CAAgB,CAD5B,KAAO,OAEjB,EACaM,EAAN,KAA0B,CAEhC,YACUN,EACAC,EACR,CAFQ,WAAAD,EACA,WAAAC,CACP,CAJM,KAAO,MAKjB,EACaM,EAAN,KAA0B,CAEhC,YACUP,EACAC,EACR,CAFQ,WAAAD,EACA,WAAAC,CACP,CAJM,KAAO,MAKjB,EACaO,EAAN,KAA2B,CAEjC,YACUR,EACAC,EACR,CAFQ,WAAAD,EACA,WAAAC,CACP,CAJM,KAAO,OAKjB,EDjGA,IAAMQ,GAAyB,IAAM,IAAE,OAAO,CAAC,CAAC,EAoBhD,SAASC,EAASC,EAAa,CAC9B,OAAO,gBAAgBA,CAAK,CAC7B,CAEA,IAAMC,EAAa,CAAOC,EAAmBC,IAAsB,CAClED,EAAO,MAAM,EACb,OAAW,CAACE,EAAGC,CAAG,IAAKF,EAAO,QAAQ,EAAGD,EAAO,IAAIE,EAAGC,CAAG,CAC3D,EAEA,SAASC,EAAcN,EAAkD,CACxE,OAAO,OAAOA,GAAU,UAAYA,IAAU,MAAQ,CAAC,MAAM,QAAQA,CAAK,CAC3E,CAEA,SAASO,EAAeJ,EAAiBK,EAA0B,CAClE,OAAI,MAAM,QAAQL,CAAM,GACR,MAAM,QAAQK,CAAM,EAAIA,EAAS,CAACA,CAAM,GACzC,MAAOC,GAASN,EAAO,KAAMO,GAAa,SAAO,MAAMA,EAAUD,CAAI,CAAC,CAAC,EAGlFH,EAAcH,CAAM,GAAKG,EAAcE,CAAM,EACzC,OAAO,QAAQA,CAAM,EAAE,MAAM,CAAC,CAACJ,EAAGO,CAAC,IAAMJ,EAAeJ,EAAOC,CAAC,EAAGO,CAAC,CAAC,EAGtE,SAAO,MAAMR,EAAQK,CAAM,CACnC,CAEA,SAASI,EAAcC,EAAYC,EAAoB,CACtD,GAAID,IAAMC,EAAG,MAAO,GACpB,GAAID,GAAK,KAAM,MAAO,GACtB,GAAIC,GAAK,KAAM,MAAO,GAEtB,GADI,OAAOD,GAAM,UAAY,OAAOC,GAAM,UACtC,OAAOD,GAAM,UAAY,OAAOC,GAAM,SAAU,OAAOD,EAAIC,EAAI,GAAK,EACxE,GAAI,OAAOD,GAAM,WAAa,OAAOC,GAAM,UAAW,OAAOD,IAAM,GAAQ,GAAK,EAChF,IAAME,EAAK,KAAK,UAAUF,CAAC,EACrBG,EAAK,KAAK,UAAUF,CAAC,EAC3B,OAAIC,IAAOC,EAAW,EACfD,EAAKC,EAAK,GAAK,CACvB,CAEA,SAASC,GAAkBC,EAAcC,EAAoC,CAC5E,MAAO,GAAGA,EAAO,QAAU,EAAE,GAAGA,EAAO,KAAK,EAC7C,CAEA,SAASC,GAAeC,EAA8BC,EAAyB,CAC9E,IAAMC,EAAaF,EAAIC,EAAO,KAAK,EAC7BtB,EAAQsB,EAAO,MAErB,OAAQA,EAAO,GAAI,CAClB,IAAK,KACJ,OAAO,SAAO,MAAMC,EAAYvB,CAAK,EACtC,IAAK,KACJ,MAAO,CAAC,SAAO,MAAMuB,EAAYvB,CAAK,EACvC,IAAK,KACJ,OAAOY,EAAcW,EAAYvB,CAAK,EAAI,EAC3C,IAAK,MACJ,OAAOY,EAAcW,EAAYvB,CAAK,GAAK,EAC5C,IAAK,KACJ,OAAOY,EAAcW,EAAYvB,CAAK,EAAI,EAC3C,IAAK,MACJ,OAAOY,EAAcW,EAAYvB,CAAK,GAAK,EAC5C,IAAK,KACJ,OAAK,MAAM,QAAQA,CAAK,EACjBA,EAAM,KAAMW,GAAM,SAAO,MAAMY,EAAYZ,CAAC,CAAC,EADlB,GAGnC,IAAK,QACJ,OAAK,MAAM,QAAQX,CAAK,EACjB,CAACA,EAAM,KAAMW,GAAM,SAAO,MAAMY,EAAYZ,CAAC,CAAC,EADnB,GAGnC,IAAK,OACJ,OAAO,OAAOY,GAAc,EAAE,EAC5B,YAAY,EACZ,SAAS,OAAOvB,GAAS,EAAE,EAAE,YAAY,CAAC,EAC7C,IAAK,SACJ,OAAOuB,GAAc,KACtB,IAAK,YACJ,OAAOA,GAAc,KACtB,IAAK,WACJ,OAAOhB,EAAegB,EAAYvB,CAAK,EACxC,IAAK,cACJ,MAAO,CAACO,EAAegB,EAAYvB,CAAK,EACzC,QACC,MAAO,EACT,CACD,CAEA,SAASwB,EAAcH,EAA8BI,EAA6B,CACjF,GAAIA,aAAiBC,EAAQ,OAAON,GAAeC,EAAKI,CAAK,EAC7D,GAAIA,aAAiBE,EAAa,CACjC,GAAIF,EAAM,KAAO,MAAO,OAAOA,EAAM,SAAS,MAAOG,GAAMJ,EAAcH,EAAKO,CAAC,CAAC,EAChF,GAAIH,EAAM,KAAO,KAAM,OAAOA,EAAM,SAAS,KAAMG,GAAMJ,EAAcH,EAAKO,CAAC,CAAC,CAC/E,CACA,MAAO,EACR,CAEA,SAASC,EAAcR,EAA8BS,EAA6B,CACjF,QAAWC,KAAUD,EAAM,SAC1B,GAAI,CAACN,EAAcH,EAAKU,CAAM,EAAG,MAAO,GAEzC,MAAO,EACR,CAEA,SAASC,GAAaC,EAAiCC,EAAmD,CACzG,IAAIC,EAAUF,EAoBd,GAlBIC,GAAS,SAAS,SACrBC,EAAU,CAAC,GAAGA,CAAO,EAAE,KAAK,CAAC,EAAGrB,IAAM,CACrC,QAAWsB,KAAOF,EAAQ,SAAW,CAAC,EAAG,CACxC,IAAMG,EAAMzB,EAAc,EAAEwB,EAAI,KAAK,EAAGtB,EAAEsB,EAAI,KAAK,CAAC,EACpD,GAAIC,IAAQ,EAAG,OAAOD,EAAI,YAAc,MAAQC,EAAM,CAACA,CACxD,CACA,MAAO,EACR,CAAC,GAGEH,GAAS,QAAU,OACtBC,EAAUA,EAAQ,MAAM,KAAK,IAAI,EAAGD,EAAQ,MAAM,CAAC,GAGhDA,GAAS,OAAS,OACrBC,EAAUA,EAAQ,MAAM,EAAGD,EAAQ,KAAK,GAGrCA,GAAS,QAAQ,OAAQ,CAC5B,IAAMI,EAAS,IAAI,IAAYJ,EAAQ,MAAM,EAC7CC,EAAUA,EAAQ,IAAKI,GAAQ,CAC9B,IAAMC,EAA+B,CAAC,EACtC,QAAWC,KAAOH,EAAQE,EAAIC,CAAG,EAAIF,EAAIE,CAAG,EAC5C,OAAOD,CACR,CAAC,CACF,CAEA,OAAOL,CACR,CAEA,SAASO,GAAcC,EAAkCF,EAAazC,EAAgB,CACrF,GAAIA,aAAiB4C,EAAO,CAC3B,IAAMC,EAAO,OAAOF,EAAQF,CAAG,GAAK,CAAC,EACrCE,EAAQF,CAAG,EAAII,EAAO7C,EAAM,MAC5B,MACD,CACA,GAAIA,aAAiB8C,EAAO,CAC3B,IAAMD,EAAO,OAAOF,EAAQF,CAAG,GAAK,CAAC,EACrCE,EAAQF,CAAG,EAAII,EAAO7C,EAAM,MAC5B,MACD,CACA,GAAIA,aAAiB+C,EAAO,CAC3B,IAAMF,EAAOF,EAAQF,CAAG,EACxBE,EAAQF,CAAG,EAAII,GAAQ,MAAQjC,EAAcZ,EAAM,MAAO6C,CAAI,EAAI,EAAI7C,EAAM,MAAQ6C,EACpF,MACD,CACA,GAAI7C,aAAiBgD,EAAO,CAC3B,IAAMH,EAAOF,EAAQF,CAAG,EACxBE,EAAQF,CAAG,EAAII,GAAQ,MAAQjC,EAAcZ,EAAM,MAAO6C,CAAI,EAAI,EAAI7C,EAAM,MAAQ6C,EACpF,MACD,CACA,GAAI7C,aAAiBiD,EAAS,CAC7BN,EAAQF,CAAG,EAAI,KACf,MACD,CACA,GAAIzC,aAAiBkD,EAAQ,CAC5B,IAAMC,EAAM,MAAM,QAAQR,EAAQF,CAAG,CAAC,EAAI,CAAC,GAAIE,EAAQF,CAAG,CAAe,EAAI,CAAC,EAC9EU,EAAI,KAAKpD,EAAMC,EAAM,KAAK,CAAC,EAC3B2C,EAAQF,CAAG,EAAIU,EACf,MACD,CACA,GAAInD,aAAiBoD,EAAQ,CAC5B,IAAMD,EAAM,MAAM,QAAQR,EAAQF,CAAG,CAAC,EAAKE,EAAQF,CAAG,EAAkB,CAAC,EACzEE,EAAQF,CAAG,EAAIU,EAAI,OAAQE,GAAU,CAAC,SAAO,MAAMA,EAAOrD,EAAM,KAAK,CAAC,EACtE,MACD,CACA,GAAIA,aAAiBsD,EAAS,CAC7B,IAAMpD,EAASI,EAAcqC,EAAQF,CAAG,CAAC,EAAI1C,EAAM4C,EAAQF,CAAG,CAA4B,EAAI,CAAC,EAC/F,GAAInC,EAAcN,EAAM,KAAK,EAC5B,OAAW,CAACI,EAAGO,CAAC,IAAK,OAAO,QAAQX,EAAM,KAAgC,EACzEE,EAAOE,CAAC,EAAIL,EAAMY,CAAC,EAGrBgC,EAAQF,CAAG,EAAIvC,EACf,MACD,CACAyC,EAAQF,CAAG,EAAI1C,EAAMC,CAAK,CAC3B,CAEA,SAASuD,GAAgBlC,EAA8BmC,EAAwD,CAC9G,IAAMC,EAAU1D,EAAMsB,CAAG,EACzB,OAAW,CAACoB,EAAKzC,CAAK,IAAK,OAAO,QAAQwD,CAAI,EAC7Cd,GAAce,EAAShB,EAAKzC,CAAK,EAElC,OAAOyD,CACR,CAEA,SAASC,EAASrC,EAA8BsC,EAA6C,CAC5F,IAAMF,EAAU1D,EAAMsB,CAAG,EACzB,QAAWuC,KAAMD,EAChB,GAAIC,aAAcC,EACjB,OAAW,CAACpB,EAAKzC,CAAK,IAAK,OAAO,QAAQ4D,EAAG,MAAM,EAClDH,EAAQhB,CAAG,EAAI1C,EAAMC,CAAK,OAG3B0C,GAAce,EAASG,EAAG,MAAOA,CAAE,EAGrC,OAAOH,CACR,CAEA,IAAMK,GAAqB,IAAI,qBAElBC,EAAN,cAA8BC,EAAalE,GAAwBmE,CAAU,CAAE,CAC5E,iBAAmB,IAAE,OAAO,CAAE,MAAO,IAAE,OAAO,CAAE,CAAC,EAEjD,oBAAsB,CAAC,SAAU,SAAU,UAAW,OAAQ,SAAU,QAAS,MAAM,EACvF,aAAe,CAAC,KAAM,KAAM,KAAM,MAAO,KAAM,MAAO,KAAM,QAAS,OAAQ,SAAU,YAAa,WAAY,aAAa,EAC7H,UAAY,CAAC,MAAO,MAAO,MAAO,MAAO,MAAO,QAAS,OAAQ,OAAQ,OAAO,EAChF,aAAe,CAAC,QAAS,gBAAiB,MAAO,MAAO,MAAO,KAAK,EAEpE,OAAS,IAAI,IACb,WAAa,IAAI,IACjB,QAAU,IAAI,IACd,OAAS,IAAI,IACb,YAAc,IAAI,IAE3BC,GAAgC,QAAQ,QAAQ,EAEtC,YAAY/C,EAAuC,CAC5D,MAAMA,CAAM,CACb,CAEAgD,GAAUC,EAAc,CACvB,OAAK,KAAK,OAAO,IAAIA,CAAI,GAAG,KAAK,OAAO,IAAIA,EAAM,IAAI,GAAK,EACpD,KAAK,OAAO,IAAIA,CAAI,CAC5B,CAEAC,GAAcC,EAAmBnD,EAAiB,CACjD,OAAO,KAAKgD,GAAUlD,GAAkBqD,EAAQnD,CAA4B,CAAC,CAC9E,CAEAoD,IAAsB,CACrB,IAAMC,EAAS,IAAI,IACnB,OAAW,CAACJ,EAAMK,CAAK,IAAK,KAAK,OAAO,QAAQ,EAAG,CAClD,IAAMC,EAAY,IAAI,IACtB,OAAW,CAACC,EAAItD,CAAG,IAAKoD,EAAM,QAAQ,EACrCC,EAAU,IAAIC,EAAI5E,EAAMsB,CAAG,CAAC,EAE7BmD,EAAO,IAAIJ,EAAMM,CAAS,CAC3B,CACA,IAAME,EAAa,IAAI,IAAI,KAAK,UAAU,EACpCC,EAAU,IAAI,IAAI,KAAK,OAAO,EAC9BC,EAAS,IAAI,IACnB,OAAW,CAACV,EAAMW,CAAI,IAAK,KAAK,OAAO,QAAQ,EAC9CD,EAAO,IAAIV,EAAM,CAAE,GAAI,CAAE,GAAGW,EAAK,EAAG,EAAG,OAAQ,IAAI,IAAIA,EAAK,MAAM,CAAE,CAAC,EAEtE,IAAMC,EAAc,IAAI,IAAI,KAAK,WAAW,EAC5C,MAAO,CAAE,OAAAR,EAAQ,WAAAI,EAAY,QAAAC,EAAS,OAAAC,EAAQ,YAAAE,CAAY,CAC3D,CAEAC,GAASC,EAAgB,CACxBjF,EAAW,KAAK,OAAQiF,EAAK,MAAM,EACnCjF,EAAW,KAAK,WAAYiF,EAAK,UAAU,EAC3CjF,EAAW,KAAK,QAASiF,EAAK,OAAO,EACrCjF,EAAW,KAAK,OAAQiF,EAAK,MAAM,EACnCjF,EAAW,KAAK,YAAaiF,EAAK,WAAW,CAC9C,CAEA,MAAM,SAASZ,EAAmBnD,EAAiBgE,EAAa,CAE/D,IAAM9D,EADQ,KAAKgD,GAAcC,EAAQnD,CAAM,EAC7B,IAAI,OAAOgE,CAAE,CAAC,EAChC,OAAO9D,EAAMtB,EAAMsB,CAAG,EAAI,IAC3B,CAEA,MAAM,WAAWiD,EAAmBnD,EAAiBqC,EAAiC,CACrF,IAAM2B,EAAKb,EAAO,QAAQ,KACpBG,EAAQ,KAAKJ,GAAcC,EAAQnD,CAAM,EAC/C,OAAOqC,EAAK,IAAK4B,GAAM,CACtB,IAAM7C,EAAMxC,EAAMqF,CAAC,EACnB,OAAAX,EAAM,IAAI,OAAOlC,EAAI4C,CAAE,CAAC,EAAG5C,CAAG,EACvBxC,EAAMwC,CAAG,CACjB,CAAC,CACF,CAEA,MAAM,WAAW+B,EAAmBnD,EAAiBgE,EAAa,CACjE,IAAMV,EAAQ,KAAKJ,GAAcC,EAAQnD,CAAM,EACzCkE,EAAQ,OAAOF,CAAE,EACjB9D,EAAMoD,EAAM,IAAIY,CAAK,EAC3B,OAAKhE,GACLoD,EAAM,OAAOY,CAAK,EACXtF,EAAMsB,CAAG,GAFC,IAGlB,CAEA,MAAM,WAAWiD,EAAmBnD,EAAiBgE,EAAaxB,EAAoB,CACrF,IAAMc,EAAQ,KAAKJ,GAAcC,EAAQnD,CAAM,EACzCkE,EAAQ,OAAOF,CAAE,EACjB9D,EAAMoD,EAAM,IAAIY,CAAK,EAC3B,GAAI,CAAChE,EAAK,OAAO,KACjB,IAAMoC,EAAUC,EAASrC,EAAKsC,CAAG,EACjC,OAAAc,EAAM,IAAIY,EAAO5B,CAAO,EACjB1D,EAAM0D,CAAO,CACrB,CAEA,MAAM,SAASa,EAAmBnD,EAAiBW,EAAoBI,EAAwB,CAE9F,IAAMD,EAAO,CAAC,GADA,KAAKoC,GAAcC,EAAQnD,CAAM,EACxB,OAAO,CAAC,EAAE,OAAQE,GAAQQ,EAAcR,EAAKS,CAAK,CAAC,EAAE,IAAKT,GAAQtB,EAAMsB,CAAG,CAAC,EACnG,OAAOW,GAAaC,EAAMC,CAAO,CAClC,CAEA,MAAM,MAAMoC,EAAmBnD,EAAiBW,EAAoB,CAEnE,MAAO,CAAC,GADM,KAAKuC,GAAcC,EAAQnD,CAAM,EAC9B,OAAO,CAAC,EAAE,OAAQE,GAAQQ,EAAcR,EAAKS,CAAK,CAAC,EAAE,MACvE,CAEA,MAAO,YAAYwC,EAAmBnD,EAAiBW,EAAoBI,EAAiC,CAC3G,IAAMuC,EAAQ,KAAKJ,GAAcC,EAAQnD,CAAM,EACzCc,EAAOD,GAAa,CAAC,GAAGyC,EAAM,OAAO,CAAC,EAAE,OAAQpD,GAAQQ,EAAcR,EAAKS,CAAK,CAAC,EAAE,IAAKT,GAAQtB,EAAMsB,CAAG,CAAC,EAAGa,CAAO,EACpHoD,EAAY,OAAOpD,GAAS,WAAc,UAAY,OAAO,cAAcA,EAAQ,SAAS,GAAKA,EAAQ,UAAY,EAAIA,EAAQ,UAAY,EACnJ,QAASqD,EAAQ,EAAGA,EAAQtD,EAAK,OAAQsD,GAASD,EACjD,QAAW/C,KAAON,EAAK,MAAMsD,EAAOA,EAAQD,CAAS,EACpD,MAAM/C,CAGT,CAEA,MAAM,WAAW+B,EAAmBnD,EAAiBW,EAAoB0B,EAA+B,CACvG,IAAMiB,EAAQ,KAAKJ,GAAcC,EAAQnD,CAAM,EACzCqE,EAAM,CAAC,GAAGf,EAAM,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,CAAEpD,CAAG,IAAMQ,EAAcR,EAAKS,CAAK,CAAC,EAAE,IAAI,CAAC,CAAC6C,CAAE,IAAMA,CAAE,EAE1FlB,EAAqC,CAAC,EAC5C,QAAWkB,KAAMa,EAAK,CACrB,IAAM7C,EAAU8B,EAAM,IAAIE,CAAE,EAC5B,GAAI,CAAChC,EAAS,SACd,IAAM8C,EAAOlC,GAAgBZ,EAASa,CAAI,EAC1CiB,EAAM,IAAIE,EAAIc,CAAI,EAClBhC,EAAQ,KAAK1D,EAAM0F,CAAI,CAAC,CACzB,CACA,OAAOhC,CACR,CAEA,MAAM,WAAWa,EAAmBnD,EAAiBG,EAAqB,CACzE,IAAMmD,EAAQ,KAAKJ,GAAcC,EAAQnD,CAAM,EACzCgE,EAAKb,EAAO,QAAQ,KACpBrC,EAAO,CAAC,GAAGwC,EAAM,OAAO,CAAC,EAAE,OAAQpD,GAAQQ,EAAcR,EAAKC,CAAM,CAAC,EAAE,IAAKD,GAAQtB,EAAMsB,CAAG,CAAC,EACpG,QAAWkB,KAAON,EAAMwC,EAAM,OAAO,OAAOlC,EAAI4C,CAAE,CAAC,CAAC,EACpD,OAAOlD,CACR,CAEA,MAAM,UAAUqC,EAAmBnD,EAAiBG,EAAqBoE,EAAiC/B,EAAoB,CAC7H,IAAMc,EAAQ,KAAKJ,GAAcC,EAAQnD,CAAM,EACzCgE,EAAKb,EAAO,QAAQ,KAEpB3B,EADO,CAAC,GAAG8B,EAAM,OAAO,CAAC,EAAE,OAAQpD,GAAQQ,EAAcR,EAAKC,CAAM,CAAC,EACtD,CAAC,EACtB,GAAIqB,EAAS,CACZ,IAAM8C,EAAO9B,EAAI,OAAS,EAAID,EAASf,EAASgB,CAAG,EAAI5D,EAAM4C,CAAO,EACpE,OAAA8B,EAAM,IAAI,OAAOgB,EAAKN,CAAE,CAAC,EAAGM,CAAI,EACzB1F,EAAM0F,CAAI,CAClB,CACA,IAAM5C,EAAO9C,EAAM2F,CAAM,EACnBC,EAAShC,EAAI,OAAS,EAAID,EAASb,EAAMc,CAAG,EAAId,EACtD,OAAA4B,EAAM,IAAI,OAAOkB,EAAOR,CAAE,CAAC,EAAGQ,CAAM,EAC7B5F,EAAM4F,CAAM,CACpB,CAEA,MAAM,UAAUrB,EAAmBnD,EAAiByE,EAA8D,CAEjH,IAAI3D,EAAO,CAAC,GADE,KAAKoC,GAAcC,EAAQnD,CAAM,EAC1B,OAAO,CAAC,EAC7B,GAAIyE,EAAK,MAAO,CACf,IAAMC,EAAQD,EAAK,MACnB3D,EAAOA,EAAK,OAAQZ,GAAQQ,EAAcR,EAAKwE,CAAK,CAAC,CACtD,CAEA,IAAMC,EAAS,IAAI,IACnB,GAAIF,EAAK,QAAQ,OAAS,EACzB,QAAWrD,KAAON,EAAM,CACvB,IAAMQ,EAAM,KAAK,UAAUmD,EAAK,QAAQ,IAAKG,GAAMxD,EAAIwD,CAAC,CAAC,CAAC,EACrDD,EAAO,IAAIrD,CAAG,GAAGqD,EAAO,IAAIrD,EAAK,CAAC,CAAC,EACxCqD,EAAO,IAAIrD,CAAG,EAAG,KAAKF,CAAG,CAC1B,MAEAuD,EAAO,IAAI,UAAW7D,CAAI,EAG3B,IAAME,EAAqC,CAAC,EAC5C,OAAW,CAAC,CAAE6D,CAAS,IAAKF,EAAQ,CACnC,IAAMH,EAAkC,CAAC,EACzC,GAAIC,EAAK,QAAQ,OAAS,EACzB,QAAWK,KAASL,EAAK,QACxBD,EAAOM,CAAK,EAAID,EAAU,CAAC,EAAEC,CAAK,EAGpC,QAAWC,KAAON,EAAK,WACtB,OAAQM,EAAI,GAAI,CACf,IAAK,QACJP,EAAOO,EAAI,KAAK,EAAIF,EAAU,OAC9B,MACD,IAAK,gBAAiB,CACrB,IAAMG,EAAO,IAAI,IAAIH,EAAU,IAAKI,GAAM,KAAK,UAAUA,EAAEF,EAAI,KAAM,CAAC,CAAC,CAAC,EACxEP,EAAOO,EAAI,KAAK,EAAIC,EAAK,KACzB,KACD,CACA,IAAK,MACJR,EAAOO,EAAI,KAAK,EAAIF,EAAU,OAAO,CAACK,EAAKD,IAAMC,EAAM,OAAOD,EAAEF,EAAI,KAAM,GAAK,CAAC,EAAG,CAAC,EACpF,MACD,IAAK,MAAO,CACX,IAAMI,EAAMN,EAAU,OAAO,CAACK,EAAKD,IAAMC,EAAM,OAAOD,EAAEF,EAAI,KAAM,GAAK,CAAC,EAAG,CAAC,EAC5EP,EAAOO,EAAI,KAAK,EAAIF,EAAU,OAAS,EAAIM,EAAMN,EAAU,OAAS,EACpE,KACD,CACA,IAAK,MAAO,CACX,IAAIO,EAAkB,KACtB,QAAWH,KAAKJ,EAAW,CAC1B,IAAM3F,EAAM+F,EAAEF,EAAI,KAAM,EACpB7F,GAAO,OAASkG,IAAW,MAAQ3F,EAAcP,EAAKkG,CAAM,EAAI,KAAIA,EAASlG,EAClF,CACAsF,EAAOO,EAAI,KAAK,EAAIK,EACpB,KACD,CACA,IAAK,MAAO,CACX,IAAIC,EAAkB,KACtB,QAAWJ,KAAKJ,EAAW,CAC1B,IAAM3F,EAAM+F,EAAEF,EAAI,KAAM,EACpB7F,GAAO,OAASmG,IAAW,MAAQ5F,EAAcP,EAAKmG,CAAM,EAAI,KAAIA,EAASnG,EAClF,CACAsF,EAAOO,EAAI,KAAK,EAAIM,EACpB,KACD,CACD,CAEDrE,EAAQ,KAAKwD,CAAM,CACpB,CAEA,GAAIC,EAAK,OAAQ,CAChB,IAAMa,EAASb,EAAK,OACpB,OAAOzD,EAAQ,OAAQiE,GAAMvE,EAAcuE,EAAGK,CAAM,CAAC,CACtD,CACA,OAAOtE,CACR,CAEA,MAAM,gBAA+D,CACpE,MAAO,CAAC,GAAG,KAAK,WAAW,OAAO,CAAC,EAAE,IAAKuE,IAAO,CAAE,GAAIA,EAAE,GAAI,UAAWA,EAAE,SAAU,EAAE,CACvF,CAEA,MAAM,gBAAgB/B,EAAYgC,EAAkC,CACnE,KAAK,WAAW,IAAIhC,EAAI,CAAE,GAAAA,EAAI,UAAAgC,CAAU,CAAC,CAC1C,CAEA,MAAM,iBAAiBC,EAA+C,CACrE,IAAMtE,EAAS,IAAI,IACnB,QAAWyD,KAAKa,EAAO,OACtBtE,EAAO,IAAIyD,EAAE,KAAM,CAAE,GAAGA,CAAE,CAAC,EAE5B,KAAK,OAAO,IAAIa,EAAO,KAAM,CAAE,GAAI,CAAE,KAAMA,EAAO,GAAG,KAAM,KAAMA,EAAO,GAAG,IAAK,EAAG,OAAAtE,CAAO,CAAC,CAC5F,CAEA,MAAM,eAAesE,EAAwC,CAC5D,KAAK,OAAO,OAAOA,EAAO,IAAI,CAC/B,CAEA,MAAM,cAAcA,EAA4C,CAC/D,IAAMC,EAAQ,KAAK,OAAO,IAAID,EAAO,KAAK,EACtCC,GACHA,EAAM,OAAO,IAAID,EAAO,MAAM,KAAM,CAAE,GAAGA,EAAO,KAAM,CAAC,CAEzD,CAEA,MAAM,eAAeA,EAAwC,CAC5D,IAAMC,EAAQ,KAAK,OAAO,IAAID,EAAO,KAAK,EACtCC,GACHA,EAAM,OAAO,OAAOD,EAAO,IAAI,CAEjC,CAEA,MAAM,iBAAiBA,EAA+C,CACrE,IAAMC,EAAQ,KAAK,OAAO,IAAID,EAAO,KAAK,EACtCC,IACHA,EAAM,OAAO,OAAOD,EAAO,IAAI,EAC/BC,EAAM,OAAO,IAAID,EAAO,GAAG,KAAM,CAAE,GAAGA,EAAO,EAAG,CAAC,EAEnD,CAEA,MAAM,iBAAiBA,EAA0C,CAChE,IAAMC,EAAQ,KAAK,OAAO,IAAID,EAAO,IAAI,EACrCC,IACH,KAAK,OAAO,OAAOD,EAAO,IAAI,EAC9B,KAAK,OAAO,IAAIA,EAAO,GAAIC,CAAK,EAElC,CAEA,MAAM,iBAAiBD,EAA0C,CAChE,IAAMC,EAAQ,KAAK,OAAO,IAAID,EAAO,KAAK,EAC1C,GAAIC,EAAO,CACV,IAAMZ,EAAQY,EAAM,OAAO,IAAID,EAAO,IAAI,EACtCX,IACHY,EAAM,OAAO,OAAOD,EAAO,IAAI,EAC/BC,EAAM,OAAO,IAAID,EAAO,GAAI,CAAE,GAAGX,EAAO,KAAMW,EAAO,EAAG,CAAC,EAE3D,CACD,CAEA,MAAM,cAAcA,EAAuC,CAC1D,IAAME,EAAYF,EAAO,MAAQ,GAAGA,EAAO,KAAK,IAAIA,EAAO,GAAG,KAAK,GAAG,CAAC,OACvE,KAAK,QAAQ,IAAIE,EAAW,CAAE,MAAOF,EAAO,MAAO,GAAIA,EAAO,GAAI,OAAQA,EAAO,QAAU,EAAM,CAAC,CACnG,CAEA,MAAM,eAAeA,EAAwC,CAC5D,KAAK,QAAQ,OAAOA,EAAO,IAAI,CAChC,CAEA,MAAM,mBAAmBA,EAA4C,CACpE,IAAMG,EAASH,EAAO,MAAQ,GAAGA,EAAO,KAAK,IAAIA,EAAO,EAAE,MAC1D,KAAK,YAAY,IAAIG,EAAQ,CAC5B,MAAOH,EAAO,MACd,GAAIA,EAAO,GACX,WAAY,CAAE,MAAOA,EAAO,WAAW,MAAO,OAAQA,EAAO,WAAW,MAAO,EAC/E,SAAUA,EAAO,SACjB,SAAUA,EAAO,QAClB,CAAC,CACF,CAEA,MAAM,oBAAoBA,EAA6C,CACtE,KAAK,YAAY,OAAOA,EAAO,IAAI,CACpC,CAEA,MAAM,YAA0C,CAC/C,IAAMI,EAA8B,CAAC,EACrC,OAAW,CAAC5C,EAAMW,CAAI,IAAK,KAAK,OAAO,QAAQ,EAAG,CACjD,IAAMzC,EAAS,CAAC,GAAGyC,EAAK,OAAO,OAAO,CAAC,EAAE,IAAKgB,IAAO,CACpD,KAAMA,EAAE,KACR,KAAMA,EAAE,KACR,SAAUA,EAAE,UAAY,GACxB,GAAIA,EAAE,UAAY,OAAY,CAAE,QAASA,EAAE,OAAQ,EAAI,CAAC,EACxD,GAAIA,EAAE,OAAS,CAAE,OAAQ,EAAK,EAAI,CAAC,CACpC,EAAE,EACIlB,EAAU,CAAC,GAAG,KAAK,QAAQ,QAAQ,CAAC,EACxC,OAAO,CAAC,CAAC,CAAEoC,CAAG,IAAMA,EAAI,QAAU7C,CAAI,EACtC,IAAI,CAAC,CAAC8C,EAASD,CAAG,KAAO,CAAE,KAAMC,EAAS,GAAID,EAAI,GAAI,OAAQA,EAAI,MAAO,EAAE,EACvEjC,EAAc,CAAC,GAAG,KAAK,YAAY,QAAQ,CAAC,EAChD,OAAO,CAAC,CAAC,CAAEmC,CAAE,IAAMA,EAAG,QAAU/C,CAAI,EACpC,IAAI,CAAC,CAAC2C,EAAQI,CAAE,KAAO,CACvB,KAAMJ,EACN,GAAII,EAAG,GACP,WAAY,CAAE,MAAOA,EAAG,WAAW,MAAO,OAAQA,EAAG,WAAW,MAAO,EACvE,GAAIA,EAAG,SAAW,CAAE,SAAUA,EAAG,QAAS,EAAI,CAAC,EAC/C,GAAIA,EAAG,SAAW,CAAE,SAAUA,EAAG,QAAS,EAAI,CAAC,CAChD,EAAE,EACHH,EAAQ,KAAK,CACZ,KAAA5C,EACA,GAAI,CAAE,KAAMW,EAAK,GAAG,KAAM,KAAMA,EAAK,GAAG,IAAsB,EAC9D,OAAAzC,EACA,QAAAuC,EACA,YAAAG,CACD,CAAC,CACF,CACA,OAAOgC,CACR,CAEA,MAAM,qBAAwBI,EAAkC,CAC/D,IAAIC,EACE5B,EAAO,IAAI,QAAeW,GAAM,CAAEiB,EAAUjB,CAAE,CAAC,EAC/CkB,EAAO,KAAKpD,GAClB,KAAKA,GAAiBuB,EACtB,MAAM6B,EACN,GAAI,CACH,OAAO,MAAMF,EAAG,CACjB,QAAE,CACDC,EAAQ,CACT,CACD,CAEA,MAAM,QAAWD,EAAkC,CAClD,GAAItD,GAAmB,SAAS,EAAG,OAAOsD,EAAG,EAC7C,IAAMlC,EAAO,KAAKX,GAAU,EAC5B,GAAI,CACH,OAAO,MAAMT,GAAmB,IAAI,GAAMsD,CAAE,CAC7C,OAASG,EAAO,CACf,WAAKtC,GAASC,CAAI,EACZqC,CACP,CACD,CACD,ETjlBA,IAAMC,GAAqB,IAC1B,IAAE,OAAO,CACR,SAAU,IAAE,OAAO,CACpB,CAAC,EAEWC,EAAN,cAA0BC,EAAaF,GAAoBG,CAAU,CAAE,CACpE,iBAAmB,IAAE,OAAO,CAAE,MAAO,IAAE,OAAO,CAAE,CAAC,EAEjDC,GAAYC,EAAgB,OAAO,CAAC,CAAC,EAErC,oBAAsB,KAAKD,GAAU,oBACrC,aAAe,KAAKA,GAAU,aAC9B,UAAY,KAAKA,GAAU,UAC3B,aAAe,KAAKA,GAAU,aAEvCE,GAA6B,QAAQ,QAAQ,EAEnC,YAAYC,EAAmC,CACxD,MAAMA,CAAM,CACb,CAEA,IAAI,QAAS,CACZ,OAAO,KAAKH,GAAU,MACvB,CAEAI,IAAqB,CACpB,IAAMC,EAA+B,CAAC,EAEhCC,EAAa,CAAC,GAAG,KAAKN,GAAU,WAAW,OAAO,CAAC,EACrDM,EAAW,OAAS,IAAGD,EAAI,aAAkBC,GAEjD,IAAMC,EAAkC,CAAC,EACzC,OAAW,CAACC,EAAMC,CAAI,IAAK,KAAKT,GAAU,OAAO,QAAQ,EACxDO,EAAOC,CAAI,EAAI,CAAE,GAAIC,EAAK,GAAI,OAAQ,OAAO,YAAYA,EAAK,OAAO,QAAQ,CAAC,CAAE,EAE7E,OAAO,KAAKF,CAAM,EAAE,OAAS,IAAGF,EAAI,SAAcE,GAEtD,IAAMG,EAAmC,CAAC,EAC1C,OAAW,CAACF,EAAMC,CAAI,IAAK,KAAKT,GAAU,QAAQ,QAAQ,EACzDU,EAAQF,CAAI,EAAI,CAAE,MAAOC,EAAK,MAAO,GAAI,CAAC,GAAGA,EAAK,EAAE,EAAG,OAAQA,EAAK,MAAO,EAExE,OAAO,KAAKC,CAAO,EAAE,OAAS,IAAGL,EAAI,UAAeK,GAExD,IAAMC,EAAuC,CAAC,EAC9C,OAAW,CAACH,EAAMC,CAAI,IAAK,KAAKT,GAAU,YAAY,QAAQ,EAC7DW,EAAYH,CAAI,EAAI,CACnB,MAAOC,EAAK,MACZ,GAAIA,EAAK,GACT,WAAYA,EAAK,WACjB,GAAIA,EAAK,SAAW,CAAE,SAAUA,EAAK,QAAS,EAAI,CAAC,EACnD,GAAIA,EAAK,SAAW,CAAE,SAAUA,EAAK,QAAS,EAAI,CAAC,CACpD,EAEG,OAAO,KAAKE,CAAW,EAAE,OAAS,IAAGN,EAAI,cAAmBM,GAEhE,OAAW,CAACH,EAAMI,CAAK,IAAK,KAAK,OAAO,QAAQ,EAAG,CAClD,IAAMC,EAAmD,CAAC,EAC1D,OAAW,CAACC,EAAIC,CAAG,IAAKH,EAAM,QAAQ,EACrCC,EAAQC,CAAE,EAAIC,EAEfV,EAAIG,CAAI,EAAIK,CACb,CAEA,OAAO,KAAK,UAAUR,CAAG,CAC1B,CAEA,KAAMW,IAA8B,CACnC,IAAMC,EAAO,KAAKb,GAAW,EACvBc,EAAU,KAAK,OAAO,SAAW,QAAU,QAAQ,IAAM,IAAM,KAAK,IAAI,EAC9E,QAAM,aAAUA,EAASD,EAAM,OAAO,EACtC,QAAM,UAAOC,EAAS,KAAK,OAAO,QAAQ,CAC3C,CAEAC,IAAgC,CAC/B,IAAMC,EAAO,KAAKlB,GAAY,KAAK,IAAM,KAAKc,GAAa,CAAC,EAC5D,YAAKd,GAAckB,EAAK,MAAM,IAAM,CAAC,CAAC,EAC/BA,CACR,CAEA,MAAM,SAAyB,CAC9B,IAAIC,EACJ,GAAI,CACHA,EAAM,QAAM,YAAS,KAAK,OAAO,SAAU,OAAO,CACnD,MAAQ,CACP,MACD,CACA,IAAMJ,EAAO,KAAK,MAAMI,CAAG,EAG3B,GADA,KAAKrB,GAAU,WAAW,MAAM,EAC5B,MAAM,QAAQiB,EAAK,YAAe,EACrC,QAAWK,KAAKL,EAAK,aACpB,KAAKjB,GAAU,WAAW,IAAIsB,EAAE,GAAI,CAAE,GAAIA,EAAE,GAAI,UAAWA,EAAE,SAAU,CAAC,EAK1E,GADA,KAAKtB,GAAU,OAAO,MAAM,EACxBiB,EAAK,UAAe,OAAOA,EAAK,UAAgB,SACnD,OAAW,CAACT,EAAMC,CAAI,IAAK,OAAO,QAAQQ,EAAK,QAAkC,EAAG,CACnF,IAAMM,EAAS,IAAI,IACnB,GAAId,EAAK,OACR,OAAW,CAACe,EAAWC,CAAK,IAAK,OAAO,QAAQhB,EAAK,MAAsC,EAC1Fc,EAAO,IAAIC,EAAWC,CAAK,EAG7B,KAAKzB,GAAU,OAAO,IAAIQ,EAAM,CAAE,GAAIC,EAAK,GAAI,OAAAc,CAAO,CAAC,CACxD,CAID,GADA,KAAKvB,GAAU,QAAQ,MAAM,EACzBiB,EAAK,WAAgB,OAAOA,EAAK,WAAiB,SACrD,OAAW,CAACT,EAAMC,CAAI,IAAK,OAAO,QAAQQ,EAAK,SAAmC,EACjF,KAAKjB,GAAU,QAAQ,IAAIQ,EAAM,CAAE,MAAOC,EAAK,MAAO,GAAIA,EAAK,GAAI,OAAQA,EAAK,MAAO,CAAC,EAK1F,GADA,KAAKT,GAAU,YAAY,MAAM,EAC7BiB,EAAK,eAAoB,OAAOA,EAAK,eAAqB,SAC7D,OAAW,CAACT,EAAMC,CAAI,IAAK,OAAO,QAAQQ,EAAK,aAAuC,EACrF,KAAKjB,GAAU,YAAY,IAAIQ,EAAMC,CAAI,EAI3C,KAAK,OAAO,MAAM,EAClB,OAAW,CAACD,EAAMK,CAAO,IAAK,OAAO,QAAQI,CAAI,EAAG,CACnD,GAAIT,EAAK,WAAW,IAAI,EAAG,SAC3B,IAAMI,EAAQ,IAAI,IAClB,OAAW,CAACE,EAAIC,CAAG,IAAK,OAAO,QAAQF,CAAkD,EACxFD,EAAM,IAAIE,EAAIC,CAAG,EAElB,KAAK,OAAO,IAAIP,EAAMI,CAAK,CAC5B,CACD,CAEA,MAAM,YAA4B,CACjC,MAAM,KAAKO,GAAe,CAC3B,CAEA,MAAM,SAASO,EAAmBvB,EAAiBW,EAAa,CAC/D,OAAO,KAAKd,GAAU,SAAS0B,EAAQvB,EAAQW,CAAE,CAClD,CAEA,MAAM,WAAWY,EAAmBvB,EAAiBc,EAAiC,CACrF,IAAMU,EAAS,MAAM,KAAK3B,GAAU,WAAW0B,EAAQvB,EAAQc,CAAI,EACnE,aAAM,KAAKE,GAAe,EACnBQ,CACR,CAEA,MAAM,WAAWD,EAAmBvB,EAAiBW,EAAac,EAAoB,CACrF,IAAMD,EAAS,MAAM,KAAK3B,GAAU,WAAW0B,EAAQvB,EAAQW,EAAIc,CAAG,EACtE,OAAID,GAAQ,MAAM,KAAKR,GAAe,EAC/BQ,CACR,CAEA,MAAM,WAAWD,EAAmBvB,EAAiBW,EAAa,CACjE,IAAMa,EAAS,MAAM,KAAK3B,GAAU,WAAW0B,EAAQvB,EAAQW,CAAE,EACjE,OAAIa,GAAQ,MAAM,KAAKR,GAAe,EAC/BQ,CACR,CAEA,MAAM,SAASD,EAAmBvB,EAAiB0B,EAAoBC,EAAwB,CAC9F,OAAO,KAAK9B,GAAU,SAAS0B,EAAQvB,EAAQ0B,EAAOC,CAAO,CAC9D,CAEA,MAAM,MAAMJ,EAAmBvB,EAAiB0B,EAAoB,CACnE,OAAO,KAAK7B,GAAU,MAAM0B,EAAQvB,EAAQ0B,CAAK,CAClD,CAEA,YAAYH,EAAmBvB,EAAiB0B,EAAoBC,EAAiC,CACpG,OAAO,KAAK9B,GAAU,YAAY0B,EAAQvB,EAAQ0B,EAAOC,CAAO,CACjE,CAEA,MAAM,WAAWJ,EAAmBvB,EAAiB0B,EAAoBZ,EAA+B,CACvG,IAAMU,EAAS,MAAM,KAAK3B,GAAU,WAAW0B,EAAQvB,EAAQ0B,EAAOZ,CAAI,EAC1E,OAAIU,EAAO,QAAQ,MAAM,KAAKR,GAAe,EACtCQ,CACR,CAEA,MAAM,WAAWD,EAAmBvB,EAAiB4B,EAAqB,CACzE,IAAMJ,EAAS,MAAM,KAAK3B,GAAU,WAAW0B,EAAQvB,EAAQ4B,CAAM,EACrE,OAAIJ,EAAO,QAAQ,MAAM,KAAKR,GAAe,EACtCQ,CACR,CAEA,MAAM,UAAUD,EAAmBvB,EAAiB4B,EAAqBC,EAAiCJ,EAAoB,CAC7H,IAAMD,EAAS,MAAM,KAAK3B,GAAU,UAAU0B,EAAQvB,EAAQ4B,EAAQC,EAAQJ,CAAG,EACjF,aAAM,KAAKT,GAAe,EACnBQ,CACR,CAEA,MAAM,UAAUD,EAAmBvB,EAAiB8B,EAAqB,CACxE,OAAO,KAAKjC,GAAU,UAAU0B,EAAQvB,EAAQ8B,CAAI,CACrD,CAEA,MAAM,QAAWC,EAAkC,CAClD,OAAO,KAAKlC,GAAU,QAAQ,SAAY,CACzC,IAAM2B,EAAS,MAAMO,EAAG,EACxB,aAAM,KAAKf,GAAe,EACnBQ,CACR,CAAC,CACF,CAEA,MAAM,gBAA+D,CACpE,aAAM,KAAK,QAAQ,EACZ,KAAK3B,GAAU,eAAe,CACtC,CAEA,MAAM,gBAAgBmC,EAAYC,EAAkC,CACnE,MAAM,KAAKpC,GAAU,gBAAgBmC,EAAIC,CAAS,EAClD,MAAM,KAAKjB,GAAe,CAC3B,CAEA,MAAM,qBAAwBe,EAAkC,CAC/D,IAAMG,EAAW,KAAK,OAAO,SAAW,QAClCC,EAAW,KAAK,IAAI,EAAI,IAC9B,OACC,GAAI,CAEH,MADe,QAAM,QAAKD,EAAU,IAAI,GAC3B,MAAM,EACnB,KACD,OAASE,EAAU,CAClB,GAAIA,EAAI,OAAS,SAAU,MAAMA,EACjC,GAAI,KAAK,IAAI,EAAID,EAAU,MAAM,IAAI,MAAM,sCAAsC,EACjF,MAAM,IAAI,QAASE,GAAM,WAAWA,EAAG,EAAE,CAAC,CAC3C,CAED,GAAI,CACH,OAAO,MAAMN,EAAG,CACjB,QAAE,CACD,QAAM,UAAOG,CAAQ,EAAE,MAAM,IAAM,CAAC,CAAC,CACtC,CACD,CAEA,MAAM,iBAAiBI,EAA+C,CACrE,MAAM,KAAKzC,GAAU,iBAAiByC,CAAM,EAC5C,MAAM,KAAKtB,GAAe,CAC3B,CAEA,MAAM,eAAesB,EAAwC,CAC5D,MAAM,KAAKzC,GAAU,eAAeyC,CAAM,EAC1C,MAAM,KAAKtB,GAAe,CAC3B,CAEA,MAAM,cAAcsB,EAA4C,CAC/D,MAAM,KAAKzC,GAAU,cAAcyC,CAAM,EACzC,MAAM,KAAKtB,GAAe,CAC3B,CAEA,MAAM,eAAesB,EAAwC,CAC5D,MAAM,KAAKzC,GAAU,eAAeyC,CAAM,EAC1C,MAAM,KAAKtB,GAAe,CAC3B,CAEA,MAAM,iBAAiBsB,EAA+C,CACrE,MAAM,KAAKzC,GAAU,iBAAiByC,CAAM,EAC5C,MAAM,KAAKtB,GAAe,CAC3B,CAEA,MAAM,iBAAiBsB,EAA0C,CAChE,MAAM,KAAKzC,GAAU,iBAAiByC,CAAM,EAC5C,MAAM,KAAKtB,GAAe,CAC3B,CAEA,MAAM,iBAAiBsB,EAA0C,CAChE,MAAM,KAAKzC,GAAU,iBAAiByC,CAAM,EAC5C,MAAM,KAAKtB,GAAe,CAC3B,CAEA,MAAM,cAAcsB,EAAuC,CAC1D,MAAM,KAAKzC,GAAU,cAAcyC,CAAM,EACzC,MAAM,KAAKtB,GAAe,CAC3B,CAEA,MAAM,eAAesB,EAAwC,CAC5D,MAAM,KAAKzC,GAAU,eAAeyC,CAAM,EAC1C,MAAM,KAAKtB,GAAe,CAC3B,CAEA,MAAM,mBAAmBsB,EAA4C,CACpE,MAAM,KAAKzC,GAAU,mBAAmByC,CAAM,EAC9C,MAAM,KAAKtB,GAAe,CAC3B,CAEA,MAAM,oBAAoBsB,EAA6C,CACtE,MAAM,KAAKzC,GAAU,oBAAoByC,CAAM,EAC/C,MAAM,KAAKtB,GAAe,CAC3B,CAEA,MAAM,YAA0C,CAC/C,OAAO,KAAKnB,GAAU,WAAW,CAClC,CACD","names":["json_exports","__export","JsonAdapter","__toCommonJS","import_promises","import_valleyed","import_valleyed","configurable","pipeFn","base","pipe","Configurable","config","baseArgs","input","args","r","EquippedError","message","context","cause","import_pino","import_ulid","import_valleyed","registerHook","hooks","record","dep","h","depName","ownerName","tentative","detectCycle","classToAfter","existing","visited","stack","visit","cls","path","cycleStart","names","c","resolveHookDAG","invert","classToHooks","anonymous","list","classes","inDegree","graph","from","to","edges","layers","queue","layer","next","neighbor","d","anonWithDeps","anonWithoutDeps","maxLayer","depLayer","l","r","insertAt","runHooks","onError","error","import_valleyed","instanceSettingsPipe","Instance","_Instance","#id","#instance","#hooks","settings","pino","#registerOnExitHandler","id","EquippedError","name","key","runHooks","error","envsPipe","envValidity","settingsValidity","instanceSettingsPipe","event","cb","options","record","registerHook","signal","code","value","opts","import_valleyed","Field","name","path","toFieldName","field","Filter","field","op","value","toFieldName","FilterGroup","_FilterGroup","children","#withChild","child","facFns","EquippedError","group","fn","c","OrmAdapter","err","wrapped","EquippedError","Instance","self","schema","config","emptyIterator","use","filter","opts","d","match","pk","pkFilter","FilterGroup","create","ops","row","args","spec","import_node_async_hooks","import_valleyed","SetOp","values","IncOp","field","value","MulOp","MinOp","MaxOp","UnsetOp","PushOp","PullOp","PatchOp","inMemoryConnectionPipe","clone","value","replaceMap","target","source","k","val","isPlainObject","containsSubset","needle","item","existing","v","compareValues","a","b","sa","sb","resolveConfigName","_","config","evaluateFilter","doc","filter","fieldValue","evaluateChild","child","Filter","FilterGroup","c","matchesFilter","group","clause","applyOptions","rows","options","results","ord","cmp","fields","row","out","key","applyUpdateOp","current","IncOp","base","MulOp","MinOp","MaxOp","UnsetOp","PushOp","arr","PullOp","entry","PatchOp","applyUpdateData","data","updated","applyOps","ops","op","SetOp","sessionActiveStore","InMemoryAdapter","configurable","OrmAdapter","#migrationLock","#getStore","name","#resolveStore","schema","#snapshot","stores","store","storeCopy","id","migrations","indexes","tables","meta","foreignKeys","#restore","snap","pk","d","pkStr","batchSize","start","ids","next","create","result","spec","where","groups","f","groupRows","field","agg","vals","r","acc","sum","minVal","maxVal","having","m","appliedAt","change","table","indexName","fkName","schemas","idx","idxName","fk","fn","release","prev","error","jsonConnectionPipe","JsonAdapter","configurable","OrmAdapter","#inMemory","InMemoryAdapter","#writeQueue","config","#serialize","obj","migrations","tables","name","meta","indexes","foreignKeys","store","records","pk","doc","#atomicWrite","data","tmpPath","#persistToDisk","next","raw","m","fields","fieldName","fspec","schema","result","ops","group","options","filter","create","spec","fn","id","appliedAt","lockPath","deadline","err","r","change"]}
|