diff --git a/backend/node_modules/.prisma/client/client.d.ts b/backend/node_modules/.prisma/client/client.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..bc20c6c16086e52f417e4f6b90906a35278e9f17 --- /dev/null +++ b/backend/node_modules/.prisma/client/client.d.ts @@ -0,0 +1 @@ +export * from "./index" \ No newline at end of file diff --git a/backend/node_modules/.prisma/client/client.js b/backend/node_modules/.prisma/client/client.js new file mode 100644 index 0000000000000000000000000000000000000000..6ac8a817ada5d382177209fd770d837eec3e0457 --- /dev/null +++ b/backend/node_modules/.prisma/client/client.js @@ -0,0 +1,5 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! +/* eslint-disable */ +// biome-ignore-all lint: generated file +module.exports = { ...require('.') } \ No newline at end of file diff --git a/backend/node_modules/.prisma/client/default.d.ts b/backend/node_modules/.prisma/client/default.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..bc20c6c16086e52f417e4f6b90906a35278e9f17 --- /dev/null +++ b/backend/node_modules/.prisma/client/default.d.ts @@ -0,0 +1 @@ +export * from "./index" \ No newline at end of file diff --git a/backend/node_modules/.prisma/client/default.js b/backend/node_modules/.prisma/client/default.js new file mode 100644 index 0000000000000000000000000000000000000000..eb5567553dd349ad6187005207a0db49c9ce8c68 --- /dev/null +++ b/backend/node_modules/.prisma/client/default.js @@ -0,0 +1,5 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! +/* eslint-disable */ +// biome-ignore-all lint: generated file +module.exports = { ...require('#main-entry-point') } \ No newline at end of file diff --git a/backend/node_modules/.prisma/client/edge.d.ts b/backend/node_modules/.prisma/client/edge.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..274b8fa61905db8cd79f40927dfc929a788dc136 --- /dev/null +++ b/backend/node_modules/.prisma/client/edge.d.ts @@ -0,0 +1 @@ +export * from "./default" \ No newline at end of file diff --git a/backend/node_modules/.prisma/client/edge.js b/backend/node_modules/.prisma/client/edge.js new file mode 100644 index 0000000000000000000000000000000000000000..04f90824b8a9c3a741b586ce348a7a52cc06e40f --- /dev/null +++ b/backend/node_modules/.prisma/client/edge.js @@ -0,0 +1,259 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! +/* eslint-disable */ +// biome-ignore-all lint: generated file + +Object.defineProperty(exports, "__esModule", { value: true }); + +const { + PrismaClientKnownRequestError, + PrismaClientUnknownRequestError, + PrismaClientRustPanicError, + PrismaClientInitializationError, + PrismaClientValidationError, + getPrismaClient, + sqltag, + empty, + join, + raw, + skip, + Decimal, + Debug, + objectEnumValues, + makeStrictEnum, + Extensions, + warnOnce, + defineDmmfProperty, + Public, + getRuntime, + createParam, +} = require('@prisma/client/runtime/edge.js') + + +const Prisma = {} + +exports.Prisma = Prisma +exports.$Enums = {} + +/** + * Prisma Client JS version: 6.19.3 + * Query Engine version: c2990dca591cba766e3b7ef5d9e8a84796e47ab7 + */ +Prisma.prismaVersion = { + client: "6.19.3", + engine: "c2990dca591cba766e3b7ef5d9e8a84796e47ab7" +} + +Prisma.PrismaClientKnownRequestError = PrismaClientKnownRequestError; +Prisma.PrismaClientUnknownRequestError = PrismaClientUnknownRequestError +Prisma.PrismaClientRustPanicError = PrismaClientRustPanicError +Prisma.PrismaClientInitializationError = PrismaClientInitializationError +Prisma.PrismaClientValidationError = PrismaClientValidationError +Prisma.Decimal = Decimal + +/** + * Re-export of sql-template-tag + */ +Prisma.sql = sqltag +Prisma.empty = empty +Prisma.join = join +Prisma.raw = raw +Prisma.validator = Public.validator + +/** +* Extensions +*/ +Prisma.getExtensionContext = Extensions.getExtensionContext +Prisma.defineExtension = Extensions.defineExtension + +/** + * Shorthand utilities for JSON filtering + */ +Prisma.DbNull = objectEnumValues.instances.DbNull +Prisma.JsonNull = objectEnumValues.instances.JsonNull +Prisma.AnyNull = objectEnumValues.instances.AnyNull + +Prisma.NullTypes = { + DbNull: objectEnumValues.classes.DbNull, + JsonNull: objectEnumValues.classes.JsonNull, + AnyNull: objectEnumValues.classes.AnyNull +} + + + + + +/** + * Enums + */ +exports.Prisma.TransactionIsolationLevel = makeStrictEnum({ + Serializable: 'Serializable' +}); + +exports.Prisma.UserScalarFieldEnum = { + id: 'id', + email: 'email', + passwordHash: 'passwordHash', + isActive: 'isActive', + telegramChatId: 'telegramChatId', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +}; + +exports.Prisma.MarketScalarFieldEnum = { + id: 'id', + question: 'question', + category: 'category', + countryCode: 'countryCode', + yesPrice: 'yesPrice', + noPrice: 'noPrice', + volumeEur: 'volumeEur', + liquidityEur: 'liquidityEur', + spread: 'spread', + bestBid: 'bestBid', + bestAsk: 'bestAsk', + clobTokenId: 'clobTokenId', + analyzable: 'analyzable', + status: 'status', + closesAt: 'closesAt', + lastSynced: 'lastSynced' +}; + +exports.Prisma.AISignalScalarFieldEnum = { + id: 'id', + marketId: 'marketId', + signal: 'signal', + confidence: 'confidence', + summary: 'summary', + keyRisk: 'keyRisk', + newsCount: 'newsCount', + modelVersion: 'modelVersion', + impliedProb: 'impliedProb', + fairProb: 'fairProb', + edgePoints: 'edgePoints', + generatedAt: 'generatedAt' +}; + +exports.Prisma.PositionScalarFieldEnum = { + id: 'id', + userId: 'userId', + marketId: 'marketId', + outcome: 'outcome', + amountEur: 'amountEur', + entryPrice: 'entryPrice', + currentPrice: 'currentPrice', + pnl: 'pnl', + kellyFraction: 'kellyFraction', + status: 'status', + openedAt: 'openedAt', + closedAt: 'closedAt' +}; + +exports.Prisma.WatchlistScalarFieldEnum = { + id: 'id', + userId: 'userId', + marketId: 'marketId', + alertThreshold: 'alertThreshold', + createdAt: 'createdAt' +}; + +exports.Prisma.AlertScalarFieldEnum = { + id: 'id', + userId: 'userId', + marketId: 'marketId', + type: 'type', + message: 'message', + sentAt: 'sentAt' +}; + +exports.Prisma.SortOrder = { + asc: 'asc', + desc: 'desc' +}; + +exports.Prisma.NullsOrder = { + first: 'first', + last: 'last' +}; + + +exports.Prisma.ModelName = { + User: 'User', + Market: 'Market', + AISignal: 'AISignal', + Position: 'Position', + Watchlist: 'Watchlist', + Alert: 'Alert' +}; +/** + * Create the Client + */ +const config = { + "generator": { + "name": "client", + "provider": { + "fromEnvVar": null, + "value": "prisma-client-js" + }, + "output": { + "value": "/Users/josesalazar/proyecto-hackaton/backend/node_modules/@prisma/client", + "fromEnvVar": null + }, + "config": { + "engineType": "library" + }, + "binaryTargets": [ + { + "fromEnvVar": null, + "value": "darwin-arm64", + "native": true + } + ], + "previewFeatures": [], + "sourceFilePath": "/Users/josesalazar/proyecto-hackaton/backend/prisma/schema.prisma" + }, + "relativeEnvPaths": { + "rootEnvPath": null, + "schemaEnvPath": "../../../.env" + }, + "relativePath": "../../../prisma", + "clientVersion": "6.19.3", + "engineVersion": "c2990dca591cba766e3b7ef5d9e8a84796e47ab7", + "datasourceNames": [ + "db" + ], + "activeProvider": "sqlite", + "postinstall": false, + "inlineDatasources": { + "db": { + "url": { + "fromEnvVar": "DATABASE_URL", + "value": null + } + } + }, + "inlineSchema": "/**\n * Schema de Prisma ORM para base de datos SQLite.\n * Define 6 modelos: User, Market, AISignal, Position, Watchlist, Alert.\n * Relaciones:\n * - Market 1:N AISignal, Position, Watchlist, Alert\n * - User 1:N Position, Watchlist, Alert\n * No modificar sin consenso del equipo. Generar migraciones con:\n * npx prisma migrate dev\n * npx prisma generate\n */\n\ngenerator client {\n provider = \"prisma-client-js\"\n}\n\ndatasource db {\n provider = \"sqlite\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel User {\n id Int @id @default(autoincrement())\n email String @unique\n passwordHash String\n isActive Boolean @default(true)\n telegramChatId String? // Configurado manualmente para demo\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n positions Position[]\n watchlist Watchlist[]\n alerts Alert[]\n}\n\nmodel Market {\n id String @id // ID nativo de Polymarket\n question String // Texto de la pregunta del mercado\n category String? // politics | crypto | economics | sports\n countryCode String? // ISO2 — usado por Leaflet para burbujas\n yesPrice Float? // Precio YES: 0.0 a 1.0\n noPrice Float? // Precio NO: 0.0 a 1.0\n volumeEur Float? // Volumen en Eur\n liquidityEur Float? // Liquidez en Eur\n spread Float? // Bid/ask spread (0-1, ej 0.02 = 2c)\n bestBid Float? // Mejor oferta de compra\n bestAsk Float? // Mejor oferta de venta\n clobTokenId String? // YES outcome CLOB token ID (para prices-history)\n analyzable Boolean @default(true) // Si la IA tiene edge plausible aqui\n status String @default(\"active\") // active | closed | resolved\n closesAt DateTime? // Fecha de cierre del mercado\n lastSynced DateTime @default(now()) // Ultima sincronizacion de precios\n\n signals AISignal[]\n positions Position[]\n watchlist Watchlist[]\n alerts Alert[]\n}\n\nmodel AISignal {\n id Int @id @default(autoincrement())\n marketId String\n market Market @relation(fields: [marketId], references: [id], onDelete: Cascade)\n signal String // bullish | bearish | neutral\n confidence Float // 0.0 a 1.0\n summary String? // 2 frases generadas por Qwen3\n keyRisk String? // 1 frase de riesgo principal\n newsCount Int @default(0) // Titulares relevantes usados\n modelVersion String @default(\"Qwen3-8B\") // Modelo LLM que genero la senal\n impliedProb Float? // Probabilidad implicita YES al generar (0-1)\n fairProb Float? // Probabilidad \"justa\" segun IA (0-1)\n edgePoints Float? // (fairProb - impliedProb) * 100, signo conserva direccion\n generatedAt DateTime @default(now())\n\n @@index([marketId, generatedAt])\n}\n\nmodel Position {\n id Int @id @default(autoincrement())\n userId Int\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n marketId String\n market Market @relation(fields: [marketId], references: [id], onDelete: Cascade)\n outcome String // YES | NO\n amountEur Float // Capital virtual apostado\n entryPrice Float // Precio al abrir la posicion\n currentPrice Float? // Precio actual (actualizado por scheduler)\n pnl Float @default(0) // Profit and Loss calculado\n kellyFraction Float? // Fraccion de Kelly al abrir\n status String @default(\"open\") // open | closed\n openedAt DateTime @default(now())\n closedAt DateTime?\n\n @@index([userId, status])\n @@index([marketId])\n}\n\nmodel Watchlist {\n id Int @id @default(autoincrement())\n userId Int\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n marketId String\n market Market @relation(fields: [marketId], references: [id], onDelete: Cascade)\n alertThreshold Float? // Umbral de precio para alerta Telegram\n createdAt DateTime @default(now())\n\n @@unique([userId, marketId])\n @@index([userId])\n}\n\nmodel Alert {\n id Int @id @default(autoincrement())\n userId Int\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n marketId String\n market Market @relation(fields: [marketId], references: [id], onDelete: Cascade)\n type String // price_threshold | signal_change\n message String // Texto enviado por Telegram\n sentAt DateTime @default(now())\n\n @@index([userId, sentAt])\n @@index([marketId])\n}\n", + "inlineSchemaHash": "317e51352744228f8aa2577b7d08529ce57f6e47ee90dbf1318c8edc1a7164fb", + "copyEngine": true +} +config.dirname = '/' + +config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"dbName\":null,\"schema\":null,\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Int\",\"nativeType\":null,\"default\":{\"name\":\"autoincrement\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"email\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":true,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"passwordHash\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"isActive\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Boolean\",\"nativeType\":null,\"default\":true,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"telegramChatId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":null,\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"DateTime\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":true},{\"name\":\"positions\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Position\",\"nativeType\":null,\"relationName\":\"PositionToUser\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"watchlist\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Watchlist\",\"nativeType\":null,\"relationName\":\"UserToWatchlist\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"alerts\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Alert\",\"nativeType\":null,\"relationName\":\"AlertToUser\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false},\"Market\":{\"dbName\":null,\"schema\":null,\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"question\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"category\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"countryCode\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"yesPrice\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"noPrice\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"volumeEur\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"liquidityEur\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"spread\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"bestBid\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"bestAsk\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"clobTokenId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"analyzable\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Boolean\",\"nativeType\":null,\"default\":true,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"status\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"String\",\"nativeType\":null,\"default\":\"active\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"closesAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"DateTime\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"lastSynced\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":null,\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"signals\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"AISignal\",\"nativeType\":null,\"relationName\":\"AISignalToMarket\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"positions\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Position\",\"nativeType\":null,\"relationName\":\"MarketToPosition\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"watchlist\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Watchlist\",\"nativeType\":null,\"relationName\":\"MarketToWatchlist\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"alerts\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Alert\",\"nativeType\":null,\"relationName\":\"AlertToMarket\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false},\"AISignal\":{\"dbName\":null,\"schema\":null,\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Int\",\"nativeType\":null,\"default\":{\"name\":\"autoincrement\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"marketId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"market\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Market\",\"nativeType\":null,\"relationName\":\"AISignalToMarket\",\"relationFromFields\":[\"marketId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"signal\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"confidence\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"summary\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"keyRisk\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"newsCount\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Int\",\"nativeType\":null,\"default\":0,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"modelVersion\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"String\",\"nativeType\":null,\"default\":\"Qwen3-8B\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"impliedProb\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"fairProb\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"edgePoints\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"generatedAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":null,\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false},\"Position\":{\"dbName\":null,\"schema\":null,\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Int\",\"nativeType\":null,\"default\":{\"name\":\"autoincrement\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"userId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"Int\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"user\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"User\",\"nativeType\":null,\"relationName\":\"PositionToUser\",\"relationFromFields\":[\"userId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"marketId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"market\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Market\",\"nativeType\":null,\"relationName\":\"MarketToPosition\",\"relationFromFields\":[\"marketId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"outcome\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"amountEur\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"entryPrice\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"currentPrice\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"pnl\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Float\",\"nativeType\":null,\"default\":0,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"kellyFraction\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"status\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"String\",\"nativeType\":null,\"default\":\"open\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"openedAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":null,\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"closedAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"DateTime\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false},\"Watchlist\":{\"dbName\":null,\"schema\":null,\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Int\",\"nativeType\":null,\"default\":{\"name\":\"autoincrement\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"userId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"Int\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"user\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"User\",\"nativeType\":null,\"relationName\":\"UserToWatchlist\",\"relationFromFields\":[\"userId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"marketId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"market\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Market\",\"nativeType\":null,\"relationName\":\"MarketToWatchlist\",\"relationFromFields\":[\"marketId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"alertThreshold\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":null,\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[[\"userId\",\"marketId\"]],\"uniqueIndexes\":[{\"name\":null,\"fields\":[\"userId\",\"marketId\"]}],\"isGenerated\":false},\"Alert\":{\"dbName\":null,\"schema\":null,\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Int\",\"nativeType\":null,\"default\":{\"name\":\"autoincrement\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"userId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"Int\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"user\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"User\",\"nativeType\":null,\"relationName\":\"AlertToUser\",\"relationFromFields\":[\"userId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"marketId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"market\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Market\",\"nativeType\":null,\"relationName\":\"AlertToMarket\",\"relationFromFields\":[\"marketId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"type\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"message\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"sentAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":null,\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false}},\"enums\":{},\"types\":{}}") +defineDmmfProperty(exports.Prisma, config.runtimeDataModel) +config.engineWasm = undefined +config.compilerWasm = undefined + +config.injectableEdgeEnv = () => ({ + parsed: { + DATABASE_URL: typeof globalThis !== 'undefined' && globalThis['DATABASE_URL'] || typeof process !== 'undefined' && process.env && process.env.DATABASE_URL || undefined + } +}) + +if (typeof globalThis !== 'undefined' && globalThis['DEBUG'] || typeof process !== 'undefined' && process.env && process.env.DEBUG || undefined) { + Debug.enable(typeof globalThis !== 'undefined' && globalThis['DEBUG'] || typeof process !== 'undefined' && process.env && process.env.DEBUG || undefined) +} + +const PrismaClient = getPrismaClient(config) +exports.PrismaClient = PrismaClient +Object.assign(exports, Prisma) + diff --git a/backend/node_modules/.prisma/client/index-browser.js b/backend/node_modules/.prisma/client/index-browser.js new file mode 100644 index 0000000000000000000000000000000000000000..a1f0eb0c56d52ed829fa20233b3e6c4a342f1cf6 --- /dev/null +++ b/backend/node_modules/.prisma/client/index-browser.js @@ -0,0 +1,246 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! +/* eslint-disable */ +// biome-ignore-all lint: generated file + +Object.defineProperty(exports, "__esModule", { value: true }); + +const { + Decimal, + objectEnumValues, + makeStrictEnum, + Public, + getRuntime, + skip +} = require('@prisma/client/runtime/index-browser.js') + + +const Prisma = {} + +exports.Prisma = Prisma +exports.$Enums = {} + +/** + * Prisma Client JS version: 6.19.3 + * Query Engine version: c2990dca591cba766e3b7ef5d9e8a84796e47ab7 + */ +Prisma.prismaVersion = { + client: "6.19.3", + engine: "c2990dca591cba766e3b7ef5d9e8a84796e47ab7" +} + +Prisma.PrismaClientKnownRequestError = () => { + const runtimeName = getRuntime().prettyName; + throw new Error(`PrismaClientKnownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}). +In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`, +)}; +Prisma.PrismaClientUnknownRequestError = () => { + const runtimeName = getRuntime().prettyName; + throw new Error(`PrismaClientUnknownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}). +In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`, +)} +Prisma.PrismaClientRustPanicError = () => { + const runtimeName = getRuntime().prettyName; + throw new Error(`PrismaClientRustPanicError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}). +In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`, +)} +Prisma.PrismaClientInitializationError = () => { + const runtimeName = getRuntime().prettyName; + throw new Error(`PrismaClientInitializationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}). +In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`, +)} +Prisma.PrismaClientValidationError = () => { + const runtimeName = getRuntime().prettyName; + throw new Error(`PrismaClientValidationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}). +In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`, +)} +Prisma.Decimal = Decimal + +/** + * Re-export of sql-template-tag + */ +Prisma.sql = () => { + const runtimeName = getRuntime().prettyName; + throw new Error(`sqltag is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}). +In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`, +)} +Prisma.empty = () => { + const runtimeName = getRuntime().prettyName; + throw new Error(`empty is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}). +In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`, +)} +Prisma.join = () => { + const runtimeName = getRuntime().prettyName; + throw new Error(`join is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}). +In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`, +)} +Prisma.raw = () => { + const runtimeName = getRuntime().prettyName; + throw new Error(`raw is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}). +In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`, +)} +Prisma.validator = Public.validator + +/** +* Extensions +*/ +Prisma.getExtensionContext = () => { + const runtimeName = getRuntime().prettyName; + throw new Error(`Extensions.getExtensionContext is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}). +In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`, +)} +Prisma.defineExtension = () => { + const runtimeName = getRuntime().prettyName; + throw new Error(`Extensions.defineExtension is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}). +In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`, +)} + +/** + * Shorthand utilities for JSON filtering + */ +Prisma.DbNull = objectEnumValues.instances.DbNull +Prisma.JsonNull = objectEnumValues.instances.JsonNull +Prisma.AnyNull = objectEnumValues.instances.AnyNull + +Prisma.NullTypes = { + DbNull: objectEnumValues.classes.DbNull, + JsonNull: objectEnumValues.classes.JsonNull, + AnyNull: objectEnumValues.classes.AnyNull +} + + + +/** + * Enums + */ + +exports.Prisma.TransactionIsolationLevel = makeStrictEnum({ + Serializable: 'Serializable' +}); + +exports.Prisma.UserScalarFieldEnum = { + id: 'id', + email: 'email', + passwordHash: 'passwordHash', + isActive: 'isActive', + telegramChatId: 'telegramChatId', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +}; + +exports.Prisma.MarketScalarFieldEnum = { + id: 'id', + question: 'question', + category: 'category', + countryCode: 'countryCode', + yesPrice: 'yesPrice', + noPrice: 'noPrice', + volumeEur: 'volumeEur', + liquidityEur: 'liquidityEur', + spread: 'spread', + bestBid: 'bestBid', + bestAsk: 'bestAsk', + clobTokenId: 'clobTokenId', + analyzable: 'analyzable', + status: 'status', + closesAt: 'closesAt', + lastSynced: 'lastSynced' +}; + +exports.Prisma.AISignalScalarFieldEnum = { + id: 'id', + marketId: 'marketId', + signal: 'signal', + confidence: 'confidence', + summary: 'summary', + keyRisk: 'keyRisk', + newsCount: 'newsCount', + modelVersion: 'modelVersion', + impliedProb: 'impliedProb', + fairProb: 'fairProb', + edgePoints: 'edgePoints', + generatedAt: 'generatedAt' +}; + +exports.Prisma.PositionScalarFieldEnum = { + id: 'id', + userId: 'userId', + marketId: 'marketId', + outcome: 'outcome', + amountEur: 'amountEur', + entryPrice: 'entryPrice', + currentPrice: 'currentPrice', + pnl: 'pnl', + kellyFraction: 'kellyFraction', + status: 'status', + openedAt: 'openedAt', + closedAt: 'closedAt' +}; + +exports.Prisma.WatchlistScalarFieldEnum = { + id: 'id', + userId: 'userId', + marketId: 'marketId', + alertThreshold: 'alertThreshold', + createdAt: 'createdAt' +}; + +exports.Prisma.AlertScalarFieldEnum = { + id: 'id', + userId: 'userId', + marketId: 'marketId', + type: 'type', + message: 'message', + sentAt: 'sentAt' +}; + +exports.Prisma.SortOrder = { + asc: 'asc', + desc: 'desc' +}; + +exports.Prisma.NullsOrder = { + first: 'first', + last: 'last' +}; + + +exports.Prisma.ModelName = { + User: 'User', + Market: 'Market', + AISignal: 'AISignal', + Position: 'Position', + Watchlist: 'Watchlist', + Alert: 'Alert' +}; + +/** + * This is a stub Prisma Client that will error at runtime if called. + */ +class PrismaClient { + constructor() { + return new Proxy(this, { + get(target, prop) { + let message + const runtime = getRuntime() + if (runtime.isEdge) { + message = `PrismaClient is not configured to run in ${runtime.prettyName}. In order to run Prisma Client on edge runtime, either: +- Use Prisma Accelerate: https://pris.ly/d/accelerate +- Use Driver Adapters: https://pris.ly/d/driver-adapters +`; + } else { + message = 'PrismaClient is unable to run in this browser environment, or has been bundled for the browser (running in `' + runtime.prettyName + '`).' + } + + message += ` +If this is unexpected, please open an issue: https://pris.ly/prisma-prisma-bug-report` + + throw new Error(message) + } + }) + } +} + +exports.PrismaClient = PrismaClient + +Object.assign(exports, Prisma) diff --git a/backend/node_modules/.prisma/client/index.d.ts b/backend/node_modules/.prisma/client/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..72f86a19bd49064ebc2b56c05b0b87e95262f559 --- /dev/null +++ b/backend/node_modules/.prisma/client/index.d.ts @@ -0,0 +1,12309 @@ + +/** + * Client +**/ + +import * as runtime from '@prisma/client/runtime/library.js'; +import $Types = runtime.Types // general types +import $Public = runtime.Types.Public +import $Utils = runtime.Types.Utils +import $Extensions = runtime.Types.Extensions +import $Result = runtime.Types.Result + +export type PrismaPromise = $Public.PrismaPromise + + +/** + * Model User + * + */ +export type User = $Result.DefaultSelection +/** + * Model Market + * + */ +export type Market = $Result.DefaultSelection +/** + * Model AISignal + * + */ +export type AISignal = $Result.DefaultSelection +/** + * Model Position + * + */ +export type Position = $Result.DefaultSelection +/** + * Model Watchlist + * + */ +export type Watchlist = $Result.DefaultSelection +/** + * Model Alert + * + */ +export type Alert = $Result.DefaultSelection + +/** + * ## Prisma Client ʲˢ + * + * Type-safe database client for TypeScript & Node.js + * @example + * ``` + * const prisma = new PrismaClient() + * // Fetch zero or more Users + * const users = await prisma.user.findMany() + * ``` + * + * + * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client). + */ +export class PrismaClient< + ClientOptions extends Prisma.PrismaClientOptions = Prisma.PrismaClientOptions, + const U = 'log' extends keyof ClientOptions ? ClientOptions['log'] extends Array ? Prisma.GetEvents : never : never, + ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs +> { + [K: symbol]: { types: Prisma.TypeMap['other'] } + + /** + * ## Prisma Client ʲˢ + * + * Type-safe database client for TypeScript & Node.js + * @example + * ``` + * const prisma = new PrismaClient() + * // Fetch zero or more Users + * const users = await prisma.user.findMany() + * ``` + * + * + * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client). + */ + + constructor(optionsArg ?: Prisma.Subset); + $on(eventType: V, callback: (event: V extends 'query' ? Prisma.QueryEvent : Prisma.LogEvent) => void): PrismaClient; + + /** + * Connect with the database + */ + $connect(): $Utils.JsPromise; + + /** + * Disconnect from the database + */ + $disconnect(): $Utils.JsPromise; + +/** + * Executes a prepared raw query and returns the number of affected rows. + * @example + * ``` + * const result = await prisma.$executeRaw`UPDATE User SET cool = ${true} WHERE email = ${'user@email.com'};` + * ``` + * + * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/raw-database-access). + */ + $executeRaw(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise; + + /** + * Executes a raw query and returns the number of affected rows. + * Susceptible to SQL injections, see documentation. + * @example + * ``` + * const result = await prisma.$executeRawUnsafe('UPDATE User SET cool = $1 WHERE email = $2 ;', true, 'user@email.com') + * ``` + * + * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/raw-database-access). + */ + $executeRawUnsafe(query: string, ...values: any[]): Prisma.PrismaPromise; + + /** + * Performs a prepared raw query and returns the `SELECT` data. + * @example + * ``` + * const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${1} OR email = ${'user@email.com'};` + * ``` + * + * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/raw-database-access). + */ + $queryRaw(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise; + + /** + * Performs a raw query and returns the `SELECT` data. + * Susceptible to SQL injections, see documentation. + * @example + * ``` + * const result = await prisma.$queryRawUnsafe('SELECT * FROM User WHERE id = $1 OR email = $2;', 1, 'user@email.com') + * ``` + * + * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/raw-database-access). + */ + $queryRawUnsafe(query: string, ...values: any[]): Prisma.PrismaPromise; + + + /** + * Allows the running of a sequence of read/write operations that are guaranteed to either succeed or fail as a whole. + * @example + * ``` + * const [george, bob, alice] = await prisma.$transaction([ + * prisma.user.create({ data: { name: 'George' } }), + * prisma.user.create({ data: { name: 'Bob' } }), + * prisma.user.create({ data: { name: 'Alice' } }), + * ]) + * ``` + * + * Read more in our [docs](https://www.prisma.io/docs/concepts/components/prisma-client/transactions). + */ + $transaction

[]>(arg: [...P], options?: { isolationLevel?: Prisma.TransactionIsolationLevel }): $Utils.JsPromise> + + $transaction(fn: (prisma: Omit) => $Utils.JsPromise, options?: { maxWait?: number, timeout?: number, isolationLevel?: Prisma.TransactionIsolationLevel }): $Utils.JsPromise + + + $extends: $Extensions.ExtendsHook<"extends", Prisma.TypeMapCb, ExtArgs, $Utils.Call, { + extArgs: ExtArgs + }>> + + /** + * `prisma.user`: Exposes CRUD operations for the **User** model. + * Example usage: + * ```ts + * // Fetch zero or more Users + * const users = await prisma.user.findMany() + * ``` + */ + get user(): Prisma.UserDelegate; + + /** + * `prisma.market`: Exposes CRUD operations for the **Market** model. + * Example usage: + * ```ts + * // Fetch zero or more Markets + * const markets = await prisma.market.findMany() + * ``` + */ + get market(): Prisma.MarketDelegate; + + /** + * `prisma.aISignal`: Exposes CRUD operations for the **AISignal** model. + * Example usage: + * ```ts + * // Fetch zero or more AISignals + * const aISignals = await prisma.aISignal.findMany() + * ``` + */ + get aISignal(): Prisma.AISignalDelegate; + + /** + * `prisma.position`: Exposes CRUD operations for the **Position** model. + * Example usage: + * ```ts + * // Fetch zero or more Positions + * const positions = await prisma.position.findMany() + * ``` + */ + get position(): Prisma.PositionDelegate; + + /** + * `prisma.watchlist`: Exposes CRUD operations for the **Watchlist** model. + * Example usage: + * ```ts + * // Fetch zero or more Watchlists + * const watchlists = await prisma.watchlist.findMany() + * ``` + */ + get watchlist(): Prisma.WatchlistDelegate; + + /** + * `prisma.alert`: Exposes CRUD operations for the **Alert** model. + * Example usage: + * ```ts + * // Fetch zero or more Alerts + * const alerts = await prisma.alert.findMany() + * ``` + */ + get alert(): Prisma.AlertDelegate; +} + +export namespace Prisma { + export import DMMF = runtime.DMMF + + export type PrismaPromise = $Public.PrismaPromise + + /** + * Validator + */ + export import validator = runtime.Public.validator + + /** + * Prisma Errors + */ + export import PrismaClientKnownRequestError = runtime.PrismaClientKnownRequestError + export import PrismaClientUnknownRequestError = runtime.PrismaClientUnknownRequestError + export import PrismaClientRustPanicError = runtime.PrismaClientRustPanicError + export import PrismaClientInitializationError = runtime.PrismaClientInitializationError + export import PrismaClientValidationError = runtime.PrismaClientValidationError + + /** + * Re-export of sql-template-tag + */ + export import sql = runtime.sqltag + export import empty = runtime.empty + export import join = runtime.join + export import raw = runtime.raw + export import Sql = runtime.Sql + + + + /** + * Decimal.js + */ + export import Decimal = runtime.Decimal + + export type DecimalJsLike = runtime.DecimalJsLike + + /** + * Metrics + */ + export type Metrics = runtime.Metrics + export type Metric = runtime.Metric + export type MetricHistogram = runtime.MetricHistogram + export type MetricHistogramBucket = runtime.MetricHistogramBucket + + /** + * Extensions + */ + export import Extension = $Extensions.UserArgs + export import getExtensionContext = runtime.Extensions.getExtensionContext + export import Args = $Public.Args + export import Payload = $Public.Payload + export import Result = $Public.Result + export import Exact = $Public.Exact + + /** + * Prisma Client JS version: 6.19.3 + * Query Engine version: c2990dca591cba766e3b7ef5d9e8a84796e47ab7 + */ + export type PrismaVersion = { + client: string + } + + export const prismaVersion: PrismaVersion + + /** + * Utility Types + */ + + + export import Bytes = runtime.Bytes + export import JsonObject = runtime.JsonObject + export import JsonArray = runtime.JsonArray + export import JsonValue = runtime.JsonValue + export import InputJsonObject = runtime.InputJsonObject + export import InputJsonArray = runtime.InputJsonArray + export import InputJsonValue = runtime.InputJsonValue + + /** + * Types of the values used to represent different kinds of `null` values when working with JSON fields. + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ + namespace NullTypes { + /** + * Type of `Prisma.DbNull`. + * + * You cannot use other instances of this class. Please use the `Prisma.DbNull` value. + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ + class DbNull { + private DbNull: never + private constructor() + } + + /** + * Type of `Prisma.JsonNull`. + * + * You cannot use other instances of this class. Please use the `Prisma.JsonNull` value. + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ + class JsonNull { + private JsonNull: never + private constructor() + } + + /** + * Type of `Prisma.AnyNull`. + * + * You cannot use other instances of this class. Please use the `Prisma.AnyNull` value. + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ + class AnyNull { + private AnyNull: never + private constructor() + } + } + + /** + * Helper for filtering JSON entries that have `null` on the database (empty on the db) + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ + export const DbNull: NullTypes.DbNull + + /** + * Helper for filtering JSON entries that have JSON `null` values (not empty on the db) + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ + export const JsonNull: NullTypes.JsonNull + + /** + * Helper for filtering JSON entries that are `Prisma.DbNull` or `Prisma.JsonNull` + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ + export const AnyNull: NullTypes.AnyNull + + type SelectAndInclude = { + select: any + include: any + } + + type SelectAndOmit = { + select: any + omit: any + } + + /** + * Get the type of the value, that the Promise holds. + */ + export type PromiseType> = T extends PromiseLike ? U : T; + + /** + * Get the return type of a function which returns a Promise. + */ + export type PromiseReturnType $Utils.JsPromise> = PromiseType> + + /** + * From T, pick a set of properties whose keys are in the union K + */ + type Prisma__Pick = { + [P in K]: T[P]; + }; + + + export type Enumerable = T | Array; + + export type RequiredKeys = { + [K in keyof T]-?: {} extends Prisma__Pick ? never : K + }[keyof T] + + export type TruthyKeys = keyof { + [K in keyof T as T[K] extends false | undefined | null ? never : K]: K + } + + export type TrueKeys = TruthyKeys>> + + /** + * Subset + * @desc From `T` pick properties that exist in `U`. Simple version of Intersection + */ + export type Subset = { + [key in keyof T]: key extends keyof U ? T[key] : never; + }; + + /** + * SelectSubset + * @desc From `T` pick properties that exist in `U`. Simple version of Intersection. + * Additionally, it validates, if both select and include are present. If the case, it errors. + */ + export type SelectSubset = { + [key in keyof T]: key extends keyof U ? T[key] : never + } & + (T extends SelectAndInclude + ? 'Please either choose `select` or `include`.' + : T extends SelectAndOmit + ? 'Please either choose `select` or `omit`.' + : {}) + + /** + * Subset + Intersection + * @desc From `T` pick properties that exist in `U` and intersect `K` + */ + export type SubsetIntersection = { + [key in keyof T]: key extends keyof U ? T[key] : never + } & + K + + type Without = { [P in Exclude]?: never }; + + /** + * XOR is needed to have a real mutually exclusive union type + * https://stackoverflow.com/questions/42123407/does-typescript-support-mutually-exclusive-types + */ + type XOR = + T extends object ? + U extends object ? + (Without & U) | (Without & T) + : U : T + + + /** + * Is T a Record? + */ + type IsObject = T extends Array + ? False + : T extends Date + ? False + : T extends Uint8Array + ? False + : T extends BigInt + ? False + : T extends object + ? True + : False + + + /** + * If it's T[], return T + */ + export type UnEnumerate = T extends Array ? U : T + + /** + * From ts-toolbelt + */ + + type __Either = Omit & + { + // Merge all but K + [P in K]: Prisma__Pick // With K possibilities + }[K] + + type EitherStrict = Strict<__Either> + + type EitherLoose = ComputeRaw<__Either> + + type _Either< + O extends object, + K extends Key, + strict extends Boolean + > = { + 1: EitherStrict + 0: EitherLoose + }[strict] + + type Either< + O extends object, + K extends Key, + strict extends Boolean = 1 + > = O extends unknown ? _Either : never + + export type Union = any + + type PatchUndefined = { + [K in keyof O]: O[K] extends undefined ? At : O[K] + } & {} + + /** Helper Types for "Merge" **/ + export type IntersectOf = ( + U extends unknown ? (k: U) => void : never + ) extends (k: infer I) => void + ? I + : never + + export type Overwrite = { + [K in keyof O]: K extends keyof O1 ? O1[K] : O[K]; + } & {}; + + type _Merge = IntersectOf; + }>>; + + type Key = string | number | symbol; + type AtBasic = K extends keyof O ? O[K] : never; + type AtStrict = O[K & keyof O]; + type AtLoose = O extends unknown ? AtStrict : never; + export type At = { + 1: AtStrict; + 0: AtLoose; + }[strict]; + + export type ComputeRaw = A extends Function ? A : { + [K in keyof A]: A[K]; + } & {}; + + export type OptionalFlat = { + [K in keyof O]?: O[K]; + } & {}; + + type _Record = { + [P in K]: T; + }; + + // cause typescript not to expand types and preserve names + type NoExpand = T extends unknown ? T : never; + + // this type assumes the passed object is entirely optional + type AtLeast = NoExpand< + O extends unknown + ? | (K extends keyof O ? { [P in K]: O[P] } & O : O) + | {[P in keyof O as P extends K ? P : never]-?: O[P]} & O + : never>; + + type _Strict = U extends unknown ? U & OptionalFlat<_Record, keyof U>, never>> : never; + + export type Strict = ComputeRaw<_Strict>; + /** End Helper Types for "Merge" **/ + + export type Merge = ComputeRaw<_Merge>>; + + /** + A [[Boolean]] + */ + export type Boolean = True | False + + // /** + // 1 + // */ + export type True = 1 + + /** + 0 + */ + export type False = 0 + + export type Not = { + 0: 1 + 1: 0 + }[B] + + export type Extends = [A1] extends [never] + ? 0 // anything `never` is false + : A1 extends A2 + ? 1 + : 0 + + export type Has = Not< + Extends, U1> + > + + export type Or = { + 0: { + 0: 0 + 1: 1 + } + 1: { + 0: 1 + 1: 1 + } + }[B1][B2] + + export type Keys = U extends unknown ? keyof U : never + + type Cast = A extends B ? A : B; + + export const type: unique symbol; + + + + /** + * Used by group by + */ + + export type GetScalarType = O extends object ? { + [P in keyof T]: P extends keyof O + ? O[P] + : never + } : never + + type FieldPaths< + T, + U = Omit + > = IsObject extends True ? U : T + + type GetHavingFields = { + [K in keyof T]: Or< + Or, Extends<'AND', K>>, + Extends<'NOT', K> + > extends True + ? // infer is only needed to not hit TS limit + // based on the brilliant idea of Pierre-Antoine Mills + // https://github.com/microsoft/TypeScript/issues/30188#issuecomment-478938437 + T[K] extends infer TK + ? GetHavingFields extends object ? Merge> : never> + : never + : {} extends FieldPaths + ? never + : K + }[keyof T] + + /** + * Convert tuple to union + */ + type _TupleToUnion = T extends (infer E)[] ? E : never + type TupleToUnion = _TupleToUnion + type MaybeTupleToUnion = T extends any[] ? TupleToUnion : T + + /** + * Like `Pick`, but additionally can also accept an array of keys + */ + type PickEnumerable | keyof T> = Prisma__Pick> + + /** + * Exclude all keys with underscores + */ + type ExcludeUnderscoreKeys = T extends `_${string}` ? never : T + + + export type FieldRef = runtime.FieldRef + + type FieldRefInputType = Model extends never ? never : FieldRef + + + export const ModelName: { + User: 'User', + Market: 'Market', + AISignal: 'AISignal', + Position: 'Position', + Watchlist: 'Watchlist', + Alert: 'Alert' + }; + + export type ModelName = (typeof ModelName)[keyof typeof ModelName] + + + export type Datasources = { + db?: Datasource + } + + interface TypeMapCb extends $Utils.Fn<{extArgs: $Extensions.InternalArgs }, $Utils.Record> { + returns: Prisma.TypeMap + } + + export type TypeMap = { + globalOmitOptions: { + omit: GlobalOmitOptions + } + meta: { + modelProps: "user" | "market" | "aISignal" | "position" | "watchlist" | "alert" + txIsolationLevel: Prisma.TransactionIsolationLevel + } + model: { + User: { + payload: Prisma.$UserPayload + fields: Prisma.UserFieldRefs + operations: { + findUnique: { + args: Prisma.UserFindUniqueArgs + result: $Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.UserFindUniqueOrThrowArgs + result: $Utils.PayloadToResult + } + findFirst: { + args: Prisma.UserFindFirstArgs + result: $Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.UserFindFirstOrThrowArgs + result: $Utils.PayloadToResult + } + findMany: { + args: Prisma.UserFindManyArgs + result: $Utils.PayloadToResult[] + } + create: { + args: Prisma.UserCreateArgs + result: $Utils.PayloadToResult + } + createMany: { + args: Prisma.UserCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.UserCreateManyAndReturnArgs + result: $Utils.PayloadToResult[] + } + delete: { + args: Prisma.UserDeleteArgs + result: $Utils.PayloadToResult + } + update: { + args: Prisma.UserUpdateArgs + result: $Utils.PayloadToResult + } + deleteMany: { + args: Prisma.UserDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.UserUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.UserUpdateManyAndReturnArgs + result: $Utils.PayloadToResult[] + } + upsert: { + args: Prisma.UserUpsertArgs + result: $Utils.PayloadToResult + } + aggregate: { + args: Prisma.UserAggregateArgs + result: $Utils.Optional + } + groupBy: { + args: Prisma.UserGroupByArgs + result: $Utils.Optional[] + } + count: { + args: Prisma.UserCountArgs + result: $Utils.Optional | number + } + } + } + Market: { + payload: Prisma.$MarketPayload + fields: Prisma.MarketFieldRefs + operations: { + findUnique: { + args: Prisma.MarketFindUniqueArgs + result: $Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.MarketFindUniqueOrThrowArgs + result: $Utils.PayloadToResult + } + findFirst: { + args: Prisma.MarketFindFirstArgs + result: $Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.MarketFindFirstOrThrowArgs + result: $Utils.PayloadToResult + } + findMany: { + args: Prisma.MarketFindManyArgs + result: $Utils.PayloadToResult[] + } + create: { + args: Prisma.MarketCreateArgs + result: $Utils.PayloadToResult + } + createMany: { + args: Prisma.MarketCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.MarketCreateManyAndReturnArgs + result: $Utils.PayloadToResult[] + } + delete: { + args: Prisma.MarketDeleteArgs + result: $Utils.PayloadToResult + } + update: { + args: Prisma.MarketUpdateArgs + result: $Utils.PayloadToResult + } + deleteMany: { + args: Prisma.MarketDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.MarketUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.MarketUpdateManyAndReturnArgs + result: $Utils.PayloadToResult[] + } + upsert: { + args: Prisma.MarketUpsertArgs + result: $Utils.PayloadToResult + } + aggregate: { + args: Prisma.MarketAggregateArgs + result: $Utils.Optional + } + groupBy: { + args: Prisma.MarketGroupByArgs + result: $Utils.Optional[] + } + count: { + args: Prisma.MarketCountArgs + result: $Utils.Optional | number + } + } + } + AISignal: { + payload: Prisma.$AISignalPayload + fields: Prisma.AISignalFieldRefs + operations: { + findUnique: { + args: Prisma.AISignalFindUniqueArgs + result: $Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.AISignalFindUniqueOrThrowArgs + result: $Utils.PayloadToResult + } + findFirst: { + args: Prisma.AISignalFindFirstArgs + result: $Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.AISignalFindFirstOrThrowArgs + result: $Utils.PayloadToResult + } + findMany: { + args: Prisma.AISignalFindManyArgs + result: $Utils.PayloadToResult[] + } + create: { + args: Prisma.AISignalCreateArgs + result: $Utils.PayloadToResult + } + createMany: { + args: Prisma.AISignalCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.AISignalCreateManyAndReturnArgs + result: $Utils.PayloadToResult[] + } + delete: { + args: Prisma.AISignalDeleteArgs + result: $Utils.PayloadToResult + } + update: { + args: Prisma.AISignalUpdateArgs + result: $Utils.PayloadToResult + } + deleteMany: { + args: Prisma.AISignalDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.AISignalUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.AISignalUpdateManyAndReturnArgs + result: $Utils.PayloadToResult[] + } + upsert: { + args: Prisma.AISignalUpsertArgs + result: $Utils.PayloadToResult + } + aggregate: { + args: Prisma.AISignalAggregateArgs + result: $Utils.Optional + } + groupBy: { + args: Prisma.AISignalGroupByArgs + result: $Utils.Optional[] + } + count: { + args: Prisma.AISignalCountArgs + result: $Utils.Optional | number + } + } + } + Position: { + payload: Prisma.$PositionPayload + fields: Prisma.PositionFieldRefs + operations: { + findUnique: { + args: Prisma.PositionFindUniqueArgs + result: $Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.PositionFindUniqueOrThrowArgs + result: $Utils.PayloadToResult + } + findFirst: { + args: Prisma.PositionFindFirstArgs + result: $Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.PositionFindFirstOrThrowArgs + result: $Utils.PayloadToResult + } + findMany: { + args: Prisma.PositionFindManyArgs + result: $Utils.PayloadToResult[] + } + create: { + args: Prisma.PositionCreateArgs + result: $Utils.PayloadToResult + } + createMany: { + args: Prisma.PositionCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.PositionCreateManyAndReturnArgs + result: $Utils.PayloadToResult[] + } + delete: { + args: Prisma.PositionDeleteArgs + result: $Utils.PayloadToResult + } + update: { + args: Prisma.PositionUpdateArgs + result: $Utils.PayloadToResult + } + deleteMany: { + args: Prisma.PositionDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.PositionUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.PositionUpdateManyAndReturnArgs + result: $Utils.PayloadToResult[] + } + upsert: { + args: Prisma.PositionUpsertArgs + result: $Utils.PayloadToResult + } + aggregate: { + args: Prisma.PositionAggregateArgs + result: $Utils.Optional + } + groupBy: { + args: Prisma.PositionGroupByArgs + result: $Utils.Optional[] + } + count: { + args: Prisma.PositionCountArgs + result: $Utils.Optional | number + } + } + } + Watchlist: { + payload: Prisma.$WatchlistPayload + fields: Prisma.WatchlistFieldRefs + operations: { + findUnique: { + args: Prisma.WatchlistFindUniqueArgs + result: $Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.WatchlistFindUniqueOrThrowArgs + result: $Utils.PayloadToResult + } + findFirst: { + args: Prisma.WatchlistFindFirstArgs + result: $Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.WatchlistFindFirstOrThrowArgs + result: $Utils.PayloadToResult + } + findMany: { + args: Prisma.WatchlistFindManyArgs + result: $Utils.PayloadToResult[] + } + create: { + args: Prisma.WatchlistCreateArgs + result: $Utils.PayloadToResult + } + createMany: { + args: Prisma.WatchlistCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.WatchlistCreateManyAndReturnArgs + result: $Utils.PayloadToResult[] + } + delete: { + args: Prisma.WatchlistDeleteArgs + result: $Utils.PayloadToResult + } + update: { + args: Prisma.WatchlistUpdateArgs + result: $Utils.PayloadToResult + } + deleteMany: { + args: Prisma.WatchlistDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.WatchlistUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.WatchlistUpdateManyAndReturnArgs + result: $Utils.PayloadToResult[] + } + upsert: { + args: Prisma.WatchlistUpsertArgs + result: $Utils.PayloadToResult + } + aggregate: { + args: Prisma.WatchlistAggregateArgs + result: $Utils.Optional + } + groupBy: { + args: Prisma.WatchlistGroupByArgs + result: $Utils.Optional[] + } + count: { + args: Prisma.WatchlistCountArgs + result: $Utils.Optional | number + } + } + } + Alert: { + payload: Prisma.$AlertPayload + fields: Prisma.AlertFieldRefs + operations: { + findUnique: { + args: Prisma.AlertFindUniqueArgs + result: $Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.AlertFindUniqueOrThrowArgs + result: $Utils.PayloadToResult + } + findFirst: { + args: Prisma.AlertFindFirstArgs + result: $Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.AlertFindFirstOrThrowArgs + result: $Utils.PayloadToResult + } + findMany: { + args: Prisma.AlertFindManyArgs + result: $Utils.PayloadToResult[] + } + create: { + args: Prisma.AlertCreateArgs + result: $Utils.PayloadToResult + } + createMany: { + args: Prisma.AlertCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.AlertCreateManyAndReturnArgs + result: $Utils.PayloadToResult[] + } + delete: { + args: Prisma.AlertDeleteArgs + result: $Utils.PayloadToResult + } + update: { + args: Prisma.AlertUpdateArgs + result: $Utils.PayloadToResult + } + deleteMany: { + args: Prisma.AlertDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.AlertUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.AlertUpdateManyAndReturnArgs + result: $Utils.PayloadToResult[] + } + upsert: { + args: Prisma.AlertUpsertArgs + result: $Utils.PayloadToResult + } + aggregate: { + args: Prisma.AlertAggregateArgs + result: $Utils.Optional + } + groupBy: { + args: Prisma.AlertGroupByArgs + result: $Utils.Optional[] + } + count: { + args: Prisma.AlertCountArgs + result: $Utils.Optional | number + } + } + } + } + } & { + other: { + payload: any + operations: { + $executeRaw: { + args: [query: TemplateStringsArray | Prisma.Sql, ...values: any[]], + result: any + } + $executeRawUnsafe: { + args: [query: string, ...values: any[]], + result: any + } + $queryRaw: { + args: [query: TemplateStringsArray | Prisma.Sql, ...values: any[]], + result: any + } + $queryRawUnsafe: { + args: [query: string, ...values: any[]], + result: any + } + } + } + } + export const defineExtension: $Extensions.ExtendsHook<"define", Prisma.TypeMapCb, $Extensions.DefaultArgs> + export type DefaultPrismaClient = PrismaClient + export type ErrorFormat = 'pretty' | 'colorless' | 'minimal' + export interface PrismaClientOptions { + /** + * Overwrites the datasource url from your schema.prisma file + */ + datasources?: Datasources + /** + * Overwrites the datasource url from your schema.prisma file + */ + datasourceUrl?: string + /** + * @default "colorless" + */ + errorFormat?: ErrorFormat + /** + * @example + * ``` + * // Shorthand for `emit: 'stdout'` + * log: ['query', 'info', 'warn', 'error'] + * + * // Emit as events only + * log: [ + * { emit: 'event', level: 'query' }, + * { emit: 'event', level: 'info' }, + * { emit: 'event', level: 'warn' } + * { emit: 'event', level: 'error' } + * ] + * + * / Emit as events and log to stdout + * og: [ + * { emit: 'stdout', level: 'query' }, + * { emit: 'stdout', level: 'info' }, + * { emit: 'stdout', level: 'warn' } + * { emit: 'stdout', level: 'error' } + * + * ``` + * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/logging#the-log-option). + */ + log?: (LogLevel | LogDefinition)[] + /** + * The default values for transactionOptions + * maxWait ?= 2000 + * timeout ?= 5000 + */ + transactionOptions?: { + maxWait?: number + timeout?: number + isolationLevel?: Prisma.TransactionIsolationLevel + } + /** + * Instance of a Driver Adapter, e.g., like one provided by `@prisma/adapter-planetscale` + */ + adapter?: runtime.SqlDriverAdapterFactory | null + /** + * Global configuration for omitting model fields by default. + * + * @example + * ``` + * const prisma = new PrismaClient({ + * omit: { + * user: { + * password: true + * } + * } + * }) + * ``` + */ + omit?: Prisma.GlobalOmitConfig + } + export type GlobalOmitConfig = { + user?: UserOmit + market?: MarketOmit + aISignal?: AISignalOmit + position?: PositionOmit + watchlist?: WatchlistOmit + alert?: AlertOmit + } + + /* Types for Logging */ + export type LogLevel = 'info' | 'query' | 'warn' | 'error' + export type LogDefinition = { + level: LogLevel + emit: 'stdout' | 'event' + } + + export type CheckIsLogLevel = T extends LogLevel ? T : never; + + export type GetLogType = CheckIsLogLevel< + T extends LogDefinition ? T['level'] : T + >; + + export type GetEvents = T extends Array + ? GetLogType + : never; + + export type QueryEvent = { + timestamp: Date + query: string + params: string + duration: number + target: string + } + + export type LogEvent = { + timestamp: Date + message: string + target: string + } + /* End Types for Logging */ + + + export type PrismaAction = + | 'findUnique' + | 'findUniqueOrThrow' + | 'findMany' + | 'findFirst' + | 'findFirstOrThrow' + | 'create' + | 'createMany' + | 'createManyAndReturn' + | 'update' + | 'updateMany' + | 'updateManyAndReturn' + | 'upsert' + | 'delete' + | 'deleteMany' + | 'executeRaw' + | 'queryRaw' + | 'aggregate' + | 'count' + | 'runCommandRaw' + | 'findRaw' + | 'groupBy' + + // tested in getLogLevel.test.ts + export function getLogLevel(log: Array): LogLevel | undefined; + + /** + * `PrismaClient` proxy available in interactive transactions. + */ + export type TransactionClient = Omit + + export type Datasource = { + url?: string + } + + /** + * Count Types + */ + + + /** + * Count Type UserCountOutputType + */ + + export type UserCountOutputType = { + positions: number + watchlist: number + alerts: number + } + + export type UserCountOutputTypeSelect = { + positions?: boolean | UserCountOutputTypeCountPositionsArgs + watchlist?: boolean | UserCountOutputTypeCountWatchlistArgs + alerts?: boolean | UserCountOutputTypeCountAlertsArgs + } + + // Custom InputTypes + /** + * UserCountOutputType without action + */ + export type UserCountOutputTypeDefaultArgs = { + /** + * Select specific fields to fetch from the UserCountOutputType + */ + select?: UserCountOutputTypeSelect | null + } + + /** + * UserCountOutputType without action + */ + export type UserCountOutputTypeCountPositionsArgs = { + where?: PositionWhereInput + } + + /** + * UserCountOutputType without action + */ + export type UserCountOutputTypeCountWatchlistArgs = { + where?: WatchlistWhereInput + } + + /** + * UserCountOutputType without action + */ + export type UserCountOutputTypeCountAlertsArgs = { + where?: AlertWhereInput + } + + + /** + * Count Type MarketCountOutputType + */ + + export type MarketCountOutputType = { + signals: number + positions: number + watchlist: number + alerts: number + } + + export type MarketCountOutputTypeSelect = { + signals?: boolean | MarketCountOutputTypeCountSignalsArgs + positions?: boolean | MarketCountOutputTypeCountPositionsArgs + watchlist?: boolean | MarketCountOutputTypeCountWatchlistArgs + alerts?: boolean | MarketCountOutputTypeCountAlertsArgs + } + + // Custom InputTypes + /** + * MarketCountOutputType without action + */ + export type MarketCountOutputTypeDefaultArgs = { + /** + * Select specific fields to fetch from the MarketCountOutputType + */ + select?: MarketCountOutputTypeSelect | null + } + + /** + * MarketCountOutputType without action + */ + export type MarketCountOutputTypeCountSignalsArgs = { + where?: AISignalWhereInput + } + + /** + * MarketCountOutputType without action + */ + export type MarketCountOutputTypeCountPositionsArgs = { + where?: PositionWhereInput + } + + /** + * MarketCountOutputType without action + */ + export type MarketCountOutputTypeCountWatchlistArgs = { + where?: WatchlistWhereInput + } + + /** + * MarketCountOutputType without action + */ + export type MarketCountOutputTypeCountAlertsArgs = { + where?: AlertWhereInput + } + + + /** + * Models + */ + + /** + * Model User + */ + + export type AggregateUser = { + _count: UserCountAggregateOutputType | null + _avg: UserAvgAggregateOutputType | null + _sum: UserSumAggregateOutputType | null + _min: UserMinAggregateOutputType | null + _max: UserMaxAggregateOutputType | null + } + + export type UserAvgAggregateOutputType = { + id: number | null + } + + export type UserSumAggregateOutputType = { + id: number | null + } + + export type UserMinAggregateOutputType = { + id: number | null + email: string | null + passwordHash: string | null + isActive: boolean | null + telegramChatId: string | null + createdAt: Date | null + updatedAt: Date | null + } + + export type UserMaxAggregateOutputType = { + id: number | null + email: string | null + passwordHash: string | null + isActive: boolean | null + telegramChatId: string | null + createdAt: Date | null + updatedAt: Date | null + } + + export type UserCountAggregateOutputType = { + id: number + email: number + passwordHash: number + isActive: number + telegramChatId: number + createdAt: number + updatedAt: number + _all: number + } + + + export type UserAvgAggregateInputType = { + id?: true + } + + export type UserSumAggregateInputType = { + id?: true + } + + export type UserMinAggregateInputType = { + id?: true + email?: true + passwordHash?: true + isActive?: true + telegramChatId?: true + createdAt?: true + updatedAt?: true + } + + export type UserMaxAggregateInputType = { + id?: true + email?: true + passwordHash?: true + isActive?: true + telegramChatId?: true + createdAt?: true + updatedAt?: true + } + + export type UserCountAggregateInputType = { + id?: true + email?: true + passwordHash?: true + isActive?: true + telegramChatId?: true + createdAt?: true + updatedAt?: true + _all?: true + } + + export type UserAggregateArgs = { + /** + * Filter which User to aggregate. + */ + where?: UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + */ + orderBy?: UserOrderByWithRelationInput | UserOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Users from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Users. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Users + **/ + _count?: true | UserCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: UserAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: UserSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: UserMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: UserMaxAggregateInputType + } + + export type GetUserAggregateType = { + [P in keyof T & keyof AggregateUser]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type UserGroupByArgs = { + where?: UserWhereInput + orderBy?: UserOrderByWithAggregationInput | UserOrderByWithAggregationInput[] + by: UserScalarFieldEnum[] | UserScalarFieldEnum + having?: UserScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: UserCountAggregateInputType | true + _avg?: UserAvgAggregateInputType + _sum?: UserSumAggregateInputType + _min?: UserMinAggregateInputType + _max?: UserMaxAggregateInputType + } + + export type UserGroupByOutputType = { + id: number + email: string + passwordHash: string + isActive: boolean + telegramChatId: string | null + createdAt: Date + updatedAt: Date + _count: UserCountAggregateOutputType | null + _avg: UserAvgAggregateOutputType | null + _sum: UserSumAggregateOutputType | null + _min: UserMinAggregateOutputType | null + _max: UserMaxAggregateOutputType | null + } + + type GetUserGroupByPayload = Prisma.PrismaPromise< + Array< + PickEnumerable & + { + [P in ((keyof T) & (keyof UserGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type UserSelect = $Extensions.GetSelect<{ + id?: boolean + email?: boolean + passwordHash?: boolean + isActive?: boolean + telegramChatId?: boolean + createdAt?: boolean + updatedAt?: boolean + positions?: boolean | User$positionsArgs + watchlist?: boolean | User$watchlistArgs + alerts?: boolean | User$alertsArgs + _count?: boolean | UserCountOutputTypeDefaultArgs + }, ExtArgs["result"]["user"]> + + export type UserSelectCreateManyAndReturn = $Extensions.GetSelect<{ + id?: boolean + email?: boolean + passwordHash?: boolean + isActive?: boolean + telegramChatId?: boolean + createdAt?: boolean + updatedAt?: boolean + }, ExtArgs["result"]["user"]> + + export type UserSelectUpdateManyAndReturn = $Extensions.GetSelect<{ + id?: boolean + email?: boolean + passwordHash?: boolean + isActive?: boolean + telegramChatId?: boolean + createdAt?: boolean + updatedAt?: boolean + }, ExtArgs["result"]["user"]> + + export type UserSelectScalar = { + id?: boolean + email?: boolean + passwordHash?: boolean + isActive?: boolean + telegramChatId?: boolean + createdAt?: boolean + updatedAt?: boolean + } + + export type UserOmit = $Extensions.GetOmit<"id" | "email" | "passwordHash" | "isActive" | "telegramChatId" | "createdAt" | "updatedAt", ExtArgs["result"]["user"]> + export type UserInclude = { + positions?: boolean | User$positionsArgs + watchlist?: boolean | User$watchlistArgs + alerts?: boolean | User$alertsArgs + _count?: boolean | UserCountOutputTypeDefaultArgs + } + export type UserIncludeCreateManyAndReturn = {} + export type UserIncludeUpdateManyAndReturn = {} + + export type $UserPayload = { + name: "User" + objects: { + positions: Prisma.$PositionPayload[] + watchlist: Prisma.$WatchlistPayload[] + alerts: Prisma.$AlertPayload[] + } + scalars: $Extensions.GetPayloadResult<{ + id: number + email: string + passwordHash: string + isActive: boolean + telegramChatId: string | null + createdAt: Date + updatedAt: Date + }, ExtArgs["result"]["user"]> + composites: {} + } + + type UserGetPayload = $Result.GetResult + + type UserCountArgs = + Omit & { + select?: UserCountAggregateInputType | true + } + + export interface UserDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['User'], meta: { name: 'User' } } + /** + * Find zero or one User that matches the filter. + * @param {UserFindUniqueArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: SelectSubset>): Prisma__UserClient<$Result.GetResult, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one User that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {UserFindUniqueOrThrowArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: SelectSubset>): Prisma__UserClient<$Result.GetResult, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first User that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserFindFirstArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: SelectSubset>): Prisma__UserClient<$Result.GetResult, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first User that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserFindFirstOrThrowArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: SelectSubset>): Prisma__UserClient<$Result.GetResult, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more Users that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all Users + * const users = await prisma.user.findMany() + * + * // Get first 10 Users + * const users = await prisma.user.findMany({ take: 10 }) + * + * // Only select the `id` + * const userWithIdOnly = await prisma.user.findMany({ select: { id: true } }) + * + */ + findMany(args?: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "findMany", GlobalOmitOptions>> + + /** + * Create a User. + * @param {UserCreateArgs} args - Arguments to create a User. + * @example + * // Create one User + * const User = await prisma.user.create({ + * data: { + * // ... data to create a User + * } + * }) + * + */ + create(args: SelectSubset>): Prisma__UserClient<$Result.GetResult, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many Users. + * @param {UserCreateManyArgs} args - Arguments to create many Users. + * @example + * // Create many Users + * const user = await prisma.user.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: SelectSubset>): Prisma.PrismaPromise + + /** + * Create many Users and returns the data saved in the database. + * @param {UserCreateManyAndReturnArgs} args - Arguments to create many Users. + * @example + * // Create many Users + * const user = await prisma.user.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many Users and only return the `id` + * const userWithIdOnly = await prisma.user.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a User. + * @param {UserDeleteArgs} args - Arguments to delete one User. + * @example + * // Delete one User + * const User = await prisma.user.delete({ + * where: { + * // ... filter to delete one User + * } + * }) + * + */ + delete(args: SelectSubset>): Prisma__UserClient<$Result.GetResult, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one User. + * @param {UserUpdateArgs} args - Arguments to update one User. + * @example + * // Update one User + * const user = await prisma.user.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: SelectSubset>): Prisma__UserClient<$Result.GetResult, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more Users. + * @param {UserDeleteManyArgs} args - Arguments to filter Users to delete. + * @example + * // Delete a few Users + * const { count } = await prisma.user.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Users. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Users + * const user = await prisma.user.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Users and returns the data updated in the database. + * @param {UserUpdateManyAndReturnArgs} args - Arguments to update many Users. + * @example + * // Update many Users + * const user = await prisma.user.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more Users and only return the `id` + * const userWithIdOnly = await prisma.user.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one User. + * @param {UserUpsertArgs} args - Arguments to update or create a User. + * @example + * // Update or create a User + * const user = await prisma.user.upsert({ + * create: { + * // ... data to create a User + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the User we want to update + * } + * }) + */ + upsert(args: SelectSubset>): Prisma__UserClient<$Result.GetResult, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of Users. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserCountArgs} args - Arguments to filter Users to count. + * @example + * // Count the number of Users + * const count = await prisma.user.count({ + * where: { + * // ... the filter for the Users we want to count + * } + * }) + **/ + count( + args?: Subset, + ): Prisma.PrismaPromise< + T extends $Utils.Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a User. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): Prisma.PrismaPromise> + + /** + * Group by User. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends UserGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: UserGroupByArgs['orderBy'] } + : { orderBy?: UserGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends MaybeTupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? `Error: "by" must not be empty.` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetUserGroupByPayload : Prisma.PrismaPromise + /** + * Fields of the User model + */ + readonly fields: UserFieldRefs; + } + + /** + * The delegate class that acts as a "Promise-like" for User. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export interface Prisma__UserClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + positions = {}>(args?: Subset>): Prisma.PrismaPromise<$Result.GetResult, T, "findMany", GlobalOmitOptions> | Null> + watchlist = {}>(args?: Subset>): Prisma.PrismaPromise<$Result.GetResult, T, "findMany", GlobalOmitOptions> | Null> + alerts = {}>(args?: Subset>): Prisma.PrismaPromise<$Result.GetResult, T, "findMany", GlobalOmitOptions> | Null> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): $Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): $Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): $Utils.JsPromise + } + + + + + /** + * Fields of the User model + */ + interface UserFieldRefs { + readonly id: FieldRef<"User", 'Int'> + readonly email: FieldRef<"User", 'String'> + readonly passwordHash: FieldRef<"User", 'String'> + readonly isActive: FieldRef<"User", 'Boolean'> + readonly telegramChatId: FieldRef<"User", 'String'> + readonly createdAt: FieldRef<"User", 'DateTime'> + readonly updatedAt: FieldRef<"User", 'DateTime'> + } + + + // Custom InputTypes + /** + * User findUnique + */ + export type UserFindUniqueArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: UserInclude | null + /** + * Filter, which User to fetch. + */ + where: UserWhereUniqueInput + } + + /** + * User findUniqueOrThrow + */ + export type UserFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: UserInclude | null + /** + * Filter, which User to fetch. + */ + where: UserWhereUniqueInput + } + + /** + * User findFirst + */ + export type UserFindFirstArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: UserInclude | null + /** + * Filter, which User to fetch. + */ + where?: UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + */ + orderBy?: UserOrderByWithRelationInput | UserOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Users. + */ + cursor?: UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Users from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Users. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Users. + */ + distinct?: UserScalarFieldEnum | UserScalarFieldEnum[] + } + + /** + * User findFirstOrThrow + */ + export type UserFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: UserInclude | null + /** + * Filter, which User to fetch. + */ + where?: UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + */ + orderBy?: UserOrderByWithRelationInput | UserOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Users. + */ + cursor?: UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Users from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Users. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Users. + */ + distinct?: UserScalarFieldEnum | UserScalarFieldEnum[] + } + + /** + * User findMany + */ + export type UserFindManyArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: UserInclude | null + /** + * Filter, which Users to fetch. + */ + where?: UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + */ + orderBy?: UserOrderByWithRelationInput | UserOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Users. + */ + cursor?: UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Users from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Users. + */ + skip?: number + distinct?: UserScalarFieldEnum | UserScalarFieldEnum[] + } + + /** + * User create + */ + export type UserCreateArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: UserInclude | null + /** + * The data needed to create a User. + */ + data: XOR + } + + /** + * User createMany + */ + export type UserCreateManyArgs = { + /** + * The data used to create many Users. + */ + data: UserCreateManyInput | UserCreateManyInput[] + } + + /** + * User createManyAndReturn + */ + export type UserCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: UserSelectCreateManyAndReturn | null + /** + * Omit specific fields from the User + */ + omit?: UserOmit | null + /** + * The data used to create many Users. + */ + data: UserCreateManyInput | UserCreateManyInput[] + } + + /** + * User update + */ + export type UserUpdateArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: UserInclude | null + /** + * The data needed to update a User. + */ + data: XOR + /** + * Choose, which User to update. + */ + where: UserWhereUniqueInput + } + + /** + * User updateMany + */ + export type UserUpdateManyArgs = { + /** + * The data used to update Users. + */ + data: XOR + /** + * Filter which Users to update + */ + where?: UserWhereInput + /** + * Limit how many Users to update. + */ + limit?: number + } + + /** + * User updateManyAndReturn + */ + export type UserUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: UserSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the User + */ + omit?: UserOmit | null + /** + * The data used to update Users. + */ + data: XOR + /** + * Filter which Users to update + */ + where?: UserWhereInput + /** + * Limit how many Users to update. + */ + limit?: number + } + + /** + * User upsert + */ + export type UserUpsertArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: UserInclude | null + /** + * The filter to search for the User to update in case it exists. + */ + where: UserWhereUniqueInput + /** + * In case the User found by the `where` argument doesn't exist, create a new User with this data. + */ + create: XOR + /** + * In case the User was found with the provided `where` argument, update it with this data. + */ + update: XOR + } + + /** + * User delete + */ + export type UserDeleteArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: UserInclude | null + /** + * Filter which User to delete. + */ + where: UserWhereUniqueInput + } + + /** + * User deleteMany + */ + export type UserDeleteManyArgs = { + /** + * Filter which Users to delete + */ + where?: UserWhereInput + /** + * Limit how many Users to delete. + */ + limit?: number + } + + /** + * User.positions + */ + export type User$positionsArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelect | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionInclude | null + where?: PositionWhereInput + orderBy?: PositionOrderByWithRelationInput | PositionOrderByWithRelationInput[] + cursor?: PositionWhereUniqueInput + take?: number + skip?: number + distinct?: PositionScalarFieldEnum | PositionScalarFieldEnum[] + } + + /** + * User.watchlist + */ + export type User$watchlistArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelect | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistInclude | null + where?: WatchlistWhereInput + orderBy?: WatchlistOrderByWithRelationInput | WatchlistOrderByWithRelationInput[] + cursor?: WatchlistWhereUniqueInput + take?: number + skip?: number + distinct?: WatchlistScalarFieldEnum | WatchlistScalarFieldEnum[] + } + + /** + * User.alerts + */ + export type User$alertsArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelect | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertInclude | null + where?: AlertWhereInput + orderBy?: AlertOrderByWithRelationInput | AlertOrderByWithRelationInput[] + cursor?: AlertWhereUniqueInput + take?: number + skip?: number + distinct?: AlertScalarFieldEnum | AlertScalarFieldEnum[] + } + + /** + * User without action + */ + export type UserDefaultArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: UserInclude | null + } + + + /** + * Model Market + */ + + export type AggregateMarket = { + _count: MarketCountAggregateOutputType | null + _avg: MarketAvgAggregateOutputType | null + _sum: MarketSumAggregateOutputType | null + _min: MarketMinAggregateOutputType | null + _max: MarketMaxAggregateOutputType | null + } + + export type MarketAvgAggregateOutputType = { + yesPrice: number | null + noPrice: number | null + volumeEur: number | null + liquidityEur: number | null + spread: number | null + bestBid: number | null + bestAsk: number | null + } + + export type MarketSumAggregateOutputType = { + yesPrice: number | null + noPrice: number | null + volumeEur: number | null + liquidityEur: number | null + spread: number | null + bestBid: number | null + bestAsk: number | null + } + + export type MarketMinAggregateOutputType = { + id: string | null + question: string | null + category: string | null + countryCode: string | null + yesPrice: number | null + noPrice: number | null + volumeEur: number | null + liquidityEur: number | null + spread: number | null + bestBid: number | null + bestAsk: number | null + clobTokenId: string | null + analyzable: boolean | null + status: string | null + closesAt: Date | null + lastSynced: Date | null + } + + export type MarketMaxAggregateOutputType = { + id: string | null + question: string | null + category: string | null + countryCode: string | null + yesPrice: number | null + noPrice: number | null + volumeEur: number | null + liquidityEur: number | null + spread: number | null + bestBid: number | null + bestAsk: number | null + clobTokenId: string | null + analyzable: boolean | null + status: string | null + closesAt: Date | null + lastSynced: Date | null + } + + export type MarketCountAggregateOutputType = { + id: number + question: number + category: number + countryCode: number + yesPrice: number + noPrice: number + volumeEur: number + liquidityEur: number + spread: number + bestBid: number + bestAsk: number + clobTokenId: number + analyzable: number + status: number + closesAt: number + lastSynced: number + _all: number + } + + + export type MarketAvgAggregateInputType = { + yesPrice?: true + noPrice?: true + volumeEur?: true + liquidityEur?: true + spread?: true + bestBid?: true + bestAsk?: true + } + + export type MarketSumAggregateInputType = { + yesPrice?: true + noPrice?: true + volumeEur?: true + liquidityEur?: true + spread?: true + bestBid?: true + bestAsk?: true + } + + export type MarketMinAggregateInputType = { + id?: true + question?: true + category?: true + countryCode?: true + yesPrice?: true + noPrice?: true + volumeEur?: true + liquidityEur?: true + spread?: true + bestBid?: true + bestAsk?: true + clobTokenId?: true + analyzable?: true + status?: true + closesAt?: true + lastSynced?: true + } + + export type MarketMaxAggregateInputType = { + id?: true + question?: true + category?: true + countryCode?: true + yesPrice?: true + noPrice?: true + volumeEur?: true + liquidityEur?: true + spread?: true + bestBid?: true + bestAsk?: true + clobTokenId?: true + analyzable?: true + status?: true + closesAt?: true + lastSynced?: true + } + + export type MarketCountAggregateInputType = { + id?: true + question?: true + category?: true + countryCode?: true + yesPrice?: true + noPrice?: true + volumeEur?: true + liquidityEur?: true + spread?: true + bestBid?: true + bestAsk?: true + clobTokenId?: true + analyzable?: true + status?: true + closesAt?: true + lastSynced?: true + _all?: true + } + + export type MarketAggregateArgs = { + /** + * Filter which Market to aggregate. + */ + where?: MarketWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Markets to fetch. + */ + orderBy?: MarketOrderByWithRelationInput | MarketOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: MarketWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Markets from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Markets. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Markets + **/ + _count?: true | MarketCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: MarketAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: MarketSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: MarketMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: MarketMaxAggregateInputType + } + + export type GetMarketAggregateType = { + [P in keyof T & keyof AggregateMarket]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type MarketGroupByArgs = { + where?: MarketWhereInput + orderBy?: MarketOrderByWithAggregationInput | MarketOrderByWithAggregationInput[] + by: MarketScalarFieldEnum[] | MarketScalarFieldEnum + having?: MarketScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: MarketCountAggregateInputType | true + _avg?: MarketAvgAggregateInputType + _sum?: MarketSumAggregateInputType + _min?: MarketMinAggregateInputType + _max?: MarketMaxAggregateInputType + } + + export type MarketGroupByOutputType = { + id: string + question: string + category: string | null + countryCode: string | null + yesPrice: number | null + noPrice: number | null + volumeEur: number | null + liquidityEur: number | null + spread: number | null + bestBid: number | null + bestAsk: number | null + clobTokenId: string | null + analyzable: boolean + status: string + closesAt: Date | null + lastSynced: Date + _count: MarketCountAggregateOutputType | null + _avg: MarketAvgAggregateOutputType | null + _sum: MarketSumAggregateOutputType | null + _min: MarketMinAggregateOutputType | null + _max: MarketMaxAggregateOutputType | null + } + + type GetMarketGroupByPayload = Prisma.PrismaPromise< + Array< + PickEnumerable & + { + [P in ((keyof T) & (keyof MarketGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type MarketSelect = $Extensions.GetSelect<{ + id?: boolean + question?: boolean + category?: boolean + countryCode?: boolean + yesPrice?: boolean + noPrice?: boolean + volumeEur?: boolean + liquidityEur?: boolean + spread?: boolean + bestBid?: boolean + bestAsk?: boolean + clobTokenId?: boolean + analyzable?: boolean + status?: boolean + closesAt?: boolean + lastSynced?: boolean + signals?: boolean | Market$signalsArgs + positions?: boolean | Market$positionsArgs + watchlist?: boolean | Market$watchlistArgs + alerts?: boolean | Market$alertsArgs + _count?: boolean | MarketCountOutputTypeDefaultArgs + }, ExtArgs["result"]["market"]> + + export type MarketSelectCreateManyAndReturn = $Extensions.GetSelect<{ + id?: boolean + question?: boolean + category?: boolean + countryCode?: boolean + yesPrice?: boolean + noPrice?: boolean + volumeEur?: boolean + liquidityEur?: boolean + spread?: boolean + bestBid?: boolean + bestAsk?: boolean + clobTokenId?: boolean + analyzable?: boolean + status?: boolean + closesAt?: boolean + lastSynced?: boolean + }, ExtArgs["result"]["market"]> + + export type MarketSelectUpdateManyAndReturn = $Extensions.GetSelect<{ + id?: boolean + question?: boolean + category?: boolean + countryCode?: boolean + yesPrice?: boolean + noPrice?: boolean + volumeEur?: boolean + liquidityEur?: boolean + spread?: boolean + bestBid?: boolean + bestAsk?: boolean + clobTokenId?: boolean + analyzable?: boolean + status?: boolean + closesAt?: boolean + lastSynced?: boolean + }, ExtArgs["result"]["market"]> + + export type MarketSelectScalar = { + id?: boolean + question?: boolean + category?: boolean + countryCode?: boolean + yesPrice?: boolean + noPrice?: boolean + volumeEur?: boolean + liquidityEur?: boolean + spread?: boolean + bestBid?: boolean + bestAsk?: boolean + clobTokenId?: boolean + analyzable?: boolean + status?: boolean + closesAt?: boolean + lastSynced?: boolean + } + + export type MarketOmit = $Extensions.GetOmit<"id" | "question" | "category" | "countryCode" | "yesPrice" | "noPrice" | "volumeEur" | "liquidityEur" | "spread" | "bestBid" | "bestAsk" | "clobTokenId" | "analyzable" | "status" | "closesAt" | "lastSynced", ExtArgs["result"]["market"]> + export type MarketInclude = { + signals?: boolean | Market$signalsArgs + positions?: boolean | Market$positionsArgs + watchlist?: boolean | Market$watchlistArgs + alerts?: boolean | Market$alertsArgs + _count?: boolean | MarketCountOutputTypeDefaultArgs + } + export type MarketIncludeCreateManyAndReturn = {} + export type MarketIncludeUpdateManyAndReturn = {} + + export type $MarketPayload = { + name: "Market" + objects: { + signals: Prisma.$AISignalPayload[] + positions: Prisma.$PositionPayload[] + watchlist: Prisma.$WatchlistPayload[] + alerts: Prisma.$AlertPayload[] + } + scalars: $Extensions.GetPayloadResult<{ + id: string + question: string + category: string | null + countryCode: string | null + yesPrice: number | null + noPrice: number | null + volumeEur: number | null + liquidityEur: number | null + spread: number | null + bestBid: number | null + bestAsk: number | null + clobTokenId: string | null + analyzable: boolean + status: string + closesAt: Date | null + lastSynced: Date + }, ExtArgs["result"]["market"]> + composites: {} + } + + type MarketGetPayload = $Result.GetResult + + type MarketCountArgs = + Omit & { + select?: MarketCountAggregateInputType | true + } + + export interface MarketDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['Market'], meta: { name: 'Market' } } + /** + * Find zero or one Market that matches the filter. + * @param {MarketFindUniqueArgs} args - Arguments to find a Market + * @example + * // Get one Market + * const market = await prisma.market.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: SelectSubset>): Prisma__MarketClient<$Result.GetResult, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one Market that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {MarketFindUniqueOrThrowArgs} args - Arguments to find a Market + * @example + * // Get one Market + * const market = await prisma.market.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: SelectSubset>): Prisma__MarketClient<$Result.GetResult, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Market that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MarketFindFirstArgs} args - Arguments to find a Market + * @example + * // Get one Market + * const market = await prisma.market.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: SelectSubset>): Prisma__MarketClient<$Result.GetResult, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Market that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MarketFindFirstOrThrowArgs} args - Arguments to find a Market + * @example + * // Get one Market + * const market = await prisma.market.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: SelectSubset>): Prisma__MarketClient<$Result.GetResult, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more Markets that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MarketFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all Markets + * const markets = await prisma.market.findMany() + * + * // Get first 10 Markets + * const markets = await prisma.market.findMany({ take: 10 }) + * + * // Only select the `id` + * const marketWithIdOnly = await prisma.market.findMany({ select: { id: true } }) + * + */ + findMany(args?: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "findMany", GlobalOmitOptions>> + + /** + * Create a Market. + * @param {MarketCreateArgs} args - Arguments to create a Market. + * @example + * // Create one Market + * const Market = await prisma.market.create({ + * data: { + * // ... data to create a Market + * } + * }) + * + */ + create(args: SelectSubset>): Prisma__MarketClient<$Result.GetResult, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many Markets. + * @param {MarketCreateManyArgs} args - Arguments to create many Markets. + * @example + * // Create many Markets + * const market = await prisma.market.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: SelectSubset>): Prisma.PrismaPromise + + /** + * Create many Markets and returns the data saved in the database. + * @param {MarketCreateManyAndReturnArgs} args - Arguments to create many Markets. + * @example + * // Create many Markets + * const market = await prisma.market.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many Markets and only return the `id` + * const marketWithIdOnly = await prisma.market.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a Market. + * @param {MarketDeleteArgs} args - Arguments to delete one Market. + * @example + * // Delete one Market + * const Market = await prisma.market.delete({ + * where: { + * // ... filter to delete one Market + * } + * }) + * + */ + delete(args: SelectSubset>): Prisma__MarketClient<$Result.GetResult, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one Market. + * @param {MarketUpdateArgs} args - Arguments to update one Market. + * @example + * // Update one Market + * const market = await prisma.market.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: SelectSubset>): Prisma__MarketClient<$Result.GetResult, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more Markets. + * @param {MarketDeleteManyArgs} args - Arguments to filter Markets to delete. + * @example + * // Delete a few Markets + * const { count } = await prisma.market.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Markets. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MarketUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Markets + * const market = await prisma.market.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Markets and returns the data updated in the database. + * @param {MarketUpdateManyAndReturnArgs} args - Arguments to update many Markets. + * @example + * // Update many Markets + * const market = await prisma.market.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more Markets and only return the `id` + * const marketWithIdOnly = await prisma.market.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one Market. + * @param {MarketUpsertArgs} args - Arguments to update or create a Market. + * @example + * // Update or create a Market + * const market = await prisma.market.upsert({ + * create: { + * // ... data to create a Market + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the Market we want to update + * } + * }) + */ + upsert(args: SelectSubset>): Prisma__MarketClient<$Result.GetResult, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of Markets. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MarketCountArgs} args - Arguments to filter Markets to count. + * @example + * // Count the number of Markets + * const count = await prisma.market.count({ + * where: { + * // ... the filter for the Markets we want to count + * } + * }) + **/ + count( + args?: Subset, + ): Prisma.PrismaPromise< + T extends $Utils.Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a Market. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MarketAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): Prisma.PrismaPromise> + + /** + * Group by Market. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {MarketGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends MarketGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: MarketGroupByArgs['orderBy'] } + : { orderBy?: MarketGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends MaybeTupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? `Error: "by" must not be empty.` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetMarketGroupByPayload : Prisma.PrismaPromise + /** + * Fields of the Market model + */ + readonly fields: MarketFieldRefs; + } + + /** + * The delegate class that acts as a "Promise-like" for Market. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export interface Prisma__MarketClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + signals = {}>(args?: Subset>): Prisma.PrismaPromise<$Result.GetResult, T, "findMany", GlobalOmitOptions> | Null> + positions = {}>(args?: Subset>): Prisma.PrismaPromise<$Result.GetResult, T, "findMany", GlobalOmitOptions> | Null> + watchlist = {}>(args?: Subset>): Prisma.PrismaPromise<$Result.GetResult, T, "findMany", GlobalOmitOptions> | Null> + alerts = {}>(args?: Subset>): Prisma.PrismaPromise<$Result.GetResult, T, "findMany", GlobalOmitOptions> | Null> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): $Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): $Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): $Utils.JsPromise + } + + + + + /** + * Fields of the Market model + */ + interface MarketFieldRefs { + readonly id: FieldRef<"Market", 'String'> + readonly question: FieldRef<"Market", 'String'> + readonly category: FieldRef<"Market", 'String'> + readonly countryCode: FieldRef<"Market", 'String'> + readonly yesPrice: FieldRef<"Market", 'Float'> + readonly noPrice: FieldRef<"Market", 'Float'> + readonly volumeEur: FieldRef<"Market", 'Float'> + readonly liquidityEur: FieldRef<"Market", 'Float'> + readonly spread: FieldRef<"Market", 'Float'> + readonly bestBid: FieldRef<"Market", 'Float'> + readonly bestAsk: FieldRef<"Market", 'Float'> + readonly clobTokenId: FieldRef<"Market", 'String'> + readonly analyzable: FieldRef<"Market", 'Boolean'> + readonly status: FieldRef<"Market", 'String'> + readonly closesAt: FieldRef<"Market", 'DateTime'> + readonly lastSynced: FieldRef<"Market", 'DateTime'> + } + + + // Custom InputTypes + /** + * Market findUnique + */ + export type MarketFindUniqueArgs = { + /** + * Select specific fields to fetch from the Market + */ + select?: MarketSelect | null + /** + * Omit specific fields from the Market + */ + omit?: MarketOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: MarketInclude | null + /** + * Filter, which Market to fetch. + */ + where: MarketWhereUniqueInput + } + + /** + * Market findUniqueOrThrow + */ + export type MarketFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the Market + */ + select?: MarketSelect | null + /** + * Omit specific fields from the Market + */ + omit?: MarketOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: MarketInclude | null + /** + * Filter, which Market to fetch. + */ + where: MarketWhereUniqueInput + } + + /** + * Market findFirst + */ + export type MarketFindFirstArgs = { + /** + * Select specific fields to fetch from the Market + */ + select?: MarketSelect | null + /** + * Omit specific fields from the Market + */ + omit?: MarketOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: MarketInclude | null + /** + * Filter, which Market to fetch. + */ + where?: MarketWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Markets to fetch. + */ + orderBy?: MarketOrderByWithRelationInput | MarketOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Markets. + */ + cursor?: MarketWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Markets from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Markets. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Markets. + */ + distinct?: MarketScalarFieldEnum | MarketScalarFieldEnum[] + } + + /** + * Market findFirstOrThrow + */ + export type MarketFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the Market + */ + select?: MarketSelect | null + /** + * Omit specific fields from the Market + */ + omit?: MarketOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: MarketInclude | null + /** + * Filter, which Market to fetch. + */ + where?: MarketWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Markets to fetch. + */ + orderBy?: MarketOrderByWithRelationInput | MarketOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Markets. + */ + cursor?: MarketWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Markets from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Markets. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Markets. + */ + distinct?: MarketScalarFieldEnum | MarketScalarFieldEnum[] + } + + /** + * Market findMany + */ + export type MarketFindManyArgs = { + /** + * Select specific fields to fetch from the Market + */ + select?: MarketSelect | null + /** + * Omit specific fields from the Market + */ + omit?: MarketOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: MarketInclude | null + /** + * Filter, which Markets to fetch. + */ + where?: MarketWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Markets to fetch. + */ + orderBy?: MarketOrderByWithRelationInput | MarketOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Markets. + */ + cursor?: MarketWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Markets from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Markets. + */ + skip?: number + distinct?: MarketScalarFieldEnum | MarketScalarFieldEnum[] + } + + /** + * Market create + */ + export type MarketCreateArgs = { + /** + * Select specific fields to fetch from the Market + */ + select?: MarketSelect | null + /** + * Omit specific fields from the Market + */ + omit?: MarketOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: MarketInclude | null + /** + * The data needed to create a Market. + */ + data: XOR + } + + /** + * Market createMany + */ + export type MarketCreateManyArgs = { + /** + * The data used to create many Markets. + */ + data: MarketCreateManyInput | MarketCreateManyInput[] + } + + /** + * Market createManyAndReturn + */ + export type MarketCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Market + */ + select?: MarketSelectCreateManyAndReturn | null + /** + * Omit specific fields from the Market + */ + omit?: MarketOmit | null + /** + * The data used to create many Markets. + */ + data: MarketCreateManyInput | MarketCreateManyInput[] + } + + /** + * Market update + */ + export type MarketUpdateArgs = { + /** + * Select specific fields to fetch from the Market + */ + select?: MarketSelect | null + /** + * Omit specific fields from the Market + */ + omit?: MarketOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: MarketInclude | null + /** + * The data needed to update a Market. + */ + data: XOR + /** + * Choose, which Market to update. + */ + where: MarketWhereUniqueInput + } + + /** + * Market updateMany + */ + export type MarketUpdateManyArgs = { + /** + * The data used to update Markets. + */ + data: XOR + /** + * Filter which Markets to update + */ + where?: MarketWhereInput + /** + * Limit how many Markets to update. + */ + limit?: number + } + + /** + * Market updateManyAndReturn + */ + export type MarketUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Market + */ + select?: MarketSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the Market + */ + omit?: MarketOmit | null + /** + * The data used to update Markets. + */ + data: XOR + /** + * Filter which Markets to update + */ + where?: MarketWhereInput + /** + * Limit how many Markets to update. + */ + limit?: number + } + + /** + * Market upsert + */ + export type MarketUpsertArgs = { + /** + * Select specific fields to fetch from the Market + */ + select?: MarketSelect | null + /** + * Omit specific fields from the Market + */ + omit?: MarketOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: MarketInclude | null + /** + * The filter to search for the Market to update in case it exists. + */ + where: MarketWhereUniqueInput + /** + * In case the Market found by the `where` argument doesn't exist, create a new Market with this data. + */ + create: XOR + /** + * In case the Market was found with the provided `where` argument, update it with this data. + */ + update: XOR + } + + /** + * Market delete + */ + export type MarketDeleteArgs = { + /** + * Select specific fields to fetch from the Market + */ + select?: MarketSelect | null + /** + * Omit specific fields from the Market + */ + omit?: MarketOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: MarketInclude | null + /** + * Filter which Market to delete. + */ + where: MarketWhereUniqueInput + } + + /** + * Market deleteMany + */ + export type MarketDeleteManyArgs = { + /** + * Filter which Markets to delete + */ + where?: MarketWhereInput + /** + * Limit how many Markets to delete. + */ + limit?: number + } + + /** + * Market.signals + */ + export type Market$signalsArgs = { + /** + * Select specific fields to fetch from the AISignal + */ + select?: AISignalSelect | null + /** + * Omit specific fields from the AISignal + */ + omit?: AISignalOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AISignalInclude | null + where?: AISignalWhereInput + orderBy?: AISignalOrderByWithRelationInput | AISignalOrderByWithRelationInput[] + cursor?: AISignalWhereUniqueInput + take?: number + skip?: number + distinct?: AISignalScalarFieldEnum | AISignalScalarFieldEnum[] + } + + /** + * Market.positions + */ + export type Market$positionsArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelect | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionInclude | null + where?: PositionWhereInput + orderBy?: PositionOrderByWithRelationInput | PositionOrderByWithRelationInput[] + cursor?: PositionWhereUniqueInput + take?: number + skip?: number + distinct?: PositionScalarFieldEnum | PositionScalarFieldEnum[] + } + + /** + * Market.watchlist + */ + export type Market$watchlistArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelect | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistInclude | null + where?: WatchlistWhereInput + orderBy?: WatchlistOrderByWithRelationInput | WatchlistOrderByWithRelationInput[] + cursor?: WatchlistWhereUniqueInput + take?: number + skip?: number + distinct?: WatchlistScalarFieldEnum | WatchlistScalarFieldEnum[] + } + + /** + * Market.alerts + */ + export type Market$alertsArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelect | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertInclude | null + where?: AlertWhereInput + orderBy?: AlertOrderByWithRelationInput | AlertOrderByWithRelationInput[] + cursor?: AlertWhereUniqueInput + take?: number + skip?: number + distinct?: AlertScalarFieldEnum | AlertScalarFieldEnum[] + } + + /** + * Market without action + */ + export type MarketDefaultArgs = { + /** + * Select specific fields to fetch from the Market + */ + select?: MarketSelect | null + /** + * Omit specific fields from the Market + */ + omit?: MarketOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: MarketInclude | null + } + + + /** + * Model AISignal + */ + + export type AggregateAISignal = { + _count: AISignalCountAggregateOutputType | null + _avg: AISignalAvgAggregateOutputType | null + _sum: AISignalSumAggregateOutputType | null + _min: AISignalMinAggregateOutputType | null + _max: AISignalMaxAggregateOutputType | null + } + + export type AISignalAvgAggregateOutputType = { + id: number | null + confidence: number | null + newsCount: number | null + impliedProb: number | null + fairProb: number | null + edgePoints: number | null + } + + export type AISignalSumAggregateOutputType = { + id: number | null + confidence: number | null + newsCount: number | null + impliedProb: number | null + fairProb: number | null + edgePoints: number | null + } + + export type AISignalMinAggregateOutputType = { + id: number | null + marketId: string | null + signal: string | null + confidence: number | null + summary: string | null + keyRisk: string | null + newsCount: number | null + modelVersion: string | null + impliedProb: number | null + fairProb: number | null + edgePoints: number | null + generatedAt: Date | null + } + + export type AISignalMaxAggregateOutputType = { + id: number | null + marketId: string | null + signal: string | null + confidence: number | null + summary: string | null + keyRisk: string | null + newsCount: number | null + modelVersion: string | null + impliedProb: number | null + fairProb: number | null + edgePoints: number | null + generatedAt: Date | null + } + + export type AISignalCountAggregateOutputType = { + id: number + marketId: number + signal: number + confidence: number + summary: number + keyRisk: number + newsCount: number + modelVersion: number + impliedProb: number + fairProb: number + edgePoints: number + generatedAt: number + _all: number + } + + + export type AISignalAvgAggregateInputType = { + id?: true + confidence?: true + newsCount?: true + impliedProb?: true + fairProb?: true + edgePoints?: true + } + + export type AISignalSumAggregateInputType = { + id?: true + confidence?: true + newsCount?: true + impliedProb?: true + fairProb?: true + edgePoints?: true + } + + export type AISignalMinAggregateInputType = { + id?: true + marketId?: true + signal?: true + confidence?: true + summary?: true + keyRisk?: true + newsCount?: true + modelVersion?: true + impliedProb?: true + fairProb?: true + edgePoints?: true + generatedAt?: true + } + + export type AISignalMaxAggregateInputType = { + id?: true + marketId?: true + signal?: true + confidence?: true + summary?: true + keyRisk?: true + newsCount?: true + modelVersion?: true + impliedProb?: true + fairProb?: true + edgePoints?: true + generatedAt?: true + } + + export type AISignalCountAggregateInputType = { + id?: true + marketId?: true + signal?: true + confidence?: true + summary?: true + keyRisk?: true + newsCount?: true + modelVersion?: true + impliedProb?: true + fairProb?: true + edgePoints?: true + generatedAt?: true + _all?: true + } + + export type AISignalAggregateArgs = { + /** + * Filter which AISignal to aggregate. + */ + where?: AISignalWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AISignals to fetch. + */ + orderBy?: AISignalOrderByWithRelationInput | AISignalOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: AISignalWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AISignals from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AISignals. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned AISignals + **/ + _count?: true | AISignalCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: AISignalAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: AISignalSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: AISignalMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: AISignalMaxAggregateInputType + } + + export type GetAISignalAggregateType = { + [P in keyof T & keyof AggregateAISignal]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type AISignalGroupByArgs = { + where?: AISignalWhereInput + orderBy?: AISignalOrderByWithAggregationInput | AISignalOrderByWithAggregationInput[] + by: AISignalScalarFieldEnum[] | AISignalScalarFieldEnum + having?: AISignalScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: AISignalCountAggregateInputType | true + _avg?: AISignalAvgAggregateInputType + _sum?: AISignalSumAggregateInputType + _min?: AISignalMinAggregateInputType + _max?: AISignalMaxAggregateInputType + } + + export type AISignalGroupByOutputType = { + id: number + marketId: string + signal: string + confidence: number + summary: string | null + keyRisk: string | null + newsCount: number + modelVersion: string + impliedProb: number | null + fairProb: number | null + edgePoints: number | null + generatedAt: Date + _count: AISignalCountAggregateOutputType | null + _avg: AISignalAvgAggregateOutputType | null + _sum: AISignalSumAggregateOutputType | null + _min: AISignalMinAggregateOutputType | null + _max: AISignalMaxAggregateOutputType | null + } + + type GetAISignalGroupByPayload = Prisma.PrismaPromise< + Array< + PickEnumerable & + { + [P in ((keyof T) & (keyof AISignalGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type AISignalSelect = $Extensions.GetSelect<{ + id?: boolean + marketId?: boolean + signal?: boolean + confidence?: boolean + summary?: boolean + keyRisk?: boolean + newsCount?: boolean + modelVersion?: boolean + impliedProb?: boolean + fairProb?: boolean + edgePoints?: boolean + generatedAt?: boolean + market?: boolean | MarketDefaultArgs + }, ExtArgs["result"]["aISignal"]> + + export type AISignalSelectCreateManyAndReturn = $Extensions.GetSelect<{ + id?: boolean + marketId?: boolean + signal?: boolean + confidence?: boolean + summary?: boolean + keyRisk?: boolean + newsCount?: boolean + modelVersion?: boolean + impliedProb?: boolean + fairProb?: boolean + edgePoints?: boolean + generatedAt?: boolean + market?: boolean | MarketDefaultArgs + }, ExtArgs["result"]["aISignal"]> + + export type AISignalSelectUpdateManyAndReturn = $Extensions.GetSelect<{ + id?: boolean + marketId?: boolean + signal?: boolean + confidence?: boolean + summary?: boolean + keyRisk?: boolean + newsCount?: boolean + modelVersion?: boolean + impliedProb?: boolean + fairProb?: boolean + edgePoints?: boolean + generatedAt?: boolean + market?: boolean | MarketDefaultArgs + }, ExtArgs["result"]["aISignal"]> + + export type AISignalSelectScalar = { + id?: boolean + marketId?: boolean + signal?: boolean + confidence?: boolean + summary?: boolean + keyRisk?: boolean + newsCount?: boolean + modelVersion?: boolean + impliedProb?: boolean + fairProb?: boolean + edgePoints?: boolean + generatedAt?: boolean + } + + export type AISignalOmit = $Extensions.GetOmit<"id" | "marketId" | "signal" | "confidence" | "summary" | "keyRisk" | "newsCount" | "modelVersion" | "impliedProb" | "fairProb" | "edgePoints" | "generatedAt", ExtArgs["result"]["aISignal"]> + export type AISignalInclude = { + market?: boolean | MarketDefaultArgs + } + export type AISignalIncludeCreateManyAndReturn = { + market?: boolean | MarketDefaultArgs + } + export type AISignalIncludeUpdateManyAndReturn = { + market?: boolean | MarketDefaultArgs + } + + export type $AISignalPayload = { + name: "AISignal" + objects: { + market: Prisma.$MarketPayload + } + scalars: $Extensions.GetPayloadResult<{ + id: number + marketId: string + signal: string + confidence: number + summary: string | null + keyRisk: string | null + newsCount: number + modelVersion: string + impliedProb: number | null + fairProb: number | null + edgePoints: number | null + generatedAt: Date + }, ExtArgs["result"]["aISignal"]> + composites: {} + } + + type AISignalGetPayload = $Result.GetResult + + type AISignalCountArgs = + Omit & { + select?: AISignalCountAggregateInputType | true + } + + export interface AISignalDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['AISignal'], meta: { name: 'AISignal' } } + /** + * Find zero or one AISignal that matches the filter. + * @param {AISignalFindUniqueArgs} args - Arguments to find a AISignal + * @example + * // Get one AISignal + * const aISignal = await prisma.aISignal.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: SelectSubset>): Prisma__AISignalClient<$Result.GetResult, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one AISignal that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {AISignalFindUniqueOrThrowArgs} args - Arguments to find a AISignal + * @example + * // Get one AISignal + * const aISignal = await prisma.aISignal.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: SelectSubset>): Prisma__AISignalClient<$Result.GetResult, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first AISignal that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AISignalFindFirstArgs} args - Arguments to find a AISignal + * @example + * // Get one AISignal + * const aISignal = await prisma.aISignal.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: SelectSubset>): Prisma__AISignalClient<$Result.GetResult, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first AISignal that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AISignalFindFirstOrThrowArgs} args - Arguments to find a AISignal + * @example + * // Get one AISignal + * const aISignal = await prisma.aISignal.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: SelectSubset>): Prisma__AISignalClient<$Result.GetResult, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more AISignals that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AISignalFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all AISignals + * const aISignals = await prisma.aISignal.findMany() + * + * // Get first 10 AISignals + * const aISignals = await prisma.aISignal.findMany({ take: 10 }) + * + * // Only select the `id` + * const aISignalWithIdOnly = await prisma.aISignal.findMany({ select: { id: true } }) + * + */ + findMany(args?: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "findMany", GlobalOmitOptions>> + + /** + * Create a AISignal. + * @param {AISignalCreateArgs} args - Arguments to create a AISignal. + * @example + * // Create one AISignal + * const AISignal = await prisma.aISignal.create({ + * data: { + * // ... data to create a AISignal + * } + * }) + * + */ + create(args: SelectSubset>): Prisma__AISignalClient<$Result.GetResult, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many AISignals. + * @param {AISignalCreateManyArgs} args - Arguments to create many AISignals. + * @example + * // Create many AISignals + * const aISignal = await prisma.aISignal.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: SelectSubset>): Prisma.PrismaPromise + + /** + * Create many AISignals and returns the data saved in the database. + * @param {AISignalCreateManyAndReturnArgs} args - Arguments to create many AISignals. + * @example + * // Create many AISignals + * const aISignal = await prisma.aISignal.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many AISignals and only return the `id` + * const aISignalWithIdOnly = await prisma.aISignal.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a AISignal. + * @param {AISignalDeleteArgs} args - Arguments to delete one AISignal. + * @example + * // Delete one AISignal + * const AISignal = await prisma.aISignal.delete({ + * where: { + * // ... filter to delete one AISignal + * } + * }) + * + */ + delete(args: SelectSubset>): Prisma__AISignalClient<$Result.GetResult, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one AISignal. + * @param {AISignalUpdateArgs} args - Arguments to update one AISignal. + * @example + * // Update one AISignal + * const aISignal = await prisma.aISignal.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: SelectSubset>): Prisma__AISignalClient<$Result.GetResult, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more AISignals. + * @param {AISignalDeleteManyArgs} args - Arguments to filter AISignals to delete. + * @example + * // Delete a few AISignals + * const { count } = await prisma.aISignal.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more AISignals. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AISignalUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many AISignals + * const aISignal = await prisma.aISignal.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more AISignals and returns the data updated in the database. + * @param {AISignalUpdateManyAndReturnArgs} args - Arguments to update many AISignals. + * @example + * // Update many AISignals + * const aISignal = await prisma.aISignal.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more AISignals and only return the `id` + * const aISignalWithIdOnly = await prisma.aISignal.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one AISignal. + * @param {AISignalUpsertArgs} args - Arguments to update or create a AISignal. + * @example + * // Update or create a AISignal + * const aISignal = await prisma.aISignal.upsert({ + * create: { + * // ... data to create a AISignal + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the AISignal we want to update + * } + * }) + */ + upsert(args: SelectSubset>): Prisma__AISignalClient<$Result.GetResult, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of AISignals. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AISignalCountArgs} args - Arguments to filter AISignals to count. + * @example + * // Count the number of AISignals + * const count = await prisma.aISignal.count({ + * where: { + * // ... the filter for the AISignals we want to count + * } + * }) + **/ + count( + args?: Subset, + ): Prisma.PrismaPromise< + T extends $Utils.Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a AISignal. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AISignalAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): Prisma.PrismaPromise> + + /** + * Group by AISignal. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AISignalGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends AISignalGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: AISignalGroupByArgs['orderBy'] } + : { orderBy?: AISignalGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends MaybeTupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? `Error: "by" must not be empty.` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetAISignalGroupByPayload : Prisma.PrismaPromise + /** + * Fields of the AISignal model + */ + readonly fields: AISignalFieldRefs; + } + + /** + * The delegate class that acts as a "Promise-like" for AISignal. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export interface Prisma__AISignalClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + market = {}>(args?: Subset>): Prisma__MarketClient<$Result.GetResult, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): $Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): $Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): $Utils.JsPromise + } + + + + + /** + * Fields of the AISignal model + */ + interface AISignalFieldRefs { + readonly id: FieldRef<"AISignal", 'Int'> + readonly marketId: FieldRef<"AISignal", 'String'> + readonly signal: FieldRef<"AISignal", 'String'> + readonly confidence: FieldRef<"AISignal", 'Float'> + readonly summary: FieldRef<"AISignal", 'String'> + readonly keyRisk: FieldRef<"AISignal", 'String'> + readonly newsCount: FieldRef<"AISignal", 'Int'> + readonly modelVersion: FieldRef<"AISignal", 'String'> + readonly impliedProb: FieldRef<"AISignal", 'Float'> + readonly fairProb: FieldRef<"AISignal", 'Float'> + readonly edgePoints: FieldRef<"AISignal", 'Float'> + readonly generatedAt: FieldRef<"AISignal", 'DateTime'> + } + + + // Custom InputTypes + /** + * AISignal findUnique + */ + export type AISignalFindUniqueArgs = { + /** + * Select specific fields to fetch from the AISignal + */ + select?: AISignalSelect | null + /** + * Omit specific fields from the AISignal + */ + omit?: AISignalOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AISignalInclude | null + /** + * Filter, which AISignal to fetch. + */ + where: AISignalWhereUniqueInput + } + + /** + * AISignal findUniqueOrThrow + */ + export type AISignalFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the AISignal + */ + select?: AISignalSelect | null + /** + * Omit specific fields from the AISignal + */ + omit?: AISignalOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AISignalInclude | null + /** + * Filter, which AISignal to fetch. + */ + where: AISignalWhereUniqueInput + } + + /** + * AISignal findFirst + */ + export type AISignalFindFirstArgs = { + /** + * Select specific fields to fetch from the AISignal + */ + select?: AISignalSelect | null + /** + * Omit specific fields from the AISignal + */ + omit?: AISignalOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AISignalInclude | null + /** + * Filter, which AISignal to fetch. + */ + where?: AISignalWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AISignals to fetch. + */ + orderBy?: AISignalOrderByWithRelationInput | AISignalOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for AISignals. + */ + cursor?: AISignalWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AISignals from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AISignals. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of AISignals. + */ + distinct?: AISignalScalarFieldEnum | AISignalScalarFieldEnum[] + } + + /** + * AISignal findFirstOrThrow + */ + export type AISignalFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the AISignal + */ + select?: AISignalSelect | null + /** + * Omit specific fields from the AISignal + */ + omit?: AISignalOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AISignalInclude | null + /** + * Filter, which AISignal to fetch. + */ + where?: AISignalWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AISignals to fetch. + */ + orderBy?: AISignalOrderByWithRelationInput | AISignalOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for AISignals. + */ + cursor?: AISignalWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AISignals from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AISignals. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of AISignals. + */ + distinct?: AISignalScalarFieldEnum | AISignalScalarFieldEnum[] + } + + /** + * AISignal findMany + */ + export type AISignalFindManyArgs = { + /** + * Select specific fields to fetch from the AISignal + */ + select?: AISignalSelect | null + /** + * Omit specific fields from the AISignal + */ + omit?: AISignalOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AISignalInclude | null + /** + * Filter, which AISignals to fetch. + */ + where?: AISignalWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of AISignals to fetch. + */ + orderBy?: AISignalOrderByWithRelationInput | AISignalOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing AISignals. + */ + cursor?: AISignalWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` AISignals from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` AISignals. + */ + skip?: number + distinct?: AISignalScalarFieldEnum | AISignalScalarFieldEnum[] + } + + /** + * AISignal create + */ + export type AISignalCreateArgs = { + /** + * Select specific fields to fetch from the AISignal + */ + select?: AISignalSelect | null + /** + * Omit specific fields from the AISignal + */ + omit?: AISignalOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AISignalInclude | null + /** + * The data needed to create a AISignal. + */ + data: XOR + } + + /** + * AISignal createMany + */ + export type AISignalCreateManyArgs = { + /** + * The data used to create many AISignals. + */ + data: AISignalCreateManyInput | AISignalCreateManyInput[] + } + + /** + * AISignal createManyAndReturn + */ + export type AISignalCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the AISignal + */ + select?: AISignalSelectCreateManyAndReturn | null + /** + * Omit specific fields from the AISignal + */ + omit?: AISignalOmit | null + /** + * The data used to create many AISignals. + */ + data: AISignalCreateManyInput | AISignalCreateManyInput[] + /** + * Choose, which related nodes to fetch as well + */ + include?: AISignalIncludeCreateManyAndReturn | null + } + + /** + * AISignal update + */ + export type AISignalUpdateArgs = { + /** + * Select specific fields to fetch from the AISignal + */ + select?: AISignalSelect | null + /** + * Omit specific fields from the AISignal + */ + omit?: AISignalOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AISignalInclude | null + /** + * The data needed to update a AISignal. + */ + data: XOR + /** + * Choose, which AISignal to update. + */ + where: AISignalWhereUniqueInput + } + + /** + * AISignal updateMany + */ + export type AISignalUpdateManyArgs = { + /** + * The data used to update AISignals. + */ + data: XOR + /** + * Filter which AISignals to update + */ + where?: AISignalWhereInput + /** + * Limit how many AISignals to update. + */ + limit?: number + } + + /** + * AISignal updateManyAndReturn + */ + export type AISignalUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the AISignal + */ + select?: AISignalSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the AISignal + */ + omit?: AISignalOmit | null + /** + * The data used to update AISignals. + */ + data: XOR + /** + * Filter which AISignals to update + */ + where?: AISignalWhereInput + /** + * Limit how many AISignals to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: AISignalIncludeUpdateManyAndReturn | null + } + + /** + * AISignal upsert + */ + export type AISignalUpsertArgs = { + /** + * Select specific fields to fetch from the AISignal + */ + select?: AISignalSelect | null + /** + * Omit specific fields from the AISignal + */ + omit?: AISignalOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AISignalInclude | null + /** + * The filter to search for the AISignal to update in case it exists. + */ + where: AISignalWhereUniqueInput + /** + * In case the AISignal found by the `where` argument doesn't exist, create a new AISignal with this data. + */ + create: XOR + /** + * In case the AISignal was found with the provided `where` argument, update it with this data. + */ + update: XOR + } + + /** + * AISignal delete + */ + export type AISignalDeleteArgs = { + /** + * Select specific fields to fetch from the AISignal + */ + select?: AISignalSelect | null + /** + * Omit specific fields from the AISignal + */ + omit?: AISignalOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AISignalInclude | null + /** + * Filter which AISignal to delete. + */ + where: AISignalWhereUniqueInput + } + + /** + * AISignal deleteMany + */ + export type AISignalDeleteManyArgs = { + /** + * Filter which AISignals to delete + */ + where?: AISignalWhereInput + /** + * Limit how many AISignals to delete. + */ + limit?: number + } + + /** + * AISignal without action + */ + export type AISignalDefaultArgs = { + /** + * Select specific fields to fetch from the AISignal + */ + select?: AISignalSelect | null + /** + * Omit specific fields from the AISignal + */ + omit?: AISignalOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AISignalInclude | null + } + + + /** + * Model Position + */ + + export type AggregatePosition = { + _count: PositionCountAggregateOutputType | null + _avg: PositionAvgAggregateOutputType | null + _sum: PositionSumAggregateOutputType | null + _min: PositionMinAggregateOutputType | null + _max: PositionMaxAggregateOutputType | null + } + + export type PositionAvgAggregateOutputType = { + id: number | null + userId: number | null + amountEur: number | null + entryPrice: number | null + currentPrice: number | null + pnl: number | null + kellyFraction: number | null + } + + export type PositionSumAggregateOutputType = { + id: number | null + userId: number | null + amountEur: number | null + entryPrice: number | null + currentPrice: number | null + pnl: number | null + kellyFraction: number | null + } + + export type PositionMinAggregateOutputType = { + id: number | null + userId: number | null + marketId: string | null + outcome: string | null + amountEur: number | null + entryPrice: number | null + currentPrice: number | null + pnl: number | null + kellyFraction: number | null + status: string | null + openedAt: Date | null + closedAt: Date | null + } + + export type PositionMaxAggregateOutputType = { + id: number | null + userId: number | null + marketId: string | null + outcome: string | null + amountEur: number | null + entryPrice: number | null + currentPrice: number | null + pnl: number | null + kellyFraction: number | null + status: string | null + openedAt: Date | null + closedAt: Date | null + } + + export type PositionCountAggregateOutputType = { + id: number + userId: number + marketId: number + outcome: number + amountEur: number + entryPrice: number + currentPrice: number + pnl: number + kellyFraction: number + status: number + openedAt: number + closedAt: number + _all: number + } + + + export type PositionAvgAggregateInputType = { + id?: true + userId?: true + amountEur?: true + entryPrice?: true + currentPrice?: true + pnl?: true + kellyFraction?: true + } + + export type PositionSumAggregateInputType = { + id?: true + userId?: true + amountEur?: true + entryPrice?: true + currentPrice?: true + pnl?: true + kellyFraction?: true + } + + export type PositionMinAggregateInputType = { + id?: true + userId?: true + marketId?: true + outcome?: true + amountEur?: true + entryPrice?: true + currentPrice?: true + pnl?: true + kellyFraction?: true + status?: true + openedAt?: true + closedAt?: true + } + + export type PositionMaxAggregateInputType = { + id?: true + userId?: true + marketId?: true + outcome?: true + amountEur?: true + entryPrice?: true + currentPrice?: true + pnl?: true + kellyFraction?: true + status?: true + openedAt?: true + closedAt?: true + } + + export type PositionCountAggregateInputType = { + id?: true + userId?: true + marketId?: true + outcome?: true + amountEur?: true + entryPrice?: true + currentPrice?: true + pnl?: true + kellyFraction?: true + status?: true + openedAt?: true + closedAt?: true + _all?: true + } + + export type PositionAggregateArgs = { + /** + * Filter which Position to aggregate. + */ + where?: PositionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Positions to fetch. + */ + orderBy?: PositionOrderByWithRelationInput | PositionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: PositionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Positions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Positions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Positions + **/ + _count?: true | PositionCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: PositionAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: PositionSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: PositionMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: PositionMaxAggregateInputType + } + + export type GetPositionAggregateType = { + [P in keyof T & keyof AggregatePosition]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type PositionGroupByArgs = { + where?: PositionWhereInput + orderBy?: PositionOrderByWithAggregationInput | PositionOrderByWithAggregationInput[] + by: PositionScalarFieldEnum[] | PositionScalarFieldEnum + having?: PositionScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: PositionCountAggregateInputType | true + _avg?: PositionAvgAggregateInputType + _sum?: PositionSumAggregateInputType + _min?: PositionMinAggregateInputType + _max?: PositionMaxAggregateInputType + } + + export type PositionGroupByOutputType = { + id: number + userId: number + marketId: string + outcome: string + amountEur: number + entryPrice: number + currentPrice: number | null + pnl: number + kellyFraction: number | null + status: string + openedAt: Date + closedAt: Date | null + _count: PositionCountAggregateOutputType | null + _avg: PositionAvgAggregateOutputType | null + _sum: PositionSumAggregateOutputType | null + _min: PositionMinAggregateOutputType | null + _max: PositionMaxAggregateOutputType | null + } + + type GetPositionGroupByPayload = Prisma.PrismaPromise< + Array< + PickEnumerable & + { + [P in ((keyof T) & (keyof PositionGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type PositionSelect = $Extensions.GetSelect<{ + id?: boolean + userId?: boolean + marketId?: boolean + outcome?: boolean + amountEur?: boolean + entryPrice?: boolean + currentPrice?: boolean + pnl?: boolean + kellyFraction?: boolean + status?: boolean + openedAt?: boolean + closedAt?: boolean + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + }, ExtArgs["result"]["position"]> + + export type PositionSelectCreateManyAndReturn = $Extensions.GetSelect<{ + id?: boolean + userId?: boolean + marketId?: boolean + outcome?: boolean + amountEur?: boolean + entryPrice?: boolean + currentPrice?: boolean + pnl?: boolean + kellyFraction?: boolean + status?: boolean + openedAt?: boolean + closedAt?: boolean + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + }, ExtArgs["result"]["position"]> + + export type PositionSelectUpdateManyAndReturn = $Extensions.GetSelect<{ + id?: boolean + userId?: boolean + marketId?: boolean + outcome?: boolean + amountEur?: boolean + entryPrice?: boolean + currentPrice?: boolean + pnl?: boolean + kellyFraction?: boolean + status?: boolean + openedAt?: boolean + closedAt?: boolean + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + }, ExtArgs["result"]["position"]> + + export type PositionSelectScalar = { + id?: boolean + userId?: boolean + marketId?: boolean + outcome?: boolean + amountEur?: boolean + entryPrice?: boolean + currentPrice?: boolean + pnl?: boolean + kellyFraction?: boolean + status?: boolean + openedAt?: boolean + closedAt?: boolean + } + + export type PositionOmit = $Extensions.GetOmit<"id" | "userId" | "marketId" | "outcome" | "amountEur" | "entryPrice" | "currentPrice" | "pnl" | "kellyFraction" | "status" | "openedAt" | "closedAt", ExtArgs["result"]["position"]> + export type PositionInclude = { + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + } + export type PositionIncludeCreateManyAndReturn = { + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + } + export type PositionIncludeUpdateManyAndReturn = { + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + } + + export type $PositionPayload = { + name: "Position" + objects: { + user: Prisma.$UserPayload + market: Prisma.$MarketPayload + } + scalars: $Extensions.GetPayloadResult<{ + id: number + userId: number + marketId: string + outcome: string + amountEur: number + entryPrice: number + currentPrice: number | null + pnl: number + kellyFraction: number | null + status: string + openedAt: Date + closedAt: Date | null + }, ExtArgs["result"]["position"]> + composites: {} + } + + type PositionGetPayload = $Result.GetResult + + type PositionCountArgs = + Omit & { + select?: PositionCountAggregateInputType | true + } + + export interface PositionDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['Position'], meta: { name: 'Position' } } + /** + * Find zero or one Position that matches the filter. + * @param {PositionFindUniqueArgs} args - Arguments to find a Position + * @example + * // Get one Position + * const position = await prisma.position.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: SelectSubset>): Prisma__PositionClient<$Result.GetResult, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one Position that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {PositionFindUniqueOrThrowArgs} args - Arguments to find a Position + * @example + * // Get one Position + * const position = await prisma.position.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: SelectSubset>): Prisma__PositionClient<$Result.GetResult, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Position that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {PositionFindFirstArgs} args - Arguments to find a Position + * @example + * // Get one Position + * const position = await prisma.position.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: SelectSubset>): Prisma__PositionClient<$Result.GetResult, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Position that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {PositionFindFirstOrThrowArgs} args - Arguments to find a Position + * @example + * // Get one Position + * const position = await prisma.position.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: SelectSubset>): Prisma__PositionClient<$Result.GetResult, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more Positions that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {PositionFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all Positions + * const positions = await prisma.position.findMany() + * + * // Get first 10 Positions + * const positions = await prisma.position.findMany({ take: 10 }) + * + * // Only select the `id` + * const positionWithIdOnly = await prisma.position.findMany({ select: { id: true } }) + * + */ + findMany(args?: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "findMany", GlobalOmitOptions>> + + /** + * Create a Position. + * @param {PositionCreateArgs} args - Arguments to create a Position. + * @example + * // Create one Position + * const Position = await prisma.position.create({ + * data: { + * // ... data to create a Position + * } + * }) + * + */ + create(args: SelectSubset>): Prisma__PositionClient<$Result.GetResult, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many Positions. + * @param {PositionCreateManyArgs} args - Arguments to create many Positions. + * @example + * // Create many Positions + * const position = await prisma.position.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: SelectSubset>): Prisma.PrismaPromise + + /** + * Create many Positions and returns the data saved in the database. + * @param {PositionCreateManyAndReturnArgs} args - Arguments to create many Positions. + * @example + * // Create many Positions + * const position = await prisma.position.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many Positions and only return the `id` + * const positionWithIdOnly = await prisma.position.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a Position. + * @param {PositionDeleteArgs} args - Arguments to delete one Position. + * @example + * // Delete one Position + * const Position = await prisma.position.delete({ + * where: { + * // ... filter to delete one Position + * } + * }) + * + */ + delete(args: SelectSubset>): Prisma__PositionClient<$Result.GetResult, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one Position. + * @param {PositionUpdateArgs} args - Arguments to update one Position. + * @example + * // Update one Position + * const position = await prisma.position.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: SelectSubset>): Prisma__PositionClient<$Result.GetResult, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more Positions. + * @param {PositionDeleteManyArgs} args - Arguments to filter Positions to delete. + * @example + * // Delete a few Positions + * const { count } = await prisma.position.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Positions. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {PositionUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Positions + * const position = await prisma.position.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Positions and returns the data updated in the database. + * @param {PositionUpdateManyAndReturnArgs} args - Arguments to update many Positions. + * @example + * // Update many Positions + * const position = await prisma.position.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more Positions and only return the `id` + * const positionWithIdOnly = await prisma.position.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one Position. + * @param {PositionUpsertArgs} args - Arguments to update or create a Position. + * @example + * // Update or create a Position + * const position = await prisma.position.upsert({ + * create: { + * // ... data to create a Position + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the Position we want to update + * } + * }) + */ + upsert(args: SelectSubset>): Prisma__PositionClient<$Result.GetResult, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of Positions. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {PositionCountArgs} args - Arguments to filter Positions to count. + * @example + * // Count the number of Positions + * const count = await prisma.position.count({ + * where: { + * // ... the filter for the Positions we want to count + * } + * }) + **/ + count( + args?: Subset, + ): Prisma.PrismaPromise< + T extends $Utils.Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a Position. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {PositionAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): Prisma.PrismaPromise> + + /** + * Group by Position. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {PositionGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends PositionGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: PositionGroupByArgs['orderBy'] } + : { orderBy?: PositionGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends MaybeTupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? `Error: "by" must not be empty.` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetPositionGroupByPayload : Prisma.PrismaPromise + /** + * Fields of the Position model + */ + readonly fields: PositionFieldRefs; + } + + /** + * The delegate class that acts as a "Promise-like" for Position. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export interface Prisma__PositionClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + user = {}>(args?: Subset>): Prisma__UserClient<$Result.GetResult, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + market = {}>(args?: Subset>): Prisma__MarketClient<$Result.GetResult, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): $Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): $Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): $Utils.JsPromise + } + + + + + /** + * Fields of the Position model + */ + interface PositionFieldRefs { + readonly id: FieldRef<"Position", 'Int'> + readonly userId: FieldRef<"Position", 'Int'> + readonly marketId: FieldRef<"Position", 'String'> + readonly outcome: FieldRef<"Position", 'String'> + readonly amountEur: FieldRef<"Position", 'Float'> + readonly entryPrice: FieldRef<"Position", 'Float'> + readonly currentPrice: FieldRef<"Position", 'Float'> + readonly pnl: FieldRef<"Position", 'Float'> + readonly kellyFraction: FieldRef<"Position", 'Float'> + readonly status: FieldRef<"Position", 'String'> + readonly openedAt: FieldRef<"Position", 'DateTime'> + readonly closedAt: FieldRef<"Position", 'DateTime'> + } + + + // Custom InputTypes + /** + * Position findUnique + */ + export type PositionFindUniqueArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelect | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionInclude | null + /** + * Filter, which Position to fetch. + */ + where: PositionWhereUniqueInput + } + + /** + * Position findUniqueOrThrow + */ + export type PositionFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelect | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionInclude | null + /** + * Filter, which Position to fetch. + */ + where: PositionWhereUniqueInput + } + + /** + * Position findFirst + */ + export type PositionFindFirstArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelect | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionInclude | null + /** + * Filter, which Position to fetch. + */ + where?: PositionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Positions to fetch. + */ + orderBy?: PositionOrderByWithRelationInput | PositionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Positions. + */ + cursor?: PositionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Positions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Positions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Positions. + */ + distinct?: PositionScalarFieldEnum | PositionScalarFieldEnum[] + } + + /** + * Position findFirstOrThrow + */ + export type PositionFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelect | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionInclude | null + /** + * Filter, which Position to fetch. + */ + where?: PositionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Positions to fetch. + */ + orderBy?: PositionOrderByWithRelationInput | PositionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Positions. + */ + cursor?: PositionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Positions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Positions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Positions. + */ + distinct?: PositionScalarFieldEnum | PositionScalarFieldEnum[] + } + + /** + * Position findMany + */ + export type PositionFindManyArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelect | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionInclude | null + /** + * Filter, which Positions to fetch. + */ + where?: PositionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Positions to fetch. + */ + orderBy?: PositionOrderByWithRelationInput | PositionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Positions. + */ + cursor?: PositionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Positions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Positions. + */ + skip?: number + distinct?: PositionScalarFieldEnum | PositionScalarFieldEnum[] + } + + /** + * Position create + */ + export type PositionCreateArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelect | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionInclude | null + /** + * The data needed to create a Position. + */ + data: XOR + } + + /** + * Position createMany + */ + export type PositionCreateManyArgs = { + /** + * The data used to create many Positions. + */ + data: PositionCreateManyInput | PositionCreateManyInput[] + } + + /** + * Position createManyAndReturn + */ + export type PositionCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelectCreateManyAndReturn | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * The data used to create many Positions. + */ + data: PositionCreateManyInput | PositionCreateManyInput[] + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionIncludeCreateManyAndReturn | null + } + + /** + * Position update + */ + export type PositionUpdateArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelect | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionInclude | null + /** + * The data needed to update a Position. + */ + data: XOR + /** + * Choose, which Position to update. + */ + where: PositionWhereUniqueInput + } + + /** + * Position updateMany + */ + export type PositionUpdateManyArgs = { + /** + * The data used to update Positions. + */ + data: XOR + /** + * Filter which Positions to update + */ + where?: PositionWhereInput + /** + * Limit how many Positions to update. + */ + limit?: number + } + + /** + * Position updateManyAndReturn + */ + export type PositionUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * The data used to update Positions. + */ + data: XOR + /** + * Filter which Positions to update + */ + where?: PositionWhereInput + /** + * Limit how many Positions to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionIncludeUpdateManyAndReturn | null + } + + /** + * Position upsert + */ + export type PositionUpsertArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelect | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionInclude | null + /** + * The filter to search for the Position to update in case it exists. + */ + where: PositionWhereUniqueInput + /** + * In case the Position found by the `where` argument doesn't exist, create a new Position with this data. + */ + create: XOR + /** + * In case the Position was found with the provided `where` argument, update it with this data. + */ + update: XOR + } + + /** + * Position delete + */ + export type PositionDeleteArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelect | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionInclude | null + /** + * Filter which Position to delete. + */ + where: PositionWhereUniqueInput + } + + /** + * Position deleteMany + */ + export type PositionDeleteManyArgs = { + /** + * Filter which Positions to delete + */ + where?: PositionWhereInput + /** + * Limit how many Positions to delete. + */ + limit?: number + } + + /** + * Position without action + */ + export type PositionDefaultArgs = { + /** + * Select specific fields to fetch from the Position + */ + select?: PositionSelect | null + /** + * Omit specific fields from the Position + */ + omit?: PositionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: PositionInclude | null + } + + + /** + * Model Watchlist + */ + + export type AggregateWatchlist = { + _count: WatchlistCountAggregateOutputType | null + _avg: WatchlistAvgAggregateOutputType | null + _sum: WatchlistSumAggregateOutputType | null + _min: WatchlistMinAggregateOutputType | null + _max: WatchlistMaxAggregateOutputType | null + } + + export type WatchlistAvgAggregateOutputType = { + id: number | null + userId: number | null + alertThreshold: number | null + } + + export type WatchlistSumAggregateOutputType = { + id: number | null + userId: number | null + alertThreshold: number | null + } + + export type WatchlistMinAggregateOutputType = { + id: number | null + userId: number | null + marketId: string | null + alertThreshold: number | null + createdAt: Date | null + } + + export type WatchlistMaxAggregateOutputType = { + id: number | null + userId: number | null + marketId: string | null + alertThreshold: number | null + createdAt: Date | null + } + + export type WatchlistCountAggregateOutputType = { + id: number + userId: number + marketId: number + alertThreshold: number + createdAt: number + _all: number + } + + + export type WatchlistAvgAggregateInputType = { + id?: true + userId?: true + alertThreshold?: true + } + + export type WatchlistSumAggregateInputType = { + id?: true + userId?: true + alertThreshold?: true + } + + export type WatchlistMinAggregateInputType = { + id?: true + userId?: true + marketId?: true + alertThreshold?: true + createdAt?: true + } + + export type WatchlistMaxAggregateInputType = { + id?: true + userId?: true + marketId?: true + alertThreshold?: true + createdAt?: true + } + + export type WatchlistCountAggregateInputType = { + id?: true + userId?: true + marketId?: true + alertThreshold?: true + createdAt?: true + _all?: true + } + + export type WatchlistAggregateArgs = { + /** + * Filter which Watchlist to aggregate. + */ + where?: WatchlistWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Watchlists to fetch. + */ + orderBy?: WatchlistOrderByWithRelationInput | WatchlistOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: WatchlistWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Watchlists from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Watchlists. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Watchlists + **/ + _count?: true | WatchlistCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: WatchlistAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: WatchlistSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: WatchlistMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: WatchlistMaxAggregateInputType + } + + export type GetWatchlistAggregateType = { + [P in keyof T & keyof AggregateWatchlist]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type WatchlistGroupByArgs = { + where?: WatchlistWhereInput + orderBy?: WatchlistOrderByWithAggregationInput | WatchlistOrderByWithAggregationInput[] + by: WatchlistScalarFieldEnum[] | WatchlistScalarFieldEnum + having?: WatchlistScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: WatchlistCountAggregateInputType | true + _avg?: WatchlistAvgAggregateInputType + _sum?: WatchlistSumAggregateInputType + _min?: WatchlistMinAggregateInputType + _max?: WatchlistMaxAggregateInputType + } + + export type WatchlistGroupByOutputType = { + id: number + userId: number + marketId: string + alertThreshold: number | null + createdAt: Date + _count: WatchlistCountAggregateOutputType | null + _avg: WatchlistAvgAggregateOutputType | null + _sum: WatchlistSumAggregateOutputType | null + _min: WatchlistMinAggregateOutputType | null + _max: WatchlistMaxAggregateOutputType | null + } + + type GetWatchlistGroupByPayload = Prisma.PrismaPromise< + Array< + PickEnumerable & + { + [P in ((keyof T) & (keyof WatchlistGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type WatchlistSelect = $Extensions.GetSelect<{ + id?: boolean + userId?: boolean + marketId?: boolean + alertThreshold?: boolean + createdAt?: boolean + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + }, ExtArgs["result"]["watchlist"]> + + export type WatchlistSelectCreateManyAndReturn = $Extensions.GetSelect<{ + id?: boolean + userId?: boolean + marketId?: boolean + alertThreshold?: boolean + createdAt?: boolean + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + }, ExtArgs["result"]["watchlist"]> + + export type WatchlistSelectUpdateManyAndReturn = $Extensions.GetSelect<{ + id?: boolean + userId?: boolean + marketId?: boolean + alertThreshold?: boolean + createdAt?: boolean + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + }, ExtArgs["result"]["watchlist"]> + + export type WatchlistSelectScalar = { + id?: boolean + userId?: boolean + marketId?: boolean + alertThreshold?: boolean + createdAt?: boolean + } + + export type WatchlistOmit = $Extensions.GetOmit<"id" | "userId" | "marketId" | "alertThreshold" | "createdAt", ExtArgs["result"]["watchlist"]> + export type WatchlistInclude = { + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + } + export type WatchlistIncludeCreateManyAndReturn = { + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + } + export type WatchlistIncludeUpdateManyAndReturn = { + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + } + + export type $WatchlistPayload = { + name: "Watchlist" + objects: { + user: Prisma.$UserPayload + market: Prisma.$MarketPayload + } + scalars: $Extensions.GetPayloadResult<{ + id: number + userId: number + marketId: string + alertThreshold: number | null + createdAt: Date + }, ExtArgs["result"]["watchlist"]> + composites: {} + } + + type WatchlistGetPayload = $Result.GetResult + + type WatchlistCountArgs = + Omit & { + select?: WatchlistCountAggregateInputType | true + } + + export interface WatchlistDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['Watchlist'], meta: { name: 'Watchlist' } } + /** + * Find zero or one Watchlist that matches the filter. + * @param {WatchlistFindUniqueArgs} args - Arguments to find a Watchlist + * @example + * // Get one Watchlist + * const watchlist = await prisma.watchlist.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: SelectSubset>): Prisma__WatchlistClient<$Result.GetResult, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one Watchlist that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {WatchlistFindUniqueOrThrowArgs} args - Arguments to find a Watchlist + * @example + * // Get one Watchlist + * const watchlist = await prisma.watchlist.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: SelectSubset>): Prisma__WatchlistClient<$Result.GetResult, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Watchlist that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {WatchlistFindFirstArgs} args - Arguments to find a Watchlist + * @example + * // Get one Watchlist + * const watchlist = await prisma.watchlist.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: SelectSubset>): Prisma__WatchlistClient<$Result.GetResult, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Watchlist that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {WatchlistFindFirstOrThrowArgs} args - Arguments to find a Watchlist + * @example + * // Get one Watchlist + * const watchlist = await prisma.watchlist.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: SelectSubset>): Prisma__WatchlistClient<$Result.GetResult, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more Watchlists that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {WatchlistFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all Watchlists + * const watchlists = await prisma.watchlist.findMany() + * + * // Get first 10 Watchlists + * const watchlists = await prisma.watchlist.findMany({ take: 10 }) + * + * // Only select the `id` + * const watchlistWithIdOnly = await prisma.watchlist.findMany({ select: { id: true } }) + * + */ + findMany(args?: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "findMany", GlobalOmitOptions>> + + /** + * Create a Watchlist. + * @param {WatchlistCreateArgs} args - Arguments to create a Watchlist. + * @example + * // Create one Watchlist + * const Watchlist = await prisma.watchlist.create({ + * data: { + * // ... data to create a Watchlist + * } + * }) + * + */ + create(args: SelectSubset>): Prisma__WatchlistClient<$Result.GetResult, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many Watchlists. + * @param {WatchlistCreateManyArgs} args - Arguments to create many Watchlists. + * @example + * // Create many Watchlists + * const watchlist = await prisma.watchlist.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: SelectSubset>): Prisma.PrismaPromise + + /** + * Create many Watchlists and returns the data saved in the database. + * @param {WatchlistCreateManyAndReturnArgs} args - Arguments to create many Watchlists. + * @example + * // Create many Watchlists + * const watchlist = await prisma.watchlist.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many Watchlists and only return the `id` + * const watchlistWithIdOnly = await prisma.watchlist.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a Watchlist. + * @param {WatchlistDeleteArgs} args - Arguments to delete one Watchlist. + * @example + * // Delete one Watchlist + * const Watchlist = await prisma.watchlist.delete({ + * where: { + * // ... filter to delete one Watchlist + * } + * }) + * + */ + delete(args: SelectSubset>): Prisma__WatchlistClient<$Result.GetResult, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one Watchlist. + * @param {WatchlistUpdateArgs} args - Arguments to update one Watchlist. + * @example + * // Update one Watchlist + * const watchlist = await prisma.watchlist.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: SelectSubset>): Prisma__WatchlistClient<$Result.GetResult, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more Watchlists. + * @param {WatchlistDeleteManyArgs} args - Arguments to filter Watchlists to delete. + * @example + * // Delete a few Watchlists + * const { count } = await prisma.watchlist.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Watchlists. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {WatchlistUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Watchlists + * const watchlist = await prisma.watchlist.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Watchlists and returns the data updated in the database. + * @param {WatchlistUpdateManyAndReturnArgs} args - Arguments to update many Watchlists. + * @example + * // Update many Watchlists + * const watchlist = await prisma.watchlist.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more Watchlists and only return the `id` + * const watchlistWithIdOnly = await prisma.watchlist.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one Watchlist. + * @param {WatchlistUpsertArgs} args - Arguments to update or create a Watchlist. + * @example + * // Update or create a Watchlist + * const watchlist = await prisma.watchlist.upsert({ + * create: { + * // ... data to create a Watchlist + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the Watchlist we want to update + * } + * }) + */ + upsert(args: SelectSubset>): Prisma__WatchlistClient<$Result.GetResult, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of Watchlists. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {WatchlistCountArgs} args - Arguments to filter Watchlists to count. + * @example + * // Count the number of Watchlists + * const count = await prisma.watchlist.count({ + * where: { + * // ... the filter for the Watchlists we want to count + * } + * }) + **/ + count( + args?: Subset, + ): Prisma.PrismaPromise< + T extends $Utils.Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a Watchlist. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {WatchlistAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): Prisma.PrismaPromise> + + /** + * Group by Watchlist. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {WatchlistGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends WatchlistGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: WatchlistGroupByArgs['orderBy'] } + : { orderBy?: WatchlistGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends MaybeTupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? `Error: "by" must not be empty.` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetWatchlistGroupByPayload : Prisma.PrismaPromise + /** + * Fields of the Watchlist model + */ + readonly fields: WatchlistFieldRefs; + } + + /** + * The delegate class that acts as a "Promise-like" for Watchlist. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export interface Prisma__WatchlistClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + user = {}>(args?: Subset>): Prisma__UserClient<$Result.GetResult, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + market = {}>(args?: Subset>): Prisma__MarketClient<$Result.GetResult, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): $Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): $Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): $Utils.JsPromise + } + + + + + /** + * Fields of the Watchlist model + */ + interface WatchlistFieldRefs { + readonly id: FieldRef<"Watchlist", 'Int'> + readonly userId: FieldRef<"Watchlist", 'Int'> + readonly marketId: FieldRef<"Watchlist", 'String'> + readonly alertThreshold: FieldRef<"Watchlist", 'Float'> + readonly createdAt: FieldRef<"Watchlist", 'DateTime'> + } + + + // Custom InputTypes + /** + * Watchlist findUnique + */ + export type WatchlistFindUniqueArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelect | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistInclude | null + /** + * Filter, which Watchlist to fetch. + */ + where: WatchlistWhereUniqueInput + } + + /** + * Watchlist findUniqueOrThrow + */ + export type WatchlistFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelect | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistInclude | null + /** + * Filter, which Watchlist to fetch. + */ + where: WatchlistWhereUniqueInput + } + + /** + * Watchlist findFirst + */ + export type WatchlistFindFirstArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelect | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistInclude | null + /** + * Filter, which Watchlist to fetch. + */ + where?: WatchlistWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Watchlists to fetch. + */ + orderBy?: WatchlistOrderByWithRelationInput | WatchlistOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Watchlists. + */ + cursor?: WatchlistWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Watchlists from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Watchlists. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Watchlists. + */ + distinct?: WatchlistScalarFieldEnum | WatchlistScalarFieldEnum[] + } + + /** + * Watchlist findFirstOrThrow + */ + export type WatchlistFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelect | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistInclude | null + /** + * Filter, which Watchlist to fetch. + */ + where?: WatchlistWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Watchlists to fetch. + */ + orderBy?: WatchlistOrderByWithRelationInput | WatchlistOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Watchlists. + */ + cursor?: WatchlistWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Watchlists from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Watchlists. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Watchlists. + */ + distinct?: WatchlistScalarFieldEnum | WatchlistScalarFieldEnum[] + } + + /** + * Watchlist findMany + */ + export type WatchlistFindManyArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelect | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistInclude | null + /** + * Filter, which Watchlists to fetch. + */ + where?: WatchlistWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Watchlists to fetch. + */ + orderBy?: WatchlistOrderByWithRelationInput | WatchlistOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Watchlists. + */ + cursor?: WatchlistWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Watchlists from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Watchlists. + */ + skip?: number + distinct?: WatchlistScalarFieldEnum | WatchlistScalarFieldEnum[] + } + + /** + * Watchlist create + */ + export type WatchlistCreateArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelect | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistInclude | null + /** + * The data needed to create a Watchlist. + */ + data: XOR + } + + /** + * Watchlist createMany + */ + export type WatchlistCreateManyArgs = { + /** + * The data used to create many Watchlists. + */ + data: WatchlistCreateManyInput | WatchlistCreateManyInput[] + } + + /** + * Watchlist createManyAndReturn + */ + export type WatchlistCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelectCreateManyAndReturn | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * The data used to create many Watchlists. + */ + data: WatchlistCreateManyInput | WatchlistCreateManyInput[] + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistIncludeCreateManyAndReturn | null + } + + /** + * Watchlist update + */ + export type WatchlistUpdateArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelect | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistInclude | null + /** + * The data needed to update a Watchlist. + */ + data: XOR + /** + * Choose, which Watchlist to update. + */ + where: WatchlistWhereUniqueInput + } + + /** + * Watchlist updateMany + */ + export type WatchlistUpdateManyArgs = { + /** + * The data used to update Watchlists. + */ + data: XOR + /** + * Filter which Watchlists to update + */ + where?: WatchlistWhereInput + /** + * Limit how many Watchlists to update. + */ + limit?: number + } + + /** + * Watchlist updateManyAndReturn + */ + export type WatchlistUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * The data used to update Watchlists. + */ + data: XOR + /** + * Filter which Watchlists to update + */ + where?: WatchlistWhereInput + /** + * Limit how many Watchlists to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistIncludeUpdateManyAndReturn | null + } + + /** + * Watchlist upsert + */ + export type WatchlistUpsertArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelect | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistInclude | null + /** + * The filter to search for the Watchlist to update in case it exists. + */ + where: WatchlistWhereUniqueInput + /** + * In case the Watchlist found by the `where` argument doesn't exist, create a new Watchlist with this data. + */ + create: XOR + /** + * In case the Watchlist was found with the provided `where` argument, update it with this data. + */ + update: XOR + } + + /** + * Watchlist delete + */ + export type WatchlistDeleteArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelect | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistInclude | null + /** + * Filter which Watchlist to delete. + */ + where: WatchlistWhereUniqueInput + } + + /** + * Watchlist deleteMany + */ + export type WatchlistDeleteManyArgs = { + /** + * Filter which Watchlists to delete + */ + where?: WatchlistWhereInput + /** + * Limit how many Watchlists to delete. + */ + limit?: number + } + + /** + * Watchlist without action + */ + export type WatchlistDefaultArgs = { + /** + * Select specific fields to fetch from the Watchlist + */ + select?: WatchlistSelect | null + /** + * Omit specific fields from the Watchlist + */ + omit?: WatchlistOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: WatchlistInclude | null + } + + + /** + * Model Alert + */ + + export type AggregateAlert = { + _count: AlertCountAggregateOutputType | null + _avg: AlertAvgAggregateOutputType | null + _sum: AlertSumAggregateOutputType | null + _min: AlertMinAggregateOutputType | null + _max: AlertMaxAggregateOutputType | null + } + + export type AlertAvgAggregateOutputType = { + id: number | null + userId: number | null + } + + export type AlertSumAggregateOutputType = { + id: number | null + userId: number | null + } + + export type AlertMinAggregateOutputType = { + id: number | null + userId: number | null + marketId: string | null + type: string | null + message: string | null + sentAt: Date | null + } + + export type AlertMaxAggregateOutputType = { + id: number | null + userId: number | null + marketId: string | null + type: string | null + message: string | null + sentAt: Date | null + } + + export type AlertCountAggregateOutputType = { + id: number + userId: number + marketId: number + type: number + message: number + sentAt: number + _all: number + } + + + export type AlertAvgAggregateInputType = { + id?: true + userId?: true + } + + export type AlertSumAggregateInputType = { + id?: true + userId?: true + } + + export type AlertMinAggregateInputType = { + id?: true + userId?: true + marketId?: true + type?: true + message?: true + sentAt?: true + } + + export type AlertMaxAggregateInputType = { + id?: true + userId?: true + marketId?: true + type?: true + message?: true + sentAt?: true + } + + export type AlertCountAggregateInputType = { + id?: true + userId?: true + marketId?: true + type?: true + message?: true + sentAt?: true + _all?: true + } + + export type AlertAggregateArgs = { + /** + * Filter which Alert to aggregate. + */ + where?: AlertWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Alerts to fetch. + */ + orderBy?: AlertOrderByWithRelationInput | AlertOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: AlertWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Alerts from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Alerts. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Alerts + **/ + _count?: true | AlertCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: AlertAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: AlertSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: AlertMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: AlertMaxAggregateInputType + } + + export type GetAlertAggregateType = { + [P in keyof T & keyof AggregateAlert]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : GetScalarType + : GetScalarType + } + + + + + export type AlertGroupByArgs = { + where?: AlertWhereInput + orderBy?: AlertOrderByWithAggregationInput | AlertOrderByWithAggregationInput[] + by: AlertScalarFieldEnum[] | AlertScalarFieldEnum + having?: AlertScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: AlertCountAggregateInputType | true + _avg?: AlertAvgAggregateInputType + _sum?: AlertSumAggregateInputType + _min?: AlertMinAggregateInputType + _max?: AlertMaxAggregateInputType + } + + export type AlertGroupByOutputType = { + id: number + userId: number + marketId: string + type: string + message: string + sentAt: Date + _count: AlertCountAggregateOutputType | null + _avg: AlertAvgAggregateOutputType | null + _sum: AlertSumAggregateOutputType | null + _min: AlertMinAggregateOutputType | null + _max: AlertMaxAggregateOutputType | null + } + + type GetAlertGroupByPayload = Prisma.PrismaPromise< + Array< + PickEnumerable & + { + [P in ((keyof T) & (keyof AlertGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : GetScalarType + : GetScalarType + } + > + > + + + export type AlertSelect = $Extensions.GetSelect<{ + id?: boolean + userId?: boolean + marketId?: boolean + type?: boolean + message?: boolean + sentAt?: boolean + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + }, ExtArgs["result"]["alert"]> + + export type AlertSelectCreateManyAndReturn = $Extensions.GetSelect<{ + id?: boolean + userId?: boolean + marketId?: boolean + type?: boolean + message?: boolean + sentAt?: boolean + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + }, ExtArgs["result"]["alert"]> + + export type AlertSelectUpdateManyAndReturn = $Extensions.GetSelect<{ + id?: boolean + userId?: boolean + marketId?: boolean + type?: boolean + message?: boolean + sentAt?: boolean + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + }, ExtArgs["result"]["alert"]> + + export type AlertSelectScalar = { + id?: boolean + userId?: boolean + marketId?: boolean + type?: boolean + message?: boolean + sentAt?: boolean + } + + export type AlertOmit = $Extensions.GetOmit<"id" | "userId" | "marketId" | "type" | "message" | "sentAt", ExtArgs["result"]["alert"]> + export type AlertInclude = { + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + } + export type AlertIncludeCreateManyAndReturn = { + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + } + export type AlertIncludeUpdateManyAndReturn = { + user?: boolean | UserDefaultArgs + market?: boolean | MarketDefaultArgs + } + + export type $AlertPayload = { + name: "Alert" + objects: { + user: Prisma.$UserPayload + market: Prisma.$MarketPayload + } + scalars: $Extensions.GetPayloadResult<{ + id: number + userId: number + marketId: string + type: string + message: string + sentAt: Date + }, ExtArgs["result"]["alert"]> + composites: {} + } + + type AlertGetPayload = $Result.GetResult + + type AlertCountArgs = + Omit & { + select?: AlertCountAggregateInputType | true + } + + export interface AlertDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['Alert'], meta: { name: 'Alert' } } + /** + * Find zero or one Alert that matches the filter. + * @param {AlertFindUniqueArgs} args - Arguments to find a Alert + * @example + * // Get one Alert + * const alert = await prisma.alert.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: SelectSubset>): Prisma__AlertClient<$Result.GetResult, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one Alert that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {AlertFindUniqueOrThrowArgs} args - Arguments to find a Alert + * @example + * // Get one Alert + * const alert = await prisma.alert.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: SelectSubset>): Prisma__AlertClient<$Result.GetResult, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Alert that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AlertFindFirstArgs} args - Arguments to find a Alert + * @example + * // Get one Alert + * const alert = await prisma.alert.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: SelectSubset>): Prisma__AlertClient<$Result.GetResult, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Alert that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AlertFindFirstOrThrowArgs} args - Arguments to find a Alert + * @example + * // Get one Alert + * const alert = await prisma.alert.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: SelectSubset>): Prisma__AlertClient<$Result.GetResult, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more Alerts that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AlertFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all Alerts + * const alerts = await prisma.alert.findMany() + * + * // Get first 10 Alerts + * const alerts = await prisma.alert.findMany({ take: 10 }) + * + * // Only select the `id` + * const alertWithIdOnly = await prisma.alert.findMany({ select: { id: true } }) + * + */ + findMany(args?: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "findMany", GlobalOmitOptions>> + + /** + * Create a Alert. + * @param {AlertCreateArgs} args - Arguments to create a Alert. + * @example + * // Create one Alert + * const Alert = await prisma.alert.create({ + * data: { + * // ... data to create a Alert + * } + * }) + * + */ + create(args: SelectSubset>): Prisma__AlertClient<$Result.GetResult, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many Alerts. + * @param {AlertCreateManyArgs} args - Arguments to create many Alerts. + * @example + * // Create many Alerts + * const alert = await prisma.alert.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: SelectSubset>): Prisma.PrismaPromise + + /** + * Create many Alerts and returns the data saved in the database. + * @param {AlertCreateManyAndReturnArgs} args - Arguments to create many Alerts. + * @example + * // Create many Alerts + * const alert = await prisma.alert.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many Alerts and only return the `id` + * const alertWithIdOnly = await prisma.alert.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a Alert. + * @param {AlertDeleteArgs} args - Arguments to delete one Alert. + * @example + * // Delete one Alert + * const Alert = await prisma.alert.delete({ + * where: { + * // ... filter to delete one Alert + * } + * }) + * + */ + delete(args: SelectSubset>): Prisma__AlertClient<$Result.GetResult, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one Alert. + * @param {AlertUpdateArgs} args - Arguments to update one Alert. + * @example + * // Update one Alert + * const alert = await prisma.alert.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: SelectSubset>): Prisma__AlertClient<$Result.GetResult, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more Alerts. + * @param {AlertDeleteManyArgs} args - Arguments to filter Alerts to delete. + * @example + * // Delete a few Alerts + * const { count } = await prisma.alert.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Alerts. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AlertUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Alerts + * const alert = await prisma.alert.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Alerts and returns the data updated in the database. + * @param {AlertUpdateManyAndReturnArgs} args - Arguments to update many Alerts. + * @example + * // Update many Alerts + * const alert = await prisma.alert.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more Alerts and only return the `id` + * const alertWithIdOnly = await prisma.alert.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: SelectSubset>): Prisma.PrismaPromise<$Result.GetResult, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one Alert. + * @param {AlertUpsertArgs} args - Arguments to update or create a Alert. + * @example + * // Update or create a Alert + * const alert = await prisma.alert.upsert({ + * create: { + * // ... data to create a Alert + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the Alert we want to update + * } + * }) + */ + upsert(args: SelectSubset>): Prisma__AlertClient<$Result.GetResult, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of Alerts. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AlertCountArgs} args - Arguments to filter Alerts to count. + * @example + * // Count the number of Alerts + * const count = await prisma.alert.count({ + * where: { + * // ... the filter for the Alerts we want to count + * } + * }) + **/ + count( + args?: Subset, + ): Prisma.PrismaPromise< + T extends $Utils.Record<'select', any> + ? T['select'] extends true + ? number + : GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a Alert. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AlertAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Subset): Prisma.PrismaPromise> + + /** + * Group by Alert. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {AlertGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends AlertGroupByArgs, + HasSelectOrTake extends Or< + Extends<'skip', Keys>, + Extends<'take', Keys> + >, + OrderByArg extends True extends HasSelectOrTake + ? { orderBy: AlertGroupByArgs['orderBy'] } + : { orderBy?: AlertGroupByArgs['orderBy'] }, + OrderFields extends ExcludeUnderscoreKeys>>, + ByFields extends MaybeTupleToUnion, + ByValid extends Has, + HavingFields extends GetHavingFields, + HavingValid extends Has, + ByEmpty extends T['by'] extends never[] ? True : False, + InputErrors extends ByEmpty extends True + ? `Error: "by" must not be empty.` + : HavingValid extends False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Keys + ? 'orderBy' extends Keys + ? ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: SubsetIntersection & InputErrors): {} extends InputErrors ? GetAlertGroupByPayload : Prisma.PrismaPromise + /** + * Fields of the Alert model + */ + readonly fields: AlertFieldRefs; + } + + /** + * The delegate class that acts as a "Promise-like" for Alert. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ + export interface Prisma__AlertClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + user = {}>(args?: Subset>): Prisma__UserClient<$Result.GetResult, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + market = {}>(args?: Subset>): Prisma__MarketClient<$Result.GetResult, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): $Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): $Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): $Utils.JsPromise + } + + + + + /** + * Fields of the Alert model + */ + interface AlertFieldRefs { + readonly id: FieldRef<"Alert", 'Int'> + readonly userId: FieldRef<"Alert", 'Int'> + readonly marketId: FieldRef<"Alert", 'String'> + readonly type: FieldRef<"Alert", 'String'> + readonly message: FieldRef<"Alert", 'String'> + readonly sentAt: FieldRef<"Alert", 'DateTime'> + } + + + // Custom InputTypes + /** + * Alert findUnique + */ + export type AlertFindUniqueArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelect | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertInclude | null + /** + * Filter, which Alert to fetch. + */ + where: AlertWhereUniqueInput + } + + /** + * Alert findUniqueOrThrow + */ + export type AlertFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelect | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertInclude | null + /** + * Filter, which Alert to fetch. + */ + where: AlertWhereUniqueInput + } + + /** + * Alert findFirst + */ + export type AlertFindFirstArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelect | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertInclude | null + /** + * Filter, which Alert to fetch. + */ + where?: AlertWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Alerts to fetch. + */ + orderBy?: AlertOrderByWithRelationInput | AlertOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Alerts. + */ + cursor?: AlertWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Alerts from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Alerts. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Alerts. + */ + distinct?: AlertScalarFieldEnum | AlertScalarFieldEnum[] + } + + /** + * Alert findFirstOrThrow + */ + export type AlertFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelect | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertInclude | null + /** + * Filter, which Alert to fetch. + */ + where?: AlertWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Alerts to fetch. + */ + orderBy?: AlertOrderByWithRelationInput | AlertOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Alerts. + */ + cursor?: AlertWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Alerts from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Alerts. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Alerts. + */ + distinct?: AlertScalarFieldEnum | AlertScalarFieldEnum[] + } + + /** + * Alert findMany + */ + export type AlertFindManyArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelect | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertInclude | null + /** + * Filter, which Alerts to fetch. + */ + where?: AlertWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Alerts to fetch. + */ + orderBy?: AlertOrderByWithRelationInput | AlertOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Alerts. + */ + cursor?: AlertWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Alerts from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Alerts. + */ + skip?: number + distinct?: AlertScalarFieldEnum | AlertScalarFieldEnum[] + } + + /** + * Alert create + */ + export type AlertCreateArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelect | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertInclude | null + /** + * The data needed to create a Alert. + */ + data: XOR + } + + /** + * Alert createMany + */ + export type AlertCreateManyArgs = { + /** + * The data used to create many Alerts. + */ + data: AlertCreateManyInput | AlertCreateManyInput[] + } + + /** + * Alert createManyAndReturn + */ + export type AlertCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelectCreateManyAndReturn | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * The data used to create many Alerts. + */ + data: AlertCreateManyInput | AlertCreateManyInput[] + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertIncludeCreateManyAndReturn | null + } + + /** + * Alert update + */ + export type AlertUpdateArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelect | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertInclude | null + /** + * The data needed to update a Alert. + */ + data: XOR + /** + * Choose, which Alert to update. + */ + where: AlertWhereUniqueInput + } + + /** + * Alert updateMany + */ + export type AlertUpdateManyArgs = { + /** + * The data used to update Alerts. + */ + data: XOR + /** + * Filter which Alerts to update + */ + where?: AlertWhereInput + /** + * Limit how many Alerts to update. + */ + limit?: number + } + + /** + * Alert updateManyAndReturn + */ + export type AlertUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * The data used to update Alerts. + */ + data: XOR + /** + * Filter which Alerts to update + */ + where?: AlertWhereInput + /** + * Limit how many Alerts to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertIncludeUpdateManyAndReturn | null + } + + /** + * Alert upsert + */ + export type AlertUpsertArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelect | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertInclude | null + /** + * The filter to search for the Alert to update in case it exists. + */ + where: AlertWhereUniqueInput + /** + * In case the Alert found by the `where` argument doesn't exist, create a new Alert with this data. + */ + create: XOR + /** + * In case the Alert was found with the provided `where` argument, update it with this data. + */ + update: XOR + } + + /** + * Alert delete + */ + export type AlertDeleteArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelect | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertInclude | null + /** + * Filter which Alert to delete. + */ + where: AlertWhereUniqueInput + } + + /** + * Alert deleteMany + */ + export type AlertDeleteManyArgs = { + /** + * Filter which Alerts to delete + */ + where?: AlertWhereInput + /** + * Limit how many Alerts to delete. + */ + limit?: number + } + + /** + * Alert without action + */ + export type AlertDefaultArgs = { + /** + * Select specific fields to fetch from the Alert + */ + select?: AlertSelect | null + /** + * Omit specific fields from the Alert + */ + omit?: AlertOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: AlertInclude | null + } + + + /** + * Enums + */ + + export const TransactionIsolationLevel: { + Serializable: 'Serializable' + }; + + export type TransactionIsolationLevel = (typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel] + + + export const UserScalarFieldEnum: { + id: 'id', + email: 'email', + passwordHash: 'passwordHash', + isActive: 'isActive', + telegramChatId: 'telegramChatId', + createdAt: 'createdAt', + updatedAt: 'updatedAt' + }; + + export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum] + + + export const MarketScalarFieldEnum: { + id: 'id', + question: 'question', + category: 'category', + countryCode: 'countryCode', + yesPrice: 'yesPrice', + noPrice: 'noPrice', + volumeEur: 'volumeEur', + liquidityEur: 'liquidityEur', + spread: 'spread', + bestBid: 'bestBid', + bestAsk: 'bestAsk', + clobTokenId: 'clobTokenId', + analyzable: 'analyzable', + status: 'status', + closesAt: 'closesAt', + lastSynced: 'lastSynced' + }; + + export type MarketScalarFieldEnum = (typeof MarketScalarFieldEnum)[keyof typeof MarketScalarFieldEnum] + + + export const AISignalScalarFieldEnum: { + id: 'id', + marketId: 'marketId', + signal: 'signal', + confidence: 'confidence', + summary: 'summary', + keyRisk: 'keyRisk', + newsCount: 'newsCount', + modelVersion: 'modelVersion', + impliedProb: 'impliedProb', + fairProb: 'fairProb', + edgePoints: 'edgePoints', + generatedAt: 'generatedAt' + }; + + export type AISignalScalarFieldEnum = (typeof AISignalScalarFieldEnum)[keyof typeof AISignalScalarFieldEnum] + + + export const PositionScalarFieldEnum: { + id: 'id', + userId: 'userId', + marketId: 'marketId', + outcome: 'outcome', + amountEur: 'amountEur', + entryPrice: 'entryPrice', + currentPrice: 'currentPrice', + pnl: 'pnl', + kellyFraction: 'kellyFraction', + status: 'status', + openedAt: 'openedAt', + closedAt: 'closedAt' + }; + + export type PositionScalarFieldEnum = (typeof PositionScalarFieldEnum)[keyof typeof PositionScalarFieldEnum] + + + export const WatchlistScalarFieldEnum: { + id: 'id', + userId: 'userId', + marketId: 'marketId', + alertThreshold: 'alertThreshold', + createdAt: 'createdAt' + }; + + export type WatchlistScalarFieldEnum = (typeof WatchlistScalarFieldEnum)[keyof typeof WatchlistScalarFieldEnum] + + + export const AlertScalarFieldEnum: { + id: 'id', + userId: 'userId', + marketId: 'marketId', + type: 'type', + message: 'message', + sentAt: 'sentAt' + }; + + export type AlertScalarFieldEnum = (typeof AlertScalarFieldEnum)[keyof typeof AlertScalarFieldEnum] + + + export const SortOrder: { + asc: 'asc', + desc: 'desc' + }; + + export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder] + + + export const NullsOrder: { + first: 'first', + last: 'last' + }; + + export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder] + + + /** + * Field references + */ + + + /** + * Reference to a field of type 'Int' + */ + export type IntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Int'> + + + + /** + * Reference to a field of type 'String' + */ + export type StringFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'String'> + + + + /** + * Reference to a field of type 'Boolean' + */ + export type BooleanFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Boolean'> + + + + /** + * Reference to a field of type 'DateTime' + */ + export type DateTimeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'DateTime'> + + + + /** + * Reference to a field of type 'Float' + */ + export type FloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float'> + + /** + * Deep Input Types + */ + + + export type UserWhereInput = { + AND?: UserWhereInput | UserWhereInput[] + OR?: UserWhereInput[] + NOT?: UserWhereInput | UserWhereInput[] + id?: IntFilter<"User"> | number + email?: StringFilter<"User"> | string + passwordHash?: StringFilter<"User"> | string + isActive?: BoolFilter<"User"> | boolean + telegramChatId?: StringNullableFilter<"User"> | string | null + createdAt?: DateTimeFilter<"User"> | Date | string + updatedAt?: DateTimeFilter<"User"> | Date | string + positions?: PositionListRelationFilter + watchlist?: WatchlistListRelationFilter + alerts?: AlertListRelationFilter + } + + export type UserOrderByWithRelationInput = { + id?: SortOrder + email?: SortOrder + passwordHash?: SortOrder + isActive?: SortOrder + telegramChatId?: SortOrderInput | SortOrder + createdAt?: SortOrder + updatedAt?: SortOrder + positions?: PositionOrderByRelationAggregateInput + watchlist?: WatchlistOrderByRelationAggregateInput + alerts?: AlertOrderByRelationAggregateInput + } + + export type UserWhereUniqueInput = Prisma.AtLeast<{ + id?: number + email?: string + AND?: UserWhereInput | UserWhereInput[] + OR?: UserWhereInput[] + NOT?: UserWhereInput | UserWhereInput[] + passwordHash?: StringFilter<"User"> | string + isActive?: BoolFilter<"User"> | boolean + telegramChatId?: StringNullableFilter<"User"> | string | null + createdAt?: DateTimeFilter<"User"> | Date | string + updatedAt?: DateTimeFilter<"User"> | Date | string + positions?: PositionListRelationFilter + watchlist?: WatchlistListRelationFilter + alerts?: AlertListRelationFilter + }, "id" | "email"> + + export type UserOrderByWithAggregationInput = { + id?: SortOrder + email?: SortOrder + passwordHash?: SortOrder + isActive?: SortOrder + telegramChatId?: SortOrderInput | SortOrder + createdAt?: SortOrder + updatedAt?: SortOrder + _count?: UserCountOrderByAggregateInput + _avg?: UserAvgOrderByAggregateInput + _max?: UserMaxOrderByAggregateInput + _min?: UserMinOrderByAggregateInput + _sum?: UserSumOrderByAggregateInput + } + + export type UserScalarWhereWithAggregatesInput = { + AND?: UserScalarWhereWithAggregatesInput | UserScalarWhereWithAggregatesInput[] + OR?: UserScalarWhereWithAggregatesInput[] + NOT?: UserScalarWhereWithAggregatesInput | UserScalarWhereWithAggregatesInput[] + id?: IntWithAggregatesFilter<"User"> | number + email?: StringWithAggregatesFilter<"User"> | string + passwordHash?: StringWithAggregatesFilter<"User"> | string + isActive?: BoolWithAggregatesFilter<"User"> | boolean + telegramChatId?: StringNullableWithAggregatesFilter<"User"> | string | null + createdAt?: DateTimeWithAggregatesFilter<"User"> | Date | string + updatedAt?: DateTimeWithAggregatesFilter<"User"> | Date | string + } + + export type MarketWhereInput = { + AND?: MarketWhereInput | MarketWhereInput[] + OR?: MarketWhereInput[] + NOT?: MarketWhereInput | MarketWhereInput[] + id?: StringFilter<"Market"> | string + question?: StringFilter<"Market"> | string + category?: StringNullableFilter<"Market"> | string | null + countryCode?: StringNullableFilter<"Market"> | string | null + yesPrice?: FloatNullableFilter<"Market"> | number | null + noPrice?: FloatNullableFilter<"Market"> | number | null + volumeEur?: FloatNullableFilter<"Market"> | number | null + liquidityEur?: FloatNullableFilter<"Market"> | number | null + spread?: FloatNullableFilter<"Market"> | number | null + bestBid?: FloatNullableFilter<"Market"> | number | null + bestAsk?: FloatNullableFilter<"Market"> | number | null + clobTokenId?: StringNullableFilter<"Market"> | string | null + analyzable?: BoolFilter<"Market"> | boolean + status?: StringFilter<"Market"> | string + closesAt?: DateTimeNullableFilter<"Market"> | Date | string | null + lastSynced?: DateTimeFilter<"Market"> | Date | string + signals?: AISignalListRelationFilter + positions?: PositionListRelationFilter + watchlist?: WatchlistListRelationFilter + alerts?: AlertListRelationFilter + } + + export type MarketOrderByWithRelationInput = { + id?: SortOrder + question?: SortOrder + category?: SortOrderInput | SortOrder + countryCode?: SortOrderInput | SortOrder + yesPrice?: SortOrderInput | SortOrder + noPrice?: SortOrderInput | SortOrder + volumeEur?: SortOrderInput | SortOrder + liquidityEur?: SortOrderInput | SortOrder + spread?: SortOrderInput | SortOrder + bestBid?: SortOrderInput | SortOrder + bestAsk?: SortOrderInput | SortOrder + clobTokenId?: SortOrderInput | SortOrder + analyzable?: SortOrder + status?: SortOrder + closesAt?: SortOrderInput | SortOrder + lastSynced?: SortOrder + signals?: AISignalOrderByRelationAggregateInput + positions?: PositionOrderByRelationAggregateInput + watchlist?: WatchlistOrderByRelationAggregateInput + alerts?: AlertOrderByRelationAggregateInput + } + + export type MarketWhereUniqueInput = Prisma.AtLeast<{ + id?: string + AND?: MarketWhereInput | MarketWhereInput[] + OR?: MarketWhereInput[] + NOT?: MarketWhereInput | MarketWhereInput[] + question?: StringFilter<"Market"> | string + category?: StringNullableFilter<"Market"> | string | null + countryCode?: StringNullableFilter<"Market"> | string | null + yesPrice?: FloatNullableFilter<"Market"> | number | null + noPrice?: FloatNullableFilter<"Market"> | number | null + volumeEur?: FloatNullableFilter<"Market"> | number | null + liquidityEur?: FloatNullableFilter<"Market"> | number | null + spread?: FloatNullableFilter<"Market"> | number | null + bestBid?: FloatNullableFilter<"Market"> | number | null + bestAsk?: FloatNullableFilter<"Market"> | number | null + clobTokenId?: StringNullableFilter<"Market"> | string | null + analyzable?: BoolFilter<"Market"> | boolean + status?: StringFilter<"Market"> | string + closesAt?: DateTimeNullableFilter<"Market"> | Date | string | null + lastSynced?: DateTimeFilter<"Market"> | Date | string + signals?: AISignalListRelationFilter + positions?: PositionListRelationFilter + watchlist?: WatchlistListRelationFilter + alerts?: AlertListRelationFilter + }, "id"> + + export type MarketOrderByWithAggregationInput = { + id?: SortOrder + question?: SortOrder + category?: SortOrderInput | SortOrder + countryCode?: SortOrderInput | SortOrder + yesPrice?: SortOrderInput | SortOrder + noPrice?: SortOrderInput | SortOrder + volumeEur?: SortOrderInput | SortOrder + liquidityEur?: SortOrderInput | SortOrder + spread?: SortOrderInput | SortOrder + bestBid?: SortOrderInput | SortOrder + bestAsk?: SortOrderInput | SortOrder + clobTokenId?: SortOrderInput | SortOrder + analyzable?: SortOrder + status?: SortOrder + closesAt?: SortOrderInput | SortOrder + lastSynced?: SortOrder + _count?: MarketCountOrderByAggregateInput + _avg?: MarketAvgOrderByAggregateInput + _max?: MarketMaxOrderByAggregateInput + _min?: MarketMinOrderByAggregateInput + _sum?: MarketSumOrderByAggregateInput + } + + export type MarketScalarWhereWithAggregatesInput = { + AND?: MarketScalarWhereWithAggregatesInput | MarketScalarWhereWithAggregatesInput[] + OR?: MarketScalarWhereWithAggregatesInput[] + NOT?: MarketScalarWhereWithAggregatesInput | MarketScalarWhereWithAggregatesInput[] + id?: StringWithAggregatesFilter<"Market"> | string + question?: StringWithAggregatesFilter<"Market"> | string + category?: StringNullableWithAggregatesFilter<"Market"> | string | null + countryCode?: StringNullableWithAggregatesFilter<"Market"> | string | null + yesPrice?: FloatNullableWithAggregatesFilter<"Market"> | number | null + noPrice?: FloatNullableWithAggregatesFilter<"Market"> | number | null + volumeEur?: FloatNullableWithAggregatesFilter<"Market"> | number | null + liquidityEur?: FloatNullableWithAggregatesFilter<"Market"> | number | null + spread?: FloatNullableWithAggregatesFilter<"Market"> | number | null + bestBid?: FloatNullableWithAggregatesFilter<"Market"> | number | null + bestAsk?: FloatNullableWithAggregatesFilter<"Market"> | number | null + clobTokenId?: StringNullableWithAggregatesFilter<"Market"> | string | null + analyzable?: BoolWithAggregatesFilter<"Market"> | boolean + status?: StringWithAggregatesFilter<"Market"> | string + closesAt?: DateTimeNullableWithAggregatesFilter<"Market"> | Date | string | null + lastSynced?: DateTimeWithAggregatesFilter<"Market"> | Date | string + } + + export type AISignalWhereInput = { + AND?: AISignalWhereInput | AISignalWhereInput[] + OR?: AISignalWhereInput[] + NOT?: AISignalWhereInput | AISignalWhereInput[] + id?: IntFilter<"AISignal"> | number + marketId?: StringFilter<"AISignal"> | string + signal?: StringFilter<"AISignal"> | string + confidence?: FloatFilter<"AISignal"> | number + summary?: StringNullableFilter<"AISignal"> | string | null + keyRisk?: StringNullableFilter<"AISignal"> | string | null + newsCount?: IntFilter<"AISignal"> | number + modelVersion?: StringFilter<"AISignal"> | string + impliedProb?: FloatNullableFilter<"AISignal"> | number | null + fairProb?: FloatNullableFilter<"AISignal"> | number | null + edgePoints?: FloatNullableFilter<"AISignal"> | number | null + generatedAt?: DateTimeFilter<"AISignal"> | Date | string + market?: XOR + } + + export type AISignalOrderByWithRelationInput = { + id?: SortOrder + marketId?: SortOrder + signal?: SortOrder + confidence?: SortOrder + summary?: SortOrderInput | SortOrder + keyRisk?: SortOrderInput | SortOrder + newsCount?: SortOrder + modelVersion?: SortOrder + impliedProb?: SortOrderInput | SortOrder + fairProb?: SortOrderInput | SortOrder + edgePoints?: SortOrderInput | SortOrder + generatedAt?: SortOrder + market?: MarketOrderByWithRelationInput + } + + export type AISignalWhereUniqueInput = Prisma.AtLeast<{ + id?: number + AND?: AISignalWhereInput | AISignalWhereInput[] + OR?: AISignalWhereInput[] + NOT?: AISignalWhereInput | AISignalWhereInput[] + marketId?: StringFilter<"AISignal"> | string + signal?: StringFilter<"AISignal"> | string + confidence?: FloatFilter<"AISignal"> | number + summary?: StringNullableFilter<"AISignal"> | string | null + keyRisk?: StringNullableFilter<"AISignal"> | string | null + newsCount?: IntFilter<"AISignal"> | number + modelVersion?: StringFilter<"AISignal"> | string + impliedProb?: FloatNullableFilter<"AISignal"> | number | null + fairProb?: FloatNullableFilter<"AISignal"> | number | null + edgePoints?: FloatNullableFilter<"AISignal"> | number | null + generatedAt?: DateTimeFilter<"AISignal"> | Date | string + market?: XOR + }, "id"> + + export type AISignalOrderByWithAggregationInput = { + id?: SortOrder + marketId?: SortOrder + signal?: SortOrder + confidence?: SortOrder + summary?: SortOrderInput | SortOrder + keyRisk?: SortOrderInput | SortOrder + newsCount?: SortOrder + modelVersion?: SortOrder + impliedProb?: SortOrderInput | SortOrder + fairProb?: SortOrderInput | SortOrder + edgePoints?: SortOrderInput | SortOrder + generatedAt?: SortOrder + _count?: AISignalCountOrderByAggregateInput + _avg?: AISignalAvgOrderByAggregateInput + _max?: AISignalMaxOrderByAggregateInput + _min?: AISignalMinOrderByAggregateInput + _sum?: AISignalSumOrderByAggregateInput + } + + export type AISignalScalarWhereWithAggregatesInput = { + AND?: AISignalScalarWhereWithAggregatesInput | AISignalScalarWhereWithAggregatesInput[] + OR?: AISignalScalarWhereWithAggregatesInput[] + NOT?: AISignalScalarWhereWithAggregatesInput | AISignalScalarWhereWithAggregatesInput[] + id?: IntWithAggregatesFilter<"AISignal"> | number + marketId?: StringWithAggregatesFilter<"AISignal"> | string + signal?: StringWithAggregatesFilter<"AISignal"> | string + confidence?: FloatWithAggregatesFilter<"AISignal"> | number + summary?: StringNullableWithAggregatesFilter<"AISignal"> | string | null + keyRisk?: StringNullableWithAggregatesFilter<"AISignal"> | string | null + newsCount?: IntWithAggregatesFilter<"AISignal"> | number + modelVersion?: StringWithAggregatesFilter<"AISignal"> | string + impliedProb?: FloatNullableWithAggregatesFilter<"AISignal"> | number | null + fairProb?: FloatNullableWithAggregatesFilter<"AISignal"> | number | null + edgePoints?: FloatNullableWithAggregatesFilter<"AISignal"> | number | null + generatedAt?: DateTimeWithAggregatesFilter<"AISignal"> | Date | string + } + + export type PositionWhereInput = { + AND?: PositionWhereInput | PositionWhereInput[] + OR?: PositionWhereInput[] + NOT?: PositionWhereInput | PositionWhereInput[] + id?: IntFilter<"Position"> | number + userId?: IntFilter<"Position"> | number + marketId?: StringFilter<"Position"> | string + outcome?: StringFilter<"Position"> | string + amountEur?: FloatFilter<"Position"> | number + entryPrice?: FloatFilter<"Position"> | number + currentPrice?: FloatNullableFilter<"Position"> | number | null + pnl?: FloatFilter<"Position"> | number + kellyFraction?: FloatNullableFilter<"Position"> | number | null + status?: StringFilter<"Position"> | string + openedAt?: DateTimeFilter<"Position"> | Date | string + closedAt?: DateTimeNullableFilter<"Position"> | Date | string | null + user?: XOR + market?: XOR + } + + export type PositionOrderByWithRelationInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + outcome?: SortOrder + amountEur?: SortOrder + entryPrice?: SortOrder + currentPrice?: SortOrderInput | SortOrder + pnl?: SortOrder + kellyFraction?: SortOrderInput | SortOrder + status?: SortOrder + openedAt?: SortOrder + closedAt?: SortOrderInput | SortOrder + user?: UserOrderByWithRelationInput + market?: MarketOrderByWithRelationInput + } + + export type PositionWhereUniqueInput = Prisma.AtLeast<{ + id?: number + AND?: PositionWhereInput | PositionWhereInput[] + OR?: PositionWhereInput[] + NOT?: PositionWhereInput | PositionWhereInput[] + userId?: IntFilter<"Position"> | number + marketId?: StringFilter<"Position"> | string + outcome?: StringFilter<"Position"> | string + amountEur?: FloatFilter<"Position"> | number + entryPrice?: FloatFilter<"Position"> | number + currentPrice?: FloatNullableFilter<"Position"> | number | null + pnl?: FloatFilter<"Position"> | number + kellyFraction?: FloatNullableFilter<"Position"> | number | null + status?: StringFilter<"Position"> | string + openedAt?: DateTimeFilter<"Position"> | Date | string + closedAt?: DateTimeNullableFilter<"Position"> | Date | string | null + user?: XOR + market?: XOR + }, "id"> + + export type PositionOrderByWithAggregationInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + outcome?: SortOrder + amountEur?: SortOrder + entryPrice?: SortOrder + currentPrice?: SortOrderInput | SortOrder + pnl?: SortOrder + kellyFraction?: SortOrderInput | SortOrder + status?: SortOrder + openedAt?: SortOrder + closedAt?: SortOrderInput | SortOrder + _count?: PositionCountOrderByAggregateInput + _avg?: PositionAvgOrderByAggregateInput + _max?: PositionMaxOrderByAggregateInput + _min?: PositionMinOrderByAggregateInput + _sum?: PositionSumOrderByAggregateInput + } + + export type PositionScalarWhereWithAggregatesInput = { + AND?: PositionScalarWhereWithAggregatesInput | PositionScalarWhereWithAggregatesInput[] + OR?: PositionScalarWhereWithAggregatesInput[] + NOT?: PositionScalarWhereWithAggregatesInput | PositionScalarWhereWithAggregatesInput[] + id?: IntWithAggregatesFilter<"Position"> | number + userId?: IntWithAggregatesFilter<"Position"> | number + marketId?: StringWithAggregatesFilter<"Position"> | string + outcome?: StringWithAggregatesFilter<"Position"> | string + amountEur?: FloatWithAggregatesFilter<"Position"> | number + entryPrice?: FloatWithAggregatesFilter<"Position"> | number + currentPrice?: FloatNullableWithAggregatesFilter<"Position"> | number | null + pnl?: FloatWithAggregatesFilter<"Position"> | number + kellyFraction?: FloatNullableWithAggregatesFilter<"Position"> | number | null + status?: StringWithAggregatesFilter<"Position"> | string + openedAt?: DateTimeWithAggregatesFilter<"Position"> | Date | string + closedAt?: DateTimeNullableWithAggregatesFilter<"Position"> | Date | string | null + } + + export type WatchlistWhereInput = { + AND?: WatchlistWhereInput | WatchlistWhereInput[] + OR?: WatchlistWhereInput[] + NOT?: WatchlistWhereInput | WatchlistWhereInput[] + id?: IntFilter<"Watchlist"> | number + userId?: IntFilter<"Watchlist"> | number + marketId?: StringFilter<"Watchlist"> | string + alertThreshold?: FloatNullableFilter<"Watchlist"> | number | null + createdAt?: DateTimeFilter<"Watchlist"> | Date | string + user?: XOR + market?: XOR + } + + export type WatchlistOrderByWithRelationInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + alertThreshold?: SortOrderInput | SortOrder + createdAt?: SortOrder + user?: UserOrderByWithRelationInput + market?: MarketOrderByWithRelationInput + } + + export type WatchlistWhereUniqueInput = Prisma.AtLeast<{ + id?: number + userId_marketId?: WatchlistUserIdMarketIdCompoundUniqueInput + AND?: WatchlistWhereInput | WatchlistWhereInput[] + OR?: WatchlistWhereInput[] + NOT?: WatchlistWhereInput | WatchlistWhereInput[] + userId?: IntFilter<"Watchlist"> | number + marketId?: StringFilter<"Watchlist"> | string + alertThreshold?: FloatNullableFilter<"Watchlist"> | number | null + createdAt?: DateTimeFilter<"Watchlist"> | Date | string + user?: XOR + market?: XOR + }, "id" | "userId_marketId"> + + export type WatchlistOrderByWithAggregationInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + alertThreshold?: SortOrderInput | SortOrder + createdAt?: SortOrder + _count?: WatchlistCountOrderByAggregateInput + _avg?: WatchlistAvgOrderByAggregateInput + _max?: WatchlistMaxOrderByAggregateInput + _min?: WatchlistMinOrderByAggregateInput + _sum?: WatchlistSumOrderByAggregateInput + } + + export type WatchlistScalarWhereWithAggregatesInput = { + AND?: WatchlistScalarWhereWithAggregatesInput | WatchlistScalarWhereWithAggregatesInput[] + OR?: WatchlistScalarWhereWithAggregatesInput[] + NOT?: WatchlistScalarWhereWithAggregatesInput | WatchlistScalarWhereWithAggregatesInput[] + id?: IntWithAggregatesFilter<"Watchlist"> | number + userId?: IntWithAggregatesFilter<"Watchlist"> | number + marketId?: StringWithAggregatesFilter<"Watchlist"> | string + alertThreshold?: FloatNullableWithAggregatesFilter<"Watchlist"> | number | null + createdAt?: DateTimeWithAggregatesFilter<"Watchlist"> | Date | string + } + + export type AlertWhereInput = { + AND?: AlertWhereInput | AlertWhereInput[] + OR?: AlertWhereInput[] + NOT?: AlertWhereInput | AlertWhereInput[] + id?: IntFilter<"Alert"> | number + userId?: IntFilter<"Alert"> | number + marketId?: StringFilter<"Alert"> | string + type?: StringFilter<"Alert"> | string + message?: StringFilter<"Alert"> | string + sentAt?: DateTimeFilter<"Alert"> | Date | string + user?: XOR + market?: XOR + } + + export type AlertOrderByWithRelationInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + type?: SortOrder + message?: SortOrder + sentAt?: SortOrder + user?: UserOrderByWithRelationInput + market?: MarketOrderByWithRelationInput + } + + export type AlertWhereUniqueInput = Prisma.AtLeast<{ + id?: number + AND?: AlertWhereInput | AlertWhereInput[] + OR?: AlertWhereInput[] + NOT?: AlertWhereInput | AlertWhereInput[] + userId?: IntFilter<"Alert"> | number + marketId?: StringFilter<"Alert"> | string + type?: StringFilter<"Alert"> | string + message?: StringFilter<"Alert"> | string + sentAt?: DateTimeFilter<"Alert"> | Date | string + user?: XOR + market?: XOR + }, "id"> + + export type AlertOrderByWithAggregationInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + type?: SortOrder + message?: SortOrder + sentAt?: SortOrder + _count?: AlertCountOrderByAggregateInput + _avg?: AlertAvgOrderByAggregateInput + _max?: AlertMaxOrderByAggregateInput + _min?: AlertMinOrderByAggregateInput + _sum?: AlertSumOrderByAggregateInput + } + + export type AlertScalarWhereWithAggregatesInput = { + AND?: AlertScalarWhereWithAggregatesInput | AlertScalarWhereWithAggregatesInput[] + OR?: AlertScalarWhereWithAggregatesInput[] + NOT?: AlertScalarWhereWithAggregatesInput | AlertScalarWhereWithAggregatesInput[] + id?: IntWithAggregatesFilter<"Alert"> | number + userId?: IntWithAggregatesFilter<"Alert"> | number + marketId?: StringWithAggregatesFilter<"Alert"> | string + type?: StringWithAggregatesFilter<"Alert"> | string + message?: StringWithAggregatesFilter<"Alert"> | string + sentAt?: DateTimeWithAggregatesFilter<"Alert"> | Date | string + } + + export type UserCreateInput = { + email: string + passwordHash: string + isActive?: boolean + telegramChatId?: string | null + createdAt?: Date | string + updatedAt?: Date | string + positions?: PositionCreateNestedManyWithoutUserInput + watchlist?: WatchlistCreateNestedManyWithoutUserInput + alerts?: AlertCreateNestedManyWithoutUserInput + } + + export type UserUncheckedCreateInput = { + id?: number + email: string + passwordHash: string + isActive?: boolean + telegramChatId?: string | null + createdAt?: Date | string + updatedAt?: Date | string + positions?: PositionUncheckedCreateNestedManyWithoutUserInput + watchlist?: WatchlistUncheckedCreateNestedManyWithoutUserInput + alerts?: AlertUncheckedCreateNestedManyWithoutUserInput + } + + export type UserUpdateInput = { + email?: StringFieldUpdateOperationsInput | string + passwordHash?: StringFieldUpdateOperationsInput | string + isActive?: BoolFieldUpdateOperationsInput | boolean + telegramChatId?: NullableStringFieldUpdateOperationsInput | string | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + positions?: PositionUpdateManyWithoutUserNestedInput + watchlist?: WatchlistUpdateManyWithoutUserNestedInput + alerts?: AlertUpdateManyWithoutUserNestedInput + } + + export type UserUncheckedUpdateInput = { + id?: IntFieldUpdateOperationsInput | number + email?: StringFieldUpdateOperationsInput | string + passwordHash?: StringFieldUpdateOperationsInput | string + isActive?: BoolFieldUpdateOperationsInput | boolean + telegramChatId?: NullableStringFieldUpdateOperationsInput | string | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + positions?: PositionUncheckedUpdateManyWithoutUserNestedInput + watchlist?: WatchlistUncheckedUpdateManyWithoutUserNestedInput + alerts?: AlertUncheckedUpdateManyWithoutUserNestedInput + } + + export type UserCreateManyInput = { + id?: number + email: string + passwordHash: string + isActive?: boolean + telegramChatId?: string | null + createdAt?: Date | string + updatedAt?: Date | string + } + + export type UserUpdateManyMutationInput = { + email?: StringFieldUpdateOperationsInput | string + passwordHash?: StringFieldUpdateOperationsInput | string + isActive?: BoolFieldUpdateOperationsInput | boolean + telegramChatId?: NullableStringFieldUpdateOperationsInput | string | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type UserUncheckedUpdateManyInput = { + id?: IntFieldUpdateOperationsInput | number + email?: StringFieldUpdateOperationsInput | string + passwordHash?: StringFieldUpdateOperationsInput | string + isActive?: BoolFieldUpdateOperationsInput | boolean + telegramChatId?: NullableStringFieldUpdateOperationsInput | string | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type MarketCreateInput = { + id: string + question: string + category?: string | null + countryCode?: string | null + yesPrice?: number | null + noPrice?: number | null + volumeEur?: number | null + liquidityEur?: number | null + spread?: number | null + bestBid?: number | null + bestAsk?: number | null + clobTokenId?: string | null + analyzable?: boolean + status?: string + closesAt?: Date | string | null + lastSynced?: Date | string + signals?: AISignalCreateNestedManyWithoutMarketInput + positions?: PositionCreateNestedManyWithoutMarketInput + watchlist?: WatchlistCreateNestedManyWithoutMarketInput + alerts?: AlertCreateNestedManyWithoutMarketInput + } + + export type MarketUncheckedCreateInput = { + id: string + question: string + category?: string | null + countryCode?: string | null + yesPrice?: number | null + noPrice?: number | null + volumeEur?: number | null + liquidityEur?: number | null + spread?: number | null + bestBid?: number | null + bestAsk?: number | null + clobTokenId?: string | null + analyzable?: boolean + status?: string + closesAt?: Date | string | null + lastSynced?: Date | string + signals?: AISignalUncheckedCreateNestedManyWithoutMarketInput + positions?: PositionUncheckedCreateNestedManyWithoutMarketInput + watchlist?: WatchlistUncheckedCreateNestedManyWithoutMarketInput + alerts?: AlertUncheckedCreateNestedManyWithoutMarketInput + } + + export type MarketUpdateInput = { + id?: StringFieldUpdateOperationsInput | string + question?: StringFieldUpdateOperationsInput | string + category?: NullableStringFieldUpdateOperationsInput | string | null + countryCode?: NullableStringFieldUpdateOperationsInput | string | null + yesPrice?: NullableFloatFieldUpdateOperationsInput | number | null + noPrice?: NullableFloatFieldUpdateOperationsInput | number | null + volumeEur?: NullableFloatFieldUpdateOperationsInput | number | null + liquidityEur?: NullableFloatFieldUpdateOperationsInput | number | null + spread?: NullableFloatFieldUpdateOperationsInput | number | null + bestBid?: NullableFloatFieldUpdateOperationsInput | number | null + bestAsk?: NullableFloatFieldUpdateOperationsInput | number | null + clobTokenId?: NullableStringFieldUpdateOperationsInput | string | null + analyzable?: BoolFieldUpdateOperationsInput | boolean + status?: StringFieldUpdateOperationsInput | string + closesAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lastSynced?: DateTimeFieldUpdateOperationsInput | Date | string + signals?: AISignalUpdateManyWithoutMarketNestedInput + positions?: PositionUpdateManyWithoutMarketNestedInput + watchlist?: WatchlistUpdateManyWithoutMarketNestedInput + alerts?: AlertUpdateManyWithoutMarketNestedInput + } + + export type MarketUncheckedUpdateInput = { + id?: StringFieldUpdateOperationsInput | string + question?: StringFieldUpdateOperationsInput | string + category?: NullableStringFieldUpdateOperationsInput | string | null + countryCode?: NullableStringFieldUpdateOperationsInput | string | null + yesPrice?: NullableFloatFieldUpdateOperationsInput | number | null + noPrice?: NullableFloatFieldUpdateOperationsInput | number | null + volumeEur?: NullableFloatFieldUpdateOperationsInput | number | null + liquidityEur?: NullableFloatFieldUpdateOperationsInput | number | null + spread?: NullableFloatFieldUpdateOperationsInput | number | null + bestBid?: NullableFloatFieldUpdateOperationsInput | number | null + bestAsk?: NullableFloatFieldUpdateOperationsInput | number | null + clobTokenId?: NullableStringFieldUpdateOperationsInput | string | null + analyzable?: BoolFieldUpdateOperationsInput | boolean + status?: StringFieldUpdateOperationsInput | string + closesAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lastSynced?: DateTimeFieldUpdateOperationsInput | Date | string + signals?: AISignalUncheckedUpdateManyWithoutMarketNestedInput + positions?: PositionUncheckedUpdateManyWithoutMarketNestedInput + watchlist?: WatchlistUncheckedUpdateManyWithoutMarketNestedInput + alerts?: AlertUncheckedUpdateManyWithoutMarketNestedInput + } + + export type MarketCreateManyInput = { + id: string + question: string + category?: string | null + countryCode?: string | null + yesPrice?: number | null + noPrice?: number | null + volumeEur?: number | null + liquidityEur?: number | null + spread?: number | null + bestBid?: number | null + bestAsk?: number | null + clobTokenId?: string | null + analyzable?: boolean + status?: string + closesAt?: Date | string | null + lastSynced?: Date | string + } + + export type MarketUpdateManyMutationInput = { + id?: StringFieldUpdateOperationsInput | string + question?: StringFieldUpdateOperationsInput | string + category?: NullableStringFieldUpdateOperationsInput | string | null + countryCode?: NullableStringFieldUpdateOperationsInput | string | null + yesPrice?: NullableFloatFieldUpdateOperationsInput | number | null + noPrice?: NullableFloatFieldUpdateOperationsInput | number | null + volumeEur?: NullableFloatFieldUpdateOperationsInput | number | null + liquidityEur?: NullableFloatFieldUpdateOperationsInput | number | null + spread?: NullableFloatFieldUpdateOperationsInput | number | null + bestBid?: NullableFloatFieldUpdateOperationsInput | number | null + bestAsk?: NullableFloatFieldUpdateOperationsInput | number | null + clobTokenId?: NullableStringFieldUpdateOperationsInput | string | null + analyzable?: BoolFieldUpdateOperationsInput | boolean + status?: StringFieldUpdateOperationsInput | string + closesAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lastSynced?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type MarketUncheckedUpdateManyInput = { + id?: StringFieldUpdateOperationsInput | string + question?: StringFieldUpdateOperationsInput | string + category?: NullableStringFieldUpdateOperationsInput | string | null + countryCode?: NullableStringFieldUpdateOperationsInput | string | null + yesPrice?: NullableFloatFieldUpdateOperationsInput | number | null + noPrice?: NullableFloatFieldUpdateOperationsInput | number | null + volumeEur?: NullableFloatFieldUpdateOperationsInput | number | null + liquidityEur?: NullableFloatFieldUpdateOperationsInput | number | null + spread?: NullableFloatFieldUpdateOperationsInput | number | null + bestBid?: NullableFloatFieldUpdateOperationsInput | number | null + bestAsk?: NullableFloatFieldUpdateOperationsInput | number | null + clobTokenId?: NullableStringFieldUpdateOperationsInput | string | null + analyzable?: BoolFieldUpdateOperationsInput | boolean + status?: StringFieldUpdateOperationsInput | string + closesAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lastSynced?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type AISignalCreateInput = { + signal: string + confidence: number + summary?: string | null + keyRisk?: string | null + newsCount?: number + modelVersion?: string + impliedProb?: number | null + fairProb?: number | null + edgePoints?: number | null + generatedAt?: Date | string + market: MarketCreateNestedOneWithoutSignalsInput + } + + export type AISignalUncheckedCreateInput = { + id?: number + marketId: string + signal: string + confidence: number + summary?: string | null + keyRisk?: string | null + newsCount?: number + modelVersion?: string + impliedProb?: number | null + fairProb?: number | null + edgePoints?: number | null + generatedAt?: Date | string + } + + export type AISignalUpdateInput = { + signal?: StringFieldUpdateOperationsInput | string + confidence?: FloatFieldUpdateOperationsInput | number + summary?: NullableStringFieldUpdateOperationsInput | string | null + keyRisk?: NullableStringFieldUpdateOperationsInput | string | null + newsCount?: IntFieldUpdateOperationsInput | number + modelVersion?: StringFieldUpdateOperationsInput | string + impliedProb?: NullableFloatFieldUpdateOperationsInput | number | null + fairProb?: NullableFloatFieldUpdateOperationsInput | number | null + edgePoints?: NullableFloatFieldUpdateOperationsInput | number | null + generatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + market?: MarketUpdateOneRequiredWithoutSignalsNestedInput + } + + export type AISignalUncheckedUpdateInput = { + id?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + signal?: StringFieldUpdateOperationsInput | string + confidence?: FloatFieldUpdateOperationsInput | number + summary?: NullableStringFieldUpdateOperationsInput | string | null + keyRisk?: NullableStringFieldUpdateOperationsInput | string | null + newsCount?: IntFieldUpdateOperationsInput | number + modelVersion?: StringFieldUpdateOperationsInput | string + impliedProb?: NullableFloatFieldUpdateOperationsInput | number | null + fairProb?: NullableFloatFieldUpdateOperationsInput | number | null + edgePoints?: NullableFloatFieldUpdateOperationsInput | number | null + generatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type AISignalCreateManyInput = { + id?: number + marketId: string + signal: string + confidence: number + summary?: string | null + keyRisk?: string | null + newsCount?: number + modelVersion?: string + impliedProb?: number | null + fairProb?: number | null + edgePoints?: number | null + generatedAt?: Date | string + } + + export type AISignalUpdateManyMutationInput = { + signal?: StringFieldUpdateOperationsInput | string + confidence?: FloatFieldUpdateOperationsInput | number + summary?: NullableStringFieldUpdateOperationsInput | string | null + keyRisk?: NullableStringFieldUpdateOperationsInput | string | null + newsCount?: IntFieldUpdateOperationsInput | number + modelVersion?: StringFieldUpdateOperationsInput | string + impliedProb?: NullableFloatFieldUpdateOperationsInput | number | null + fairProb?: NullableFloatFieldUpdateOperationsInput | number | null + edgePoints?: NullableFloatFieldUpdateOperationsInput | number | null + generatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type AISignalUncheckedUpdateManyInput = { + id?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + signal?: StringFieldUpdateOperationsInput | string + confidence?: FloatFieldUpdateOperationsInput | number + summary?: NullableStringFieldUpdateOperationsInput | string | null + keyRisk?: NullableStringFieldUpdateOperationsInput | string | null + newsCount?: IntFieldUpdateOperationsInput | number + modelVersion?: StringFieldUpdateOperationsInput | string + impliedProb?: NullableFloatFieldUpdateOperationsInput | number | null + fairProb?: NullableFloatFieldUpdateOperationsInput | number | null + edgePoints?: NullableFloatFieldUpdateOperationsInput | number | null + generatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type PositionCreateInput = { + outcome: string + amountEur: number + entryPrice: number + currentPrice?: number | null + pnl?: number + kellyFraction?: number | null + status?: string + openedAt?: Date | string + closedAt?: Date | string | null + user: UserCreateNestedOneWithoutPositionsInput + market: MarketCreateNestedOneWithoutPositionsInput + } + + export type PositionUncheckedCreateInput = { + id?: number + userId: number + marketId: string + outcome: string + amountEur: number + entryPrice: number + currentPrice?: number | null + pnl?: number + kellyFraction?: number | null + status?: string + openedAt?: Date | string + closedAt?: Date | string | null + } + + export type PositionUpdateInput = { + outcome?: StringFieldUpdateOperationsInput | string + amountEur?: FloatFieldUpdateOperationsInput | number + entryPrice?: FloatFieldUpdateOperationsInput | number + currentPrice?: NullableFloatFieldUpdateOperationsInput | number | null + pnl?: FloatFieldUpdateOperationsInput | number + kellyFraction?: NullableFloatFieldUpdateOperationsInput | number | null + status?: StringFieldUpdateOperationsInput | string + openedAt?: DateTimeFieldUpdateOperationsInput | Date | string + closedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + user?: UserUpdateOneRequiredWithoutPositionsNestedInput + market?: MarketUpdateOneRequiredWithoutPositionsNestedInput + } + + export type PositionUncheckedUpdateInput = { + id?: IntFieldUpdateOperationsInput | number + userId?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + outcome?: StringFieldUpdateOperationsInput | string + amountEur?: FloatFieldUpdateOperationsInput | number + entryPrice?: FloatFieldUpdateOperationsInput | number + currentPrice?: NullableFloatFieldUpdateOperationsInput | number | null + pnl?: FloatFieldUpdateOperationsInput | number + kellyFraction?: NullableFloatFieldUpdateOperationsInput | number | null + status?: StringFieldUpdateOperationsInput | string + openedAt?: DateTimeFieldUpdateOperationsInput | Date | string + closedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + } + + export type PositionCreateManyInput = { + id?: number + userId: number + marketId: string + outcome: string + amountEur: number + entryPrice: number + currentPrice?: number | null + pnl?: number + kellyFraction?: number | null + status?: string + openedAt?: Date | string + closedAt?: Date | string | null + } + + export type PositionUpdateManyMutationInput = { + outcome?: StringFieldUpdateOperationsInput | string + amountEur?: FloatFieldUpdateOperationsInput | number + entryPrice?: FloatFieldUpdateOperationsInput | number + currentPrice?: NullableFloatFieldUpdateOperationsInput | number | null + pnl?: FloatFieldUpdateOperationsInput | number + kellyFraction?: NullableFloatFieldUpdateOperationsInput | number | null + status?: StringFieldUpdateOperationsInput | string + openedAt?: DateTimeFieldUpdateOperationsInput | Date | string + closedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + } + + export type PositionUncheckedUpdateManyInput = { + id?: IntFieldUpdateOperationsInput | number + userId?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + outcome?: StringFieldUpdateOperationsInput | string + amountEur?: FloatFieldUpdateOperationsInput | number + entryPrice?: FloatFieldUpdateOperationsInput | number + currentPrice?: NullableFloatFieldUpdateOperationsInput | number | null + pnl?: FloatFieldUpdateOperationsInput | number + kellyFraction?: NullableFloatFieldUpdateOperationsInput | number | null + status?: StringFieldUpdateOperationsInput | string + openedAt?: DateTimeFieldUpdateOperationsInput | Date | string + closedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + } + + export type WatchlistCreateInput = { + alertThreshold?: number | null + createdAt?: Date | string + user: UserCreateNestedOneWithoutWatchlistInput + market: MarketCreateNestedOneWithoutWatchlistInput + } + + export type WatchlistUncheckedCreateInput = { + id?: number + userId: number + marketId: string + alertThreshold?: number | null + createdAt?: Date | string + } + + export type WatchlistUpdateInput = { + alertThreshold?: NullableFloatFieldUpdateOperationsInput | number | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + user?: UserUpdateOneRequiredWithoutWatchlistNestedInput + market?: MarketUpdateOneRequiredWithoutWatchlistNestedInput + } + + export type WatchlistUncheckedUpdateInput = { + id?: IntFieldUpdateOperationsInput | number + userId?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + alertThreshold?: NullableFloatFieldUpdateOperationsInput | number | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type WatchlistCreateManyInput = { + id?: number + userId: number + marketId: string + alertThreshold?: number | null + createdAt?: Date | string + } + + export type WatchlistUpdateManyMutationInput = { + alertThreshold?: NullableFloatFieldUpdateOperationsInput | number | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type WatchlistUncheckedUpdateManyInput = { + id?: IntFieldUpdateOperationsInput | number + userId?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + alertThreshold?: NullableFloatFieldUpdateOperationsInput | number | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type AlertCreateInput = { + type: string + message: string + sentAt?: Date | string + user: UserCreateNestedOneWithoutAlertsInput + market: MarketCreateNestedOneWithoutAlertsInput + } + + export type AlertUncheckedCreateInput = { + id?: number + userId: number + marketId: string + type: string + message: string + sentAt?: Date | string + } + + export type AlertUpdateInput = { + type?: StringFieldUpdateOperationsInput | string + message?: StringFieldUpdateOperationsInput | string + sentAt?: DateTimeFieldUpdateOperationsInput | Date | string + user?: UserUpdateOneRequiredWithoutAlertsNestedInput + market?: MarketUpdateOneRequiredWithoutAlertsNestedInput + } + + export type AlertUncheckedUpdateInput = { + id?: IntFieldUpdateOperationsInput | number + userId?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + type?: StringFieldUpdateOperationsInput | string + message?: StringFieldUpdateOperationsInput | string + sentAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type AlertCreateManyInput = { + id?: number + userId: number + marketId: string + type: string + message: string + sentAt?: Date | string + } + + export type AlertUpdateManyMutationInput = { + type?: StringFieldUpdateOperationsInput | string + message?: StringFieldUpdateOperationsInput | string + sentAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type AlertUncheckedUpdateManyInput = { + id?: IntFieldUpdateOperationsInput | number + userId?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + type?: StringFieldUpdateOperationsInput | string + message?: StringFieldUpdateOperationsInput | string + sentAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type IntFilter<$PrismaModel = never> = { + equals?: number | IntFieldRefInput<$PrismaModel> + in?: number[] + notIn?: number[] + lt?: number | IntFieldRefInput<$PrismaModel> + lte?: number | IntFieldRefInput<$PrismaModel> + gt?: number | IntFieldRefInput<$PrismaModel> + gte?: number | IntFieldRefInput<$PrismaModel> + not?: NestedIntFilter<$PrismaModel> | number + } + + export type StringFilter<$PrismaModel = never> = { + equals?: string | StringFieldRefInput<$PrismaModel> + in?: string[] + notIn?: string[] + lt?: string | StringFieldRefInput<$PrismaModel> + lte?: string | StringFieldRefInput<$PrismaModel> + gt?: string | StringFieldRefInput<$PrismaModel> + gte?: string | StringFieldRefInput<$PrismaModel> + contains?: string | StringFieldRefInput<$PrismaModel> + startsWith?: string | StringFieldRefInput<$PrismaModel> + endsWith?: string | StringFieldRefInput<$PrismaModel> + not?: NestedStringFilter<$PrismaModel> | string + } + + export type BoolFilter<$PrismaModel = never> = { + equals?: boolean | BooleanFieldRefInput<$PrismaModel> + not?: NestedBoolFilter<$PrismaModel> | boolean + } + + export type StringNullableFilter<$PrismaModel = never> = { + equals?: string | StringFieldRefInput<$PrismaModel> | null + in?: string[] | null + notIn?: string[] | null + lt?: string | StringFieldRefInput<$PrismaModel> + lte?: string | StringFieldRefInput<$PrismaModel> + gt?: string | StringFieldRefInput<$PrismaModel> + gte?: string | StringFieldRefInput<$PrismaModel> + contains?: string | StringFieldRefInput<$PrismaModel> + startsWith?: string | StringFieldRefInput<$PrismaModel> + endsWith?: string | StringFieldRefInput<$PrismaModel> + not?: NestedStringNullableFilter<$PrismaModel> | string | null + } + + export type DateTimeFilter<$PrismaModel = never> = { + equals?: Date | string | DateTimeFieldRefInput<$PrismaModel> + in?: Date[] | string[] + notIn?: Date[] | string[] + lt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + not?: NestedDateTimeFilter<$PrismaModel> | Date | string + } + + export type PositionListRelationFilter = { + every?: PositionWhereInput + some?: PositionWhereInput + none?: PositionWhereInput + } + + export type WatchlistListRelationFilter = { + every?: WatchlistWhereInput + some?: WatchlistWhereInput + none?: WatchlistWhereInput + } + + export type AlertListRelationFilter = { + every?: AlertWhereInput + some?: AlertWhereInput + none?: AlertWhereInput + } + + export type SortOrderInput = { + sort: SortOrder + nulls?: NullsOrder + } + + export type PositionOrderByRelationAggregateInput = { + _count?: SortOrder + } + + export type WatchlistOrderByRelationAggregateInput = { + _count?: SortOrder + } + + export type AlertOrderByRelationAggregateInput = { + _count?: SortOrder + } + + export type UserCountOrderByAggregateInput = { + id?: SortOrder + email?: SortOrder + passwordHash?: SortOrder + isActive?: SortOrder + telegramChatId?: SortOrder + createdAt?: SortOrder + updatedAt?: SortOrder + } + + export type UserAvgOrderByAggregateInput = { + id?: SortOrder + } + + export type UserMaxOrderByAggregateInput = { + id?: SortOrder + email?: SortOrder + passwordHash?: SortOrder + isActive?: SortOrder + telegramChatId?: SortOrder + createdAt?: SortOrder + updatedAt?: SortOrder + } + + export type UserMinOrderByAggregateInput = { + id?: SortOrder + email?: SortOrder + passwordHash?: SortOrder + isActive?: SortOrder + telegramChatId?: SortOrder + createdAt?: SortOrder + updatedAt?: SortOrder + } + + export type UserSumOrderByAggregateInput = { + id?: SortOrder + } + + export type IntWithAggregatesFilter<$PrismaModel = never> = { + equals?: number | IntFieldRefInput<$PrismaModel> + in?: number[] + notIn?: number[] + lt?: number | IntFieldRefInput<$PrismaModel> + lte?: number | IntFieldRefInput<$PrismaModel> + gt?: number | IntFieldRefInput<$PrismaModel> + gte?: number | IntFieldRefInput<$PrismaModel> + not?: NestedIntWithAggregatesFilter<$PrismaModel> | number + _count?: NestedIntFilter<$PrismaModel> + _avg?: NestedFloatFilter<$PrismaModel> + _sum?: NestedIntFilter<$PrismaModel> + _min?: NestedIntFilter<$PrismaModel> + _max?: NestedIntFilter<$PrismaModel> + } + + export type StringWithAggregatesFilter<$PrismaModel = never> = { + equals?: string | StringFieldRefInput<$PrismaModel> + in?: string[] + notIn?: string[] + lt?: string | StringFieldRefInput<$PrismaModel> + lte?: string | StringFieldRefInput<$PrismaModel> + gt?: string | StringFieldRefInput<$PrismaModel> + gte?: string | StringFieldRefInput<$PrismaModel> + contains?: string | StringFieldRefInput<$PrismaModel> + startsWith?: string | StringFieldRefInput<$PrismaModel> + endsWith?: string | StringFieldRefInput<$PrismaModel> + not?: NestedStringWithAggregatesFilter<$PrismaModel> | string + _count?: NestedIntFilter<$PrismaModel> + _min?: NestedStringFilter<$PrismaModel> + _max?: NestedStringFilter<$PrismaModel> + } + + export type BoolWithAggregatesFilter<$PrismaModel = never> = { + equals?: boolean | BooleanFieldRefInput<$PrismaModel> + not?: NestedBoolWithAggregatesFilter<$PrismaModel> | boolean + _count?: NestedIntFilter<$PrismaModel> + _min?: NestedBoolFilter<$PrismaModel> + _max?: NestedBoolFilter<$PrismaModel> + } + + export type StringNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: string | StringFieldRefInput<$PrismaModel> | null + in?: string[] | null + notIn?: string[] | null + lt?: string | StringFieldRefInput<$PrismaModel> + lte?: string | StringFieldRefInput<$PrismaModel> + gt?: string | StringFieldRefInput<$PrismaModel> + gte?: string | StringFieldRefInput<$PrismaModel> + contains?: string | StringFieldRefInput<$PrismaModel> + startsWith?: string | StringFieldRefInput<$PrismaModel> + endsWith?: string | StringFieldRefInput<$PrismaModel> + not?: NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null + _count?: NestedIntNullableFilter<$PrismaModel> + _min?: NestedStringNullableFilter<$PrismaModel> + _max?: NestedStringNullableFilter<$PrismaModel> + } + + export type DateTimeWithAggregatesFilter<$PrismaModel = never> = { + equals?: Date | string | DateTimeFieldRefInput<$PrismaModel> + in?: Date[] | string[] + notIn?: Date[] | string[] + lt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + not?: NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string + _count?: NestedIntFilter<$PrismaModel> + _min?: NestedDateTimeFilter<$PrismaModel> + _max?: NestedDateTimeFilter<$PrismaModel> + } + + export type FloatNullableFilter<$PrismaModel = never> = { + equals?: number | FloatFieldRefInput<$PrismaModel> | null + in?: number[] | null + notIn?: number[] | null + lt?: number | FloatFieldRefInput<$PrismaModel> + lte?: number | FloatFieldRefInput<$PrismaModel> + gt?: number | FloatFieldRefInput<$PrismaModel> + gte?: number | FloatFieldRefInput<$PrismaModel> + not?: NestedFloatNullableFilter<$PrismaModel> | number | null + } + + export type DateTimeNullableFilter<$PrismaModel = never> = { + equals?: Date | string | DateTimeFieldRefInput<$PrismaModel> | null + in?: Date[] | string[] | null + notIn?: Date[] | string[] | null + lt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + not?: NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null + } + + export type AISignalListRelationFilter = { + every?: AISignalWhereInput + some?: AISignalWhereInput + none?: AISignalWhereInput + } + + export type AISignalOrderByRelationAggregateInput = { + _count?: SortOrder + } + + export type MarketCountOrderByAggregateInput = { + id?: SortOrder + question?: SortOrder + category?: SortOrder + countryCode?: SortOrder + yesPrice?: SortOrder + noPrice?: SortOrder + volumeEur?: SortOrder + liquidityEur?: SortOrder + spread?: SortOrder + bestBid?: SortOrder + bestAsk?: SortOrder + clobTokenId?: SortOrder + analyzable?: SortOrder + status?: SortOrder + closesAt?: SortOrder + lastSynced?: SortOrder + } + + export type MarketAvgOrderByAggregateInput = { + yesPrice?: SortOrder + noPrice?: SortOrder + volumeEur?: SortOrder + liquidityEur?: SortOrder + spread?: SortOrder + bestBid?: SortOrder + bestAsk?: SortOrder + } + + export type MarketMaxOrderByAggregateInput = { + id?: SortOrder + question?: SortOrder + category?: SortOrder + countryCode?: SortOrder + yesPrice?: SortOrder + noPrice?: SortOrder + volumeEur?: SortOrder + liquidityEur?: SortOrder + spread?: SortOrder + bestBid?: SortOrder + bestAsk?: SortOrder + clobTokenId?: SortOrder + analyzable?: SortOrder + status?: SortOrder + closesAt?: SortOrder + lastSynced?: SortOrder + } + + export type MarketMinOrderByAggregateInput = { + id?: SortOrder + question?: SortOrder + category?: SortOrder + countryCode?: SortOrder + yesPrice?: SortOrder + noPrice?: SortOrder + volumeEur?: SortOrder + liquidityEur?: SortOrder + spread?: SortOrder + bestBid?: SortOrder + bestAsk?: SortOrder + clobTokenId?: SortOrder + analyzable?: SortOrder + status?: SortOrder + closesAt?: SortOrder + lastSynced?: SortOrder + } + + export type MarketSumOrderByAggregateInput = { + yesPrice?: SortOrder + noPrice?: SortOrder + volumeEur?: SortOrder + liquidityEur?: SortOrder + spread?: SortOrder + bestBid?: SortOrder + bestAsk?: SortOrder + } + + export type FloatNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: number | FloatFieldRefInput<$PrismaModel> | null + in?: number[] | null + notIn?: number[] | null + lt?: number | FloatFieldRefInput<$PrismaModel> + lte?: number | FloatFieldRefInput<$PrismaModel> + gt?: number | FloatFieldRefInput<$PrismaModel> + gte?: number | FloatFieldRefInput<$PrismaModel> + not?: NestedFloatNullableWithAggregatesFilter<$PrismaModel> | number | null + _count?: NestedIntNullableFilter<$PrismaModel> + _avg?: NestedFloatNullableFilter<$PrismaModel> + _sum?: NestedFloatNullableFilter<$PrismaModel> + _min?: NestedFloatNullableFilter<$PrismaModel> + _max?: NestedFloatNullableFilter<$PrismaModel> + } + + export type DateTimeNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: Date | string | DateTimeFieldRefInput<$PrismaModel> | null + in?: Date[] | string[] | null + notIn?: Date[] | string[] | null + lt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + not?: NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null + _count?: NestedIntNullableFilter<$PrismaModel> + _min?: NestedDateTimeNullableFilter<$PrismaModel> + _max?: NestedDateTimeNullableFilter<$PrismaModel> + } + + export type FloatFilter<$PrismaModel = never> = { + equals?: number | FloatFieldRefInput<$PrismaModel> + in?: number[] + notIn?: number[] + lt?: number | FloatFieldRefInput<$PrismaModel> + lte?: number | FloatFieldRefInput<$PrismaModel> + gt?: number | FloatFieldRefInput<$PrismaModel> + gte?: number | FloatFieldRefInput<$PrismaModel> + not?: NestedFloatFilter<$PrismaModel> | number + } + + export type MarketScalarRelationFilter = { + is?: MarketWhereInput + isNot?: MarketWhereInput + } + + export type AISignalCountOrderByAggregateInput = { + id?: SortOrder + marketId?: SortOrder + signal?: SortOrder + confidence?: SortOrder + summary?: SortOrder + keyRisk?: SortOrder + newsCount?: SortOrder + modelVersion?: SortOrder + impliedProb?: SortOrder + fairProb?: SortOrder + edgePoints?: SortOrder + generatedAt?: SortOrder + } + + export type AISignalAvgOrderByAggregateInput = { + id?: SortOrder + confidence?: SortOrder + newsCount?: SortOrder + impliedProb?: SortOrder + fairProb?: SortOrder + edgePoints?: SortOrder + } + + export type AISignalMaxOrderByAggregateInput = { + id?: SortOrder + marketId?: SortOrder + signal?: SortOrder + confidence?: SortOrder + summary?: SortOrder + keyRisk?: SortOrder + newsCount?: SortOrder + modelVersion?: SortOrder + impliedProb?: SortOrder + fairProb?: SortOrder + edgePoints?: SortOrder + generatedAt?: SortOrder + } + + export type AISignalMinOrderByAggregateInput = { + id?: SortOrder + marketId?: SortOrder + signal?: SortOrder + confidence?: SortOrder + summary?: SortOrder + keyRisk?: SortOrder + newsCount?: SortOrder + modelVersion?: SortOrder + impliedProb?: SortOrder + fairProb?: SortOrder + edgePoints?: SortOrder + generatedAt?: SortOrder + } + + export type AISignalSumOrderByAggregateInput = { + id?: SortOrder + confidence?: SortOrder + newsCount?: SortOrder + impliedProb?: SortOrder + fairProb?: SortOrder + edgePoints?: SortOrder + } + + export type FloatWithAggregatesFilter<$PrismaModel = never> = { + equals?: number | FloatFieldRefInput<$PrismaModel> + in?: number[] + notIn?: number[] + lt?: number | FloatFieldRefInput<$PrismaModel> + lte?: number | FloatFieldRefInput<$PrismaModel> + gt?: number | FloatFieldRefInput<$PrismaModel> + gte?: number | FloatFieldRefInput<$PrismaModel> + not?: NestedFloatWithAggregatesFilter<$PrismaModel> | number + _count?: NestedIntFilter<$PrismaModel> + _avg?: NestedFloatFilter<$PrismaModel> + _sum?: NestedFloatFilter<$PrismaModel> + _min?: NestedFloatFilter<$PrismaModel> + _max?: NestedFloatFilter<$PrismaModel> + } + + export type UserScalarRelationFilter = { + is?: UserWhereInput + isNot?: UserWhereInput + } + + export type PositionCountOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + outcome?: SortOrder + amountEur?: SortOrder + entryPrice?: SortOrder + currentPrice?: SortOrder + pnl?: SortOrder + kellyFraction?: SortOrder + status?: SortOrder + openedAt?: SortOrder + closedAt?: SortOrder + } + + export type PositionAvgOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + amountEur?: SortOrder + entryPrice?: SortOrder + currentPrice?: SortOrder + pnl?: SortOrder + kellyFraction?: SortOrder + } + + export type PositionMaxOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + outcome?: SortOrder + amountEur?: SortOrder + entryPrice?: SortOrder + currentPrice?: SortOrder + pnl?: SortOrder + kellyFraction?: SortOrder + status?: SortOrder + openedAt?: SortOrder + closedAt?: SortOrder + } + + export type PositionMinOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + outcome?: SortOrder + amountEur?: SortOrder + entryPrice?: SortOrder + currentPrice?: SortOrder + pnl?: SortOrder + kellyFraction?: SortOrder + status?: SortOrder + openedAt?: SortOrder + closedAt?: SortOrder + } + + export type PositionSumOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + amountEur?: SortOrder + entryPrice?: SortOrder + currentPrice?: SortOrder + pnl?: SortOrder + kellyFraction?: SortOrder + } + + export type WatchlistUserIdMarketIdCompoundUniqueInput = { + userId: number + marketId: string + } + + export type WatchlistCountOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + alertThreshold?: SortOrder + createdAt?: SortOrder + } + + export type WatchlistAvgOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + alertThreshold?: SortOrder + } + + export type WatchlistMaxOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + alertThreshold?: SortOrder + createdAt?: SortOrder + } + + export type WatchlistMinOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + alertThreshold?: SortOrder + createdAt?: SortOrder + } + + export type WatchlistSumOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + alertThreshold?: SortOrder + } + + export type AlertCountOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + type?: SortOrder + message?: SortOrder + sentAt?: SortOrder + } + + export type AlertAvgOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + } + + export type AlertMaxOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + type?: SortOrder + message?: SortOrder + sentAt?: SortOrder + } + + export type AlertMinOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + marketId?: SortOrder + type?: SortOrder + message?: SortOrder + sentAt?: SortOrder + } + + export type AlertSumOrderByAggregateInput = { + id?: SortOrder + userId?: SortOrder + } + + export type PositionCreateNestedManyWithoutUserInput = { + create?: XOR | PositionCreateWithoutUserInput[] | PositionUncheckedCreateWithoutUserInput[] + connectOrCreate?: PositionCreateOrConnectWithoutUserInput | PositionCreateOrConnectWithoutUserInput[] + createMany?: PositionCreateManyUserInputEnvelope + connect?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + } + + export type WatchlistCreateNestedManyWithoutUserInput = { + create?: XOR | WatchlistCreateWithoutUserInput[] | WatchlistUncheckedCreateWithoutUserInput[] + connectOrCreate?: WatchlistCreateOrConnectWithoutUserInput | WatchlistCreateOrConnectWithoutUserInput[] + createMany?: WatchlistCreateManyUserInputEnvelope + connect?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + } + + export type AlertCreateNestedManyWithoutUserInput = { + create?: XOR | AlertCreateWithoutUserInput[] | AlertUncheckedCreateWithoutUserInput[] + connectOrCreate?: AlertCreateOrConnectWithoutUserInput | AlertCreateOrConnectWithoutUserInput[] + createMany?: AlertCreateManyUserInputEnvelope + connect?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + } + + export type PositionUncheckedCreateNestedManyWithoutUserInput = { + create?: XOR | PositionCreateWithoutUserInput[] | PositionUncheckedCreateWithoutUserInput[] + connectOrCreate?: PositionCreateOrConnectWithoutUserInput | PositionCreateOrConnectWithoutUserInput[] + createMany?: PositionCreateManyUserInputEnvelope + connect?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + } + + export type WatchlistUncheckedCreateNestedManyWithoutUserInput = { + create?: XOR | WatchlistCreateWithoutUserInput[] | WatchlistUncheckedCreateWithoutUserInput[] + connectOrCreate?: WatchlistCreateOrConnectWithoutUserInput | WatchlistCreateOrConnectWithoutUserInput[] + createMany?: WatchlistCreateManyUserInputEnvelope + connect?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + } + + export type AlertUncheckedCreateNestedManyWithoutUserInput = { + create?: XOR | AlertCreateWithoutUserInput[] | AlertUncheckedCreateWithoutUserInput[] + connectOrCreate?: AlertCreateOrConnectWithoutUserInput | AlertCreateOrConnectWithoutUserInput[] + createMany?: AlertCreateManyUserInputEnvelope + connect?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + } + + export type StringFieldUpdateOperationsInput = { + set?: string + } + + export type BoolFieldUpdateOperationsInput = { + set?: boolean + } + + export type NullableStringFieldUpdateOperationsInput = { + set?: string | null + } + + export type DateTimeFieldUpdateOperationsInput = { + set?: Date | string + } + + export type PositionUpdateManyWithoutUserNestedInput = { + create?: XOR | PositionCreateWithoutUserInput[] | PositionUncheckedCreateWithoutUserInput[] + connectOrCreate?: PositionCreateOrConnectWithoutUserInput | PositionCreateOrConnectWithoutUserInput[] + upsert?: PositionUpsertWithWhereUniqueWithoutUserInput | PositionUpsertWithWhereUniqueWithoutUserInput[] + createMany?: PositionCreateManyUserInputEnvelope + set?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + disconnect?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + delete?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + connect?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + update?: PositionUpdateWithWhereUniqueWithoutUserInput | PositionUpdateWithWhereUniqueWithoutUserInput[] + updateMany?: PositionUpdateManyWithWhereWithoutUserInput | PositionUpdateManyWithWhereWithoutUserInput[] + deleteMany?: PositionScalarWhereInput | PositionScalarWhereInput[] + } + + export type WatchlistUpdateManyWithoutUserNestedInput = { + create?: XOR | WatchlistCreateWithoutUserInput[] | WatchlistUncheckedCreateWithoutUserInput[] + connectOrCreate?: WatchlistCreateOrConnectWithoutUserInput | WatchlistCreateOrConnectWithoutUserInput[] + upsert?: WatchlistUpsertWithWhereUniqueWithoutUserInput | WatchlistUpsertWithWhereUniqueWithoutUserInput[] + createMany?: WatchlistCreateManyUserInputEnvelope + set?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + disconnect?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + delete?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + connect?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + update?: WatchlistUpdateWithWhereUniqueWithoutUserInput | WatchlistUpdateWithWhereUniqueWithoutUserInput[] + updateMany?: WatchlistUpdateManyWithWhereWithoutUserInput | WatchlistUpdateManyWithWhereWithoutUserInput[] + deleteMany?: WatchlistScalarWhereInput | WatchlistScalarWhereInput[] + } + + export type AlertUpdateManyWithoutUserNestedInput = { + create?: XOR | AlertCreateWithoutUserInput[] | AlertUncheckedCreateWithoutUserInput[] + connectOrCreate?: AlertCreateOrConnectWithoutUserInput | AlertCreateOrConnectWithoutUserInput[] + upsert?: AlertUpsertWithWhereUniqueWithoutUserInput | AlertUpsertWithWhereUniqueWithoutUserInput[] + createMany?: AlertCreateManyUserInputEnvelope + set?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + disconnect?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + delete?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + connect?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + update?: AlertUpdateWithWhereUniqueWithoutUserInput | AlertUpdateWithWhereUniqueWithoutUserInput[] + updateMany?: AlertUpdateManyWithWhereWithoutUserInput | AlertUpdateManyWithWhereWithoutUserInput[] + deleteMany?: AlertScalarWhereInput | AlertScalarWhereInput[] + } + + export type IntFieldUpdateOperationsInput = { + set?: number + increment?: number + decrement?: number + multiply?: number + divide?: number + } + + export type PositionUncheckedUpdateManyWithoutUserNestedInput = { + create?: XOR | PositionCreateWithoutUserInput[] | PositionUncheckedCreateWithoutUserInput[] + connectOrCreate?: PositionCreateOrConnectWithoutUserInput | PositionCreateOrConnectWithoutUserInput[] + upsert?: PositionUpsertWithWhereUniqueWithoutUserInput | PositionUpsertWithWhereUniqueWithoutUserInput[] + createMany?: PositionCreateManyUserInputEnvelope + set?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + disconnect?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + delete?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + connect?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + update?: PositionUpdateWithWhereUniqueWithoutUserInput | PositionUpdateWithWhereUniqueWithoutUserInput[] + updateMany?: PositionUpdateManyWithWhereWithoutUserInput | PositionUpdateManyWithWhereWithoutUserInput[] + deleteMany?: PositionScalarWhereInput | PositionScalarWhereInput[] + } + + export type WatchlistUncheckedUpdateManyWithoutUserNestedInput = { + create?: XOR | WatchlistCreateWithoutUserInput[] | WatchlistUncheckedCreateWithoutUserInput[] + connectOrCreate?: WatchlistCreateOrConnectWithoutUserInput | WatchlistCreateOrConnectWithoutUserInput[] + upsert?: WatchlistUpsertWithWhereUniqueWithoutUserInput | WatchlistUpsertWithWhereUniqueWithoutUserInput[] + createMany?: WatchlistCreateManyUserInputEnvelope + set?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + disconnect?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + delete?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + connect?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + update?: WatchlistUpdateWithWhereUniqueWithoutUserInput | WatchlistUpdateWithWhereUniqueWithoutUserInput[] + updateMany?: WatchlistUpdateManyWithWhereWithoutUserInput | WatchlistUpdateManyWithWhereWithoutUserInput[] + deleteMany?: WatchlistScalarWhereInput | WatchlistScalarWhereInput[] + } + + export type AlertUncheckedUpdateManyWithoutUserNestedInput = { + create?: XOR | AlertCreateWithoutUserInput[] | AlertUncheckedCreateWithoutUserInput[] + connectOrCreate?: AlertCreateOrConnectWithoutUserInput | AlertCreateOrConnectWithoutUserInput[] + upsert?: AlertUpsertWithWhereUniqueWithoutUserInput | AlertUpsertWithWhereUniqueWithoutUserInput[] + createMany?: AlertCreateManyUserInputEnvelope + set?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + disconnect?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + delete?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + connect?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + update?: AlertUpdateWithWhereUniqueWithoutUserInput | AlertUpdateWithWhereUniqueWithoutUserInput[] + updateMany?: AlertUpdateManyWithWhereWithoutUserInput | AlertUpdateManyWithWhereWithoutUserInput[] + deleteMany?: AlertScalarWhereInput | AlertScalarWhereInput[] + } + + export type AISignalCreateNestedManyWithoutMarketInput = { + create?: XOR | AISignalCreateWithoutMarketInput[] | AISignalUncheckedCreateWithoutMarketInput[] + connectOrCreate?: AISignalCreateOrConnectWithoutMarketInput | AISignalCreateOrConnectWithoutMarketInput[] + createMany?: AISignalCreateManyMarketInputEnvelope + connect?: AISignalWhereUniqueInput | AISignalWhereUniqueInput[] + } + + export type PositionCreateNestedManyWithoutMarketInput = { + create?: XOR | PositionCreateWithoutMarketInput[] | PositionUncheckedCreateWithoutMarketInput[] + connectOrCreate?: PositionCreateOrConnectWithoutMarketInput | PositionCreateOrConnectWithoutMarketInput[] + createMany?: PositionCreateManyMarketInputEnvelope + connect?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + } + + export type WatchlistCreateNestedManyWithoutMarketInput = { + create?: XOR | WatchlistCreateWithoutMarketInput[] | WatchlistUncheckedCreateWithoutMarketInput[] + connectOrCreate?: WatchlistCreateOrConnectWithoutMarketInput | WatchlistCreateOrConnectWithoutMarketInput[] + createMany?: WatchlistCreateManyMarketInputEnvelope + connect?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + } + + export type AlertCreateNestedManyWithoutMarketInput = { + create?: XOR | AlertCreateWithoutMarketInput[] | AlertUncheckedCreateWithoutMarketInput[] + connectOrCreate?: AlertCreateOrConnectWithoutMarketInput | AlertCreateOrConnectWithoutMarketInput[] + createMany?: AlertCreateManyMarketInputEnvelope + connect?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + } + + export type AISignalUncheckedCreateNestedManyWithoutMarketInput = { + create?: XOR | AISignalCreateWithoutMarketInput[] | AISignalUncheckedCreateWithoutMarketInput[] + connectOrCreate?: AISignalCreateOrConnectWithoutMarketInput | AISignalCreateOrConnectWithoutMarketInput[] + createMany?: AISignalCreateManyMarketInputEnvelope + connect?: AISignalWhereUniqueInput | AISignalWhereUniqueInput[] + } + + export type PositionUncheckedCreateNestedManyWithoutMarketInput = { + create?: XOR | PositionCreateWithoutMarketInput[] | PositionUncheckedCreateWithoutMarketInput[] + connectOrCreate?: PositionCreateOrConnectWithoutMarketInput | PositionCreateOrConnectWithoutMarketInput[] + createMany?: PositionCreateManyMarketInputEnvelope + connect?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + } + + export type WatchlistUncheckedCreateNestedManyWithoutMarketInput = { + create?: XOR | WatchlistCreateWithoutMarketInput[] | WatchlistUncheckedCreateWithoutMarketInput[] + connectOrCreate?: WatchlistCreateOrConnectWithoutMarketInput | WatchlistCreateOrConnectWithoutMarketInput[] + createMany?: WatchlistCreateManyMarketInputEnvelope + connect?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + } + + export type AlertUncheckedCreateNestedManyWithoutMarketInput = { + create?: XOR | AlertCreateWithoutMarketInput[] | AlertUncheckedCreateWithoutMarketInput[] + connectOrCreate?: AlertCreateOrConnectWithoutMarketInput | AlertCreateOrConnectWithoutMarketInput[] + createMany?: AlertCreateManyMarketInputEnvelope + connect?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + } + + export type NullableFloatFieldUpdateOperationsInput = { + set?: number | null + increment?: number + decrement?: number + multiply?: number + divide?: number + } + + export type NullableDateTimeFieldUpdateOperationsInput = { + set?: Date | string | null + } + + export type AISignalUpdateManyWithoutMarketNestedInput = { + create?: XOR | AISignalCreateWithoutMarketInput[] | AISignalUncheckedCreateWithoutMarketInput[] + connectOrCreate?: AISignalCreateOrConnectWithoutMarketInput | AISignalCreateOrConnectWithoutMarketInput[] + upsert?: AISignalUpsertWithWhereUniqueWithoutMarketInput | AISignalUpsertWithWhereUniqueWithoutMarketInput[] + createMany?: AISignalCreateManyMarketInputEnvelope + set?: AISignalWhereUniqueInput | AISignalWhereUniqueInput[] + disconnect?: AISignalWhereUniqueInput | AISignalWhereUniqueInput[] + delete?: AISignalWhereUniqueInput | AISignalWhereUniqueInput[] + connect?: AISignalWhereUniqueInput | AISignalWhereUniqueInput[] + update?: AISignalUpdateWithWhereUniqueWithoutMarketInput | AISignalUpdateWithWhereUniqueWithoutMarketInput[] + updateMany?: AISignalUpdateManyWithWhereWithoutMarketInput | AISignalUpdateManyWithWhereWithoutMarketInput[] + deleteMany?: AISignalScalarWhereInput | AISignalScalarWhereInput[] + } + + export type PositionUpdateManyWithoutMarketNestedInput = { + create?: XOR | PositionCreateWithoutMarketInput[] | PositionUncheckedCreateWithoutMarketInput[] + connectOrCreate?: PositionCreateOrConnectWithoutMarketInput | PositionCreateOrConnectWithoutMarketInput[] + upsert?: PositionUpsertWithWhereUniqueWithoutMarketInput | PositionUpsertWithWhereUniqueWithoutMarketInput[] + createMany?: PositionCreateManyMarketInputEnvelope + set?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + disconnect?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + delete?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + connect?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + update?: PositionUpdateWithWhereUniqueWithoutMarketInput | PositionUpdateWithWhereUniqueWithoutMarketInput[] + updateMany?: PositionUpdateManyWithWhereWithoutMarketInput | PositionUpdateManyWithWhereWithoutMarketInput[] + deleteMany?: PositionScalarWhereInput | PositionScalarWhereInput[] + } + + export type WatchlistUpdateManyWithoutMarketNestedInput = { + create?: XOR | WatchlistCreateWithoutMarketInput[] | WatchlistUncheckedCreateWithoutMarketInput[] + connectOrCreate?: WatchlistCreateOrConnectWithoutMarketInput | WatchlistCreateOrConnectWithoutMarketInput[] + upsert?: WatchlistUpsertWithWhereUniqueWithoutMarketInput | WatchlistUpsertWithWhereUniqueWithoutMarketInput[] + createMany?: WatchlistCreateManyMarketInputEnvelope + set?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + disconnect?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + delete?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + connect?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + update?: WatchlistUpdateWithWhereUniqueWithoutMarketInput | WatchlistUpdateWithWhereUniqueWithoutMarketInput[] + updateMany?: WatchlistUpdateManyWithWhereWithoutMarketInput | WatchlistUpdateManyWithWhereWithoutMarketInput[] + deleteMany?: WatchlistScalarWhereInput | WatchlistScalarWhereInput[] + } + + export type AlertUpdateManyWithoutMarketNestedInput = { + create?: XOR | AlertCreateWithoutMarketInput[] | AlertUncheckedCreateWithoutMarketInput[] + connectOrCreate?: AlertCreateOrConnectWithoutMarketInput | AlertCreateOrConnectWithoutMarketInput[] + upsert?: AlertUpsertWithWhereUniqueWithoutMarketInput | AlertUpsertWithWhereUniqueWithoutMarketInput[] + createMany?: AlertCreateManyMarketInputEnvelope + set?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + disconnect?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + delete?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + connect?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + update?: AlertUpdateWithWhereUniqueWithoutMarketInput | AlertUpdateWithWhereUniqueWithoutMarketInput[] + updateMany?: AlertUpdateManyWithWhereWithoutMarketInput | AlertUpdateManyWithWhereWithoutMarketInput[] + deleteMany?: AlertScalarWhereInput | AlertScalarWhereInput[] + } + + export type AISignalUncheckedUpdateManyWithoutMarketNestedInput = { + create?: XOR | AISignalCreateWithoutMarketInput[] | AISignalUncheckedCreateWithoutMarketInput[] + connectOrCreate?: AISignalCreateOrConnectWithoutMarketInput | AISignalCreateOrConnectWithoutMarketInput[] + upsert?: AISignalUpsertWithWhereUniqueWithoutMarketInput | AISignalUpsertWithWhereUniqueWithoutMarketInput[] + createMany?: AISignalCreateManyMarketInputEnvelope + set?: AISignalWhereUniqueInput | AISignalWhereUniqueInput[] + disconnect?: AISignalWhereUniqueInput | AISignalWhereUniqueInput[] + delete?: AISignalWhereUniqueInput | AISignalWhereUniqueInput[] + connect?: AISignalWhereUniqueInput | AISignalWhereUniqueInput[] + update?: AISignalUpdateWithWhereUniqueWithoutMarketInput | AISignalUpdateWithWhereUniqueWithoutMarketInput[] + updateMany?: AISignalUpdateManyWithWhereWithoutMarketInput | AISignalUpdateManyWithWhereWithoutMarketInput[] + deleteMany?: AISignalScalarWhereInput | AISignalScalarWhereInput[] + } + + export type PositionUncheckedUpdateManyWithoutMarketNestedInput = { + create?: XOR | PositionCreateWithoutMarketInput[] | PositionUncheckedCreateWithoutMarketInput[] + connectOrCreate?: PositionCreateOrConnectWithoutMarketInput | PositionCreateOrConnectWithoutMarketInput[] + upsert?: PositionUpsertWithWhereUniqueWithoutMarketInput | PositionUpsertWithWhereUniqueWithoutMarketInput[] + createMany?: PositionCreateManyMarketInputEnvelope + set?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + disconnect?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + delete?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + connect?: PositionWhereUniqueInput | PositionWhereUniqueInput[] + update?: PositionUpdateWithWhereUniqueWithoutMarketInput | PositionUpdateWithWhereUniqueWithoutMarketInput[] + updateMany?: PositionUpdateManyWithWhereWithoutMarketInput | PositionUpdateManyWithWhereWithoutMarketInput[] + deleteMany?: PositionScalarWhereInput | PositionScalarWhereInput[] + } + + export type WatchlistUncheckedUpdateManyWithoutMarketNestedInput = { + create?: XOR | WatchlistCreateWithoutMarketInput[] | WatchlistUncheckedCreateWithoutMarketInput[] + connectOrCreate?: WatchlistCreateOrConnectWithoutMarketInput | WatchlistCreateOrConnectWithoutMarketInput[] + upsert?: WatchlistUpsertWithWhereUniqueWithoutMarketInput | WatchlistUpsertWithWhereUniqueWithoutMarketInput[] + createMany?: WatchlistCreateManyMarketInputEnvelope + set?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + disconnect?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + delete?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + connect?: WatchlistWhereUniqueInput | WatchlistWhereUniqueInput[] + update?: WatchlistUpdateWithWhereUniqueWithoutMarketInput | WatchlistUpdateWithWhereUniqueWithoutMarketInput[] + updateMany?: WatchlistUpdateManyWithWhereWithoutMarketInput | WatchlistUpdateManyWithWhereWithoutMarketInput[] + deleteMany?: WatchlistScalarWhereInput | WatchlistScalarWhereInput[] + } + + export type AlertUncheckedUpdateManyWithoutMarketNestedInput = { + create?: XOR | AlertCreateWithoutMarketInput[] | AlertUncheckedCreateWithoutMarketInput[] + connectOrCreate?: AlertCreateOrConnectWithoutMarketInput | AlertCreateOrConnectWithoutMarketInput[] + upsert?: AlertUpsertWithWhereUniqueWithoutMarketInput | AlertUpsertWithWhereUniqueWithoutMarketInput[] + createMany?: AlertCreateManyMarketInputEnvelope + set?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + disconnect?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + delete?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + connect?: AlertWhereUniqueInput | AlertWhereUniqueInput[] + update?: AlertUpdateWithWhereUniqueWithoutMarketInput | AlertUpdateWithWhereUniqueWithoutMarketInput[] + updateMany?: AlertUpdateManyWithWhereWithoutMarketInput | AlertUpdateManyWithWhereWithoutMarketInput[] + deleteMany?: AlertScalarWhereInput | AlertScalarWhereInput[] + } + + export type MarketCreateNestedOneWithoutSignalsInput = { + create?: XOR + connectOrCreate?: MarketCreateOrConnectWithoutSignalsInput + connect?: MarketWhereUniqueInput + } + + export type FloatFieldUpdateOperationsInput = { + set?: number + increment?: number + decrement?: number + multiply?: number + divide?: number + } + + export type MarketUpdateOneRequiredWithoutSignalsNestedInput = { + create?: XOR + connectOrCreate?: MarketCreateOrConnectWithoutSignalsInput + upsert?: MarketUpsertWithoutSignalsInput + connect?: MarketWhereUniqueInput + update?: XOR, MarketUncheckedUpdateWithoutSignalsInput> + } + + export type UserCreateNestedOneWithoutPositionsInput = { + create?: XOR + connectOrCreate?: UserCreateOrConnectWithoutPositionsInput + connect?: UserWhereUniqueInput + } + + export type MarketCreateNestedOneWithoutPositionsInput = { + create?: XOR + connectOrCreate?: MarketCreateOrConnectWithoutPositionsInput + connect?: MarketWhereUniqueInput + } + + export type UserUpdateOneRequiredWithoutPositionsNestedInput = { + create?: XOR + connectOrCreate?: UserCreateOrConnectWithoutPositionsInput + upsert?: UserUpsertWithoutPositionsInput + connect?: UserWhereUniqueInput + update?: XOR, UserUncheckedUpdateWithoutPositionsInput> + } + + export type MarketUpdateOneRequiredWithoutPositionsNestedInput = { + create?: XOR + connectOrCreate?: MarketCreateOrConnectWithoutPositionsInput + upsert?: MarketUpsertWithoutPositionsInput + connect?: MarketWhereUniqueInput + update?: XOR, MarketUncheckedUpdateWithoutPositionsInput> + } + + export type UserCreateNestedOneWithoutWatchlistInput = { + create?: XOR + connectOrCreate?: UserCreateOrConnectWithoutWatchlistInput + connect?: UserWhereUniqueInput + } + + export type MarketCreateNestedOneWithoutWatchlistInput = { + create?: XOR + connectOrCreate?: MarketCreateOrConnectWithoutWatchlistInput + connect?: MarketWhereUniqueInput + } + + export type UserUpdateOneRequiredWithoutWatchlistNestedInput = { + create?: XOR + connectOrCreate?: UserCreateOrConnectWithoutWatchlistInput + upsert?: UserUpsertWithoutWatchlistInput + connect?: UserWhereUniqueInput + update?: XOR, UserUncheckedUpdateWithoutWatchlistInput> + } + + export type MarketUpdateOneRequiredWithoutWatchlistNestedInput = { + create?: XOR + connectOrCreate?: MarketCreateOrConnectWithoutWatchlistInput + upsert?: MarketUpsertWithoutWatchlistInput + connect?: MarketWhereUniqueInput + update?: XOR, MarketUncheckedUpdateWithoutWatchlistInput> + } + + export type UserCreateNestedOneWithoutAlertsInput = { + create?: XOR + connectOrCreate?: UserCreateOrConnectWithoutAlertsInput + connect?: UserWhereUniqueInput + } + + export type MarketCreateNestedOneWithoutAlertsInput = { + create?: XOR + connectOrCreate?: MarketCreateOrConnectWithoutAlertsInput + connect?: MarketWhereUniqueInput + } + + export type UserUpdateOneRequiredWithoutAlertsNestedInput = { + create?: XOR + connectOrCreate?: UserCreateOrConnectWithoutAlertsInput + upsert?: UserUpsertWithoutAlertsInput + connect?: UserWhereUniqueInput + update?: XOR, UserUncheckedUpdateWithoutAlertsInput> + } + + export type MarketUpdateOneRequiredWithoutAlertsNestedInput = { + create?: XOR + connectOrCreate?: MarketCreateOrConnectWithoutAlertsInput + upsert?: MarketUpsertWithoutAlertsInput + connect?: MarketWhereUniqueInput + update?: XOR, MarketUncheckedUpdateWithoutAlertsInput> + } + + export type NestedIntFilter<$PrismaModel = never> = { + equals?: number | IntFieldRefInput<$PrismaModel> + in?: number[] + notIn?: number[] + lt?: number | IntFieldRefInput<$PrismaModel> + lte?: number | IntFieldRefInput<$PrismaModel> + gt?: number | IntFieldRefInput<$PrismaModel> + gte?: number | IntFieldRefInput<$PrismaModel> + not?: NestedIntFilter<$PrismaModel> | number + } + + export type NestedStringFilter<$PrismaModel = never> = { + equals?: string | StringFieldRefInput<$PrismaModel> + in?: string[] + notIn?: string[] + lt?: string | StringFieldRefInput<$PrismaModel> + lte?: string | StringFieldRefInput<$PrismaModel> + gt?: string | StringFieldRefInput<$PrismaModel> + gte?: string | StringFieldRefInput<$PrismaModel> + contains?: string | StringFieldRefInput<$PrismaModel> + startsWith?: string | StringFieldRefInput<$PrismaModel> + endsWith?: string | StringFieldRefInput<$PrismaModel> + not?: NestedStringFilter<$PrismaModel> | string + } + + export type NestedBoolFilter<$PrismaModel = never> = { + equals?: boolean | BooleanFieldRefInput<$PrismaModel> + not?: NestedBoolFilter<$PrismaModel> | boolean + } + + export type NestedStringNullableFilter<$PrismaModel = never> = { + equals?: string | StringFieldRefInput<$PrismaModel> | null + in?: string[] | null + notIn?: string[] | null + lt?: string | StringFieldRefInput<$PrismaModel> + lte?: string | StringFieldRefInput<$PrismaModel> + gt?: string | StringFieldRefInput<$PrismaModel> + gte?: string | StringFieldRefInput<$PrismaModel> + contains?: string | StringFieldRefInput<$PrismaModel> + startsWith?: string | StringFieldRefInput<$PrismaModel> + endsWith?: string | StringFieldRefInput<$PrismaModel> + not?: NestedStringNullableFilter<$PrismaModel> | string | null + } + + export type NestedDateTimeFilter<$PrismaModel = never> = { + equals?: Date | string | DateTimeFieldRefInput<$PrismaModel> + in?: Date[] | string[] + notIn?: Date[] | string[] + lt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + not?: NestedDateTimeFilter<$PrismaModel> | Date | string + } + + export type NestedIntWithAggregatesFilter<$PrismaModel = never> = { + equals?: number | IntFieldRefInput<$PrismaModel> + in?: number[] + notIn?: number[] + lt?: number | IntFieldRefInput<$PrismaModel> + lte?: number | IntFieldRefInput<$PrismaModel> + gt?: number | IntFieldRefInput<$PrismaModel> + gte?: number | IntFieldRefInput<$PrismaModel> + not?: NestedIntWithAggregatesFilter<$PrismaModel> | number + _count?: NestedIntFilter<$PrismaModel> + _avg?: NestedFloatFilter<$PrismaModel> + _sum?: NestedIntFilter<$PrismaModel> + _min?: NestedIntFilter<$PrismaModel> + _max?: NestedIntFilter<$PrismaModel> + } + + export type NestedFloatFilter<$PrismaModel = never> = { + equals?: number | FloatFieldRefInput<$PrismaModel> + in?: number[] + notIn?: number[] + lt?: number | FloatFieldRefInput<$PrismaModel> + lte?: number | FloatFieldRefInput<$PrismaModel> + gt?: number | FloatFieldRefInput<$PrismaModel> + gte?: number | FloatFieldRefInput<$PrismaModel> + not?: NestedFloatFilter<$PrismaModel> | number + } + + export type NestedStringWithAggregatesFilter<$PrismaModel = never> = { + equals?: string | StringFieldRefInput<$PrismaModel> + in?: string[] + notIn?: string[] + lt?: string | StringFieldRefInput<$PrismaModel> + lte?: string | StringFieldRefInput<$PrismaModel> + gt?: string | StringFieldRefInput<$PrismaModel> + gte?: string | StringFieldRefInput<$PrismaModel> + contains?: string | StringFieldRefInput<$PrismaModel> + startsWith?: string | StringFieldRefInput<$PrismaModel> + endsWith?: string | StringFieldRefInput<$PrismaModel> + not?: NestedStringWithAggregatesFilter<$PrismaModel> | string + _count?: NestedIntFilter<$PrismaModel> + _min?: NestedStringFilter<$PrismaModel> + _max?: NestedStringFilter<$PrismaModel> + } + + export type NestedBoolWithAggregatesFilter<$PrismaModel = never> = { + equals?: boolean | BooleanFieldRefInput<$PrismaModel> + not?: NestedBoolWithAggregatesFilter<$PrismaModel> | boolean + _count?: NestedIntFilter<$PrismaModel> + _min?: NestedBoolFilter<$PrismaModel> + _max?: NestedBoolFilter<$PrismaModel> + } + + export type NestedStringNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: string | StringFieldRefInput<$PrismaModel> | null + in?: string[] | null + notIn?: string[] | null + lt?: string | StringFieldRefInput<$PrismaModel> + lte?: string | StringFieldRefInput<$PrismaModel> + gt?: string | StringFieldRefInput<$PrismaModel> + gte?: string | StringFieldRefInput<$PrismaModel> + contains?: string | StringFieldRefInput<$PrismaModel> + startsWith?: string | StringFieldRefInput<$PrismaModel> + endsWith?: string | StringFieldRefInput<$PrismaModel> + not?: NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null + _count?: NestedIntNullableFilter<$PrismaModel> + _min?: NestedStringNullableFilter<$PrismaModel> + _max?: NestedStringNullableFilter<$PrismaModel> + } + + export type NestedIntNullableFilter<$PrismaModel = never> = { + equals?: number | IntFieldRefInput<$PrismaModel> | null + in?: number[] | null + notIn?: number[] | null + lt?: number | IntFieldRefInput<$PrismaModel> + lte?: number | IntFieldRefInput<$PrismaModel> + gt?: number | IntFieldRefInput<$PrismaModel> + gte?: number | IntFieldRefInput<$PrismaModel> + not?: NestedIntNullableFilter<$PrismaModel> | number | null + } + + export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = { + equals?: Date | string | DateTimeFieldRefInput<$PrismaModel> + in?: Date[] | string[] + notIn?: Date[] | string[] + lt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + not?: NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string + _count?: NestedIntFilter<$PrismaModel> + _min?: NestedDateTimeFilter<$PrismaModel> + _max?: NestedDateTimeFilter<$PrismaModel> + } + + export type NestedFloatNullableFilter<$PrismaModel = never> = { + equals?: number | FloatFieldRefInput<$PrismaModel> | null + in?: number[] | null + notIn?: number[] | null + lt?: number | FloatFieldRefInput<$PrismaModel> + lte?: number | FloatFieldRefInput<$PrismaModel> + gt?: number | FloatFieldRefInput<$PrismaModel> + gte?: number | FloatFieldRefInput<$PrismaModel> + not?: NestedFloatNullableFilter<$PrismaModel> | number | null + } + + export type NestedDateTimeNullableFilter<$PrismaModel = never> = { + equals?: Date | string | DateTimeFieldRefInput<$PrismaModel> | null + in?: Date[] | string[] | null + notIn?: Date[] | string[] | null + lt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + not?: NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null + } + + export type NestedFloatNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: number | FloatFieldRefInput<$PrismaModel> | null + in?: number[] | null + notIn?: number[] | null + lt?: number | FloatFieldRefInput<$PrismaModel> + lte?: number | FloatFieldRefInput<$PrismaModel> + gt?: number | FloatFieldRefInput<$PrismaModel> + gte?: number | FloatFieldRefInput<$PrismaModel> + not?: NestedFloatNullableWithAggregatesFilter<$PrismaModel> | number | null + _count?: NestedIntNullableFilter<$PrismaModel> + _avg?: NestedFloatNullableFilter<$PrismaModel> + _sum?: NestedFloatNullableFilter<$PrismaModel> + _min?: NestedFloatNullableFilter<$PrismaModel> + _max?: NestedFloatNullableFilter<$PrismaModel> + } + + export type NestedDateTimeNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: Date | string | DateTimeFieldRefInput<$PrismaModel> | null + in?: Date[] | string[] | null + notIn?: Date[] | string[] | null + lt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | DateTimeFieldRefInput<$PrismaModel> + not?: NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null + _count?: NestedIntNullableFilter<$PrismaModel> + _min?: NestedDateTimeNullableFilter<$PrismaModel> + _max?: NestedDateTimeNullableFilter<$PrismaModel> + } + + export type NestedFloatWithAggregatesFilter<$PrismaModel = never> = { + equals?: number | FloatFieldRefInput<$PrismaModel> + in?: number[] + notIn?: number[] + lt?: number | FloatFieldRefInput<$PrismaModel> + lte?: number | FloatFieldRefInput<$PrismaModel> + gt?: number | FloatFieldRefInput<$PrismaModel> + gte?: number | FloatFieldRefInput<$PrismaModel> + not?: NestedFloatWithAggregatesFilter<$PrismaModel> | number + _count?: NestedIntFilter<$PrismaModel> + _avg?: NestedFloatFilter<$PrismaModel> + _sum?: NestedFloatFilter<$PrismaModel> + _min?: NestedFloatFilter<$PrismaModel> + _max?: NestedFloatFilter<$PrismaModel> + } + + export type PositionCreateWithoutUserInput = { + outcome: string + amountEur: number + entryPrice: number + currentPrice?: number | null + pnl?: number + kellyFraction?: number | null + status?: string + openedAt?: Date | string + closedAt?: Date | string | null + market: MarketCreateNestedOneWithoutPositionsInput + } + + export type PositionUncheckedCreateWithoutUserInput = { + id?: number + marketId: string + outcome: string + amountEur: number + entryPrice: number + currentPrice?: number | null + pnl?: number + kellyFraction?: number | null + status?: string + openedAt?: Date | string + closedAt?: Date | string | null + } + + export type PositionCreateOrConnectWithoutUserInput = { + where: PositionWhereUniqueInput + create: XOR + } + + export type PositionCreateManyUserInputEnvelope = { + data: PositionCreateManyUserInput | PositionCreateManyUserInput[] + } + + export type WatchlistCreateWithoutUserInput = { + alertThreshold?: number | null + createdAt?: Date | string + market: MarketCreateNestedOneWithoutWatchlistInput + } + + export type WatchlistUncheckedCreateWithoutUserInput = { + id?: number + marketId: string + alertThreshold?: number | null + createdAt?: Date | string + } + + export type WatchlistCreateOrConnectWithoutUserInput = { + where: WatchlistWhereUniqueInput + create: XOR + } + + export type WatchlistCreateManyUserInputEnvelope = { + data: WatchlistCreateManyUserInput | WatchlistCreateManyUserInput[] + } + + export type AlertCreateWithoutUserInput = { + type: string + message: string + sentAt?: Date | string + market: MarketCreateNestedOneWithoutAlertsInput + } + + export type AlertUncheckedCreateWithoutUserInput = { + id?: number + marketId: string + type: string + message: string + sentAt?: Date | string + } + + export type AlertCreateOrConnectWithoutUserInput = { + where: AlertWhereUniqueInput + create: XOR + } + + export type AlertCreateManyUserInputEnvelope = { + data: AlertCreateManyUserInput | AlertCreateManyUserInput[] + } + + export type PositionUpsertWithWhereUniqueWithoutUserInput = { + where: PositionWhereUniqueInput + update: XOR + create: XOR + } + + export type PositionUpdateWithWhereUniqueWithoutUserInput = { + where: PositionWhereUniqueInput + data: XOR + } + + export type PositionUpdateManyWithWhereWithoutUserInput = { + where: PositionScalarWhereInput + data: XOR + } + + export type PositionScalarWhereInput = { + AND?: PositionScalarWhereInput | PositionScalarWhereInput[] + OR?: PositionScalarWhereInput[] + NOT?: PositionScalarWhereInput | PositionScalarWhereInput[] + id?: IntFilter<"Position"> | number + userId?: IntFilter<"Position"> | number + marketId?: StringFilter<"Position"> | string + outcome?: StringFilter<"Position"> | string + amountEur?: FloatFilter<"Position"> | number + entryPrice?: FloatFilter<"Position"> | number + currentPrice?: FloatNullableFilter<"Position"> | number | null + pnl?: FloatFilter<"Position"> | number + kellyFraction?: FloatNullableFilter<"Position"> | number | null + status?: StringFilter<"Position"> | string + openedAt?: DateTimeFilter<"Position"> | Date | string + closedAt?: DateTimeNullableFilter<"Position"> | Date | string | null + } + + export type WatchlistUpsertWithWhereUniqueWithoutUserInput = { + where: WatchlistWhereUniqueInput + update: XOR + create: XOR + } + + export type WatchlistUpdateWithWhereUniqueWithoutUserInput = { + where: WatchlistWhereUniqueInput + data: XOR + } + + export type WatchlistUpdateManyWithWhereWithoutUserInput = { + where: WatchlistScalarWhereInput + data: XOR + } + + export type WatchlistScalarWhereInput = { + AND?: WatchlistScalarWhereInput | WatchlistScalarWhereInput[] + OR?: WatchlistScalarWhereInput[] + NOT?: WatchlistScalarWhereInput | WatchlistScalarWhereInput[] + id?: IntFilter<"Watchlist"> | number + userId?: IntFilter<"Watchlist"> | number + marketId?: StringFilter<"Watchlist"> | string + alertThreshold?: FloatNullableFilter<"Watchlist"> | number | null + createdAt?: DateTimeFilter<"Watchlist"> | Date | string + } + + export type AlertUpsertWithWhereUniqueWithoutUserInput = { + where: AlertWhereUniqueInput + update: XOR + create: XOR + } + + export type AlertUpdateWithWhereUniqueWithoutUserInput = { + where: AlertWhereUniqueInput + data: XOR + } + + export type AlertUpdateManyWithWhereWithoutUserInput = { + where: AlertScalarWhereInput + data: XOR + } + + export type AlertScalarWhereInput = { + AND?: AlertScalarWhereInput | AlertScalarWhereInput[] + OR?: AlertScalarWhereInput[] + NOT?: AlertScalarWhereInput | AlertScalarWhereInput[] + id?: IntFilter<"Alert"> | number + userId?: IntFilter<"Alert"> | number + marketId?: StringFilter<"Alert"> | string + type?: StringFilter<"Alert"> | string + message?: StringFilter<"Alert"> | string + sentAt?: DateTimeFilter<"Alert"> | Date | string + } + + export type AISignalCreateWithoutMarketInput = { + signal: string + confidence: number + summary?: string | null + keyRisk?: string | null + newsCount?: number + modelVersion?: string + impliedProb?: number | null + fairProb?: number | null + edgePoints?: number | null + generatedAt?: Date | string + } + + export type AISignalUncheckedCreateWithoutMarketInput = { + id?: number + signal: string + confidence: number + summary?: string | null + keyRisk?: string | null + newsCount?: number + modelVersion?: string + impliedProb?: number | null + fairProb?: number | null + edgePoints?: number | null + generatedAt?: Date | string + } + + export type AISignalCreateOrConnectWithoutMarketInput = { + where: AISignalWhereUniqueInput + create: XOR + } + + export type AISignalCreateManyMarketInputEnvelope = { + data: AISignalCreateManyMarketInput | AISignalCreateManyMarketInput[] + } + + export type PositionCreateWithoutMarketInput = { + outcome: string + amountEur: number + entryPrice: number + currentPrice?: number | null + pnl?: number + kellyFraction?: number | null + status?: string + openedAt?: Date | string + closedAt?: Date | string | null + user: UserCreateNestedOneWithoutPositionsInput + } + + export type PositionUncheckedCreateWithoutMarketInput = { + id?: number + userId: number + outcome: string + amountEur: number + entryPrice: number + currentPrice?: number | null + pnl?: number + kellyFraction?: number | null + status?: string + openedAt?: Date | string + closedAt?: Date | string | null + } + + export type PositionCreateOrConnectWithoutMarketInput = { + where: PositionWhereUniqueInput + create: XOR + } + + export type PositionCreateManyMarketInputEnvelope = { + data: PositionCreateManyMarketInput | PositionCreateManyMarketInput[] + } + + export type WatchlistCreateWithoutMarketInput = { + alertThreshold?: number | null + createdAt?: Date | string + user: UserCreateNestedOneWithoutWatchlistInput + } + + export type WatchlistUncheckedCreateWithoutMarketInput = { + id?: number + userId: number + alertThreshold?: number | null + createdAt?: Date | string + } + + export type WatchlistCreateOrConnectWithoutMarketInput = { + where: WatchlistWhereUniqueInput + create: XOR + } + + export type WatchlistCreateManyMarketInputEnvelope = { + data: WatchlistCreateManyMarketInput | WatchlistCreateManyMarketInput[] + } + + export type AlertCreateWithoutMarketInput = { + type: string + message: string + sentAt?: Date | string + user: UserCreateNestedOneWithoutAlertsInput + } + + export type AlertUncheckedCreateWithoutMarketInput = { + id?: number + userId: number + type: string + message: string + sentAt?: Date | string + } + + export type AlertCreateOrConnectWithoutMarketInput = { + where: AlertWhereUniqueInput + create: XOR + } + + export type AlertCreateManyMarketInputEnvelope = { + data: AlertCreateManyMarketInput | AlertCreateManyMarketInput[] + } + + export type AISignalUpsertWithWhereUniqueWithoutMarketInput = { + where: AISignalWhereUniqueInput + update: XOR + create: XOR + } + + export type AISignalUpdateWithWhereUniqueWithoutMarketInput = { + where: AISignalWhereUniqueInput + data: XOR + } + + export type AISignalUpdateManyWithWhereWithoutMarketInput = { + where: AISignalScalarWhereInput + data: XOR + } + + export type AISignalScalarWhereInput = { + AND?: AISignalScalarWhereInput | AISignalScalarWhereInput[] + OR?: AISignalScalarWhereInput[] + NOT?: AISignalScalarWhereInput | AISignalScalarWhereInput[] + id?: IntFilter<"AISignal"> | number + marketId?: StringFilter<"AISignal"> | string + signal?: StringFilter<"AISignal"> | string + confidence?: FloatFilter<"AISignal"> | number + summary?: StringNullableFilter<"AISignal"> | string | null + keyRisk?: StringNullableFilter<"AISignal"> | string | null + newsCount?: IntFilter<"AISignal"> | number + modelVersion?: StringFilter<"AISignal"> | string + impliedProb?: FloatNullableFilter<"AISignal"> | number | null + fairProb?: FloatNullableFilter<"AISignal"> | number | null + edgePoints?: FloatNullableFilter<"AISignal"> | number | null + generatedAt?: DateTimeFilter<"AISignal"> | Date | string + } + + export type PositionUpsertWithWhereUniqueWithoutMarketInput = { + where: PositionWhereUniqueInput + update: XOR + create: XOR + } + + export type PositionUpdateWithWhereUniqueWithoutMarketInput = { + where: PositionWhereUniqueInput + data: XOR + } + + export type PositionUpdateManyWithWhereWithoutMarketInput = { + where: PositionScalarWhereInput + data: XOR + } + + export type WatchlistUpsertWithWhereUniqueWithoutMarketInput = { + where: WatchlistWhereUniqueInput + update: XOR + create: XOR + } + + export type WatchlistUpdateWithWhereUniqueWithoutMarketInput = { + where: WatchlistWhereUniqueInput + data: XOR + } + + export type WatchlistUpdateManyWithWhereWithoutMarketInput = { + where: WatchlistScalarWhereInput + data: XOR + } + + export type AlertUpsertWithWhereUniqueWithoutMarketInput = { + where: AlertWhereUniqueInput + update: XOR + create: XOR + } + + export type AlertUpdateWithWhereUniqueWithoutMarketInput = { + where: AlertWhereUniqueInput + data: XOR + } + + export type AlertUpdateManyWithWhereWithoutMarketInput = { + where: AlertScalarWhereInput + data: XOR + } + + export type MarketCreateWithoutSignalsInput = { + id: string + question: string + category?: string | null + countryCode?: string | null + yesPrice?: number | null + noPrice?: number | null + volumeEur?: number | null + liquidityEur?: number | null + spread?: number | null + bestBid?: number | null + bestAsk?: number | null + clobTokenId?: string | null + analyzable?: boolean + status?: string + closesAt?: Date | string | null + lastSynced?: Date | string + positions?: PositionCreateNestedManyWithoutMarketInput + watchlist?: WatchlistCreateNestedManyWithoutMarketInput + alerts?: AlertCreateNestedManyWithoutMarketInput + } + + export type MarketUncheckedCreateWithoutSignalsInput = { + id: string + question: string + category?: string | null + countryCode?: string | null + yesPrice?: number | null + noPrice?: number | null + volumeEur?: number | null + liquidityEur?: number | null + spread?: number | null + bestBid?: number | null + bestAsk?: number | null + clobTokenId?: string | null + analyzable?: boolean + status?: string + closesAt?: Date | string | null + lastSynced?: Date | string + positions?: PositionUncheckedCreateNestedManyWithoutMarketInput + watchlist?: WatchlistUncheckedCreateNestedManyWithoutMarketInput + alerts?: AlertUncheckedCreateNestedManyWithoutMarketInput + } + + export type MarketCreateOrConnectWithoutSignalsInput = { + where: MarketWhereUniqueInput + create: XOR + } + + export type MarketUpsertWithoutSignalsInput = { + update: XOR + create: XOR + where?: MarketWhereInput + } + + export type MarketUpdateToOneWithWhereWithoutSignalsInput = { + where?: MarketWhereInput + data: XOR + } + + export type MarketUpdateWithoutSignalsInput = { + id?: StringFieldUpdateOperationsInput | string + question?: StringFieldUpdateOperationsInput | string + category?: NullableStringFieldUpdateOperationsInput | string | null + countryCode?: NullableStringFieldUpdateOperationsInput | string | null + yesPrice?: NullableFloatFieldUpdateOperationsInput | number | null + noPrice?: NullableFloatFieldUpdateOperationsInput | number | null + volumeEur?: NullableFloatFieldUpdateOperationsInput | number | null + liquidityEur?: NullableFloatFieldUpdateOperationsInput | number | null + spread?: NullableFloatFieldUpdateOperationsInput | number | null + bestBid?: NullableFloatFieldUpdateOperationsInput | number | null + bestAsk?: NullableFloatFieldUpdateOperationsInput | number | null + clobTokenId?: NullableStringFieldUpdateOperationsInput | string | null + analyzable?: BoolFieldUpdateOperationsInput | boolean + status?: StringFieldUpdateOperationsInput | string + closesAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lastSynced?: DateTimeFieldUpdateOperationsInput | Date | string + positions?: PositionUpdateManyWithoutMarketNestedInput + watchlist?: WatchlistUpdateManyWithoutMarketNestedInput + alerts?: AlertUpdateManyWithoutMarketNestedInput + } + + export type MarketUncheckedUpdateWithoutSignalsInput = { + id?: StringFieldUpdateOperationsInput | string + question?: StringFieldUpdateOperationsInput | string + category?: NullableStringFieldUpdateOperationsInput | string | null + countryCode?: NullableStringFieldUpdateOperationsInput | string | null + yesPrice?: NullableFloatFieldUpdateOperationsInput | number | null + noPrice?: NullableFloatFieldUpdateOperationsInput | number | null + volumeEur?: NullableFloatFieldUpdateOperationsInput | number | null + liquidityEur?: NullableFloatFieldUpdateOperationsInput | number | null + spread?: NullableFloatFieldUpdateOperationsInput | number | null + bestBid?: NullableFloatFieldUpdateOperationsInput | number | null + bestAsk?: NullableFloatFieldUpdateOperationsInput | number | null + clobTokenId?: NullableStringFieldUpdateOperationsInput | string | null + analyzable?: BoolFieldUpdateOperationsInput | boolean + status?: StringFieldUpdateOperationsInput | string + closesAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lastSynced?: DateTimeFieldUpdateOperationsInput | Date | string + positions?: PositionUncheckedUpdateManyWithoutMarketNestedInput + watchlist?: WatchlistUncheckedUpdateManyWithoutMarketNestedInput + alerts?: AlertUncheckedUpdateManyWithoutMarketNestedInput + } + + export type UserCreateWithoutPositionsInput = { + email: string + passwordHash: string + isActive?: boolean + telegramChatId?: string | null + createdAt?: Date | string + updatedAt?: Date | string + watchlist?: WatchlistCreateNestedManyWithoutUserInput + alerts?: AlertCreateNestedManyWithoutUserInput + } + + export type UserUncheckedCreateWithoutPositionsInput = { + id?: number + email: string + passwordHash: string + isActive?: boolean + telegramChatId?: string | null + createdAt?: Date | string + updatedAt?: Date | string + watchlist?: WatchlistUncheckedCreateNestedManyWithoutUserInput + alerts?: AlertUncheckedCreateNestedManyWithoutUserInput + } + + export type UserCreateOrConnectWithoutPositionsInput = { + where: UserWhereUniqueInput + create: XOR + } + + export type MarketCreateWithoutPositionsInput = { + id: string + question: string + category?: string | null + countryCode?: string | null + yesPrice?: number | null + noPrice?: number | null + volumeEur?: number | null + liquidityEur?: number | null + spread?: number | null + bestBid?: number | null + bestAsk?: number | null + clobTokenId?: string | null + analyzable?: boolean + status?: string + closesAt?: Date | string | null + lastSynced?: Date | string + signals?: AISignalCreateNestedManyWithoutMarketInput + watchlist?: WatchlistCreateNestedManyWithoutMarketInput + alerts?: AlertCreateNestedManyWithoutMarketInput + } + + export type MarketUncheckedCreateWithoutPositionsInput = { + id: string + question: string + category?: string | null + countryCode?: string | null + yesPrice?: number | null + noPrice?: number | null + volumeEur?: number | null + liquidityEur?: number | null + spread?: number | null + bestBid?: number | null + bestAsk?: number | null + clobTokenId?: string | null + analyzable?: boolean + status?: string + closesAt?: Date | string | null + lastSynced?: Date | string + signals?: AISignalUncheckedCreateNestedManyWithoutMarketInput + watchlist?: WatchlistUncheckedCreateNestedManyWithoutMarketInput + alerts?: AlertUncheckedCreateNestedManyWithoutMarketInput + } + + export type MarketCreateOrConnectWithoutPositionsInput = { + where: MarketWhereUniqueInput + create: XOR + } + + export type UserUpsertWithoutPositionsInput = { + update: XOR + create: XOR + where?: UserWhereInput + } + + export type UserUpdateToOneWithWhereWithoutPositionsInput = { + where?: UserWhereInput + data: XOR + } + + export type UserUpdateWithoutPositionsInput = { + email?: StringFieldUpdateOperationsInput | string + passwordHash?: StringFieldUpdateOperationsInput | string + isActive?: BoolFieldUpdateOperationsInput | boolean + telegramChatId?: NullableStringFieldUpdateOperationsInput | string | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + watchlist?: WatchlistUpdateManyWithoutUserNestedInput + alerts?: AlertUpdateManyWithoutUserNestedInput + } + + export type UserUncheckedUpdateWithoutPositionsInput = { + id?: IntFieldUpdateOperationsInput | number + email?: StringFieldUpdateOperationsInput | string + passwordHash?: StringFieldUpdateOperationsInput | string + isActive?: BoolFieldUpdateOperationsInput | boolean + telegramChatId?: NullableStringFieldUpdateOperationsInput | string | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + watchlist?: WatchlistUncheckedUpdateManyWithoutUserNestedInput + alerts?: AlertUncheckedUpdateManyWithoutUserNestedInput + } + + export type MarketUpsertWithoutPositionsInput = { + update: XOR + create: XOR + where?: MarketWhereInput + } + + export type MarketUpdateToOneWithWhereWithoutPositionsInput = { + where?: MarketWhereInput + data: XOR + } + + export type MarketUpdateWithoutPositionsInput = { + id?: StringFieldUpdateOperationsInput | string + question?: StringFieldUpdateOperationsInput | string + category?: NullableStringFieldUpdateOperationsInput | string | null + countryCode?: NullableStringFieldUpdateOperationsInput | string | null + yesPrice?: NullableFloatFieldUpdateOperationsInput | number | null + noPrice?: NullableFloatFieldUpdateOperationsInput | number | null + volumeEur?: NullableFloatFieldUpdateOperationsInput | number | null + liquidityEur?: NullableFloatFieldUpdateOperationsInput | number | null + spread?: NullableFloatFieldUpdateOperationsInput | number | null + bestBid?: NullableFloatFieldUpdateOperationsInput | number | null + bestAsk?: NullableFloatFieldUpdateOperationsInput | number | null + clobTokenId?: NullableStringFieldUpdateOperationsInput | string | null + analyzable?: BoolFieldUpdateOperationsInput | boolean + status?: StringFieldUpdateOperationsInput | string + closesAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lastSynced?: DateTimeFieldUpdateOperationsInput | Date | string + signals?: AISignalUpdateManyWithoutMarketNestedInput + watchlist?: WatchlistUpdateManyWithoutMarketNestedInput + alerts?: AlertUpdateManyWithoutMarketNestedInput + } + + export type MarketUncheckedUpdateWithoutPositionsInput = { + id?: StringFieldUpdateOperationsInput | string + question?: StringFieldUpdateOperationsInput | string + category?: NullableStringFieldUpdateOperationsInput | string | null + countryCode?: NullableStringFieldUpdateOperationsInput | string | null + yesPrice?: NullableFloatFieldUpdateOperationsInput | number | null + noPrice?: NullableFloatFieldUpdateOperationsInput | number | null + volumeEur?: NullableFloatFieldUpdateOperationsInput | number | null + liquidityEur?: NullableFloatFieldUpdateOperationsInput | number | null + spread?: NullableFloatFieldUpdateOperationsInput | number | null + bestBid?: NullableFloatFieldUpdateOperationsInput | number | null + bestAsk?: NullableFloatFieldUpdateOperationsInput | number | null + clobTokenId?: NullableStringFieldUpdateOperationsInput | string | null + analyzable?: BoolFieldUpdateOperationsInput | boolean + status?: StringFieldUpdateOperationsInput | string + closesAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lastSynced?: DateTimeFieldUpdateOperationsInput | Date | string + signals?: AISignalUncheckedUpdateManyWithoutMarketNestedInput + watchlist?: WatchlistUncheckedUpdateManyWithoutMarketNestedInput + alerts?: AlertUncheckedUpdateManyWithoutMarketNestedInput + } + + export type UserCreateWithoutWatchlistInput = { + email: string + passwordHash: string + isActive?: boolean + telegramChatId?: string | null + createdAt?: Date | string + updatedAt?: Date | string + positions?: PositionCreateNestedManyWithoutUserInput + alerts?: AlertCreateNestedManyWithoutUserInput + } + + export type UserUncheckedCreateWithoutWatchlistInput = { + id?: number + email: string + passwordHash: string + isActive?: boolean + telegramChatId?: string | null + createdAt?: Date | string + updatedAt?: Date | string + positions?: PositionUncheckedCreateNestedManyWithoutUserInput + alerts?: AlertUncheckedCreateNestedManyWithoutUserInput + } + + export type UserCreateOrConnectWithoutWatchlistInput = { + where: UserWhereUniqueInput + create: XOR + } + + export type MarketCreateWithoutWatchlistInput = { + id: string + question: string + category?: string | null + countryCode?: string | null + yesPrice?: number | null + noPrice?: number | null + volumeEur?: number | null + liquidityEur?: number | null + spread?: number | null + bestBid?: number | null + bestAsk?: number | null + clobTokenId?: string | null + analyzable?: boolean + status?: string + closesAt?: Date | string | null + lastSynced?: Date | string + signals?: AISignalCreateNestedManyWithoutMarketInput + positions?: PositionCreateNestedManyWithoutMarketInput + alerts?: AlertCreateNestedManyWithoutMarketInput + } + + export type MarketUncheckedCreateWithoutWatchlistInput = { + id: string + question: string + category?: string | null + countryCode?: string | null + yesPrice?: number | null + noPrice?: number | null + volumeEur?: number | null + liquidityEur?: number | null + spread?: number | null + bestBid?: number | null + bestAsk?: number | null + clobTokenId?: string | null + analyzable?: boolean + status?: string + closesAt?: Date | string | null + lastSynced?: Date | string + signals?: AISignalUncheckedCreateNestedManyWithoutMarketInput + positions?: PositionUncheckedCreateNestedManyWithoutMarketInput + alerts?: AlertUncheckedCreateNestedManyWithoutMarketInput + } + + export type MarketCreateOrConnectWithoutWatchlistInput = { + where: MarketWhereUniqueInput + create: XOR + } + + export type UserUpsertWithoutWatchlistInput = { + update: XOR + create: XOR + where?: UserWhereInput + } + + export type UserUpdateToOneWithWhereWithoutWatchlistInput = { + where?: UserWhereInput + data: XOR + } + + export type UserUpdateWithoutWatchlistInput = { + email?: StringFieldUpdateOperationsInput | string + passwordHash?: StringFieldUpdateOperationsInput | string + isActive?: BoolFieldUpdateOperationsInput | boolean + telegramChatId?: NullableStringFieldUpdateOperationsInput | string | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + positions?: PositionUpdateManyWithoutUserNestedInput + alerts?: AlertUpdateManyWithoutUserNestedInput + } + + export type UserUncheckedUpdateWithoutWatchlistInput = { + id?: IntFieldUpdateOperationsInput | number + email?: StringFieldUpdateOperationsInput | string + passwordHash?: StringFieldUpdateOperationsInput | string + isActive?: BoolFieldUpdateOperationsInput | boolean + telegramChatId?: NullableStringFieldUpdateOperationsInput | string | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + positions?: PositionUncheckedUpdateManyWithoutUserNestedInput + alerts?: AlertUncheckedUpdateManyWithoutUserNestedInput + } + + export type MarketUpsertWithoutWatchlistInput = { + update: XOR + create: XOR + where?: MarketWhereInput + } + + export type MarketUpdateToOneWithWhereWithoutWatchlistInput = { + where?: MarketWhereInput + data: XOR + } + + export type MarketUpdateWithoutWatchlistInput = { + id?: StringFieldUpdateOperationsInput | string + question?: StringFieldUpdateOperationsInput | string + category?: NullableStringFieldUpdateOperationsInput | string | null + countryCode?: NullableStringFieldUpdateOperationsInput | string | null + yesPrice?: NullableFloatFieldUpdateOperationsInput | number | null + noPrice?: NullableFloatFieldUpdateOperationsInput | number | null + volumeEur?: NullableFloatFieldUpdateOperationsInput | number | null + liquidityEur?: NullableFloatFieldUpdateOperationsInput | number | null + spread?: NullableFloatFieldUpdateOperationsInput | number | null + bestBid?: NullableFloatFieldUpdateOperationsInput | number | null + bestAsk?: NullableFloatFieldUpdateOperationsInput | number | null + clobTokenId?: NullableStringFieldUpdateOperationsInput | string | null + analyzable?: BoolFieldUpdateOperationsInput | boolean + status?: StringFieldUpdateOperationsInput | string + closesAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lastSynced?: DateTimeFieldUpdateOperationsInput | Date | string + signals?: AISignalUpdateManyWithoutMarketNestedInput + positions?: PositionUpdateManyWithoutMarketNestedInput + alerts?: AlertUpdateManyWithoutMarketNestedInput + } + + export type MarketUncheckedUpdateWithoutWatchlistInput = { + id?: StringFieldUpdateOperationsInput | string + question?: StringFieldUpdateOperationsInput | string + category?: NullableStringFieldUpdateOperationsInput | string | null + countryCode?: NullableStringFieldUpdateOperationsInput | string | null + yesPrice?: NullableFloatFieldUpdateOperationsInput | number | null + noPrice?: NullableFloatFieldUpdateOperationsInput | number | null + volumeEur?: NullableFloatFieldUpdateOperationsInput | number | null + liquidityEur?: NullableFloatFieldUpdateOperationsInput | number | null + spread?: NullableFloatFieldUpdateOperationsInput | number | null + bestBid?: NullableFloatFieldUpdateOperationsInput | number | null + bestAsk?: NullableFloatFieldUpdateOperationsInput | number | null + clobTokenId?: NullableStringFieldUpdateOperationsInput | string | null + analyzable?: BoolFieldUpdateOperationsInput | boolean + status?: StringFieldUpdateOperationsInput | string + closesAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lastSynced?: DateTimeFieldUpdateOperationsInput | Date | string + signals?: AISignalUncheckedUpdateManyWithoutMarketNestedInput + positions?: PositionUncheckedUpdateManyWithoutMarketNestedInput + alerts?: AlertUncheckedUpdateManyWithoutMarketNestedInput + } + + export type UserCreateWithoutAlertsInput = { + email: string + passwordHash: string + isActive?: boolean + telegramChatId?: string | null + createdAt?: Date | string + updatedAt?: Date | string + positions?: PositionCreateNestedManyWithoutUserInput + watchlist?: WatchlistCreateNestedManyWithoutUserInput + } + + export type UserUncheckedCreateWithoutAlertsInput = { + id?: number + email: string + passwordHash: string + isActive?: boolean + telegramChatId?: string | null + createdAt?: Date | string + updatedAt?: Date | string + positions?: PositionUncheckedCreateNestedManyWithoutUserInput + watchlist?: WatchlistUncheckedCreateNestedManyWithoutUserInput + } + + export type UserCreateOrConnectWithoutAlertsInput = { + where: UserWhereUniqueInput + create: XOR + } + + export type MarketCreateWithoutAlertsInput = { + id: string + question: string + category?: string | null + countryCode?: string | null + yesPrice?: number | null + noPrice?: number | null + volumeEur?: number | null + liquidityEur?: number | null + spread?: number | null + bestBid?: number | null + bestAsk?: number | null + clobTokenId?: string | null + analyzable?: boolean + status?: string + closesAt?: Date | string | null + lastSynced?: Date | string + signals?: AISignalCreateNestedManyWithoutMarketInput + positions?: PositionCreateNestedManyWithoutMarketInput + watchlist?: WatchlistCreateNestedManyWithoutMarketInput + } + + export type MarketUncheckedCreateWithoutAlertsInput = { + id: string + question: string + category?: string | null + countryCode?: string | null + yesPrice?: number | null + noPrice?: number | null + volumeEur?: number | null + liquidityEur?: number | null + spread?: number | null + bestBid?: number | null + bestAsk?: number | null + clobTokenId?: string | null + analyzable?: boolean + status?: string + closesAt?: Date | string | null + lastSynced?: Date | string + signals?: AISignalUncheckedCreateNestedManyWithoutMarketInput + positions?: PositionUncheckedCreateNestedManyWithoutMarketInput + watchlist?: WatchlistUncheckedCreateNestedManyWithoutMarketInput + } + + export type MarketCreateOrConnectWithoutAlertsInput = { + where: MarketWhereUniqueInput + create: XOR + } + + export type UserUpsertWithoutAlertsInput = { + update: XOR + create: XOR + where?: UserWhereInput + } + + export type UserUpdateToOneWithWhereWithoutAlertsInput = { + where?: UserWhereInput + data: XOR + } + + export type UserUpdateWithoutAlertsInput = { + email?: StringFieldUpdateOperationsInput | string + passwordHash?: StringFieldUpdateOperationsInput | string + isActive?: BoolFieldUpdateOperationsInput | boolean + telegramChatId?: NullableStringFieldUpdateOperationsInput | string | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + positions?: PositionUpdateManyWithoutUserNestedInput + watchlist?: WatchlistUpdateManyWithoutUserNestedInput + } + + export type UserUncheckedUpdateWithoutAlertsInput = { + id?: IntFieldUpdateOperationsInput | number + email?: StringFieldUpdateOperationsInput | string + passwordHash?: StringFieldUpdateOperationsInput | string + isActive?: BoolFieldUpdateOperationsInput | boolean + telegramChatId?: NullableStringFieldUpdateOperationsInput | string | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + positions?: PositionUncheckedUpdateManyWithoutUserNestedInput + watchlist?: WatchlistUncheckedUpdateManyWithoutUserNestedInput + } + + export type MarketUpsertWithoutAlertsInput = { + update: XOR + create: XOR + where?: MarketWhereInput + } + + export type MarketUpdateToOneWithWhereWithoutAlertsInput = { + where?: MarketWhereInput + data: XOR + } + + export type MarketUpdateWithoutAlertsInput = { + id?: StringFieldUpdateOperationsInput | string + question?: StringFieldUpdateOperationsInput | string + category?: NullableStringFieldUpdateOperationsInput | string | null + countryCode?: NullableStringFieldUpdateOperationsInput | string | null + yesPrice?: NullableFloatFieldUpdateOperationsInput | number | null + noPrice?: NullableFloatFieldUpdateOperationsInput | number | null + volumeEur?: NullableFloatFieldUpdateOperationsInput | number | null + liquidityEur?: NullableFloatFieldUpdateOperationsInput | number | null + spread?: NullableFloatFieldUpdateOperationsInput | number | null + bestBid?: NullableFloatFieldUpdateOperationsInput | number | null + bestAsk?: NullableFloatFieldUpdateOperationsInput | number | null + clobTokenId?: NullableStringFieldUpdateOperationsInput | string | null + analyzable?: BoolFieldUpdateOperationsInput | boolean + status?: StringFieldUpdateOperationsInput | string + closesAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lastSynced?: DateTimeFieldUpdateOperationsInput | Date | string + signals?: AISignalUpdateManyWithoutMarketNestedInput + positions?: PositionUpdateManyWithoutMarketNestedInput + watchlist?: WatchlistUpdateManyWithoutMarketNestedInput + } + + export type MarketUncheckedUpdateWithoutAlertsInput = { + id?: StringFieldUpdateOperationsInput | string + question?: StringFieldUpdateOperationsInput | string + category?: NullableStringFieldUpdateOperationsInput | string | null + countryCode?: NullableStringFieldUpdateOperationsInput | string | null + yesPrice?: NullableFloatFieldUpdateOperationsInput | number | null + noPrice?: NullableFloatFieldUpdateOperationsInput | number | null + volumeEur?: NullableFloatFieldUpdateOperationsInput | number | null + liquidityEur?: NullableFloatFieldUpdateOperationsInput | number | null + spread?: NullableFloatFieldUpdateOperationsInput | number | null + bestBid?: NullableFloatFieldUpdateOperationsInput | number | null + bestAsk?: NullableFloatFieldUpdateOperationsInput | number | null + clobTokenId?: NullableStringFieldUpdateOperationsInput | string | null + analyzable?: BoolFieldUpdateOperationsInput | boolean + status?: StringFieldUpdateOperationsInput | string + closesAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + lastSynced?: DateTimeFieldUpdateOperationsInput | Date | string + signals?: AISignalUncheckedUpdateManyWithoutMarketNestedInput + positions?: PositionUncheckedUpdateManyWithoutMarketNestedInput + watchlist?: WatchlistUncheckedUpdateManyWithoutMarketNestedInput + } + + export type PositionCreateManyUserInput = { + id?: number + marketId: string + outcome: string + amountEur: number + entryPrice: number + currentPrice?: number | null + pnl?: number + kellyFraction?: number | null + status?: string + openedAt?: Date | string + closedAt?: Date | string | null + } + + export type WatchlistCreateManyUserInput = { + id?: number + marketId: string + alertThreshold?: number | null + createdAt?: Date | string + } + + export type AlertCreateManyUserInput = { + id?: number + marketId: string + type: string + message: string + sentAt?: Date | string + } + + export type PositionUpdateWithoutUserInput = { + outcome?: StringFieldUpdateOperationsInput | string + amountEur?: FloatFieldUpdateOperationsInput | number + entryPrice?: FloatFieldUpdateOperationsInput | number + currentPrice?: NullableFloatFieldUpdateOperationsInput | number | null + pnl?: FloatFieldUpdateOperationsInput | number + kellyFraction?: NullableFloatFieldUpdateOperationsInput | number | null + status?: StringFieldUpdateOperationsInput | string + openedAt?: DateTimeFieldUpdateOperationsInput | Date | string + closedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + market?: MarketUpdateOneRequiredWithoutPositionsNestedInput + } + + export type PositionUncheckedUpdateWithoutUserInput = { + id?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + outcome?: StringFieldUpdateOperationsInput | string + amountEur?: FloatFieldUpdateOperationsInput | number + entryPrice?: FloatFieldUpdateOperationsInput | number + currentPrice?: NullableFloatFieldUpdateOperationsInput | number | null + pnl?: FloatFieldUpdateOperationsInput | number + kellyFraction?: NullableFloatFieldUpdateOperationsInput | number | null + status?: StringFieldUpdateOperationsInput | string + openedAt?: DateTimeFieldUpdateOperationsInput | Date | string + closedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + } + + export type PositionUncheckedUpdateManyWithoutUserInput = { + id?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + outcome?: StringFieldUpdateOperationsInput | string + amountEur?: FloatFieldUpdateOperationsInput | number + entryPrice?: FloatFieldUpdateOperationsInput | number + currentPrice?: NullableFloatFieldUpdateOperationsInput | number | null + pnl?: FloatFieldUpdateOperationsInput | number + kellyFraction?: NullableFloatFieldUpdateOperationsInput | number | null + status?: StringFieldUpdateOperationsInput | string + openedAt?: DateTimeFieldUpdateOperationsInput | Date | string + closedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + } + + export type WatchlistUpdateWithoutUserInput = { + alertThreshold?: NullableFloatFieldUpdateOperationsInput | number | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + market?: MarketUpdateOneRequiredWithoutWatchlistNestedInput + } + + export type WatchlistUncheckedUpdateWithoutUserInput = { + id?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + alertThreshold?: NullableFloatFieldUpdateOperationsInput | number | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type WatchlistUncheckedUpdateManyWithoutUserInput = { + id?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + alertThreshold?: NullableFloatFieldUpdateOperationsInput | number | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type AlertUpdateWithoutUserInput = { + type?: StringFieldUpdateOperationsInput | string + message?: StringFieldUpdateOperationsInput | string + sentAt?: DateTimeFieldUpdateOperationsInput | Date | string + market?: MarketUpdateOneRequiredWithoutAlertsNestedInput + } + + export type AlertUncheckedUpdateWithoutUserInput = { + id?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + type?: StringFieldUpdateOperationsInput | string + message?: StringFieldUpdateOperationsInput | string + sentAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type AlertUncheckedUpdateManyWithoutUserInput = { + id?: IntFieldUpdateOperationsInput | number + marketId?: StringFieldUpdateOperationsInput | string + type?: StringFieldUpdateOperationsInput | string + message?: StringFieldUpdateOperationsInput | string + sentAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type AISignalCreateManyMarketInput = { + id?: number + signal: string + confidence: number + summary?: string | null + keyRisk?: string | null + newsCount?: number + modelVersion?: string + impliedProb?: number | null + fairProb?: number | null + edgePoints?: number | null + generatedAt?: Date | string + } + + export type PositionCreateManyMarketInput = { + id?: number + userId: number + outcome: string + amountEur: number + entryPrice: number + currentPrice?: number | null + pnl?: number + kellyFraction?: number | null + status?: string + openedAt?: Date | string + closedAt?: Date | string | null + } + + export type WatchlistCreateManyMarketInput = { + id?: number + userId: number + alertThreshold?: number | null + createdAt?: Date | string + } + + export type AlertCreateManyMarketInput = { + id?: number + userId: number + type: string + message: string + sentAt?: Date | string + } + + export type AISignalUpdateWithoutMarketInput = { + signal?: StringFieldUpdateOperationsInput | string + confidence?: FloatFieldUpdateOperationsInput | number + summary?: NullableStringFieldUpdateOperationsInput | string | null + keyRisk?: NullableStringFieldUpdateOperationsInput | string | null + newsCount?: IntFieldUpdateOperationsInput | number + modelVersion?: StringFieldUpdateOperationsInput | string + impliedProb?: NullableFloatFieldUpdateOperationsInput | number | null + fairProb?: NullableFloatFieldUpdateOperationsInput | number | null + edgePoints?: NullableFloatFieldUpdateOperationsInput | number | null + generatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type AISignalUncheckedUpdateWithoutMarketInput = { + id?: IntFieldUpdateOperationsInput | number + signal?: StringFieldUpdateOperationsInput | string + confidence?: FloatFieldUpdateOperationsInput | number + summary?: NullableStringFieldUpdateOperationsInput | string | null + keyRisk?: NullableStringFieldUpdateOperationsInput | string | null + newsCount?: IntFieldUpdateOperationsInput | number + modelVersion?: StringFieldUpdateOperationsInput | string + impliedProb?: NullableFloatFieldUpdateOperationsInput | number | null + fairProb?: NullableFloatFieldUpdateOperationsInput | number | null + edgePoints?: NullableFloatFieldUpdateOperationsInput | number | null + generatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type AISignalUncheckedUpdateManyWithoutMarketInput = { + id?: IntFieldUpdateOperationsInput | number + signal?: StringFieldUpdateOperationsInput | string + confidence?: FloatFieldUpdateOperationsInput | number + summary?: NullableStringFieldUpdateOperationsInput | string | null + keyRisk?: NullableStringFieldUpdateOperationsInput | string | null + newsCount?: IntFieldUpdateOperationsInput | number + modelVersion?: StringFieldUpdateOperationsInput | string + impliedProb?: NullableFloatFieldUpdateOperationsInput | number | null + fairProb?: NullableFloatFieldUpdateOperationsInput | number | null + edgePoints?: NullableFloatFieldUpdateOperationsInput | number | null + generatedAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type PositionUpdateWithoutMarketInput = { + outcome?: StringFieldUpdateOperationsInput | string + amountEur?: FloatFieldUpdateOperationsInput | number + entryPrice?: FloatFieldUpdateOperationsInput | number + currentPrice?: NullableFloatFieldUpdateOperationsInput | number | null + pnl?: FloatFieldUpdateOperationsInput | number + kellyFraction?: NullableFloatFieldUpdateOperationsInput | number | null + status?: StringFieldUpdateOperationsInput | string + openedAt?: DateTimeFieldUpdateOperationsInput | Date | string + closedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + user?: UserUpdateOneRequiredWithoutPositionsNestedInput + } + + export type PositionUncheckedUpdateWithoutMarketInput = { + id?: IntFieldUpdateOperationsInput | number + userId?: IntFieldUpdateOperationsInput | number + outcome?: StringFieldUpdateOperationsInput | string + amountEur?: FloatFieldUpdateOperationsInput | number + entryPrice?: FloatFieldUpdateOperationsInput | number + currentPrice?: NullableFloatFieldUpdateOperationsInput | number | null + pnl?: FloatFieldUpdateOperationsInput | number + kellyFraction?: NullableFloatFieldUpdateOperationsInput | number | null + status?: StringFieldUpdateOperationsInput | string + openedAt?: DateTimeFieldUpdateOperationsInput | Date | string + closedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + } + + export type PositionUncheckedUpdateManyWithoutMarketInput = { + id?: IntFieldUpdateOperationsInput | number + userId?: IntFieldUpdateOperationsInput | number + outcome?: StringFieldUpdateOperationsInput | string + amountEur?: FloatFieldUpdateOperationsInput | number + entryPrice?: FloatFieldUpdateOperationsInput | number + currentPrice?: NullableFloatFieldUpdateOperationsInput | number | null + pnl?: FloatFieldUpdateOperationsInput | number + kellyFraction?: NullableFloatFieldUpdateOperationsInput | number | null + status?: StringFieldUpdateOperationsInput | string + openedAt?: DateTimeFieldUpdateOperationsInput | Date | string + closedAt?: NullableDateTimeFieldUpdateOperationsInput | Date | string | null + } + + export type WatchlistUpdateWithoutMarketInput = { + alertThreshold?: NullableFloatFieldUpdateOperationsInput | number | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + user?: UserUpdateOneRequiredWithoutWatchlistNestedInput + } + + export type WatchlistUncheckedUpdateWithoutMarketInput = { + id?: IntFieldUpdateOperationsInput | number + userId?: IntFieldUpdateOperationsInput | number + alertThreshold?: NullableFloatFieldUpdateOperationsInput | number | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type WatchlistUncheckedUpdateManyWithoutMarketInput = { + id?: IntFieldUpdateOperationsInput | number + userId?: IntFieldUpdateOperationsInput | number + alertThreshold?: NullableFloatFieldUpdateOperationsInput | number | null + createdAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type AlertUpdateWithoutMarketInput = { + type?: StringFieldUpdateOperationsInput | string + message?: StringFieldUpdateOperationsInput | string + sentAt?: DateTimeFieldUpdateOperationsInput | Date | string + user?: UserUpdateOneRequiredWithoutAlertsNestedInput + } + + export type AlertUncheckedUpdateWithoutMarketInput = { + id?: IntFieldUpdateOperationsInput | number + userId?: IntFieldUpdateOperationsInput | number + type?: StringFieldUpdateOperationsInput | string + message?: StringFieldUpdateOperationsInput | string + sentAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + export type AlertUncheckedUpdateManyWithoutMarketInput = { + id?: IntFieldUpdateOperationsInput | number + userId?: IntFieldUpdateOperationsInput | number + type?: StringFieldUpdateOperationsInput | string + message?: StringFieldUpdateOperationsInput | string + sentAt?: DateTimeFieldUpdateOperationsInput | Date | string + } + + + + /** + * Batch Payload for updateMany & deleteMany & createMany + */ + + export type BatchPayload = { + count: number + } + + /** + * DMMF + */ + export const dmmf: runtime.BaseDMMF +} \ No newline at end of file diff --git a/backend/node_modules/.prisma/client/index.js b/backend/node_modules/.prisma/client/index.js new file mode 100644 index 0000000000000000000000000000000000000000..da231bbcf6a5b251c874000e9272773abb186702 --- /dev/null +++ b/backend/node_modules/.prisma/client/index.js @@ -0,0 +1,280 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! +/* eslint-disable */ +// biome-ignore-all lint: generated file + +Object.defineProperty(exports, "__esModule", { value: true }); + +const { + PrismaClientKnownRequestError, + PrismaClientUnknownRequestError, + PrismaClientRustPanicError, + PrismaClientInitializationError, + PrismaClientValidationError, + getPrismaClient, + sqltag, + empty, + join, + raw, + skip, + Decimal, + Debug, + objectEnumValues, + makeStrictEnum, + Extensions, + warnOnce, + defineDmmfProperty, + Public, + getRuntime, + createParam, +} = require('@prisma/client/runtime/library.js') + + +const Prisma = {} + +exports.Prisma = Prisma +exports.$Enums = {} + +/** + * Prisma Client JS version: 6.19.3 + * Query Engine version: c2990dca591cba766e3b7ef5d9e8a84796e47ab7 + */ +Prisma.prismaVersion = { + client: "6.19.3", + engine: "c2990dca591cba766e3b7ef5d9e8a84796e47ab7" +} + +Prisma.PrismaClientKnownRequestError = PrismaClientKnownRequestError; +Prisma.PrismaClientUnknownRequestError = PrismaClientUnknownRequestError +Prisma.PrismaClientRustPanicError = PrismaClientRustPanicError +Prisma.PrismaClientInitializationError = PrismaClientInitializationError +Prisma.PrismaClientValidationError = PrismaClientValidationError +Prisma.Decimal = Decimal + +/** + * Re-export of sql-template-tag + */ +Prisma.sql = sqltag +Prisma.empty = empty +Prisma.join = join +Prisma.raw = raw +Prisma.validator = Public.validator + +/** +* Extensions +*/ +Prisma.getExtensionContext = Extensions.getExtensionContext +Prisma.defineExtension = Extensions.defineExtension + +/** + * Shorthand utilities for JSON filtering + */ +Prisma.DbNull = objectEnumValues.instances.DbNull +Prisma.JsonNull = objectEnumValues.instances.JsonNull +Prisma.AnyNull = objectEnumValues.instances.AnyNull + +Prisma.NullTypes = { + DbNull: objectEnumValues.classes.DbNull, + JsonNull: objectEnumValues.classes.JsonNull, + AnyNull: objectEnumValues.classes.AnyNull +} + + + + + const path = require('path') + +/** + * Enums + */ +exports.Prisma.TransactionIsolationLevel = makeStrictEnum({ + Serializable: 'Serializable' +}); + +exports.Prisma.UserScalarFieldEnum = { + id: 'id', + email: 'email', + passwordHash: 'passwordHash', + isActive: 'isActive', + telegramChatId: 'telegramChatId', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +}; + +exports.Prisma.MarketScalarFieldEnum = { + id: 'id', + question: 'question', + category: 'category', + countryCode: 'countryCode', + yesPrice: 'yesPrice', + noPrice: 'noPrice', + volumeEur: 'volumeEur', + liquidityEur: 'liquidityEur', + spread: 'spread', + bestBid: 'bestBid', + bestAsk: 'bestAsk', + clobTokenId: 'clobTokenId', + analyzable: 'analyzable', + status: 'status', + closesAt: 'closesAt', + lastSynced: 'lastSynced' +}; + +exports.Prisma.AISignalScalarFieldEnum = { + id: 'id', + marketId: 'marketId', + signal: 'signal', + confidence: 'confidence', + summary: 'summary', + keyRisk: 'keyRisk', + newsCount: 'newsCount', + modelVersion: 'modelVersion', + impliedProb: 'impliedProb', + fairProb: 'fairProb', + edgePoints: 'edgePoints', + generatedAt: 'generatedAt' +}; + +exports.Prisma.PositionScalarFieldEnum = { + id: 'id', + userId: 'userId', + marketId: 'marketId', + outcome: 'outcome', + amountEur: 'amountEur', + entryPrice: 'entryPrice', + currentPrice: 'currentPrice', + pnl: 'pnl', + kellyFraction: 'kellyFraction', + status: 'status', + openedAt: 'openedAt', + closedAt: 'closedAt' +}; + +exports.Prisma.WatchlistScalarFieldEnum = { + id: 'id', + userId: 'userId', + marketId: 'marketId', + alertThreshold: 'alertThreshold', + createdAt: 'createdAt' +}; + +exports.Prisma.AlertScalarFieldEnum = { + id: 'id', + userId: 'userId', + marketId: 'marketId', + type: 'type', + message: 'message', + sentAt: 'sentAt' +}; + +exports.Prisma.SortOrder = { + asc: 'asc', + desc: 'desc' +}; + +exports.Prisma.NullsOrder = { + first: 'first', + last: 'last' +}; + + +exports.Prisma.ModelName = { + User: 'User', + Market: 'Market', + AISignal: 'AISignal', + Position: 'Position', + Watchlist: 'Watchlist', + Alert: 'Alert' +}; +/** + * Create the Client + */ +const config = { + "generator": { + "name": "client", + "provider": { + "fromEnvVar": null, + "value": "prisma-client-js" + }, + "output": { + "value": "/Users/josesalazar/proyecto-hackaton/backend/node_modules/@prisma/client", + "fromEnvVar": null + }, + "config": { + "engineType": "library" + }, + "binaryTargets": [ + { + "fromEnvVar": null, + "value": "darwin-arm64", + "native": true + } + ], + "previewFeatures": [], + "sourceFilePath": "/Users/josesalazar/proyecto-hackaton/backend/prisma/schema.prisma" + }, + "relativeEnvPaths": { + "rootEnvPath": null, + "schemaEnvPath": "../../../.env" + }, + "relativePath": "../../../prisma", + "clientVersion": "6.19.3", + "engineVersion": "c2990dca591cba766e3b7ef5d9e8a84796e47ab7", + "datasourceNames": [ + "db" + ], + "activeProvider": "sqlite", + "postinstall": false, + "inlineDatasources": { + "db": { + "url": { + "fromEnvVar": "DATABASE_URL", + "value": null + } + } + }, + "inlineSchema": "/**\n * Schema de Prisma ORM para base de datos SQLite.\n * Define 6 modelos: User, Market, AISignal, Position, Watchlist, Alert.\n * Relaciones:\n * - Market 1:N AISignal, Position, Watchlist, Alert\n * - User 1:N Position, Watchlist, Alert\n * No modificar sin consenso del equipo. Generar migraciones con:\n * npx prisma migrate dev\n * npx prisma generate\n */\n\ngenerator client {\n provider = \"prisma-client-js\"\n}\n\ndatasource db {\n provider = \"sqlite\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel User {\n id Int @id @default(autoincrement())\n email String @unique\n passwordHash String\n isActive Boolean @default(true)\n telegramChatId String? // Configurado manualmente para demo\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n positions Position[]\n watchlist Watchlist[]\n alerts Alert[]\n}\n\nmodel Market {\n id String @id // ID nativo de Polymarket\n question String // Texto de la pregunta del mercado\n category String? // politics | crypto | economics | sports\n countryCode String? // ISO2 — usado por Leaflet para burbujas\n yesPrice Float? // Precio YES: 0.0 a 1.0\n noPrice Float? // Precio NO: 0.0 a 1.0\n volumeEur Float? // Volumen en Eur\n liquidityEur Float? // Liquidez en Eur\n spread Float? // Bid/ask spread (0-1, ej 0.02 = 2c)\n bestBid Float? // Mejor oferta de compra\n bestAsk Float? // Mejor oferta de venta\n clobTokenId String? // YES outcome CLOB token ID (para prices-history)\n analyzable Boolean @default(true) // Si la IA tiene edge plausible aqui\n status String @default(\"active\") // active | closed | resolved\n closesAt DateTime? // Fecha de cierre del mercado\n lastSynced DateTime @default(now()) // Ultima sincronizacion de precios\n\n signals AISignal[]\n positions Position[]\n watchlist Watchlist[]\n alerts Alert[]\n}\n\nmodel AISignal {\n id Int @id @default(autoincrement())\n marketId String\n market Market @relation(fields: [marketId], references: [id], onDelete: Cascade)\n signal String // bullish | bearish | neutral\n confidence Float // 0.0 a 1.0\n summary String? // 2 frases generadas por Qwen3\n keyRisk String? // 1 frase de riesgo principal\n newsCount Int @default(0) // Titulares relevantes usados\n modelVersion String @default(\"Qwen3-8B\") // Modelo LLM que genero la senal\n impliedProb Float? // Probabilidad implicita YES al generar (0-1)\n fairProb Float? // Probabilidad \"justa\" segun IA (0-1)\n edgePoints Float? // (fairProb - impliedProb) * 100, signo conserva direccion\n generatedAt DateTime @default(now())\n\n @@index([marketId, generatedAt])\n}\n\nmodel Position {\n id Int @id @default(autoincrement())\n userId Int\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n marketId String\n market Market @relation(fields: [marketId], references: [id], onDelete: Cascade)\n outcome String // YES | NO\n amountEur Float // Capital virtual apostado\n entryPrice Float // Precio al abrir la posicion\n currentPrice Float? // Precio actual (actualizado por scheduler)\n pnl Float @default(0) // Profit and Loss calculado\n kellyFraction Float? // Fraccion de Kelly al abrir\n status String @default(\"open\") // open | closed\n openedAt DateTime @default(now())\n closedAt DateTime?\n\n @@index([userId, status])\n @@index([marketId])\n}\n\nmodel Watchlist {\n id Int @id @default(autoincrement())\n userId Int\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n marketId String\n market Market @relation(fields: [marketId], references: [id], onDelete: Cascade)\n alertThreshold Float? // Umbral de precio para alerta Telegram\n createdAt DateTime @default(now())\n\n @@unique([userId, marketId])\n @@index([userId])\n}\n\nmodel Alert {\n id Int @id @default(autoincrement())\n userId Int\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n marketId String\n market Market @relation(fields: [marketId], references: [id], onDelete: Cascade)\n type String // price_threshold | signal_change\n message String // Texto enviado por Telegram\n sentAt DateTime @default(now())\n\n @@index([userId, sentAt])\n @@index([marketId])\n}\n", + "inlineSchemaHash": "317e51352744228f8aa2577b7d08529ce57f6e47ee90dbf1318c8edc1a7164fb", + "copyEngine": true +} + +const fs = require('fs') + +config.dirname = __dirname +if (!fs.existsSync(path.join(__dirname, 'schema.prisma'))) { + const alternativePaths = [ + "node_modules/.prisma/client", + ".prisma/client", + ] + + const alternativePath = alternativePaths.find((altPath) => { + return fs.existsSync(path.join(process.cwd(), altPath, 'schema.prisma')) + }) ?? alternativePaths[0] + + config.dirname = path.join(process.cwd(), alternativePath) + config.isBundled = true +} + +config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"dbName\":null,\"schema\":null,\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Int\",\"nativeType\":null,\"default\":{\"name\":\"autoincrement\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"email\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":true,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"passwordHash\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"isActive\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Boolean\",\"nativeType\":null,\"default\":true,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"telegramChatId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":null,\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"DateTime\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":true},{\"name\":\"positions\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Position\",\"nativeType\":null,\"relationName\":\"PositionToUser\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"watchlist\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Watchlist\",\"nativeType\":null,\"relationName\":\"UserToWatchlist\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"alerts\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Alert\",\"nativeType\":null,\"relationName\":\"AlertToUser\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false},\"Market\":{\"dbName\":null,\"schema\":null,\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"question\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"category\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"countryCode\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"yesPrice\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"noPrice\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"volumeEur\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"liquidityEur\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"spread\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"bestBid\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"bestAsk\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"clobTokenId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"analyzable\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Boolean\",\"nativeType\":null,\"default\":true,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"status\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"String\",\"nativeType\":null,\"default\":\"active\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"closesAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"DateTime\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"lastSynced\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":null,\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"signals\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"AISignal\",\"nativeType\":null,\"relationName\":\"AISignalToMarket\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"positions\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Position\",\"nativeType\":null,\"relationName\":\"MarketToPosition\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"watchlist\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Watchlist\",\"nativeType\":null,\"relationName\":\"MarketToWatchlist\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"alerts\",\"kind\":\"object\",\"isList\":true,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Alert\",\"nativeType\":null,\"relationName\":\"AlertToMarket\",\"relationFromFields\":[],\"relationToFields\":[],\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false},\"AISignal\":{\"dbName\":null,\"schema\":null,\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Int\",\"nativeType\":null,\"default\":{\"name\":\"autoincrement\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"marketId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"market\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Market\",\"nativeType\":null,\"relationName\":\"AISignalToMarket\",\"relationFromFields\":[\"marketId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"signal\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"confidence\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"summary\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"keyRisk\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"newsCount\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Int\",\"nativeType\":null,\"default\":0,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"modelVersion\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"String\",\"nativeType\":null,\"default\":\"Qwen3-8B\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"impliedProb\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"fairProb\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"edgePoints\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"generatedAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":null,\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false},\"Position\":{\"dbName\":null,\"schema\":null,\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Int\",\"nativeType\":null,\"default\":{\"name\":\"autoincrement\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"userId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"Int\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"user\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"User\",\"nativeType\":null,\"relationName\":\"PositionToUser\",\"relationFromFields\":[\"userId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"marketId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"market\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Market\",\"nativeType\":null,\"relationName\":\"MarketToPosition\",\"relationFromFields\":[\"marketId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"outcome\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"amountEur\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"entryPrice\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"currentPrice\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"pnl\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Float\",\"nativeType\":null,\"default\":0,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"kellyFraction\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"status\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"String\",\"nativeType\":null,\"default\":\"open\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"openedAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":null,\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"closedAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"DateTime\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false},\"Watchlist\":{\"dbName\":null,\"schema\":null,\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Int\",\"nativeType\":null,\"default\":{\"name\":\"autoincrement\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"userId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"Int\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"user\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"User\",\"nativeType\":null,\"relationName\":\"UserToWatchlist\",\"relationFromFields\":[\"userId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"marketId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"market\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Market\",\"nativeType\":null,\"relationName\":\"MarketToWatchlist\",\"relationFromFields\":[\"marketId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"alertThreshold\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":false,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Float\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":null,\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[[\"userId\",\"marketId\"]],\"uniqueIndexes\":[{\"name\":null,\"fields\":[\"userId\",\"marketId\"]}],\"isGenerated\":false},\"Alert\":{\"dbName\":null,\"schema\":null,\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":true,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"Int\",\"nativeType\":null,\"default\":{\"name\":\"autoincrement\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"userId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"Int\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"user\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"User\",\"nativeType\":null,\"relationName\":\"AlertToUser\",\"relationFromFields\":[\"userId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"marketId\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":true,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"market\",\"kind\":\"object\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"Market\",\"nativeType\":null,\"relationName\":\"AlertToMarket\",\"relationFromFields\":[\"marketId\"],\"relationToFields\":[\"id\"],\"relationOnDelete\":\"Cascade\",\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"type\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"message\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":false,\"type\":\"String\",\"nativeType\":null,\"isGenerated\":false,\"isUpdatedAt\":false},{\"name\":\"sentAt\",\"kind\":\"scalar\",\"isList\":false,\"isRequired\":true,\"isUnique\":false,\"isId\":false,\"isReadOnly\":false,\"hasDefaultValue\":true,\"type\":\"DateTime\",\"nativeType\":null,\"default\":{\"name\":\"now\",\"args\":[]},\"isGenerated\":false,\"isUpdatedAt\":false}],\"primaryKey\":null,\"uniqueFields\":[],\"uniqueIndexes\":[],\"isGenerated\":false}},\"enums\":{},\"types\":{}}") +defineDmmfProperty(exports.Prisma, config.runtimeDataModel) +config.engineWasm = undefined +config.compilerWasm = undefined + + +const { warnEnvConflicts } = require('@prisma/client/runtime/library.js') + +warnEnvConflicts({ + rootEnvPath: config.relativeEnvPaths.rootEnvPath && path.resolve(config.dirname, config.relativeEnvPaths.rootEnvPath), + schemaEnvPath: config.relativeEnvPaths.schemaEnvPath && path.resolve(config.dirname, config.relativeEnvPaths.schemaEnvPath) +}) + +const PrismaClient = getPrismaClient(config) +exports.PrismaClient = PrismaClient +Object.assign(exports, Prisma) + +// file annotations for bundling tools to include these files +path.join(__dirname, "libquery_engine-darwin-arm64.dylib.node"); +path.join(process.cwd(), "node_modules/.prisma/client/libquery_engine-darwin-arm64.dylib.node") +// file annotations for bundling tools to include these files +path.join(__dirname, "schema.prisma"); +path.join(process.cwd(), "node_modules/.prisma/client/schema.prisma") diff --git a/backend/node_modules/.prisma/client/package.json b/backend/node_modules/.prisma/client/package.json new file mode 100644 index 0000000000000000000000000000000000000000..b58d23b363d6b684dada9036dc97f75b10c98701 --- /dev/null +++ b/backend/node_modules/.prisma/client/package.json @@ -0,0 +1,183 @@ +{ + "name": "prisma-client-0634aaa4a404cb6a55c8296bd6bae6d8210c064fb5efe184937dbdfcfb1dac35", + "main": "index.js", + "types": "index.d.ts", + "browser": "default.js", + "exports": { + "./client": { + "require": { + "node": "./index.js", + "edge-light": "./wasm.js", + "workerd": "./wasm.js", + "worker": "./wasm.js", + "browser": "./index-browser.js", + "default": "./index.js" + }, + "import": { + "node": "./index.js", + "edge-light": "./wasm.js", + "workerd": "./wasm.js", + "worker": "./wasm.js", + "browser": "./index-browser.js", + "default": "./index.js" + }, + "default": "./index.js" + }, + "./package.json": "./package.json", + ".": { + "require": { + "node": "./index.js", + "edge-light": "./wasm.js", + "workerd": "./wasm.js", + "worker": "./wasm.js", + "browser": "./index-browser.js", + "default": "./index.js" + }, + "import": { + "node": "./index.js", + "edge-light": "./wasm.js", + "workerd": "./wasm.js", + "worker": "./wasm.js", + "browser": "./index-browser.js", + "default": "./index.js" + }, + "default": "./index.js" + }, + "./edge": { + "types": "./edge.d.ts", + "require": "./edge.js", + "import": "./edge.js", + "default": "./edge.js" + }, + "./react-native": { + "types": "./react-native.d.ts", + "require": "./react-native.js", + "import": "./react-native.js", + "default": "./react-native.js" + }, + "./extension": { + "types": "./extension.d.ts", + "require": "./extension.js", + "import": "./extension.js", + "default": "./extension.js" + }, + "./index-browser": { + "types": "./index.d.ts", + "require": "./index-browser.js", + "import": "./index-browser.js", + "default": "./index-browser.js" + }, + "./index": { + "types": "./index.d.ts", + "require": "./index.js", + "import": "./index.js", + "default": "./index.js" + }, + "./wasm": { + "types": "./wasm.d.ts", + "require": "./wasm.js", + "import": "./wasm.mjs", + "default": "./wasm.mjs" + }, + "./runtime/client": { + "types": "./runtime/client.d.ts", + "node": { + "require": "./runtime/client.js", + "default": "./runtime/client.js" + }, + "require": "./runtime/client.js", + "import": "./runtime/client.mjs", + "default": "./runtime/client.mjs" + }, + "./runtime/library": { + "types": "./runtime/library.d.ts", + "require": "./runtime/library.js", + "import": "./runtime/library.mjs", + "default": "./runtime/library.mjs" + }, + "./runtime/binary": { + "types": "./runtime/binary.d.ts", + "require": "./runtime/binary.js", + "import": "./runtime/binary.mjs", + "default": "./runtime/binary.mjs" + }, + "./runtime/wasm-engine-edge": { + "types": "./runtime/wasm-engine-edge.d.ts", + "require": "./runtime/wasm-engine-edge.js", + "import": "./runtime/wasm-engine-edge.mjs", + "default": "./runtime/wasm-engine-edge.mjs" + }, + "./runtime/wasm-compiler-edge": { + "types": "./runtime/wasm-compiler-edge.d.ts", + "require": "./runtime/wasm-compiler-edge.js", + "import": "./runtime/wasm-compiler-edge.mjs", + "default": "./runtime/wasm-compiler-edge.mjs" + }, + "./runtime/edge": { + "types": "./runtime/edge.d.ts", + "require": "./runtime/edge.js", + "import": "./runtime/edge-esm.js", + "default": "./runtime/edge-esm.js" + }, + "./runtime/react-native": { + "types": "./runtime/react-native.d.ts", + "require": "./runtime/react-native.js", + "import": "./runtime/react-native.js", + "default": "./runtime/react-native.js" + }, + "./runtime/index-browser": { + "types": "./runtime/index-browser.d.ts", + "require": "./runtime/index-browser.js", + "import": "./runtime/index-browser.mjs", + "default": "./runtime/index-browser.mjs" + }, + "./generator-build": { + "require": "./generator-build/index.js", + "import": "./generator-build/index.js", + "default": "./generator-build/index.js" + }, + "./sql": { + "require": { + "types": "./sql.d.ts", + "node": "./sql.js", + "default": "./sql.js" + }, + "import": { + "types": "./sql.d.ts", + "node": "./sql.mjs", + "default": "./sql.mjs" + }, + "default": "./sql.js" + }, + "./*": "./*" + }, + "version": "6.19.3", + "sideEffects": false, + "imports": { + "#wasm-engine-loader": { + "edge-light": "./wasm-edge-light-loader.mjs", + "workerd": "./wasm-worker-loader.mjs", + "worker": "./wasm-worker-loader.mjs", + "default": "./wasm-worker-loader.mjs" + }, + "#main-entry-point": { + "require": { + "node": "./index.js", + "edge-light": "./wasm.js", + "workerd": "./wasm.js", + "worker": "./wasm.js", + "browser": "./index-browser.js", + "default": "./index.js" + }, + "import": { + "node": "./index.js", + "edge-light": "./wasm.js", + "workerd": "./wasm.js", + "worker": "./wasm.js", + "browser": "./index-browser.js", + "default": "./index.js" + }, + "default": "./index.js" + } + } +} \ No newline at end of file diff --git a/backend/node_modules/.prisma/client/query_engine_bg.js b/backend/node_modules/.prisma/client/query_engine_bg.js new file mode 100644 index 0000000000000000000000000000000000000000..4ade61f681dcab56fbd3121f4d0cfed60f809d37 --- /dev/null +++ b/backend/node_modules/.prisma/client/query_engine_bg.js @@ -0,0 +1,2 @@ +"use strict";var F=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var U=Object.prototype.hasOwnProperty;var L=(e,t)=>{for(var n in t)F(e,n,{get:t[n],enumerable:!0})},N=(e,t,n,_)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of R(t))!U.call(e,o)&&o!==n&&F(e,o,{get:()=>t[o],enumerable:!(_=B(t,o))||_.enumerable});return e};var C=e=>N(F({},"__esModule",{value:!0}),e);var qt={};L(qt,{QueryEngine:()=>E,__wbg_Error_e83987f665cf5504:()=>J,__wbg_Number_bb48ca12f395cd08:()=>X,__wbg_String_8f0eb39a4a4c2f66:()=>Y,__wbg___wbindgen_bigint_get_as_i64_f3ebc5a755000afd:()=>K,__wbg___wbindgen_boolean_get_6d5a1ee65bab5f68:()=>Z,__wbg___wbindgen_debug_string_df47ffb5e35e6763:()=>ee,__wbg___wbindgen_in_bb933bd9e1b3bc0f:()=>te,__wbg___wbindgen_is_bigint_cb320707dcd35f0b:()=>ne,__wbg___wbindgen_is_function_ee8a6c5833c90377:()=>re,__wbg___wbindgen_is_object_c818261d21f283a4:()=>_e,__wbg___wbindgen_is_string_fbb76cb2940daafd:()=>oe,__wbg___wbindgen_is_undefined_2d472862bd29a478:()=>ce,__wbg___wbindgen_jsval_eq_6b13ab83478b1c50:()=>ie,__wbg___wbindgen_jsval_loose_eq_b664b38a2f582147:()=>se,__wbg___wbindgen_number_get_a20bf9b85341449d:()=>ue,__wbg___wbindgen_string_get_e4f06c90489ad01b:()=>be,__wbg___wbindgen_throw_b855445ff6a94295:()=>fe,__wbg__wbg_cb_unref_2454a539ea5790d9:()=>ae,__wbg_call_525440f72fbfc0ea:()=>ge,__wbg_call_e762c39fa8ea36bf:()=>le,__wbg_crypto_805be4ce92f1e370:()=>de,__wbg_done_2042aa2670fb1db1:()=>we,__wbg_entries_e171b586f8f6bdbf:()=>pe,__wbg_getRandomValues_f6a868620c8bab49:()=>xe,__wbg_getTime_14776bfb48a1bff9:()=>ye,__wbg_get_7bed016f185add81:()=>me,__wbg_get_ece95cf6585650d9:()=>he,__wbg_get_efcb449f58ec27c2:()=>Te,__wbg_get_with_ref_key_1dc361bd10053bfe:()=>Ae,__wbg_has_787fafc980c3ccdb:()=>Se,__wbg_instanceof_ArrayBuffer_70beb1189ca63b38:()=>Fe,__wbg_instanceof_Map_8579b5e2ab5437c7:()=>Ie,__wbg_instanceof_Promise_001fdd42afa1b7ef:()=>qe,__wbg_instanceof_Uint8Array_20c8e73002f7af98:()=>ke,__wbg_isArray_96e0af9891d0945d:()=>Ee,__wbg_isSafeInteger_d216eda7911dde36:()=>Oe,__wbg_iterator_e5822695327a3c39:()=>Me,__wbg_keys_b4d27b02ad14f4be:()=>ve,__wbg_length_69bca3cb64fc8748:()=>De,__wbg_length_cdd215e10d9dd507:()=>je,__wbg_msCrypto_2ac4d17c4748234a:()=>Be,__wbg_new_0_f9740686d739025c:()=>Re,__wbg_new_1acc0b6eea89d040:()=>Ue,__wbg_new_3c3d849046688a66:()=>Le,__wbg_new_5a79be3ab53b8aa5:()=>Ne,__wbg_new_68651c719dcda04e:()=>Ce,__wbg_new_e17d9f43105b08be:()=>$e,__wbg_new_from_slice_92f4d78ca282a2d2:()=>Ve,__wbg_new_no_args_ee98eee5275000a4:()=>We,__wbg_new_with_length_01aa0dc35aa13543:()=>ze,__wbg_next_020810e0ae8ebcb0:()=>Pe,__wbg_next_2c826fe5dfec6b6a:()=>Ge,__wbg_node_ecc8306b9857f33d:()=>Qe,__wbg_now_793306c526e2e3b6:()=>He,__wbg_now_7fd00a794a07d388:()=>Je,__wbg_now_b3f7572f6ef3d3a9:()=>Xe,__wbg_process_5cff2739921be718:()=>Ye,__wbg_prototypesetcall_2a6620b6922694b2:()=>Ke,__wbg_push_df81a39d04db858c:()=>Ze,__wbg_queueMicrotask_5a8a9131f3f0b37b:()=>et,__wbg_queueMicrotask_6d79674585219521:()=>tt,__wbg_randomFillSync_d3c85af7e31cf1f8:()=>nt,__wbg_require_0c566c6f2eef6c79:()=>rt,__wbg_resolve_caf97c30b83f7053:()=>_t,__wbg_setTimeout_5d6a1d4fc51ea450:()=>ot,__wbg_set_3f1d0b984ed272ed:()=>ct,__wbg_set_907fb406c34a251d:()=>it,__wbg_set_c213c871859d6500:()=>st,__wbg_set_c2abbebe8b9ebee1:()=>ut,__wbg_set_wasm:()=>$,__wbg_static_accessor_GLOBAL_89e1d9ac6a1b250e:()=>bt,__wbg_static_accessor_GLOBAL_THIS_8b530f326a9e48ac:()=>ft,__wbg_static_accessor_SELF_6fdf4b64710cc91b:()=>at,__wbg_static_accessor_WINDOW_b45bfc5a37f6cfa2:()=>gt,__wbg_subarray_480600f3d6a9f26c:()=>lt,__wbg_then_4f46f6544e6b4a28:()=>dt,__wbg_then_70d05cf780a18d77:()=>wt,__wbg_valueOf_9eee4828c11458ca:()=>pt,__wbg_value_692627309814bb8c:()=>xt,__wbg_versions_a8e5a362e1f16442:()=>yt,__wbindgen_cast_126e48f66237b479:()=>mt,__wbindgen_cast_2241b6af4c4b2941:()=>ht,__wbindgen_cast_4625c577ab2ec9ee:()=>Tt,__wbindgen_cast_9ae0607507abb057:()=>At,__wbindgen_cast_cb9088102bce6b30:()=>St,__wbindgen_cast_d6cd19b81560fd6e:()=>Ft,__wbindgen_init_externref_table:()=>It,debug_panic:()=>P,getBuildTimeInfo:()=>G});module.exports=C(qt);var h=()=>{};h.prototype=h;let r;function $(e){r=e}let T=null;function p(){return(T===null||T.byteLength===0)&&(T=new Uint8Array(r.memory.buffer)),T}let A=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0});A.decode();const V=2146435072;let I=0;function W(e,t){return I+=t,I>=V&&(A=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0}),A.decode(),I=t),A.decode(p().subarray(e,e+t))}function S(e,t){return e=e>>>0,W(e,t)}let u=0;const x=new TextEncoder;"encodeInto"in x||(x.encodeInto=function(e,t){const n=x.encode(e);return t.set(n),{read:e.length,written:n.length}});function b(e,t,n){if(n===void 0){const s=x.encode(e),f=t(s.length,1)>>>0;return p().subarray(f,f+s.length).set(s),u=s.length,f}let _=e.length,o=t(_,1)>>>0;const i=p();let c=0;for(;c<_;c++){const s=e.charCodeAt(c);if(s>127)break;i[o+c]=s}if(c!==_){c!==0&&(e=e.slice(c)),o=n(o,_,_=c+e.length*3,1)>>>0;const s=p().subarray(o+c,o+_),f=x.encodeInto(e,s);c+=f.written,o=n(o,_,c,1)>>>0}return u=c,o}let w=null;function l(){return(w===null||w.buffer.detached===!0||w.buffer.detached===void 0&&w.buffer!==r.memory.buffer)&&(w=new DataView(r.memory.buffer)),w}function a(e){return e==null}function q(e){const t=typeof e;if(t=="number"||t=="boolean"||e==null)return`${e}`;if(t=="string")return`"${e}"`;if(t=="symbol"){const o=e.description;return o==null?"Symbol":`Symbol(${o})`}if(t=="function"){const o=e.name;return typeof o=="string"&&o.length>0?`Function(${o})`:"Function"}if(Array.isArray(e)){const o=e.length;let i="[";o>0&&(i+=q(e[0]));for(let c=1;c1)_=n[1];else return toString.call(e);if(_=="Object")try{return"Object("+JSON.stringify(e)+")"}catch{return"Object"}return e instanceof Error?`${e.name}: ${e.message} +${e.stack}`:_}function y(e){const t=r.__externref_table_alloc();return r.__wbindgen_externrefs.set(t,e),t}function g(e,t){try{return e.apply(this,t)}catch(n){const _=y(n);r.__wbindgen_exn_store(_)}}function k(e,t){return e=e>>>0,p().subarray(e/1,e/1+t)}const O=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(e=>e.dtor(e.a,e.b));function z(e,t,n,_){const o={a:e,b:t,cnt:1,dtor:n},i=(...c)=>{o.cnt++;const s=o.a;o.a=0;try{return _(s,o.b,...c)}finally{o.a=s,i._wbg_cb_unref()}};return i._wbg_cb_unref=()=>{--o.cnt===0&&(o.dtor(o.a,o.b),o.a=0,O.unregister(o))},O.register(i,o,o),i}function M(e){const t=r.__wbindgen_externrefs.get(e);return r.__externref_table_dealloc(e),t}function P(e){var t=a(e)?0:b(e,r.__wbindgen_malloc,r.__wbindgen_realloc),n=u;const _=r.debug_panic(t,n);if(_[1])throw M(_[0])}function G(){return r.getBuildTimeInfo()}function Q(e,t,n){r.wasm_bindgen__convert__closures_____invoke__ha235f3ea55a06a09(e,t,n)}function H(e,t,n,_){r.wasm_bindgen__convert__closures_____invoke__h1a2f20be69ab8911(e,t,n,_)}const v=typeof FinalizationRegistry>"u"?{register:()=>{},unregister:()=>{}}:new FinalizationRegistry(e=>r.__wbg_queryengine_free(e>>>0,1));class E{__destroy_into_raw(){const t=this.__wbg_ptr;return this.__wbg_ptr=0,v.unregister(this),t}free(){const t=this.__destroy_into_raw();r.__wbg_queryengine_free(t,0)}disconnect(t,n){const _=b(t,r.__wbindgen_malloc,r.__wbindgen_realloc),o=u,i=b(n,r.__wbindgen_malloc,r.__wbindgen_realloc),c=u;return r.queryengine_disconnect(this.__wbg_ptr,_,o,i,c)}startTransaction(t,n,_){const o=b(t,r.__wbindgen_malloc,r.__wbindgen_realloc),i=u,c=b(n,r.__wbindgen_malloc,r.__wbindgen_realloc),s=u,f=b(_,r.__wbindgen_malloc,r.__wbindgen_realloc),d=u;return r.queryengine_startTransaction(this.__wbg_ptr,o,i,c,s,f,d)}commitTransaction(t,n,_){const o=b(t,r.__wbindgen_malloc,r.__wbindgen_realloc),i=u,c=b(n,r.__wbindgen_malloc,r.__wbindgen_realloc),s=u,f=b(_,r.__wbindgen_malloc,r.__wbindgen_realloc),d=u;return r.queryengine_commitTransaction(this.__wbg_ptr,o,i,c,s,f,d)}rollbackTransaction(t,n,_){const o=b(t,r.__wbindgen_malloc,r.__wbindgen_realloc),i=u,c=b(n,r.__wbindgen_malloc,r.__wbindgen_realloc),s=u,f=b(_,r.__wbindgen_malloc,r.__wbindgen_realloc),d=u;return r.queryengine_rollbackTransaction(this.__wbg_ptr,o,i,c,s,f,d)}constructor(t,n,_){const o=r.queryengine_new(t,n,_);if(o[2])throw M(o[1]);return this.__wbg_ptr=o[0]>>>0,v.register(this,this.__wbg_ptr,this),this}query(t,n,_,o){const i=b(t,r.__wbindgen_malloc,r.__wbindgen_realloc),c=u,s=b(n,r.__wbindgen_malloc,r.__wbindgen_realloc),f=u;var d=a(_)?0:b(_,r.__wbindgen_malloc,r.__wbindgen_realloc),m=u;const D=b(o,r.__wbindgen_malloc,r.__wbindgen_realloc),j=u;return r.queryengine_query(this.__wbg_ptr,i,c,s,f,d,m,D,j)}trace(t){const n=b(t,r.__wbindgen_malloc,r.__wbindgen_realloc),_=u;return r.queryengine_trace(this.__wbg_ptr,n,_)}connect(t,n){const _=b(t,r.__wbindgen_malloc,r.__wbindgen_realloc),o=u,i=b(n,r.__wbindgen_malloc,r.__wbindgen_realloc),c=u;return r.queryengine_connect(this.__wbg_ptr,_,o,i,c)}metrics(t){const n=b(t,r.__wbindgen_malloc,r.__wbindgen_realloc),_=u;return r.queryengine_metrics(this.__wbg_ptr,n,_)}}Symbol.dispose&&(E.prototype[Symbol.dispose]=E.prototype.free);function J(e,t){return Error(S(e,t))}function X(e){return Number(e)}function Y(e,t){const n=String(t),_=b(n,r.__wbindgen_malloc,r.__wbindgen_realloc),o=u;l().setInt32(e+4*1,o,!0),l().setInt32(e+4*0,_,!0)}function K(e,t){const n=t,_=typeof n=="bigint"?n:void 0;l().setBigInt64(e+8*1,a(_)?BigInt(0):_,!0),l().setInt32(e+4*0,!a(_),!0)}function Z(e){const t=e,n=typeof t=="boolean"?t:void 0;return a(n)?16777215:n?1:0}function ee(e,t){const n=q(t),_=b(n,r.__wbindgen_malloc,r.__wbindgen_realloc),o=u;l().setInt32(e+4*1,o,!0),l().setInt32(e+4*0,_,!0)}function te(e,t){return e in t}function ne(e){return typeof e=="bigint"}function re(e){return typeof e=="function"}function _e(e){const t=e;return typeof t=="object"&&t!==null}function oe(e){return typeof e=="string"}function ce(e){return e===void 0}function ie(e,t){return e===t}function se(e,t){return e==t}function ue(e,t){const n=t,_=typeof n=="number"?n:void 0;l().setFloat64(e+8*1,a(_)?0:_,!0),l().setInt32(e+4*0,!a(_),!0)}function be(e,t){const n=t,_=typeof n=="string"?n:void 0;var o=a(_)?0:b(_,r.__wbindgen_malloc,r.__wbindgen_realloc),i=u;l().setInt32(e+4*1,i,!0),l().setInt32(e+4*0,o,!0)}function fe(e,t){throw new Error(S(e,t))}function ae(e){e._wbg_cb_unref()}function ge(){return g(function(e,t,n){return e.call(t,n)},arguments)}function le(){return g(function(e,t){return e.call(t)},arguments)}function de(e){return e.crypto}function we(e){return e.done}function pe(e){return Object.entries(e)}function xe(){return g(function(e,t){e.getRandomValues(t)},arguments)}function ye(e){return e.getTime()}function me(e,t){return e[t>>>0]}function he(){return g(function(e,t){return e[t]},arguments)}function Te(){return g(function(e,t){return Reflect.get(e,t)},arguments)}function Ae(e,t){return e[t]}function Se(){return g(function(e,t){return Reflect.has(e,t)},arguments)}function Fe(e){let t;try{t=e instanceof ArrayBuffer}catch{t=!1}return t}function Ie(e){let t;try{t=e instanceof Map}catch{t=!1}return t}function qe(e){let t;try{t=e instanceof Promise}catch{t=!1}return t}function ke(e){let t;try{t=e instanceof Uint8Array}catch{t=!1}return t}function Ee(e){return Array.isArray(e)}function Oe(e){return Number.isSafeInteger(e)}function Me(){return Symbol.iterator}function ve(e){return Object.keys(e)}function De(e){return e.length}function je(e){return e.length}function Be(e){return e.msCrypto}function Re(){return new Date}function Ue(){return new Object}function Le(e,t){try{var n={a:e,b:t},_=(i,c)=>{const s=n.a;n.a=0;try{return H(s,n.b,i,c)}finally{n.a=s}};return new Promise(_)}finally{n.a=n.b=0}}function Ne(e){return new Uint8Array(e)}function Ce(){return new Map}function $e(){return new Array}function Ve(e,t){return new Uint8Array(k(e,t))}function We(e,t){return new h(S(e,t))}function ze(e){return new Uint8Array(e>>>0)}function Pe(){return g(function(e){return e.next()},arguments)}function Ge(e){return e.next}function Qe(e){return e.node}function He(){return Date.now()}function Je(e){return e.now()}function Xe(){return g(function(){return Date.now()},arguments)}function Ye(e){return e.process}function Ke(e,t,n){Uint8Array.prototype.set.call(k(e,t),n)}function Ze(e,t){return e.push(t)}function et(e){return e.queueMicrotask}function tt(e){queueMicrotask(e)}function nt(){return g(function(e,t){e.randomFillSync(t)},arguments)}function rt(){return g(function(){return module.require},arguments)}function _t(e){return Promise.resolve(e)}function ot(e,t){return setTimeout(e,t>>>0)}function ct(e,t,n){e[t]=n}function it(e,t,n){return e.set(t,n)}function st(e,t,n){e[t>>>0]=n}function ut(){return g(function(e,t,n){return Reflect.set(e,t,n)},arguments)}function bt(){const e=typeof global>"u"?null:global;return a(e)?0:y(e)}function ft(){const e=typeof globalThis>"u"?null:globalThis;return a(e)?0:y(e)}function at(){const e=typeof self>"u"?null:self;return a(e)?0:y(e)}function gt(){const e=typeof window>"u"?null:window;return a(e)?0:y(e)}function lt(e,t,n){return e.subarray(t>>>0,n>>>0)}function dt(e,t){return e.then(t)}function wt(e,t,n){return e.then(t,n)}function pt(e){return e.valueOf()}function xt(e){return e.value}function yt(e){return e.versions}function mt(e,t){return z(e,t,r.wasm_bindgen__closure__destroy__hf9ae564cf31e91c2,Q)}function ht(e,t){return S(e,t)}function Tt(e){return BigInt.asUintN(64,e)}function At(e){return e}function St(e,t){return k(e,t)}function Ft(e){return e}function It(){const e=r.__wbindgen_externrefs,t=e.grow(4);e.set(0,void 0),e.set(t+0,void 0),e.set(t+1,null),e.set(t+2,!0),e.set(t+3,!1)}0&&(module.exports={QueryEngine,__wbg_Error_e83987f665cf5504,__wbg_Number_bb48ca12f395cd08,__wbg_String_8f0eb39a4a4c2f66,__wbg___wbindgen_bigint_get_as_i64_f3ebc5a755000afd,__wbg___wbindgen_boolean_get_6d5a1ee65bab5f68,__wbg___wbindgen_debug_string_df47ffb5e35e6763,__wbg___wbindgen_in_bb933bd9e1b3bc0f,__wbg___wbindgen_is_bigint_cb320707dcd35f0b,__wbg___wbindgen_is_function_ee8a6c5833c90377,__wbg___wbindgen_is_object_c818261d21f283a4,__wbg___wbindgen_is_string_fbb76cb2940daafd,__wbg___wbindgen_is_undefined_2d472862bd29a478,__wbg___wbindgen_jsval_eq_6b13ab83478b1c50,__wbg___wbindgen_jsval_loose_eq_b664b38a2f582147,__wbg___wbindgen_number_get_a20bf9b85341449d,__wbg___wbindgen_string_get_e4f06c90489ad01b,__wbg___wbindgen_throw_b855445ff6a94295,__wbg__wbg_cb_unref_2454a539ea5790d9,__wbg_call_525440f72fbfc0ea,__wbg_call_e762c39fa8ea36bf,__wbg_crypto_805be4ce92f1e370,__wbg_done_2042aa2670fb1db1,__wbg_entries_e171b586f8f6bdbf,__wbg_getRandomValues_f6a868620c8bab49,__wbg_getTime_14776bfb48a1bff9,__wbg_get_7bed016f185add81,__wbg_get_ece95cf6585650d9,__wbg_get_efcb449f58ec27c2,__wbg_get_with_ref_key_1dc361bd10053bfe,__wbg_has_787fafc980c3ccdb,__wbg_instanceof_ArrayBuffer_70beb1189ca63b38,__wbg_instanceof_Map_8579b5e2ab5437c7,__wbg_instanceof_Promise_001fdd42afa1b7ef,__wbg_instanceof_Uint8Array_20c8e73002f7af98,__wbg_isArray_96e0af9891d0945d,__wbg_isSafeInteger_d216eda7911dde36,__wbg_iterator_e5822695327a3c39,__wbg_keys_b4d27b02ad14f4be,__wbg_length_69bca3cb64fc8748,__wbg_length_cdd215e10d9dd507,__wbg_msCrypto_2ac4d17c4748234a,__wbg_new_0_f9740686d739025c,__wbg_new_1acc0b6eea89d040,__wbg_new_3c3d849046688a66,__wbg_new_5a79be3ab53b8aa5,__wbg_new_68651c719dcda04e,__wbg_new_e17d9f43105b08be,__wbg_new_from_slice_92f4d78ca282a2d2,__wbg_new_no_args_ee98eee5275000a4,__wbg_new_with_length_01aa0dc35aa13543,__wbg_next_020810e0ae8ebcb0,__wbg_next_2c826fe5dfec6b6a,__wbg_node_ecc8306b9857f33d,__wbg_now_793306c526e2e3b6,__wbg_now_7fd00a794a07d388,__wbg_now_b3f7572f6ef3d3a9,__wbg_process_5cff2739921be718,__wbg_prototypesetcall_2a6620b6922694b2,__wbg_push_df81a39d04db858c,__wbg_queueMicrotask_5a8a9131f3f0b37b,__wbg_queueMicrotask_6d79674585219521,__wbg_randomFillSync_d3c85af7e31cf1f8,__wbg_require_0c566c6f2eef6c79,__wbg_resolve_caf97c30b83f7053,__wbg_setTimeout_5d6a1d4fc51ea450,__wbg_set_3f1d0b984ed272ed,__wbg_set_907fb406c34a251d,__wbg_set_c213c871859d6500,__wbg_set_c2abbebe8b9ebee1,__wbg_set_wasm,__wbg_static_accessor_GLOBAL_89e1d9ac6a1b250e,__wbg_static_accessor_GLOBAL_THIS_8b530f326a9e48ac,__wbg_static_accessor_SELF_6fdf4b64710cc91b,__wbg_static_accessor_WINDOW_b45bfc5a37f6cfa2,__wbg_subarray_480600f3d6a9f26c,__wbg_then_4f46f6544e6b4a28,__wbg_then_70d05cf780a18d77,__wbg_valueOf_9eee4828c11458ca,__wbg_value_692627309814bb8c,__wbg_versions_a8e5a362e1f16442,__wbindgen_cast_126e48f66237b479,__wbindgen_cast_2241b6af4c4b2941,__wbindgen_cast_4625c577ab2ec9ee,__wbindgen_cast_9ae0607507abb057,__wbindgen_cast_cb9088102bce6b30,__wbindgen_cast_d6cd19b81560fd6e,__wbindgen_init_externref_table,debug_panic,getBuildTimeInfo}); diff --git a/backend/node_modules/.prisma/client/schema.prisma b/backend/node_modules/.prisma/client/schema.prisma new file mode 100644 index 0000000000000000000000000000000000000000..97e35f166eb122b73e82ed6aac05fedbd3f58411 --- /dev/null +++ b/backend/node_modules/.prisma/client/schema.prisma @@ -0,0 +1,122 @@ +/** + * Schema de Prisma ORM para base de datos SQLite. + * Define 6 modelos: User, Market, AISignal, Position, Watchlist, Alert. + * Relaciones: + * - Market 1:N AISignal, Position, Watchlist, Alert + * - User 1:N Position, Watchlist, Alert + * No modificar sin consenso del equipo. Generar migraciones con: + * npx prisma migrate dev + * npx prisma generate + */ + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "sqlite" + url = env("DATABASE_URL") +} + +model User { + id Int @id @default(autoincrement()) + email String @unique + passwordHash String + isActive Boolean @default(true) + telegramChatId String? // Configurado manualmente para demo + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + positions Position[] + watchlist Watchlist[] + alerts Alert[] +} + +model Market { + id String @id // ID nativo de Polymarket + question String // Texto de la pregunta del mercado + category String? // politics | crypto | economics | sports + countryCode String? // ISO2 — usado por Leaflet para burbujas + yesPrice Float? // Precio YES: 0.0 a 1.0 + noPrice Float? // Precio NO: 0.0 a 1.0 + volumeEur Float? // Volumen en Eur + liquidityEur Float? // Liquidez en Eur + spread Float? // Bid/ask spread (0-1, ej 0.02 = 2c) + bestBid Float? // Mejor oferta de compra + bestAsk Float? // Mejor oferta de venta + clobTokenId String? // YES outcome CLOB token ID (para prices-history) + analyzable Boolean @default(true) // Si la IA tiene edge plausible aqui + status String @default("active") // active | closed | resolved + closesAt DateTime? // Fecha de cierre del mercado + lastSynced DateTime @default(now()) // Ultima sincronizacion de precios + + signals AISignal[] + positions Position[] + watchlist Watchlist[] + alerts Alert[] +} + +model AISignal { + id Int @id @default(autoincrement()) + marketId String + market Market @relation(fields: [marketId], references: [id], onDelete: Cascade) + signal String // bullish | bearish | neutral + confidence Float // 0.0 a 1.0 + summary String? // 2 frases generadas por Qwen3 + keyRisk String? // 1 frase de riesgo principal + newsCount Int @default(0) // Titulares relevantes usados + modelVersion String @default("Qwen3-8B") // Modelo LLM que genero la senal + impliedProb Float? // Probabilidad implicita YES al generar (0-1) + fairProb Float? // Probabilidad "justa" segun IA (0-1) + edgePoints Float? // (fairProb - impliedProb) * 100, signo conserva direccion + generatedAt DateTime @default(now()) + + @@index([marketId, generatedAt]) +} + +model Position { + id Int @id @default(autoincrement()) + userId Int + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + marketId String + market Market @relation(fields: [marketId], references: [id], onDelete: Cascade) + outcome String // YES | NO + amountEur Float // Capital virtual apostado + entryPrice Float // Precio al abrir la posicion + currentPrice Float? // Precio actual (actualizado por scheduler) + pnl Float @default(0) // Profit and Loss calculado + kellyFraction Float? // Fraccion de Kelly al abrir + status String @default("open") // open | closed + openedAt DateTime @default(now()) + closedAt DateTime? + + @@index([userId, status]) + @@index([marketId]) +} + +model Watchlist { + id Int @id @default(autoincrement()) + userId Int + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + marketId String + market Market @relation(fields: [marketId], references: [id], onDelete: Cascade) + alertThreshold Float? // Umbral de precio para alerta Telegram + createdAt DateTime @default(now()) + + @@unique([userId, marketId]) + @@index([userId]) +} + +model Alert { + id Int @id @default(autoincrement()) + userId Int + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + marketId String + market Market @relation(fields: [marketId], references: [id], onDelete: Cascade) + type String // price_threshold | signal_change + message String // Texto enviado por Telegram + sentAt DateTime @default(now()) + + @@index([userId, sentAt]) + @@index([marketId]) +} diff --git a/backend/node_modules/.prisma/client/wasm-edge-light-loader.mjs b/backend/node_modules/.prisma/client/wasm-edge-light-loader.mjs new file mode 100644 index 0000000000000000000000000000000000000000..dcf01f0a9b6c6a7a1b26d59c0f5513a561f95fba --- /dev/null +++ b/backend/node_modules/.prisma/client/wasm-edge-light-loader.mjs @@ -0,0 +1,5 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! +/* eslint-disable */ +// biome-ignore-all lint: generated file +export default import('./query_engine_bg.wasm?module') \ No newline at end of file diff --git a/backend/node_modules/.prisma/client/wasm-worker-loader.mjs b/backend/node_modules/.prisma/client/wasm-worker-loader.mjs new file mode 100644 index 0000000000000000000000000000000000000000..e60a3fa8a1b3cbf3c8002baf9ecaabb50927cbf5 --- /dev/null +++ b/backend/node_modules/.prisma/client/wasm-worker-loader.mjs @@ -0,0 +1,5 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! +/* eslint-disable */ +// biome-ignore-all lint: generated file +export default import('./query_engine_bg.wasm') \ No newline at end of file diff --git a/backend/node_modules/.prisma/client/wasm.d.ts b/backend/node_modules/.prisma/client/wasm.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..274b8fa61905db8cd79f40927dfc929a788dc136 --- /dev/null +++ b/backend/node_modules/.prisma/client/wasm.d.ts @@ -0,0 +1 @@ +export * from "./default" \ No newline at end of file diff --git a/backend/node_modules/.prisma/client/wasm.js b/backend/node_modules/.prisma/client/wasm.js new file mode 100644 index 0000000000000000000000000000000000000000..f1757e73747bbc44e27479d7c8b718da603ddf70 --- /dev/null +++ b/backend/node_modules/.prisma/client/wasm.js @@ -0,0 +1,266 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! +/* eslint-disable */ +// biome-ignore-all lint: generated file + +Object.defineProperty(exports, "__esModule", { value: true }); + +const { + PrismaClientKnownRequestError, + PrismaClientUnknownRequestError, + PrismaClientRustPanicError, + PrismaClientInitializationError, + PrismaClientValidationError, + getPrismaClient, + sqltag, + empty, + join, + raw, + skip, + Decimal, + Debug, + objectEnumValues, + makeStrictEnum, + Extensions, + warnOnce, + defineDmmfProperty, + Public, + getRuntime, + createParam, +} = require('@prisma/client/runtime/wasm-engine-edge.js') + + +const Prisma = {} + +exports.Prisma = Prisma +exports.$Enums = {} + +/** + * Prisma Client JS version: 6.19.3 + * Query Engine version: c2990dca591cba766e3b7ef5d9e8a84796e47ab7 + */ +Prisma.prismaVersion = { + client: "6.19.3", + engine: "c2990dca591cba766e3b7ef5d9e8a84796e47ab7" +} + +Prisma.PrismaClientKnownRequestError = PrismaClientKnownRequestError; +Prisma.PrismaClientUnknownRequestError = PrismaClientUnknownRequestError +Prisma.PrismaClientRustPanicError = PrismaClientRustPanicError +Prisma.PrismaClientInitializationError = PrismaClientInitializationError +Prisma.PrismaClientValidationError = PrismaClientValidationError +Prisma.Decimal = Decimal + +/** + * Re-export of sql-template-tag + */ +Prisma.sql = sqltag +Prisma.empty = empty +Prisma.join = join +Prisma.raw = raw +Prisma.validator = Public.validator + +/** +* Extensions +*/ +Prisma.getExtensionContext = Extensions.getExtensionContext +Prisma.defineExtension = Extensions.defineExtension + +/** + * Shorthand utilities for JSON filtering + */ +Prisma.DbNull = objectEnumValues.instances.DbNull +Prisma.JsonNull = objectEnumValues.instances.JsonNull +Prisma.AnyNull = objectEnumValues.instances.AnyNull + +Prisma.NullTypes = { + DbNull: objectEnumValues.classes.DbNull, + JsonNull: objectEnumValues.classes.JsonNull, + AnyNull: objectEnumValues.classes.AnyNull +} + + + + + +/** + * Enums + */ +exports.Prisma.TransactionIsolationLevel = makeStrictEnum({ + Serializable: 'Serializable' +}); + +exports.Prisma.UserScalarFieldEnum = { + id: 'id', + email: 'email', + passwordHash: 'passwordHash', + isActive: 'isActive', + telegramChatId: 'telegramChatId', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +}; + +exports.Prisma.MarketScalarFieldEnum = { + id: 'id', + question: 'question', + category: 'category', + countryCode: 'countryCode', + yesPrice: 'yesPrice', + noPrice: 'noPrice', + volumeEur: 'volumeEur', + liquidityEur: 'liquidityEur', + spread: 'spread', + bestBid: 'bestBid', + bestAsk: 'bestAsk', + clobTokenId: 'clobTokenId', + analyzable: 'analyzable', + status: 'status', + closesAt: 'closesAt', + lastSynced: 'lastSynced' +}; + +exports.Prisma.AISignalScalarFieldEnum = { + id: 'id', + marketId: 'marketId', + signal: 'signal', + confidence: 'confidence', + summary: 'summary', + keyRisk: 'keyRisk', + newsCount: 'newsCount', + modelVersion: 'modelVersion', + impliedProb: 'impliedProb', + fairProb: 'fairProb', + edgePoints: 'edgePoints', + generatedAt: 'generatedAt' +}; + +exports.Prisma.PositionScalarFieldEnum = { + id: 'id', + userId: 'userId', + marketId: 'marketId', + outcome: 'outcome', + amountEur: 'amountEur', + entryPrice: 'entryPrice', + currentPrice: 'currentPrice', + pnl: 'pnl', + kellyFraction: 'kellyFraction', + status: 'status', + openedAt: 'openedAt', + closedAt: 'closedAt' +}; + +exports.Prisma.WatchlistScalarFieldEnum = { + id: 'id', + userId: 'userId', + marketId: 'marketId', + alertThreshold: 'alertThreshold', + createdAt: 'createdAt' +}; + +exports.Prisma.AlertScalarFieldEnum = { + id: 'id', + userId: 'userId', + marketId: 'marketId', + type: 'type', + message: 'message', + sentAt: 'sentAt' +}; + +exports.Prisma.SortOrder = { + asc: 'asc', + desc: 'desc' +}; + +exports.Prisma.NullsOrder = { + first: 'first', + last: 'last' +}; + + +exports.Prisma.ModelName = { + User: 'User', + Market: 'Market', + AISignal: 'AISignal', + Position: 'Position', + Watchlist: 'Watchlist', + Alert: 'Alert' +}; +/** + * Create the Client + */ +const config = { + "generator": { + "name": "client", + "provider": { + "fromEnvVar": null, + "value": "prisma-client-js" + }, + "output": { + "value": "/Users/josesalazar/proyecto-hackaton/backend/node_modules/@prisma/client", + "fromEnvVar": null + }, + "config": { + "engineType": "library" + }, + "binaryTargets": [ + { + "fromEnvVar": null, + "value": "darwin-arm64", + "native": true + } + ], + "previewFeatures": [], + "sourceFilePath": "/Users/josesalazar/proyecto-hackaton/backend/prisma/schema.prisma" + }, + "relativeEnvPaths": { + "rootEnvPath": null, + "schemaEnvPath": "../../../.env" + }, + "relativePath": "../../../prisma", + "clientVersion": "6.19.3", + "engineVersion": "c2990dca591cba766e3b7ef5d9e8a84796e47ab7", + "datasourceNames": [ + "db" + ], + "activeProvider": "sqlite", + "postinstall": false, + "inlineDatasources": { + "db": { + "url": { + "fromEnvVar": "DATABASE_URL", + "value": null + } + } + }, + "inlineSchema": "/**\n * Schema de Prisma ORM para base de datos SQLite.\n * Define 6 modelos: User, Market, AISignal, Position, Watchlist, Alert.\n * Relaciones:\n * - Market 1:N AISignal, Position, Watchlist, Alert\n * - User 1:N Position, Watchlist, Alert\n * No modificar sin consenso del equipo. Generar migraciones con:\n * npx prisma migrate dev\n * npx prisma generate\n */\n\ngenerator client {\n provider = \"prisma-client-js\"\n}\n\ndatasource db {\n provider = \"sqlite\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel User {\n id Int @id @default(autoincrement())\n email String @unique\n passwordHash String\n isActive Boolean @default(true)\n telegramChatId String? // Configurado manualmente para demo\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n positions Position[]\n watchlist Watchlist[]\n alerts Alert[]\n}\n\nmodel Market {\n id String @id // ID nativo de Polymarket\n question String // Texto de la pregunta del mercado\n category String? // politics | crypto | economics | sports\n countryCode String? // ISO2 — usado por Leaflet para burbujas\n yesPrice Float? // Precio YES: 0.0 a 1.0\n noPrice Float? // Precio NO: 0.0 a 1.0\n volumeEur Float? // Volumen en Eur\n liquidityEur Float? // Liquidez en Eur\n spread Float? // Bid/ask spread (0-1, ej 0.02 = 2c)\n bestBid Float? // Mejor oferta de compra\n bestAsk Float? // Mejor oferta de venta\n clobTokenId String? // YES outcome CLOB token ID (para prices-history)\n analyzable Boolean @default(true) // Si la IA tiene edge plausible aqui\n status String @default(\"active\") // active | closed | resolved\n closesAt DateTime? // Fecha de cierre del mercado\n lastSynced DateTime @default(now()) // Ultima sincronizacion de precios\n\n signals AISignal[]\n positions Position[]\n watchlist Watchlist[]\n alerts Alert[]\n}\n\nmodel AISignal {\n id Int @id @default(autoincrement())\n marketId String\n market Market @relation(fields: [marketId], references: [id], onDelete: Cascade)\n signal String // bullish | bearish | neutral\n confidence Float // 0.0 a 1.0\n summary String? // 2 frases generadas por Qwen3\n keyRisk String? // 1 frase de riesgo principal\n newsCount Int @default(0) // Titulares relevantes usados\n modelVersion String @default(\"Qwen3-8B\") // Modelo LLM que genero la senal\n impliedProb Float? // Probabilidad implicita YES al generar (0-1)\n fairProb Float? // Probabilidad \"justa\" segun IA (0-1)\n edgePoints Float? // (fairProb - impliedProb) * 100, signo conserva direccion\n generatedAt DateTime @default(now())\n\n @@index([marketId, generatedAt])\n}\n\nmodel Position {\n id Int @id @default(autoincrement())\n userId Int\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n marketId String\n market Market @relation(fields: [marketId], references: [id], onDelete: Cascade)\n outcome String // YES | NO\n amountEur Float // Capital virtual apostado\n entryPrice Float // Precio al abrir la posicion\n currentPrice Float? // Precio actual (actualizado por scheduler)\n pnl Float @default(0) // Profit and Loss calculado\n kellyFraction Float? // Fraccion de Kelly al abrir\n status String @default(\"open\") // open | closed\n openedAt DateTime @default(now())\n closedAt DateTime?\n\n @@index([userId, status])\n @@index([marketId])\n}\n\nmodel Watchlist {\n id Int @id @default(autoincrement())\n userId Int\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n marketId String\n market Market @relation(fields: [marketId], references: [id], onDelete: Cascade)\n alertThreshold Float? // Umbral de precio para alerta Telegram\n createdAt DateTime @default(now())\n\n @@unique([userId, marketId])\n @@index([userId])\n}\n\nmodel Alert {\n id Int @id @default(autoincrement())\n userId Int\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n marketId String\n market Market @relation(fields: [marketId], references: [id], onDelete: Cascade)\n type String // price_threshold | signal_change\n message String // Texto enviado por Telegram\n sentAt DateTime @default(now())\n\n @@index([userId, sentAt])\n @@index([marketId])\n}\n", + "inlineSchemaHash": "317e51352744228f8aa2577b7d08529ce57f6e47ee90dbf1318c8edc1a7164fb", + "copyEngine": true +} +config.dirname = '/' + +config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"passwordHash\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"isActive\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"telegramChatId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"positions\",\"kind\":\"object\",\"type\":\"Position\",\"relationName\":\"PositionToUser\"},{\"name\":\"watchlist\",\"kind\":\"object\",\"type\":\"Watchlist\",\"relationName\":\"UserToWatchlist\"},{\"name\":\"alerts\",\"kind\":\"object\",\"type\":\"Alert\",\"relationName\":\"AlertToUser\"}],\"dbName\":null},\"Market\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"question\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"category\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"countryCode\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"yesPrice\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"noPrice\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"volumeEur\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"liquidityEur\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"spread\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"bestBid\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"bestAsk\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"clobTokenId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"analyzable\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"status\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"closesAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"lastSynced\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"signals\",\"kind\":\"object\",\"type\":\"AISignal\",\"relationName\":\"AISignalToMarket\"},{\"name\":\"positions\",\"kind\":\"object\",\"type\":\"Position\",\"relationName\":\"MarketToPosition\"},{\"name\":\"watchlist\",\"kind\":\"object\",\"type\":\"Watchlist\",\"relationName\":\"MarketToWatchlist\"},{\"name\":\"alerts\",\"kind\":\"object\",\"type\":\"Alert\",\"relationName\":\"AlertToMarket\"}],\"dbName\":null},\"AISignal\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"marketId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"market\",\"kind\":\"object\",\"type\":\"Market\",\"relationName\":\"AISignalToMarket\"},{\"name\":\"signal\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"confidence\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"summary\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"keyRisk\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"newsCount\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"modelVersion\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"impliedProb\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"fairProb\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"edgePoints\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"generatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Position\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"PositionToUser\"},{\"name\":\"marketId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"market\",\"kind\":\"object\",\"type\":\"Market\",\"relationName\":\"MarketToPosition\"},{\"name\":\"outcome\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"amountEur\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"entryPrice\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"currentPrice\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"pnl\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"kellyFraction\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"status\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"openedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"closedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Watchlist\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"UserToWatchlist\"},{\"name\":\"marketId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"market\",\"kind\":\"object\",\"type\":\"Market\",\"relationName\":\"MarketToWatchlist\"},{\"name\":\"alertThreshold\",\"kind\":\"scalar\",\"type\":\"Float\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Alert\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"AlertToUser\"},{\"name\":\"marketId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"market\",\"kind\":\"object\",\"type\":\"Market\",\"relationName\":\"AlertToMarket\"},{\"name\":\"type\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"message\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sentAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") +defineDmmfProperty(exports.Prisma, config.runtimeDataModel) +config.engineWasm = { + getRuntime: async () => require('./query_engine_bg.js'), + getQueryEngineWasmModule: async () => { + const loader = (await import('#wasm-engine-loader')).default + const engine = (await loader).default + return engine + } +} +config.compilerWasm = undefined + +config.injectableEdgeEnv = () => ({ + parsed: { + DATABASE_URL: typeof globalThis !== 'undefined' && globalThis['DATABASE_URL'] || typeof process !== 'undefined' && process.env && process.env.DATABASE_URL || undefined + } +}) + +if (typeof globalThis !== 'undefined' && globalThis['DEBUG'] || typeof process !== 'undefined' && process.env && process.env.DEBUG || undefined) { + Debug.enable(typeof globalThis !== 'undefined' && globalThis['DEBUG'] || typeof process !== 'undefined' && process.env && process.env.DEBUG || undefined) +} + +const PrismaClient = getPrismaClient(config) +exports.PrismaClient = PrismaClient +Object.assign(exports, Prisma) + diff --git a/backend/node_modules/@prisma/config/dist/index.d.ts b/backend/node_modules/@prisma/config/dist/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..6e70ad73a3ee10b2ea2907e8256721e7d41e8001 --- /dev/null +++ b/backend/node_modules/@prisma/config/dist/index.d.ts @@ -0,0 +1,650 @@ +import { Schema } from 'effect'; + +/** + * An interface that exposes some basic information about the + * adapter like its name and provider type. + */ +declare interface AdapterInfo { + readonly provider: Provider; + readonly adapterName: (typeof officialPrismaAdapters)[number] | (string & {}); +} + +declare type ArgScalarType = 'string' | 'int' | 'bigint' | 'float' | 'decimal' | 'boolean' | 'enum' | 'uuid' | 'json' | 'datetime' | 'bytes' | 'unknown'; + +declare type ArgType = { + scalarType: ArgScalarType; + dbType?: string; + arity: Arity; +}; + +declare type Arity = 'scalar' | 'list'; + +declare type ColumnType = (typeof ColumnTypeEnum)[keyof typeof ColumnTypeEnum]; + +declare const ColumnTypeEnum: { + readonly Int32: 0; + readonly Int64: 1; + readonly Float: 2; + readonly Double: 3; + readonly Numeric: 4; + readonly Boolean: 5; + readonly Character: 6; + readonly Text: 7; + readonly Date: 8; + readonly Time: 9; + readonly DateTime: 10; + readonly Json: 11; + readonly Enum: 12; + readonly Bytes: 13; + readonly Set: 14; + readonly Uuid: 15; + readonly Int32Array: 64; + readonly Int64Array: 65; + readonly FloatArray: 66; + readonly DoubleArray: 67; + readonly NumericArray: 68; + readonly BooleanArray: 69; + readonly CharacterArray: 70; + readonly TextArray: 71; + readonly DateArray: 72; + readonly TimeArray: 73; + readonly DateTimeArray: 74; + readonly JsonArray: 75; + readonly EnumArray: 76; + readonly BytesArray: 77; + readonly UuidArray: 78; + readonly UnknownNumber: 128; +}; + +export declare type ConfigDiagnostic = { + _tag: 'log'; + value: (formatters: InjectFormatters) => () => void; +} | { + _tag: 'warn'; + value: (formatters: InjectFormatters) => () => void; +}; + +export declare type ConfigFromFile = { + resolvedPath: string; + config: PrismaConfigInternal; + error?: never; + diagnostics: ConfigDiagnostic[]; +} | { + resolvedPath: string; + config?: never; + error: LoadConfigFromFileError; + diagnostics: ConfigDiagnostic[]; +} | { + resolvedPath: null; + config: PrismaConfigInternal; + error?: never; + diagnostics: ConfigDiagnostic[]; +}; + +declare type ConnectionInfo = { + schemaName?: string; + maxBindValues?: number; + supportsRelationJoins: boolean; +}; + +/** + * This default config can be used as basis for unit and integration tests. + */ +export declare function defaultTestConfig(): PrismaConfigInternal; + +/** + * Define the configuration for the Prisma Development Kit. + */ +export declare function defineConfig(configInput: PrismaConfig): PrismaConfigInternal; + +/** + * A generic driver adapter factory that allows the user to instantiate a + * driver adapter. The query and result types are specific to the adapter. + */ +declare interface DriverAdapterFactory extends AdapterInfo { + /** + * Instantiate a driver adapter. + */ + connect(): Promise>; +} + +declare type EnumsConfigShape = { + /** + * List of enums that are externally managed. + * Prisma will not modify the structure of these enums and not generate migrations for those enums. + * These enums will still be represented in schema.prisma file and be available in the client API. + */ + external?: string[]; +}; + +export declare function env>(name: keyof Env & string): string; + +declare type Error_2 = MappedError & { + originalCode?: string; + originalMessage?: string; +}; + +declare type ErrorCapturingFunction = T extends (...args: infer A) => Promise ? (...args: A) => Promise>> : T extends (...args: infer A) => infer R ? (...args: A) => Result> : T; + +declare type ErrorCapturingInterface = { + [K in keyof T]: ErrorCapturingFunction; +}; + +declare interface ErrorCapturingSqlMigrationAwareDriverAdapterFactory extends ErrorCapturingInterface { + readonly errorRegistry: ErrorRegistry; +} + +declare type ErrorRecord = { + error: unknown; +}; + +declare interface ErrorRegistry { + consumeError(id: number): ErrorRecord | undefined; +} + +declare type ExperimentalConfig = { + /** + * Enable experimental adapter support. + */ + adapter?: boolean; + /** + * Enable experimental Prisma Studio features. + */ + studio?: boolean; + /** + * Enable experimental external tables support. + */ + externalTables?: boolean; + /** + * Enable experimental extensions support. This is required to use the `extensions` config option. + */ + extensions?: boolean; +}; + +export declare type InjectFormatters = { + dim: (data: string) => string; + log: (data: string) => void; + warn: (data: string) => void; + link: (data: string) => string; +}; + +declare type IsolationLevel = 'READ UNCOMMITTED' | 'READ COMMITTED' | 'REPEATABLE READ' | 'SNAPSHOT' | 'SERIALIZABLE'; + +/** + * Load a Prisma config file from the given directory. + * This function may fail, but it will never throw. + * The possible error is returned in the result object, so the caller can handle it as needed. + */ +export declare function loadConfigFromFile({ configFile, configRoot, }: LoadConfigFromFileInput): Promise; + +export declare type LoadConfigFromFileError = { + /** + * The config file was not found at the specified path. + */ + _tag: 'ConfigFileNotFound'; +} | { + _tag: 'ConfigLoadError'; + error: Error; +} | { + _tag: 'ConfigFileSyntaxError'; + error: Error; +} | { + _tag: 'UnknownError'; + error: Error; +}; + +declare type LoadConfigFromFileInput = { + /** + * The path to the config file to load. If not provided, we will attempt to find a config file in the `configRoot` directory. + */ + configFile?: string; + /** + * The directory to search for the config file in. Defaults to the current working directory. + */ + configRoot?: string; +}; + +/** + * User's Prisma configuration should live in `prisma.config.ts` instead of `package.json#prisma`. + * See: https://pris.ly/prisma-config. + * + * This function returns `null` if no `package.json` is found, or if the `prisma` property is not defined therein. + * + * TODO: remove in Prisma 7. + * @deprecated + */ +export declare function loadConfigFromPackageJson(cwd?: string): Promise<{ + config: PrismaConfigPackageJson; + loadedFromFile: string; +} | null>; + +declare type MappedError = { + kind: 'GenericJs'; + id: number; +} | { + kind: 'UnsupportedNativeDataType'; + type: string; +} | { + kind: 'InvalidIsolationLevel'; + level: string; +} | { + kind: 'LengthMismatch'; + column?: string; +} | { + kind: 'UniqueConstraintViolation'; + constraint?: { + fields: string[]; + } | { + index: string; + } | { + foreignKey: {}; + }; +} | { + kind: 'NullConstraintViolation'; + constraint?: { + fields: string[]; + } | { + index: string; + } | { + foreignKey: {}; + }; +} | { + kind: 'ForeignKeyConstraintViolation'; + constraint?: { + fields: string[]; + } | { + index: string; + } | { + foreignKey: {}; + }; +} | { + kind: 'DatabaseNotReachable'; + host?: string; + port?: number; +} | { + kind: 'DatabaseDoesNotExist'; + db?: string; +} | { + kind: 'DatabaseAlreadyExists'; + db?: string; +} | { + kind: 'DatabaseAccessDenied'; + db?: string; +} | { + kind: 'ConnectionClosed'; +} | { + kind: 'TlsConnectionError'; + reason: string; +} | { + kind: 'AuthenticationFailed'; + user?: string; +} | { + kind: 'TransactionWriteConflict'; +} | { + kind: 'TableDoesNotExist'; + table?: string; +} | { + kind: 'ColumnNotFound'; + column?: string; +} | { + kind: 'TooManyConnections'; + cause: string; +} | { + kind: 'ValueOutOfRange'; + cause: string; +} | { + kind: 'MissingFullTextSearchIndex'; +} | { + kind: 'SocketTimeout'; +} | { + kind: 'InconsistentColumnData'; + cause: string; +} | { + kind: 'TransactionAlreadyClosed'; + cause: string; +} | { + kind: 'postgres'; + code: string; + severity: string; + message: string; + detail: string | undefined; + column: string | undefined; + hint: string | undefined; +} | { + kind: 'mysql'; + code: number; + message: string; + state: string; +} | { + kind: 'sqlite'; + /** + * Sqlite extended error code: https://www.sqlite.org/rescode.html + */ + extendedCode: number; + message: string; +} | { + kind: 'mssql'; + code: number; + message: string; +}; + +declare type MigrationsConfigShape = { + /** + * The path to the directory where Prisma should store migration files, and look for them. + */ + path?: string; + /** + * Provide a SQL script that will be used to setup external tables and enums during migration diffing. + * Also see `tables.external` and `enums.external`. + */ + initShadowDb?: string; + /** + * The command to run to seed the database after schema migrations are applied. + */ + seed?: string; +}; + +declare const officialPrismaAdapters: readonly ["@prisma/adapter-planetscale", "@prisma/adapter-neon", "@prisma/adapter-libsql", "@prisma/adapter-better-sqlite3", "@prisma/adapter-d1", "@prisma/adapter-pg", "@prisma/adapter-mssql", "@prisma/adapter-mariadb"]; + +declare const PRISMA_CONFIG_INTERNAL_BRAND: unique symbol; + +/** + * The configuration for the Prisma Development Kit, before it is passed to the `defineConfig` function. + * Thanks to the branding, this type is opaque and cannot be constructed directly. + */ +export declare type PrismaConfig = PrismaConfigUnconditional & SchemaEngineConfig; + +export declare class PrismaConfigEnvError extends Error { + constructor(name: string); +} + +/** + * The configuration for the Prisma Development Kit, after it has been parsed and processed + * by the `defineConfig` function. + * Thanks to the branding, this type is opaque and cannot be constructed directly. + */ +export declare type PrismaConfigInternal = _PrismaConfigInternal & { + __brand: typeof PRISMA_CONFIG_INTERNAL_BRAND; +}; + +declare type _PrismaConfigInternal = Omit & { + loadedFromFile: string | null; + /** + * The deprecated Prisma configuration from `package.json#prisma`. + * This is set to `null` if no `package.json#prisma` config was found. + * The configuration read from the Prisma config file (e.g., `prisma.config.ts`) takes precedence over + * this `package.json#prisma` config. + * @deprecated + */ + deprecatedPackageJson: { + /** + * The Prisma configuration from `package.json#prisma`. + * @deprecated + */ + config: PrismaConfigPackageJson; + /** + * The path from where the `package.json` config was loaded. + * @deprecated + */ + loadedFromFile: string; + } | null; +} & ({ + engine: 'classic'; + datasource: { + url: string; + shadowDatabaseUrl?: string; + }; +} | { + engine: 'js'; + adapter: () => Promise; +} | { + engine?: never; +}); + +/** + * Example: + * ```json + * { + * "schema": "./prisma/schema.prisma", + * "seed": "tsx ./prisma/seed.ts" + * } + * ``` + */ +declare type PrismaConfigPackageJson = { + schema?: string; + seed?: string; +}; + +declare type PrismaConfigUnconditional = { + /** + * Experimental feature gates. Each experimental feature must be explicitly enabled. + */ + experimental?: Simplify; + /** + * The path to the schema file, or path to a folder that shall be recursively searched for *.prisma files. + */ + schema?: string; + /** + * The configuration for Prisma Studio. + */ + studio?: Simplify; + /** + * Configuration for Prisma migrations. + */ + migrations?: Simplify; + /** + * Configuration for the database table entities. + */ + tables?: Simplify; + /** + * Configuration for the database enum entities. + */ + enums?: Simplify; + /** + * Configuration for the database view entities. + */ + views?: Simplify; + /** + * Configuration for the `typedSql` preview feature. + */ + typedSql?: Simplify; +}; + +declare type PrismaStudioConfigShape = { + adapter: () => Promise; +}; + +declare type Provider = 'mysql' | 'postgres' | 'sqlite' | 'sqlserver'; + +declare interface Queryable extends AdapterInfo { + /** + * Execute a query and return its result. + */ + queryRaw(params: Query): Promise; + /** + * Execute a query and return the number of affected rows. + */ + executeRaw(params: Query): Promise; +} + +declare type Result = { + map(fn: (value: T) => U): Result; + flatMap(fn: (value: T) => Result): Result; +} & ({ + readonly ok: true; + readonly value: T; +} | { + readonly ok: false; + readonly error: Error_2; +}); + +declare type SchemaEngineConfig = SchemaEngineConfigJs | SchemaEngineConfigClassic | SchemaEngineConfigAbsent; + +declare type SchemaEngineConfigAbsent = { + engine?: never; +}; + +declare type SchemaEngineConfigClassic = { + /** + * Uses the "old classic" Schema Engine binary + */ + engine: 'classic'; + /** + * The database connection configuration, which overwrites the `datasource` block's `url`-like attributes in the Prisma schema file. + */ + datasource: SchemaEngineConfigClassicDatasource; +}; + +export declare type SchemaEngineConfigClassicDatasource = { + url: string; + directUrl?: string; + shadowDatabaseUrl?: string; +}; + +export declare type SchemaEngineConfigInternal = SchemaEngineConfigJsInternal | SchemaEngineConfigClassic | SchemaEngineConfigAbsent; + +declare type SchemaEngineConfigJs = { + /** + * Uses the new, unstable JavaScript based Schema Engine. + */ + engine: 'js'; + /** + * The function that instantiates the driver adapter to use for the JavaScript based Schema Engine. + */ + adapter: () => Promise; +}; + +declare type SchemaEngineConfigJsInternal = { + /** + * Uses the new, unstable JavaScript based Schema Engine. + */ + engine: 'js'; + /** + * The function that instantiates the driver adapter to use for the JavaScript based Schema Engine. + */ + adapter: () => Promise; +}; + +declare const SchemaEngineConfigJsInternal: Schema.Struct<{ + engine: Schema.Literal<["js"]>; + adapter: Schema.declare<() => Promise, () => Promise, readonly [], never>; +}>; + +/** + * Simplifies the type signature of a type. + * Re-exported from `effect/Types`. + * + * @example + * ```ts + * type Res = Simplify<{ a: number } & { b: number }> // { a: number; b: number; } + * ``` + */ +declare type Simplify = { + [K in keyof A]: A[K]; +} extends infer B ? B : never; + +declare interface SqlDriverAdapter extends SqlQueryable { + /** + * Execute multiple SQL statements separated by semicolon. + */ + executeScript(script: string): Promise; + /** + * Start new transaction. + */ + startTransaction(isolationLevel?: IsolationLevel): Promise; + /** + * Optional method that returns extra connection info + */ + getConnectionInfo?(): ConnectionInfo; + /** + * Dispose of the connection and release any resources. + */ + dispose(): Promise; +} + +declare interface SqlDriverAdapterFactory extends DriverAdapterFactory { + connect(): Promise; +} + +/** + * An SQL migration adapter that is aware of the notion of a shadow database + * and can create a connection to it. + */ +declare interface SqlMigrationAwareDriverAdapterFactory extends SqlDriverAdapterFactory { + connectToShadowDb(): Promise; +} + +declare type SqlQuery = { + sql: string; + args: Array; + argTypes: Array; +}; + +declare interface SqlQueryable extends Queryable { +} + +declare interface SqlResultSet { + /** + * List of column types appearing in a database query, in the same order as `columnNames`. + * They are used within the Query Engine to convert values from JS to Quaint values. + */ + columnTypes: Array; + /** + * List of column names appearing in a database query, in the same order as `columnTypes`. + */ + columnNames: Array; + /** + * List of rows retrieved from a database query. + * Each row is a list of values, whose length matches `columnNames` and `columnTypes`. + */ + rows: Array>; + /** + * The last ID of an `INSERT` statement, if any. + * This is required for `AUTO_INCREMENT` columns in databases based on MySQL and SQLite. + */ + lastInsertId?: string; +} + +declare type TablesConfigShape = { + /** + * List of tables that are externally managed. + * Prisma will not modify the structure of these tables and not generate migrations for those tables. + * These tables will still be represented in schema.prisma file and be available in the client API. + */ + external?: string[]; +}; + +declare interface Transaction extends AdapterInfo, SqlQueryable { + /** + * Transaction options. + */ + readonly options: TransactionOptions; + /** + * Commit the transaction. + */ + commit(): Promise; + /** + * Roll back the transaction. + */ + rollback(): Promise; +} + +declare type TransactionOptions = { + usePhantomQuery: boolean; +}; + +declare type TypedSqlConfigShape = { + /** + * The path to the directory where Prisma should look for the `typedSql` queries, where *.sql files will be loaded. + */ + path?: string; +}; + +declare type ViewsConfigShape = { + /** + * The path to the directory where Prisma should look for the view definitions, where *.sql files will be loaded. + */ + path?: string; +}; + +export { } diff --git a/backend/node_modules/@prisma/config/dist/index.js b/backend/node_modules/@prisma/config/dist/index.js new file mode 100644 index 0000000000000000000000000000000000000000..c628ae9ab0e6994e0cb8ae3a43764492040c46df --- /dev/null +++ b/backend/node_modules/@prisma/config/dist/index.js @@ -0,0 +1,1000 @@ +"use strict"; +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/index.ts +var index_exports = {}; +__export(index_exports, { + PrismaConfigEnvError: () => PrismaConfigEnvError, + defaultTestConfig: () => defaultTestConfig, + defineConfig: () => defineConfig, + env: () => env, + loadConfigFromFile: () => loadConfigFromFile, + loadConfigFromPackageJson: () => loadConfigFromPackageJson +}); +module.exports = __toCommonJS(index_exports); + +// ../debug/dist/index.mjs +var __defProp2 = Object.defineProperty; +var __export2 = (target, all) => { + for (var name in all) + __defProp2(target, name, { get: all[name], enumerable: true }); +}; +var colors_exports = {}; +__export2(colors_exports, { + $: () => $, + bgBlack: () => bgBlack, + bgBlue: () => bgBlue, + bgCyan: () => bgCyan, + bgGreen: () => bgGreen, + bgMagenta: () => bgMagenta, + bgRed: () => bgRed, + bgWhite: () => bgWhite, + bgYellow: () => bgYellow, + black: () => black, + blue: () => blue, + bold: () => bold, + cyan: () => cyan, + dim: () => dim, + gray: () => gray, + green: () => green, + grey: () => grey, + hidden: () => hidden, + inverse: () => inverse, + italic: () => italic, + magenta: () => magenta, + red: () => red, + reset: () => reset, + strikethrough: () => strikethrough, + underline: () => underline, + white: () => white, + yellow: () => yellow +}); +var FORCE_COLOR; +var NODE_DISABLE_COLORS; +var NO_COLOR; +var TERM; +var isTTY = true; +if (typeof process !== "undefined") { + ({ FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM } = process.env || {}); + isTTY = process.stdout && process.stdout.isTTY; +} +var $ = { + enabled: !NODE_DISABLE_COLORS && NO_COLOR == null && TERM !== "dumb" && (FORCE_COLOR != null && FORCE_COLOR !== "0" || isTTY) +}; +function init(x, y) { + let rgx = new RegExp(`\\x1b\\[${y}m`, "g"); + let open = `\x1B[${x}m`, close = `\x1B[${y}m`; + return function(txt) { + if (!$.enabled || txt == null) return txt; + return open + (!!~("" + txt).indexOf(close) ? txt.replace(rgx, close + open) : txt) + close; + }; +} +var reset = init(0, 0); +var bold = init(1, 22); +var dim = init(2, 22); +var italic = init(3, 23); +var underline = init(4, 24); +var inverse = init(7, 27); +var hidden = init(8, 28); +var strikethrough = init(9, 29); +var black = init(30, 39); +var red = init(31, 39); +var green = init(32, 39); +var yellow = init(33, 39); +var blue = init(34, 39); +var magenta = init(35, 39); +var cyan = init(36, 39); +var white = init(37, 39); +var gray = init(90, 39); +var grey = init(90, 39); +var bgBlack = init(40, 49); +var bgRed = init(41, 49); +var bgGreen = init(42, 49); +var bgYellow = init(43, 49); +var bgBlue = init(44, 49); +var bgMagenta = init(45, 49); +var bgCyan = init(46, 49); +var bgWhite = init(47, 49); +var MAX_ARGS_HISTORY = 100; +var COLORS = ["green", "yellow", "blue", "magenta", "cyan", "red"]; +var argsHistory = []; +var lastTimestamp = Date.now(); +var lastColor = 0; +var processEnv = typeof process !== "undefined" ? process.env : {}; +globalThis.DEBUG ??= processEnv.DEBUG ?? ""; +globalThis.DEBUG_COLORS ??= processEnv.DEBUG_COLORS ? processEnv.DEBUG_COLORS === "true" : true; +var topProps = { + enable(namespace) { + if (typeof namespace === "string") { + globalThis.DEBUG = namespace; + } + }, + disable() { + const prev = globalThis.DEBUG; + globalThis.DEBUG = ""; + return prev; + }, + // this is the core logic to check if logging should happen or not + enabled(namespace) { + const listenedNamespaces = globalThis.DEBUG.split(",").map((s) => { + return s.replace(/[.+?^${}()|[\]\\]/g, "\\$&"); + }); + const isListened = listenedNamespaces.some((listenedNamespace) => { + if (listenedNamespace === "" || listenedNamespace[0] === "-") return false; + return namespace.match(RegExp(listenedNamespace.split("*").join(".*") + "$")); + }); + const isExcluded = listenedNamespaces.some((listenedNamespace) => { + if (listenedNamespace === "" || listenedNamespace[0] !== "-") return false; + return namespace.match(RegExp(listenedNamespace.slice(1).split("*").join(".*") + "$")); + }); + return isListened && !isExcluded; + }, + log: (...args) => { + const [namespace, format, ...rest] = args; + const logWithFormatting = console.warn ?? console.log; + logWithFormatting(`${namespace} ${format}`, ...rest); + }, + formatters: {} + // not implemented +}; +function debugCreate(namespace) { + const instanceProps = { + color: COLORS[lastColor++ % COLORS.length], + enabled: topProps.enabled(namespace), + namespace, + log: topProps.log, + extend: () => { + } + // not implemented + }; + const debugCall = (...args) => { + const { enabled, namespace: namespace2, color, log } = instanceProps; + if (args.length !== 0) { + argsHistory.push([namespace2, ...args]); + } + if (argsHistory.length > MAX_ARGS_HISTORY) { + argsHistory.shift(); + } + if (topProps.enabled(namespace2) || enabled) { + const stringArgs = args.map((arg) => { + if (typeof arg === "string") { + return arg; + } + return safeStringify(arg); + }); + const ms = `+${Date.now() - lastTimestamp}ms`; + lastTimestamp = Date.now(); + if (globalThis.DEBUG_COLORS) { + log(colors_exports[color](bold(namespace2)), ...stringArgs, colors_exports[color](ms)); + } else { + log(namespace2, ...stringArgs, ms); + } + } + }; + return new Proxy(debugCall, { + get: (_, prop) => instanceProps[prop], + set: (_, prop, value) => instanceProps[prop] = value + }); +} +var Debug = new Proxy(debugCreate, { + get: (_, prop) => topProps[prop], + set: (_, prop, value) => topProps[prop] = value +}); +function safeStringify(value, indent = 2) { + const cache = /* @__PURE__ */ new Set(); + return JSON.stringify( + value, + (key, value2) => { + if (typeof value2 === "object" && value2 !== null) { + if (cache.has(value2)) { + return `[Circular *]`; + } + cache.add(value2); + } else if (typeof value2 === "bigint") { + return value2.toString(); + } + return value2; + }, + indent + ); +} + +// ../driver-adapter-utils/dist/index.mjs +function isDriverAdapterError(error) { + return error["name"] === "DriverAdapterError" && typeof error["cause"] === "object"; +} +function ok(value) { + return { + ok: true, + value, + map(fn) { + return ok(fn(value)); + }, + flatMap(fn) { + return fn(value); + } + }; +} +function err(error) { + return { + ok: false, + error, + map() { + return err(error); + }, + flatMap() { + return err(error); + } + }; +} +var debug = Debug("driver-adapter-utils"); +var ErrorRegistryInternal = class { + registeredErrors = []; + consumeError(id) { + return this.registeredErrors[id]; + } + registerNewError(error) { + let i = 0; + while (this.registeredErrors[i] !== void 0) { + i++; + } + this.registeredErrors[i] = { error }; + return i; + } +}; +function copySymbolsFromSource(source, target) { + const symbols = Object.getOwnPropertySymbols(source); + const symbolObject = Object.fromEntries(symbols.map((symbol) => [symbol, true])); + Object.assign(target, symbolObject); +} +var bindMigrationAwareSqlAdapterFactory = (adapterFactory) => { + const errorRegistry = new ErrorRegistryInternal(); + const boundFactory = { + adapterName: adapterFactory.adapterName, + provider: adapterFactory.provider, + errorRegistry, + connect: async (...args) => { + const ctx = await wrapAsync(errorRegistry, adapterFactory.connect.bind(adapterFactory))(...args); + return ctx.map((ctx2) => bindAdapter(ctx2, errorRegistry)); + }, + connectToShadowDb: async (...args) => { + const ctx = await wrapAsync(errorRegistry, adapterFactory.connectToShadowDb.bind(adapterFactory))(...args); + return ctx.map((ctx2) => bindAdapter(ctx2, errorRegistry)); + } + }; + copySymbolsFromSource(adapterFactory, boundFactory); + return boundFactory; +}; +var bindAdapter = (adapter, errorRegistry = new ErrorRegistryInternal()) => { + const boundAdapter = { + adapterName: adapter.adapterName, + errorRegistry, + queryRaw: wrapAsync(errorRegistry, adapter.queryRaw.bind(adapter)), + executeRaw: wrapAsync(errorRegistry, adapter.executeRaw.bind(adapter)), + executeScript: wrapAsync(errorRegistry, adapter.executeScript.bind(adapter)), + dispose: wrapAsync(errorRegistry, adapter.dispose.bind(adapter)), + provider: adapter.provider, + startTransaction: async (...args) => { + const ctx = await wrapAsync(errorRegistry, adapter.startTransaction.bind(adapter))(...args); + return ctx.map((ctx2) => bindTransaction(errorRegistry, ctx2)); + } + }; + if (adapter.getConnectionInfo) { + boundAdapter.getConnectionInfo = wrapSync(errorRegistry, adapter.getConnectionInfo.bind(adapter)); + } + return boundAdapter; +}; +var bindTransaction = (errorRegistry, transaction) => { + return { + adapterName: transaction.adapterName, + provider: transaction.provider, + options: transaction.options, + queryRaw: wrapAsync(errorRegistry, transaction.queryRaw.bind(transaction)), + executeRaw: wrapAsync(errorRegistry, transaction.executeRaw.bind(transaction)), + commit: wrapAsync(errorRegistry, transaction.commit.bind(transaction)), + rollback: wrapAsync(errorRegistry, transaction.rollback.bind(transaction)) + }; +}; +function wrapAsync(registry, fn) { + return async (...args) => { + try { + return ok(await fn(...args)); + } catch (error) { + debug("[error@wrapAsync]", error); + if (isDriverAdapterError(error)) { + return err(error.cause); + } + const id = registry.registerNewError(error); + return err({ kind: "GenericJs", id }); + } + }; +} +function wrapSync(registry, fn) { + return (...args) => { + try { + return ok(fn(...args)); + } catch (error) { + debug("[error@wrapSync]", error); + if (isDriverAdapterError(error)) { + return err(error.cause); + } + const id = registry.registerNewError(error); + return err({ kind: "GenericJs", id }); + } + }; +} +var mockAdapterErrors = { + queryRaw: new Error("Not implemented: queryRaw"), + executeRaw: new Error("Not implemented: executeRaw"), + startTransaction: new Error("Not implemented: startTransaction"), + executeScript: new Error("Not implemented: executeScript"), + dispose: new Error("Not implemented: dispose") +}; + +// src/PrismaConfig.ts +var import_effect3 = require("effect"); +var import_Function = require("effect/Function"); + +// src/defineConfig.ts +var import_effect = require("effect"); + +// src/defaultConfig.ts +function defaultConfig() { + return makePrismaConfigInternal({ + loadedFromFile: null, + deprecatedPackageJson: null + }); +} + +// src/defineConfig.ts +function validateExperimentalFeatures(config) { + const experimental = config.experimental || {}; + if (config.engine === "js" && !experimental.adapter) { + return import_effect.Either.left( + new Error('The `engine === "js"` configuration requires `experimental.adapter` to be set to `true`.') + ); + } + if (config.studio && !experimental.studio) { + return import_effect.Either.left(new Error("The `studio` configuration requires `experimental.studio` to be set to `true`.")); + } + if (config.tables?.external && !experimental.externalTables) { + return import_effect.Either.left( + new Error("The `tables.external` configuration requires `experimental.externalTables` to be set to `true`.") + ); + } + if (config.migrations?.initShadowDb && !experimental.externalTables) { + return import_effect.Either.left( + new Error( + "The `migrations.initShadowDb` configuration requires `experimental.externalTables` to be set to `true`." + ) + ); + } + if (config["extensions"] !== void 0 && !experimental.extensions) { + return import_effect.Either.left( + new Error("The `extensions` configuration requires `experimental.extensions` to be set to `true`.") + ); + } + return import_effect.Either.right(config); +} +var debug2 = Debug("prisma:config:defineConfig"); +function defineConfig(configInput) { + const validationResult = validateExperimentalFeatures(configInput); + if (validationResult._tag === "Left") { + throw validationResult.left; + } + const config = defaultConfig(); + debug2("[default]: %o", config); + defineExperimentalConfig(config, configInput); + defineSchemaConfig(config, configInput); + defineEngineConfig(config, configInput); + defineStudioConfig(config, configInput); + defineMigrationsConfig(config, configInput); + defineTablesConfig(config, configInput); + defineEnumsConfig(config, configInput); + defineTypedSqlConfig(config, configInput); + defineViewsConfig(config, configInput); + defineExtensionsConfig(config, configInput); + return config; +} +function defineExperimentalConfig(config, configInput) { + if (!configInput.experimental) { + return; + } + config.experimental = configInput.experimental; + debug2("[config.experimental]: %o", config.experimental); +} +function defineSchemaConfig(config, configInput) { + if (!configInput.schema) { + return; + } + config.schema = configInput.schema; + debug2("[config.schema]: %o", config.schema); +} +function defineMigrationsConfig(config, configInput) { + if (!configInput.migrations) { + return; + } + config.migrations = configInput.migrations; + debug2("[config.migrations]: %o", config.migrations); +} +function defineTypedSqlConfig(config, configInput) { + if (!configInput.typedSql) { + return; + } + config.typedSql = configInput.typedSql; + debug2("[config.typedSql]: %o", config.typedSql); +} +function defineViewsConfig(config, configInput) { + if (!configInput.views) { + return; + } + config.views = configInput.views; + debug2("[config.views]: %o", config.views); +} +function defineTablesConfig(config, configInput) { + if (!configInput.tables) { + return; + } + config.tables = configInput.tables; + debug2("[config.tables]: %o", config.tables); +} +function defineEnumsConfig(config, configInput) { + if (!configInput.enums) { + return; + } + config.enums = configInput.enums; + debug2("[config.enums]: %o", config.enums); +} +function defineStudioConfig(config, configInput) { + if (!configInput.studio?.adapter) { + return; + } + const { adapter: getAdapterFactory } = configInput.studio; + config.studio = { + adapter: async () => { + const adapterFactory = await getAdapterFactory(); + debug2("[config.studio.adapter]: %o", adapterFactory.adapterName); + return adapterFactory; + } + }; + debug2("[config.studio]: %o", config.studio); +} +function defineEngineConfig(config, configInput) { + if (configInput.engine === void 0) { + return; + } else if (configInput.engine === "js") { + const { engine, adapter: getAdapterFactory } = configInput; + const adapter = async () => { + const adapterFactory = await getAdapterFactory(); + debug2("[config.adapter]: %o", adapterFactory.adapterName); + return bindMigrationAwareSqlAdapterFactory(adapterFactory); + }; + Object.assign(config, { engine, adapter }); + debug2("[config.engine]: %o", engine); + debug2("[config.adapter]: %o", adapter); + } else if (configInput.engine === "classic") { + const { engine, datasource } = configInput; + Object.assign(config, { engine, datasource }); + debug2("[config.engine]: %o", engine); + debug2("[config.datasource]: %o", datasource); + } +} +function defineExtensionsConfig(config, configInput) { + if (!configInput["extensions"]) { + return; + } + config["extensions"] = configInput["extensions"]; + debug2("[config.extensions]: %o", config["extensions"]); +} + +// src/loadConfigFromPackageJson.ts +var import_promises = require("node:fs/promises"); +var import_node_process = __toESM(require("node:process")); +var import_effect2 = require("effect"); +var import_package = require("empathic/package"); +var PrismaConfigPackageJsonShape = import_effect2.Schema.Struct({ + schema: import_effect2.Schema.optional(import_effect2.Schema.String), + seed: import_effect2.Schema.optional(import_effect2.Schema.NonEmptyString) +}); +async function loadConfigFromPackageJson(cwd = import_node_process.default.cwd()) { + const pkgPath = (0, import_package.up)({ cwd }); + if (pkgPath === void 0) { + return null; + } + const pkgJson = await (0, import_promises.readFile)(pkgPath, { encoding: "utf-8" }).then((p) => JSON.parse(p)); + const deprecatedConfig = pkgJson["prisma"]; + if (deprecatedConfig === void 0) { + return null; + } + if (Object.keys(deprecatedConfig).length === 1 && deprecatedConfig["prismaCommit"] !== void 0) { + return null; + } + return { + config: deprecatedConfig, + loadedFromFile: pkgPath + }; +} + +// src/PrismaConfig.ts +var debug3 = Debug("prisma:config:PrismaConfig"); +var SqlMigrationAwareDriverAdapterFactoryShape = import_effect3.Schema.declare( + (input) => { + return typeof input === "function"; + }, + { + identifier: "SqlMigrationAwareDriverAdapterFactory", + encode: import_effect3.identity, + decode: import_effect3.identity + } +); +var ErrorCapturingSqlMigrationAwareDriverAdapterFactoryShape = import_effect3.Schema.declare( + (input) => { + return typeof input === "function"; + }, + { + identifier: "ErrorCapturingSqlMigrationAwareDriverAdapterFactory", + encode: import_effect3.identity, + decode: import_effect3.identity + } +); +var SchemaEngineConfigClassicShape = import_effect3.Schema.Struct({ + engine: import_effect3.Schema.Literal("classic"), + datasource: import_effect3.Schema.Struct({ + url: import_effect3.Schema.String, + directUrl: import_effect3.Schema.optional(import_effect3.Schema.String), + shadowDatabaseUrl: import_effect3.Schema.optional(import_effect3.Schema.String) + }) +}); +var SchemaEngineConfigJsShape = import_effect3.Schema.Struct({ + engine: import_effect3.Schema.Literal("js"), + adapter: SqlMigrationAwareDriverAdapterFactoryShape +}); +var SchemaEngineConfigAbsentShape = import_effect3.Schema.Struct({ + engine: import_effect3.Schema.optional(import_effect3.Schema.Never) +}); +var SchemaEngineConfigShape = import_effect3.Schema.Union( + SchemaEngineConfigClassicShape, + SchemaEngineConfigJsShape, + SchemaEngineConfigAbsentShape +); +var SchemaEngineConfigJsInternal = import_effect3.Schema.Struct({ + engine: import_effect3.Schema.Literal("js"), + adapter: ErrorCapturingSqlMigrationAwareDriverAdapterFactoryShape +}); +var SchemaEngineConfigInternal = import_effect3.Schema.Union( + SchemaEngineConfigClassicShape, + SchemaEngineConfigJsInternal, + SchemaEngineConfigAbsentShape +); +var ExperimentalConfigShape = import_effect3.Schema.Struct({ + adapter: import_effect3.Schema.optional(import_effect3.Schema.Boolean), + studio: import_effect3.Schema.optional(import_effect3.Schema.Boolean), + externalTables: import_effect3.Schema.optional(import_effect3.Schema.Boolean), + extensions: import_effect3.Schema.optional(import_effect3.Schema.Boolean) +}); +if (false) { + __testExperimentalConfigShapeValueA; + __testExperimentalConfigShapeValueB; +} +var MigrationsConfigShape = import_effect3.Schema.Struct({ + path: import_effect3.Schema.optional(import_effect3.Schema.String), + initShadowDb: import_effect3.Schema.optional(import_effect3.Schema.String), + seed: import_effect3.Schema.optional(import_effect3.Schema.NonEmptyString) +}); +if (false) { + __testMigrationsConfigShapeValueA; + __testMigrationsConfigShapeValueB; +} +var TablesConfigShape = import_effect3.Schema.Struct({ + external: import_effect3.Schema.optional(import_effect3.Schema.mutable(import_effect3.Schema.Array(import_effect3.Schema.String))) +}); +if (false) { + __testTablesConfigShapeValueA; + __testTablesConfigShapeValueB; +} +var EnumsConfigShape = import_effect3.Schema.Struct({ + external: import_effect3.Schema.optional(import_effect3.Schema.mutable(import_effect3.Schema.Array(import_effect3.Schema.String))) +}); +if (false) { + __testEnumsConfigShapeValueA; + __testEnumsConfigShapeValueB; +} +var ViewsConfigShape = import_effect3.Schema.Struct({ + path: import_effect3.Schema.optional(import_effect3.Schema.String) +}); +if (false) { + __testViewsConfigShapeValueA; + __testViewsConfigShapeValueB; +} +var TypedSqlConfigShape = import_effect3.Schema.Struct({ + path: import_effect3.Schema.optional(import_effect3.Schema.String) +}); +if (false) { + __testTypedSqlConfigShapeValueA; + __testTypedSqlConfigShapeValueB; +} +var PrismaStudioConfigShape = import_effect3.Schema.Struct({ + /** + * Instantiates the Prisma driver adapter to use for Prisma Studio. + */ + adapter: SqlMigrationAwareDriverAdapterFactoryShape +}); +if (false) { + __testPrismaStudioConfigShapeValueA; + __testPrismaStudioConfigShapeValueB; +} +if (false) { + __testPrismaConfig; + __testPrismaConfigInternal; +} +var PrismaConfigUnconditionalShape = import_effect3.Schema.Struct({ + experimental: import_effect3.Schema.optional(ExperimentalConfigShape), + schema: import_effect3.Schema.optional(import_effect3.Schema.String), + studio: import_effect3.Schema.optional(PrismaStudioConfigShape), + migrations: import_effect3.Schema.optional(MigrationsConfigShape), + tables: import_effect3.Schema.optional(TablesConfigShape), + enums: import_effect3.Schema.optional(EnumsConfigShape), + views: import_effect3.Schema.optional(ViewsConfigShape), + typedSql: import_effect3.Schema.optional(TypedSqlConfigShape), + extensions: import_effect3.Schema.optional(import_effect3.Schema.Any) +}); +var PrismaConfigShape = import_effect3.Schema.extend(SchemaEngineConfigShape, PrismaConfigUnconditionalShape); +if (false) { + __testPrismaConfigValueA; + __testPrismaConfigValueB; +} +function validateExperimentalFeatures2(config) { + const experimental = config.experimental || {}; + if (config.engine === "js" && !experimental.adapter) { + return import_effect3.Either.left( + new Error("The `engine === 'js'` configuration requires `experimental.adapter` to be set to `true`.") + ); + } + if (config.studio && !experimental.studio) { + return import_effect3.Either.left(new Error("The `studio` configuration requires `experimental.studio` to be set to `true`.")); + } + if (config.tables?.external && !experimental.externalTables) { + return import_effect3.Either.left( + new Error("The `tables.external` configuration requires `experimental.externalTables` to be set to `true`.") + ); + } + if (config.enums?.external && !experimental.externalTables) { + return import_effect3.Either.left( + new Error("The `enums.external` configuration requires `experimental.externalTables` to be set to `true`.") + ); + } + if (config.migrations?.initShadowDb && !experimental.externalTables) { + return import_effect3.Either.left( + new Error( + "The `migrations.initShadowDb` configuration requires `experimental.externalTables` to be set to `true`." + ) + ); + } + if (config["extensions"] && !experimental.extensions) { + return import_effect3.Either.left( + new Error("The `extensions` configuration requires `experimental.extensions` to be set to `true`.") + ); + } + return import_effect3.Either.right(config); +} +function parsePrismaConfigShape(input) { + return (0, import_Function.pipe)( + import_effect3.Schema.decodeUnknownEither(PrismaConfigShape, {})(input, { + onExcessProperty: "error" + }), + import_effect3.Either.flatMap(validateExperimentalFeatures2) + ); +} +var PRISMA_CONFIG_INTERNAL_BRAND = Symbol.for("PrismaConfigInternal"); +var PrismaConfigInternalShape = import_effect3.Schema.extend( + PrismaConfigUnconditionalShape, + import_effect3.Schema.extend( + SchemaEngineConfigInternal, + import_effect3.Schema.Struct({ + loadedFromFile: import_effect3.Schema.NullOr(import_effect3.Schema.String), + deprecatedPackageJson: import_effect3.Schema.NullOr( + import_effect3.Schema.Struct({ + config: PrismaConfigPackageJsonShape, + loadedFromFile: import_effect3.Schema.String + }) + ) + }) + ) +); +function brandPrismaConfigInternal(config) { + Object.defineProperty(config, "__brand", { + value: PRISMA_CONFIG_INTERNAL_BRAND, + writable: true, + configurable: true, + enumerable: false + }); + return config; +} +function parsePrismaConfigInternalShape(input) { + debug3("Parsing PrismaConfigInternal: %o", input); + if (typeof input === "object" && input !== null && input["__brand"] === PRISMA_CONFIG_INTERNAL_BRAND) { + debug3("Short-circuit: input is already a PrismaConfigInternal object"); + return import_effect3.Either.right(input); + } + return (0, import_Function.pipe)( + import_effect3.Schema.decodeUnknownEither(PrismaConfigInternalShape, {})(input, { + onExcessProperty: "error" + }), + // Brand the output type to make `PrismaConfigInternal` opaque, without exposing the `Effect/Brand` type + // to the public API. + // This is done to work around the following issues: + // - https://github.com/microsoft/rushstack/issues/1308 + // - https://github.com/microsoft/rushstack/issues/4034 + // - https://github.com/microsoft/TypeScript/issues/58914 + import_effect3.Either.map(brandPrismaConfigInternal) + ); +} +function makePrismaConfigInternal(makeArgs) { + return brandPrismaConfigInternal(makeArgs); +} +function parseDefaultExport(defaultExport) { + const parseResultEither = (0, import_Function.pipe)( + // If the given config conforms to the `PrismaConfig` shape, feed it to `defineConfig`. + parsePrismaConfigShape(defaultExport), + import_effect3.Either.map((config) => { + debug3("Parsed `PrismaConfig` shape: %o", config); + return defineConfig(config); + }), + // Otherwise, try to parse it as a `PrismaConfigInternal` shape. + import_effect3.Either.orElse(() => parsePrismaConfigInternalShape(defaultExport)) + ); + if (import_effect3.Either.isLeft(parseResultEither)) { + throw parseResultEither.left; + } + return parseResultEither.right; +} + +// src/defaultTestConfig.ts +function defaultTestConfig() { + return makePrismaConfigInternal({ + loadedFromFile: null, + deprecatedPackageJson: null + }); +} + +// src/env.ts +var PrismaConfigEnvError = class extends Error { + constructor(name) { + super(`Missing required environment variable: ${name}`); + this.name = "PrismaConfigEnvError"; + } +}; +function env(name) { + const value = process.env[name]; + if (!value) { + throw new PrismaConfigEnvError(name); + } + return value; +} + +// src/loadConfigFromFile.ts +var import_node_path = __toESM(require("node:path")); +var import_node_process2 = __toESM(require("node:process")); +var debug4 = Debug("prisma:config:loadConfigFromFile"); +var SUPPORTED_EXTENSIONS = [".js", ".ts", ".mjs", ".cjs", ".mts", ".cts"]; +async function loadConfigFromFile({ + configFile, + configRoot = import_node_process2.default.cwd() +}) { + const start = performance.now(); + const getTime = () => `${(performance.now() - start).toFixed(2)}ms`; + const diagnostics = []; + const deprecatedPrismaConfigFromJson = await loadConfigFromPackageJson(configRoot); + if (deprecatedPrismaConfigFromJson) { + diagnostics.push({ + _tag: "warn", + value: ({ warn, link }) => () => warn( + `The configuration property \`package.json#prisma\` is deprecated and will be removed in Prisma 7. Please migrate to a Prisma config file (e.g., \`prisma.config.ts\`). +For more information, see: ${link("https://pris.ly/prisma-config")} +` + ) + }); + } + try { + const { configModule, resolvedPath, error } = await loadConfigTsOrJs(configRoot, configFile); + if (error) { + return { + resolvedPath, + error, + diagnostics + }; + } + debug4(`Config file loaded in %s`, getTime()); + if (resolvedPath === null) { + debug4(`No config file found in the current working directory %s`, configRoot); + return { resolvedPath: null, config: defaultConfig(), diagnostics }; + } + let parsedConfig; + try { + parsedConfig = parseDefaultExport(configModule); + } catch (e) { + const error2 = e; + return { + resolvedPath, + error: { + _tag: "ConfigFileSyntaxError", + error: error2 + }, + diagnostics + }; + } + diagnostics.push({ + _tag: "log", + value: ({ log, dim: dim2 }) => () => log(dim2(`Loaded Prisma config from ${import_node_path.default.relative(configRoot, resolvedPath)}. +`)) + }); + const prismaConfig = transformPathsInConfigToAbsolute(parsedConfig, resolvedPath); + if (deprecatedPrismaConfigFromJson) { + diagnostics.push({ + _tag: "warn", + value: ({ warn, link }) => () => warn(`The Prisma config file in ${import_node_path.default.relative( + configRoot, + resolvedPath + )} overrides the deprecated \`package.json#prisma\` property in ${import_node_path.default.relative( + configRoot, + deprecatedPrismaConfigFromJson.loadedFromFile + )}. + For more information, see: ${link("https://pris.ly/prisma-config")} +`) + }); + } + return { + config: { + ...prismaConfig, + loadedFromFile: resolvedPath + }, + resolvedPath, + diagnostics + }; + } catch (e) { + const error = e; + return { + resolvedPath: configRoot, + error: { + _tag: "UnknownError", + error + }, + diagnostics + }; + } +} +async function loadConfigTsOrJs(configRoot, configFile) { + const { loadConfig: loadConfigWithC12 } = await import("c12"); + const { deepmerge } = await import("deepmerge-ts"); + try { + const { + config, + configFile: _resolvedPath, + meta + } = await loadConfigWithC12({ + cwd: configRoot, + // configuration base name + name: "prisma", + // the config file to load (without file extensions), defaulting to `${cwd}.${name}` + configFile, + // do not load .env files + dotenv: false, + // do not load RC config + rcFile: false, + // do not extend remote config files + giget: false, + // do not extend the default config + extend: false, + // do not load from nearest package.json + packageJson: false, + // @ts-expect-error: this is a type-error in `c12` itself + merger: deepmerge, + jitiOptions: { + interopDefault: true, + moduleCache: false, + extensions: SUPPORTED_EXTENSIONS + } + }); + const resolvedPath = _resolvedPath ? import_node_path.default.normalize(_resolvedPath) : void 0; + const doesConfigFileExist = resolvedPath !== void 0 && meta !== void 0; + if (configFile && !doesConfigFileExist) { + debug4(`The given config file was not found at %s`, resolvedPath); + return { + require: null, + resolvedPath: import_node_path.default.join(configRoot, configFile), + error: { _tag: "ConfigFileNotFound" } + }; + } + if (doesConfigFileExist) { + const extension = import_node_path.default.extname(import_node_path.default.basename(resolvedPath)); + if (!SUPPORTED_EXTENSIONS.includes(extension)) { + return { + configModule: config, + resolvedPath, + error: { + _tag: "ConfigLoadError", + error: new Error(`Unsupported Prisma config file extension: ${extension}`) + } + }; + } + } + return { + configModule: config, + resolvedPath: doesConfigFileExist ? resolvedPath : null, + error: null + }; + } catch (e) { + const error = e; + debug4("jiti import failed: %s", error.message); + const configFileMatch = error.message.match(/prisma\.config\.(\w+)/); + const extension = configFileMatch?.[1]; + const filenameWithExtension = import_node_path.default.join(configRoot, extension ? `prisma.config.${extension}` : ""); + debug4("faulty config file: %s", filenameWithExtension); + return { + error: { + _tag: "ConfigLoadError", + error + }, + resolvedPath: filenameWithExtension + }; + } +} +function transformPathsInConfigToAbsolute(prismaConfig, resolvedPath) { + function resolvePath(value) { + if (!value) { + return void 0; + } + return import_node_path.default.resolve(import_node_path.default.dirname(resolvedPath), value); + } + return { + ...prismaConfig, + schema: resolvePath(prismaConfig.schema), + migrations: { + ...prismaConfig.migrations, + path: resolvePath(prismaConfig.migrations?.path) + }, + typedSql: { + ...prismaConfig.typedSql, + path: resolvePath(prismaConfig.typedSql?.path) + }, + views: { + ...prismaConfig.views, + path: resolvePath(prismaConfig.views?.path) + } + }; +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + PrismaConfigEnvError, + defaultTestConfig, + defineConfig, + env, + loadConfigFromFile, + loadConfigFromPackageJson +}); diff --git a/backend/node_modules/@prisma/engines/dist/index.d.ts b/backend/node_modules/@prisma/engines/dist/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..6d7be0bdadace31383aa6822551c397267a6397e --- /dev/null +++ b/backend/node_modules/@prisma/engines/dist/index.d.ts @@ -0,0 +1,26 @@ +import type { BinaryPaths } from '@prisma/fetch-engine'; +import { BinaryType as BinaryType_2 } from '@prisma/fetch-engine'; +import type { DownloadOptions } from '@prisma/fetch-engine'; +import { enginesVersion } from '@prisma/engines-version'; + +export declare const DEFAULT_CLI_QUERY_ENGINE_BINARY_TYPE = BinaryType.QueryEngineLibrary; + +export { enginesVersion } + +export declare function ensureNeededBinariesExist({ clientEngineType, download, hasMigrateAdapterInConfig, }: EnsureSomeBinariesExistInput): Promise; + +declare type EnsureSomeBinariesExistInput = { + clientEngineType: 'library' | 'binary' | 'client'; + hasMigrateAdapterInConfig: boolean; + download: (options: DownloadOptions) => Promise; +}; + +/** + * Checks if the env override `PRISMA_CLI_QUERY_ENGINE_TYPE` is set to `library` or `binary` + * Otherwise returns the default + */ +export declare function getCliQueryEngineBinaryType(clientEngineType?: string | undefined): BinaryType_2; + +export declare function getEnginesPath(): string; + +export { } diff --git a/backend/node_modules/@prisma/engines/dist/index.js b/backend/node_modules/@prisma/engines/dist/index.js new file mode 100644 index 0000000000000000000000000000000000000000..a09d4d7d045b256f4d8b8bbdf9f1c7ed45b34101 --- /dev/null +++ b/backend/node_modules/@prisma/engines/dist/index.js @@ -0,0 +1,112 @@ +"use strict"; +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/index.ts +var index_exports = {}; +__export(index_exports, { + DEFAULT_CLI_QUERY_ENGINE_BINARY_TYPE: () => DEFAULT_CLI_QUERY_ENGINE_BINARY_TYPE, + enginesVersion: () => import_engines_version2.enginesVersion, + ensureNeededBinariesExist: () => ensureNeededBinariesExist, + getCliQueryEngineBinaryType: () => getCliQueryEngineBinaryType, + getEnginesPath: () => getEnginesPath +}); +module.exports = __toCommonJS(index_exports); +var import_debug = require("@prisma/debug"); +var import_engines_version = require("@prisma/engines-version"); +var import_fetch_engine = require("@prisma/fetch-engine"); +var import_path = __toESM(require("path")); +var import_engines_version2 = require("@prisma/engines-version"); +var debug = (0, import_debug.Debug)("prisma:engines"); +function getEnginesPath() { + return import_path.default.join(__dirname, "../"); +} +var DEFAULT_CLI_QUERY_ENGINE_BINARY_TYPE = import_fetch_engine.BinaryType.QueryEngineLibrary; +function getCliQueryEngineBinaryType(clientEngineType = process.env.PRISMA_CLI_QUERY_ENGINE_TYPE) { + if (clientEngineType === "binary") { + return import_fetch_engine.BinaryType.QueryEngineBinary; + } + return DEFAULT_CLI_QUERY_ENGINE_BINARY_TYPE; +} +async function ensureNeededBinariesExist({ + clientEngineType, + download, + hasMigrateAdapterInConfig +}) { + const binaryDir = import_path.default.join(__dirname, "../"); + const binaries = {}; + if (!hasMigrateAdapterInConfig) { + binaries[import_fetch_engine.BinaryType.SchemaEngineBinary] = binaryDir; + } + const usesQueryCompiler = clientEngineType === "client"; + if (!usesQueryCompiler) { + const cliQueryEngineBinaryType = getCliQueryEngineBinaryType(clientEngineType); + binaries[cliQueryEngineBinaryType] = binaryDir; + } + debug(`binaries to download ${Object.keys(binaries).join(", ")}`); + const binaryTargets = process.env.PRISMA_CLI_BINARY_TARGETS ? process.env.PRISMA_CLI_BINARY_TARGETS.split(",") : void 0; + await download({ + binaries, + showProgress: true, + version: import_engines_version.enginesVersion, + failSilent: false, + binaryTargets + }); +} +import_path.default.join(__dirname, "../query-engine-darwin"); +import_path.default.join(__dirname, "../query-engine-darwin-arm64"); +import_path.default.join(__dirname, "../query-engine-debian-openssl-1.0.x"); +import_path.default.join(__dirname, "../query-engine-debian-openssl-1.1.x"); +import_path.default.join(__dirname, "../query-engine-debian-openssl-3.0.x"); +import_path.default.join(__dirname, "../query-engine-linux-static-x64"); +import_path.default.join(__dirname, "../query-engine-linux-static-arm64"); +import_path.default.join(__dirname, "../query-engine-rhel-openssl-1.0.x"); +import_path.default.join(__dirname, "../query-engine-rhel-openssl-1.1.x"); +import_path.default.join(__dirname, "../query-engine-rhel-openssl-3.0.x"); +import_path.default.join(__dirname, "../libquery_engine-darwin.dylib.node"); +import_path.default.join(__dirname, "../libquery_engine-darwin-arm64.dylib.node"); +import_path.default.join(__dirname, "../libquery_engine-debian-openssl-1.0.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-debian-openssl-1.1.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-debian-openssl-3.0.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-linux-arm64-openssl-1.0.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-linux-arm64-openssl-1.1.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-linux-arm64-openssl-3.0.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-linux-musl.so.node"); +import_path.default.join(__dirname, "../libquery_engine-linux-musl-openssl-3.0.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-rhel-openssl-1.0.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-rhel-openssl-1.1.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-rhel-openssl-3.0.x.so.node"); +import_path.default.join(__dirname, "../query_engine-windows.dll.node"); +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + DEFAULT_CLI_QUERY_ENGINE_BINARY_TYPE, + enginesVersion, + ensureNeededBinariesExist, + getCliQueryEngineBinaryType, + getEnginesPath +}); diff --git a/backend/node_modules/@prisma/engines/dist/scripts/localinstall.d.ts b/backend/node_modules/@prisma/engines/dist/scripts/localinstall.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb0ff5c3b541f646105198ee23ac0fc3d805023e --- /dev/null +++ b/backend/node_modules/@prisma/engines/dist/scripts/localinstall.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/backend/node_modules/@prisma/engines/dist/scripts/localinstall.js b/backend/node_modules/@prisma/engines/dist/scripts/localinstall.js new file mode 100644 index 0000000000000000000000000000000000000000..e17d474963c5437cb752afe8f2f7dc8f7739cb0d --- /dev/null +++ b/backend/node_modules/@prisma/engines/dist/scripts/localinstall.js @@ -0,0 +1,2048 @@ +"use strict"; +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); + +// ../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.js +var require_windows = __commonJS({ + "../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.js"(exports2, module2) { + "use strict"; + module2.exports = isexe; + isexe.sync = sync; + var fs2 = require("fs"); + function checkPathExt(path2, options) { + var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT; + if (!pathext) { + return true; + } + pathext = pathext.split(";"); + if (pathext.indexOf("") !== -1) { + return true; + } + for (var i = 0; i < pathext.length; i++) { + var p = pathext[i].toLowerCase(); + if (p && path2.substr(-p.length).toLowerCase() === p) { + return true; + } + } + return false; + } + function checkStat(stat, path2, options) { + if (!stat.isSymbolicLink() && !stat.isFile()) { + return false; + } + return checkPathExt(path2, options); + } + function isexe(path2, options, cb) { + fs2.stat(path2, function(er, stat) { + cb(er, er ? false : checkStat(stat, path2, options)); + }); + } + function sync(path2, options) { + return checkStat(fs2.statSync(path2), path2, options); + } + } +}); + +// ../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.js +var require_mode = __commonJS({ + "../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.js"(exports2, module2) { + "use strict"; + module2.exports = isexe; + isexe.sync = sync; + var fs2 = require("fs"); + function isexe(path2, options, cb) { + fs2.stat(path2, function(er, stat) { + cb(er, er ? false : checkStat(stat, options)); + }); + } + function sync(path2, options) { + return checkStat(fs2.statSync(path2), options); + } + function checkStat(stat, options) { + return stat.isFile() && checkMode(stat, options); + } + function checkMode(stat, options) { + var mod = stat.mode; + var uid = stat.uid; + var gid = stat.gid; + var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid(); + var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid(); + var u = parseInt("100", 8); + var g = parseInt("010", 8); + var o = parseInt("001", 8); + var ug = u | g; + var ret = mod & o || mod & g && gid === myGid || mod & u && uid === myUid || mod & ug && myUid === 0; + return ret; + } + } +}); + +// ../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js +var require_isexe = __commonJS({ + "../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js"(exports2, module2) { + "use strict"; + var fs2 = require("fs"); + var core; + if (process.platform === "win32" || global.TESTING_WINDOWS) { + core = require_windows(); + } else { + core = require_mode(); + } + module2.exports = isexe; + isexe.sync = sync; + function isexe(path2, options, cb) { + if (typeof options === "function") { + cb = options; + options = {}; + } + if (!cb) { + if (typeof Promise !== "function") { + throw new TypeError("callback not provided"); + } + return new Promise(function(resolve, reject) { + isexe(path2, options || {}, function(er, is) { + if (er) { + reject(er); + } else { + resolve(is); + } + }); + }); + } + core(path2, options || {}, function(er, is) { + if (er) { + if (er.code === "EACCES" || options && options.ignoreErrors) { + er = null; + is = false; + } + } + cb(er, is); + }); + } + function sync(path2, options) { + try { + return core.sync(path2, options || {}); + } catch (er) { + if (options && options.ignoreErrors || er.code === "EACCES") { + return false; + } else { + throw er; + } + } + } + } +}); + +// ../../node_modules/.pnpm/which@2.0.2/node_modules/which/which.js +var require_which = __commonJS({ + "../../node_modules/.pnpm/which@2.0.2/node_modules/which/which.js"(exports2, module2) { + "use strict"; + var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys"; + var path2 = require("path"); + var COLON = isWindows ? ";" : ":"; + var isexe = require_isexe(); + var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" }); + var getPathInfo = (cmd, opt) => { + const colon = opt.colon || COLON; + const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [""] : [ + // windows always checks the cwd first + ...isWindows ? [process.cwd()] : [], + ...(opt.path || process.env.PATH || /* istanbul ignore next: very unusual */ + "").split(colon) + ]; + const pathExtExe = isWindows ? opt.pathExt || process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM" : ""; + const pathExt = isWindows ? pathExtExe.split(colon) : [""]; + if (isWindows) { + if (cmd.indexOf(".") !== -1 && pathExt[0] !== "") + pathExt.unshift(""); + } + return { + pathEnv, + pathExt, + pathExtExe + }; + }; + var which = (cmd, opt, cb) => { + if (typeof opt === "function") { + cb = opt; + opt = {}; + } + if (!opt) + opt = {}; + const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt); + const found = []; + const step = (i) => new Promise((resolve, reject) => { + if (i === pathEnv.length) + return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd)); + const ppRaw = pathEnv[i]; + const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw; + const pCmd = path2.join(pathPart, cmd); + const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd; + resolve(subStep(p, i, 0)); + }); + const subStep = (p, i, ii) => new Promise((resolve, reject) => { + if (ii === pathExt.length) + return resolve(step(i + 1)); + const ext = pathExt[ii]; + isexe(p + ext, { pathExt: pathExtExe }, (er, is) => { + if (!er && is) { + if (opt.all) + found.push(p + ext); + else + return resolve(p + ext); + } + return resolve(subStep(p, i, ii + 1)); + }); + }); + return cb ? step(0).then((res) => cb(null, res), cb) : step(0); + }; + var whichSync = (cmd, opt) => { + opt = opt || {}; + const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt); + const found = []; + for (let i = 0; i < pathEnv.length; i++) { + const ppRaw = pathEnv[i]; + const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw; + const pCmd = path2.join(pathPart, cmd); + const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd; + for (let j = 0; j < pathExt.length; j++) { + const cur = p + pathExt[j]; + try { + const is = isexe.sync(cur, { pathExt: pathExtExe }); + if (is) { + if (opt.all) + found.push(cur); + else + return cur; + } + } catch (ex) { + } + } + } + if (opt.all && found.length) + return found; + if (opt.nothrow) + return null; + throw getNotFoundError(cmd); + }; + module2.exports = which; + which.sync = whichSync; + } +}); + +// ../../node_modules/.pnpm/path-key@3.1.1/node_modules/path-key/index.js +var require_path_key = __commonJS({ + "../../node_modules/.pnpm/path-key@3.1.1/node_modules/path-key/index.js"(exports2, module2) { + "use strict"; + var pathKey = (options = {}) => { + const environment = options.env || process.env; + const platform = options.platform || process.platform; + if (platform !== "win32") { + return "PATH"; + } + return Object.keys(environment).reverse().find((key) => key.toUpperCase() === "PATH") || "Path"; + }; + module2.exports = pathKey; + module2.exports.default = pathKey; + } +}); + +// ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js +var require_resolveCommand = __commonJS({ + "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js"(exports2, module2) { + "use strict"; + var path2 = require("path"); + var which = require_which(); + var getPathKey = require_path_key(); + function resolveCommandAttempt(parsed, withoutPathExt) { + const env = parsed.options.env || process.env; + const cwd = process.cwd(); + const hasCustomCwd = parsed.options.cwd != null; + const shouldSwitchCwd = hasCustomCwd && process.chdir !== void 0 && !process.chdir.disabled; + if (shouldSwitchCwd) { + try { + process.chdir(parsed.options.cwd); + } catch (err) { + } + } + let resolved; + try { + resolved = which.sync(parsed.command, { + path: env[getPathKey({ env })], + pathExt: withoutPathExt ? path2.delimiter : void 0 + }); + } catch (e) { + } finally { + if (shouldSwitchCwd) { + process.chdir(cwd); + } + } + if (resolved) { + resolved = path2.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved); + } + return resolved; + } + function resolveCommand(parsed) { + return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true); + } + module2.exports = resolveCommand; + } +}); + +// ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/escape.js +var require_escape = __commonJS({ + "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/escape.js"(exports2, module2) { + "use strict"; + var metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g; + function escapeCommand(arg) { + arg = arg.replace(metaCharsRegExp, "^$1"); + return arg; + } + function escapeArgument(arg, doubleEscapeMetaChars) { + arg = `${arg}`; + arg = arg.replace(/(?=(\\+?)?)\1"/g, '$1$1\\"'); + arg = arg.replace(/(?=(\\+?)?)\1$/, "$1$1"); + arg = `"${arg}"`; + arg = arg.replace(metaCharsRegExp, "^$1"); + if (doubleEscapeMetaChars) { + arg = arg.replace(metaCharsRegExp, "^$1"); + } + return arg; + } + module2.exports.command = escapeCommand; + module2.exports.argument = escapeArgument; + } +}); + +// ../../node_modules/.pnpm/shebang-regex@3.0.0/node_modules/shebang-regex/index.js +var require_shebang_regex = __commonJS({ + "../../node_modules/.pnpm/shebang-regex@3.0.0/node_modules/shebang-regex/index.js"(exports2, module2) { + "use strict"; + module2.exports = /^#!(.*)/; + } +}); + +// ../../node_modules/.pnpm/shebang-command@2.0.0/node_modules/shebang-command/index.js +var require_shebang_command = __commonJS({ + "../../node_modules/.pnpm/shebang-command@2.0.0/node_modules/shebang-command/index.js"(exports2, module2) { + "use strict"; + var shebangRegex = require_shebang_regex(); + module2.exports = (string = "") => { + const match = string.match(shebangRegex); + if (!match) { + return null; + } + const [path2, argument] = match[0].replace(/#! ?/, "").split(" "); + const binary = path2.split("/").pop(); + if (binary === "env") { + return argument; + } + return argument ? `${binary} ${argument}` : binary; + }; + } +}); + +// ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js +var require_readShebang = __commonJS({ + "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js"(exports2, module2) { + "use strict"; + var fs2 = require("fs"); + var shebangCommand = require_shebang_command(); + function readShebang(command) { + const size = 150; + const buffer = Buffer.alloc(size); + let fd; + try { + fd = fs2.openSync(command, "r"); + fs2.readSync(fd, buffer, 0, size, 0); + fs2.closeSync(fd); + } catch (e) { + } + return shebangCommand(buffer.toString()); + } + module2.exports = readShebang; + } +}); + +// ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js +var require_parse = __commonJS({ + "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js"(exports2, module2) { + "use strict"; + var path2 = require("path"); + var resolveCommand = require_resolveCommand(); + var escape = require_escape(); + var readShebang = require_readShebang(); + var isWin = process.platform === "win32"; + var isExecutableRegExp = /\.(?:com|exe)$/i; + var isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i; + function detectShebang(parsed) { + parsed.file = resolveCommand(parsed); + const shebang = parsed.file && readShebang(parsed.file); + if (shebang) { + parsed.args.unshift(parsed.file); + parsed.command = shebang; + return resolveCommand(parsed); + } + return parsed.file; + } + function parseNonShell(parsed) { + if (!isWin) { + return parsed; + } + const commandFile = detectShebang(parsed); + const needsShell = !isExecutableRegExp.test(commandFile); + if (parsed.options.forceShell || needsShell) { + const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile); + parsed.command = path2.normalize(parsed.command); + parsed.command = escape.command(parsed.command); + parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars)); + const shellCommand = [parsed.command].concat(parsed.args).join(" "); + parsed.args = ["/d", "/s", "/c", `"${shellCommand}"`]; + parsed.command = process.env.comspec || "cmd.exe"; + parsed.options.windowsVerbatimArguments = true; + } + return parsed; + } + function parse(command, args, options) { + if (args && !Array.isArray(args)) { + options = args; + args = null; + } + args = args ? args.slice(0) : []; + options = Object.assign({}, options); + const parsed = { + command, + args, + options, + file: void 0, + original: { + command, + args + } + }; + return options.shell ? parsed : parseNonShell(parsed); + } + module2.exports = parse; + } +}); + +// ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/enoent.js +var require_enoent = __commonJS({ + "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/enoent.js"(exports2, module2) { + "use strict"; + var isWin = process.platform === "win32"; + function notFoundError(original, syscall) { + return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), { + code: "ENOENT", + errno: "ENOENT", + syscall: `${syscall} ${original.command}`, + path: original.command, + spawnargs: original.args + }); + } + function hookChildProcess(cp, parsed) { + if (!isWin) { + return; + } + const originalEmit = cp.emit; + cp.emit = function(name, arg1) { + if (name === "exit") { + const err = verifyENOENT(arg1, parsed); + if (err) { + return originalEmit.call(cp, "error", err); + } + } + return originalEmit.apply(cp, arguments); + }; + } + function verifyENOENT(status, parsed) { + if (isWin && status === 1 && !parsed.file) { + return notFoundError(parsed.original, "spawn"); + } + return null; + } + function verifyENOENTSync(status, parsed) { + if (isWin && status === 1 && !parsed.file) { + return notFoundError(parsed.original, "spawnSync"); + } + return null; + } + module2.exports = { + hookChildProcess, + verifyENOENT, + verifyENOENTSync, + notFoundError + }; + } +}); + +// ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/index.js +var require_cross_spawn = __commonJS({ + "../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/index.js"(exports2, module2) { + "use strict"; + var cp = require("child_process"); + var parse = require_parse(); + var enoent = require_enoent(); + function spawn(command, args, options) { + const parsed = parse(command, args, options); + const spawned = cp.spawn(parsed.command, parsed.args, parsed.options); + enoent.hookChildProcess(spawned, parsed); + return spawned; + } + function spawnSync(command, args, options) { + const parsed = parse(command, args, options); + const result = cp.spawnSync(parsed.command, parsed.args, parsed.options); + result.error = result.error || enoent.verifyENOENTSync(result.status, parsed); + return result; + } + module2.exports = spawn; + module2.exports.spawn = spawn; + module2.exports.sync = spawnSync; + module2.exports._parse = parse; + module2.exports._enoent = enoent; + } +}); + +// ../../node_modules/.pnpm/strip-final-newline@2.0.0/node_modules/strip-final-newline/index.js +var require_strip_final_newline = __commonJS({ + "../../node_modules/.pnpm/strip-final-newline@2.0.0/node_modules/strip-final-newline/index.js"(exports2, module2) { + "use strict"; + module2.exports = (input) => { + const LF = typeof input === "string" ? "\n" : "\n".charCodeAt(); + const CR = typeof input === "string" ? "\r" : "\r".charCodeAt(); + if (input[input.length - 1] === LF) { + input = input.slice(0, input.length - 1); + } + if (input[input.length - 1] === CR) { + input = input.slice(0, input.length - 1); + } + return input; + }; + } +}); + +// ../../node_modules/.pnpm/npm-run-path@4.0.1/node_modules/npm-run-path/index.js +var require_npm_run_path = __commonJS({ + "../../node_modules/.pnpm/npm-run-path@4.0.1/node_modules/npm-run-path/index.js"(exports2, module2) { + "use strict"; + var path2 = require("path"); + var pathKey = require_path_key(); + var npmRunPath = (options) => { + options = { + cwd: process.cwd(), + path: process.env[pathKey()], + execPath: process.execPath, + ...options + }; + let previous; + let cwdPath = path2.resolve(options.cwd); + const result = []; + while (previous !== cwdPath) { + result.push(path2.join(cwdPath, "node_modules/.bin")); + previous = cwdPath; + cwdPath = path2.resolve(cwdPath, ".."); + } + const execPathDir = path2.resolve(options.cwd, options.execPath, ".."); + result.push(execPathDir); + return result.concat(options.path).join(path2.delimiter); + }; + module2.exports = npmRunPath; + module2.exports.default = npmRunPath; + module2.exports.env = (options) => { + options = { + env: process.env, + ...options + }; + const env = { ...options.env }; + const path3 = pathKey({ env }); + options.path = env[path3]; + env[path3] = module2.exports(options); + return env; + }; + } +}); + +// ../../node_modules/.pnpm/mimic-fn@2.1.0/node_modules/mimic-fn/index.js +var require_mimic_fn = __commonJS({ + "../../node_modules/.pnpm/mimic-fn@2.1.0/node_modules/mimic-fn/index.js"(exports2, module2) { + "use strict"; + var mimicFn = (to, from) => { + for (const prop of Reflect.ownKeys(from)) { + Object.defineProperty(to, prop, Object.getOwnPropertyDescriptor(from, prop)); + } + return to; + }; + module2.exports = mimicFn; + module2.exports.default = mimicFn; + } +}); + +// ../../node_modules/.pnpm/onetime@5.1.2/node_modules/onetime/index.js +var require_onetime = __commonJS({ + "../../node_modules/.pnpm/onetime@5.1.2/node_modules/onetime/index.js"(exports2, module2) { + "use strict"; + var mimicFn = require_mimic_fn(); + var calledFunctions = /* @__PURE__ */ new WeakMap(); + var onetime = (function_, options = {}) => { + if (typeof function_ !== "function") { + throw new TypeError("Expected a function"); + } + let returnValue; + let callCount = 0; + const functionName = function_.displayName || function_.name || ""; + const onetime2 = function(...arguments_) { + calledFunctions.set(onetime2, ++callCount); + if (callCount === 1) { + returnValue = function_.apply(this, arguments_); + function_ = null; + } else if (options.throw === true) { + throw new Error(`Function \`${functionName}\` can only be called once`); + } + return returnValue; + }; + mimicFn(onetime2, function_); + calledFunctions.set(onetime2, callCount); + return onetime2; + }; + module2.exports = onetime; + module2.exports.default = onetime; + module2.exports.callCount = (function_) => { + if (!calledFunctions.has(function_)) { + throw new Error(`The given function \`${function_.name}\` is not wrapped by the \`onetime\` package`); + } + return calledFunctions.get(function_); + }; + } +}); + +// ../../node_modules/.pnpm/human-signals@2.1.0/node_modules/human-signals/build/src/core.js +var require_core = __commonJS({ + "../../node_modules/.pnpm/human-signals@2.1.0/node_modules/human-signals/build/src/core.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.SIGNALS = void 0; + var SIGNALS = [ + { + name: "SIGHUP", + number: 1, + action: "terminate", + description: "Terminal closed", + standard: "posix" + }, + { + name: "SIGINT", + number: 2, + action: "terminate", + description: "User interruption with CTRL-C", + standard: "ansi" + }, + { + name: "SIGQUIT", + number: 3, + action: "core", + description: "User interruption with CTRL-\\", + standard: "posix" + }, + { + name: "SIGILL", + number: 4, + action: "core", + description: "Invalid machine instruction", + standard: "ansi" + }, + { + name: "SIGTRAP", + number: 5, + action: "core", + description: "Debugger breakpoint", + standard: "posix" + }, + { + name: "SIGABRT", + number: 6, + action: "core", + description: "Aborted", + standard: "ansi" + }, + { + name: "SIGIOT", + number: 6, + action: "core", + description: "Aborted", + standard: "bsd" + }, + { + name: "SIGBUS", + number: 7, + action: "core", + description: "Bus error due to misaligned, non-existing address or paging error", + standard: "bsd" + }, + { + name: "SIGEMT", + number: 7, + action: "terminate", + description: "Command should be emulated but is not implemented", + standard: "other" + }, + { + name: "SIGFPE", + number: 8, + action: "core", + description: "Floating point arithmetic error", + standard: "ansi" + }, + { + name: "SIGKILL", + number: 9, + action: "terminate", + description: "Forced termination", + standard: "posix", + forced: true + }, + { + name: "SIGUSR1", + number: 10, + action: "terminate", + description: "Application-specific signal", + standard: "posix" + }, + { + name: "SIGSEGV", + number: 11, + action: "core", + description: "Segmentation fault", + standard: "ansi" + }, + { + name: "SIGUSR2", + number: 12, + action: "terminate", + description: "Application-specific signal", + standard: "posix" + }, + { + name: "SIGPIPE", + number: 13, + action: "terminate", + description: "Broken pipe or socket", + standard: "posix" + }, + { + name: "SIGALRM", + number: 14, + action: "terminate", + description: "Timeout or timer", + standard: "posix" + }, + { + name: "SIGTERM", + number: 15, + action: "terminate", + description: "Termination", + standard: "ansi" + }, + { + name: "SIGSTKFLT", + number: 16, + action: "terminate", + description: "Stack is empty or overflowed", + standard: "other" + }, + { + name: "SIGCHLD", + number: 17, + action: "ignore", + description: "Child process terminated, paused or unpaused", + standard: "posix" + }, + { + name: "SIGCLD", + number: 17, + action: "ignore", + description: "Child process terminated, paused or unpaused", + standard: "other" + }, + { + name: "SIGCONT", + number: 18, + action: "unpause", + description: "Unpaused", + standard: "posix", + forced: true + }, + { + name: "SIGSTOP", + number: 19, + action: "pause", + description: "Paused", + standard: "posix", + forced: true + }, + { + name: "SIGTSTP", + number: 20, + action: "pause", + description: 'Paused using CTRL-Z or "suspend"', + standard: "posix" + }, + { + name: "SIGTTIN", + number: 21, + action: "pause", + description: "Background process cannot read terminal input", + standard: "posix" + }, + { + name: "SIGBREAK", + number: 21, + action: "terminate", + description: "User interruption with CTRL-BREAK", + standard: "other" + }, + { + name: "SIGTTOU", + number: 22, + action: "pause", + description: "Background process cannot write to terminal output", + standard: "posix" + }, + { + name: "SIGURG", + number: 23, + action: "ignore", + description: "Socket received out-of-band data", + standard: "bsd" + }, + { + name: "SIGXCPU", + number: 24, + action: "core", + description: "Process timed out", + standard: "bsd" + }, + { + name: "SIGXFSZ", + number: 25, + action: "core", + description: "File too big", + standard: "bsd" + }, + { + name: "SIGVTALRM", + number: 26, + action: "terminate", + description: "Timeout or timer", + standard: "bsd" + }, + { + name: "SIGPROF", + number: 27, + action: "terminate", + description: "Timeout or timer", + standard: "bsd" + }, + { + name: "SIGWINCH", + number: 28, + action: "ignore", + description: "Terminal window size changed", + standard: "bsd" + }, + { + name: "SIGIO", + number: 29, + action: "terminate", + description: "I/O is available", + standard: "other" + }, + { + name: "SIGPOLL", + number: 29, + action: "terminate", + description: "Watched event", + standard: "other" + }, + { + name: "SIGINFO", + number: 29, + action: "ignore", + description: "Request for process information", + standard: "other" + }, + { + name: "SIGPWR", + number: 30, + action: "terminate", + description: "Device running out of power", + standard: "systemv" + }, + { + name: "SIGSYS", + number: 31, + action: "core", + description: "Invalid system call", + standard: "other" + }, + { + name: "SIGUNUSED", + number: 31, + action: "terminate", + description: "Invalid system call", + standard: "other" + } + ]; + exports2.SIGNALS = SIGNALS; + } +}); + +// ../../node_modules/.pnpm/human-signals@2.1.0/node_modules/human-signals/build/src/realtime.js +var require_realtime = __commonJS({ + "../../node_modules/.pnpm/human-signals@2.1.0/node_modules/human-signals/build/src/realtime.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.SIGRTMAX = exports2.getRealtimeSignals = void 0; + var getRealtimeSignals = function() { + const length = SIGRTMAX - SIGRTMIN + 1; + return Array.from({ length }, getRealtimeSignal); + }; + exports2.getRealtimeSignals = getRealtimeSignals; + var getRealtimeSignal = function(value, index) { + return { + name: `SIGRT${index + 1}`, + number: SIGRTMIN + index, + action: "terminate", + description: "Application-specific signal (realtime)", + standard: "posix" + }; + }; + var SIGRTMIN = 34; + var SIGRTMAX = 64; + exports2.SIGRTMAX = SIGRTMAX; + } +}); + +// ../../node_modules/.pnpm/human-signals@2.1.0/node_modules/human-signals/build/src/signals.js +var require_signals = __commonJS({ + "../../node_modules/.pnpm/human-signals@2.1.0/node_modules/human-signals/build/src/signals.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.getSignals = void 0; + var _os = require("os"); + var _core = require_core(); + var _realtime = require_realtime(); + var getSignals = function() { + const realtimeSignals = (0, _realtime.getRealtimeSignals)(); + const signals = [..._core.SIGNALS, ...realtimeSignals].map(normalizeSignal); + return signals; + }; + exports2.getSignals = getSignals; + var normalizeSignal = function({ + name, + number: defaultNumber, + description, + action, + forced = false, + standard + }) { + const { + signals: { [name]: constantSignal } + } = _os.constants; + const supported = constantSignal !== void 0; + const number = supported ? constantSignal : defaultNumber; + return { name, number, description, supported, action, forced, standard }; + }; + } +}); + +// ../../node_modules/.pnpm/human-signals@2.1.0/node_modules/human-signals/build/src/main.js +var require_main = __commonJS({ + "../../node_modules/.pnpm/human-signals@2.1.0/node_modules/human-signals/build/src/main.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.signalsByNumber = exports2.signalsByName = void 0; + var _os = require("os"); + var _signals = require_signals(); + var _realtime = require_realtime(); + var getSignalsByName = function() { + const signals = (0, _signals.getSignals)(); + return signals.reduce(getSignalByName, {}); + }; + var getSignalByName = function(signalByNameMemo, { name, number, description, supported, action, forced, standard }) { + return { + ...signalByNameMemo, + [name]: { name, number, description, supported, action, forced, standard } + }; + }; + var signalsByName = getSignalsByName(); + exports2.signalsByName = signalsByName; + var getSignalsByNumber = function() { + const signals = (0, _signals.getSignals)(); + const length = _realtime.SIGRTMAX + 1; + const signalsA = Array.from({ length }, (value, number) => getSignalByNumber(number, signals)); + return Object.assign({}, ...signalsA); + }; + var getSignalByNumber = function(number, signals) { + const signal = findSignalByNumber(number, signals); + if (signal === void 0) { + return {}; + } + const { name, description, supported, action, forced, standard } = signal; + return { + [number]: { + name, + number, + description, + supported, + action, + forced, + standard + } + }; + }; + var findSignalByNumber = function(number, signals) { + const signal = signals.find(({ name }) => _os.constants.signals[name] === number); + if (signal !== void 0) { + return signal; + } + return signals.find((signalA) => signalA.number === number); + }; + var signalsByNumber = getSignalsByNumber(); + exports2.signalsByNumber = signalsByNumber; + } +}); + +// ../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/lib/error.js +var require_error = __commonJS({ + "../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/lib/error.js"(exports2, module2) { + "use strict"; + var { signalsByName } = require_main(); + var getErrorPrefix = ({ timedOut, timeout, errorCode, signal, signalDescription, exitCode, isCanceled }) => { + if (timedOut) { + return `timed out after ${timeout} milliseconds`; + } + if (isCanceled) { + return "was canceled"; + } + if (errorCode !== void 0) { + return `failed with ${errorCode}`; + } + if (signal !== void 0) { + return `was killed with ${signal} (${signalDescription})`; + } + if (exitCode !== void 0) { + return `failed with exit code ${exitCode}`; + } + return "failed"; + }; + var makeError = ({ + stdout, + stderr, + all, + error, + signal, + exitCode, + command, + escapedCommand, + timedOut, + isCanceled, + killed, + parsed: { options: { timeout } } + }) => { + exitCode = exitCode === null ? void 0 : exitCode; + signal = signal === null ? void 0 : signal; + const signalDescription = signal === void 0 ? void 0 : signalsByName[signal].description; + const errorCode = error && error.code; + const prefix = getErrorPrefix({ timedOut, timeout, errorCode, signal, signalDescription, exitCode, isCanceled }); + const execaMessage = `Command ${prefix}: ${command}`; + const isError = Object.prototype.toString.call(error) === "[object Error]"; + const shortMessage = isError ? `${execaMessage} +${error.message}` : execaMessage; + const message = [shortMessage, stderr, stdout].filter(Boolean).join("\n"); + if (isError) { + error.originalMessage = error.message; + error.message = message; + } else { + error = new Error(message); + } + error.shortMessage = shortMessage; + error.command = command; + error.escapedCommand = escapedCommand; + error.exitCode = exitCode; + error.signal = signal; + error.signalDescription = signalDescription; + error.stdout = stdout; + error.stderr = stderr; + if (all !== void 0) { + error.all = all; + } + if ("bufferedData" in error) { + delete error.bufferedData; + } + error.failed = true; + error.timedOut = Boolean(timedOut); + error.isCanceled = isCanceled; + error.killed = killed && !timedOut; + return error; + }; + module2.exports = makeError; + } +}); + +// ../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/lib/stdio.js +var require_stdio = __commonJS({ + "../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/lib/stdio.js"(exports2, module2) { + "use strict"; + var aliases = ["stdin", "stdout", "stderr"]; + var hasAlias = (options) => aliases.some((alias) => options[alias] !== void 0); + var normalizeStdio = (options) => { + if (!options) { + return; + } + const { stdio } = options; + if (stdio === void 0) { + return aliases.map((alias) => options[alias]); + } + if (hasAlias(options)) { + throw new Error(`It's not possible to provide \`stdio\` in combination with one of ${aliases.map((alias) => `\`${alias}\``).join(", ")}`); + } + if (typeof stdio === "string") { + return stdio; + } + if (!Array.isArray(stdio)) { + throw new TypeError(`Expected \`stdio\` to be of type \`string\` or \`Array\`, got \`${typeof stdio}\``); + } + const length = Math.max(stdio.length, aliases.length); + return Array.from({ length }, (value, index) => stdio[index]); + }; + module2.exports = normalizeStdio; + module2.exports.node = (options) => { + const stdio = normalizeStdio(options); + if (stdio === "ipc") { + return "ipc"; + } + if (stdio === void 0 || typeof stdio === "string") { + return [stdio, stdio, stdio, "ipc"]; + } + if (stdio.includes("ipc")) { + return stdio; + } + return [...stdio, "ipc"]; + }; + } +}); + +// ../../node_modules/.pnpm/signal-exit@3.0.7/node_modules/signal-exit/signals.js +var require_signals2 = __commonJS({ + "../../node_modules/.pnpm/signal-exit@3.0.7/node_modules/signal-exit/signals.js"(exports2, module2) { + "use strict"; + module2.exports = [ + "SIGABRT", + "SIGALRM", + "SIGHUP", + "SIGINT", + "SIGTERM" + ]; + if (process.platform !== "win32") { + module2.exports.push( + "SIGVTALRM", + "SIGXCPU", + "SIGXFSZ", + "SIGUSR2", + "SIGTRAP", + "SIGSYS", + "SIGQUIT", + "SIGIOT" + // should detect profiler and enable/disable accordingly. + // see #21 + // 'SIGPROF' + ); + } + if (process.platform === "linux") { + module2.exports.push( + "SIGIO", + "SIGPOLL", + "SIGPWR", + "SIGSTKFLT", + "SIGUNUSED" + ); + } + } +}); + +// ../../node_modules/.pnpm/signal-exit@3.0.7/node_modules/signal-exit/index.js +var require_signal_exit = __commonJS({ + "../../node_modules/.pnpm/signal-exit@3.0.7/node_modules/signal-exit/index.js"(exports2, module2) { + "use strict"; + var process2 = global.process; + var processOk = function(process3) { + return process3 && typeof process3 === "object" && typeof process3.removeListener === "function" && typeof process3.emit === "function" && typeof process3.reallyExit === "function" && typeof process3.listeners === "function" && typeof process3.kill === "function" && typeof process3.pid === "number" && typeof process3.on === "function"; + }; + if (!processOk(process2)) { + module2.exports = function() { + return function() { + }; + }; + } else { + assert = require("assert"); + signals = require_signals2(); + isWin = /^win/i.test(process2.platform); + EE = require("events"); + if (typeof EE !== "function") { + EE = EE.EventEmitter; + } + if (process2.__signal_exit_emitter__) { + emitter = process2.__signal_exit_emitter__; + } else { + emitter = process2.__signal_exit_emitter__ = new EE(); + emitter.count = 0; + emitter.emitted = {}; + } + if (!emitter.infinite) { + emitter.setMaxListeners(Infinity); + emitter.infinite = true; + } + module2.exports = function(cb, opts) { + if (!processOk(global.process)) { + return function() { + }; + } + assert.equal(typeof cb, "function", "a callback must be provided for exit handler"); + if (loaded === false) { + load(); + } + var ev = "exit"; + if (opts && opts.alwaysLast) { + ev = "afterexit"; + } + var remove = function() { + emitter.removeListener(ev, cb); + if (emitter.listeners("exit").length === 0 && emitter.listeners("afterexit").length === 0) { + unload(); + } + }; + emitter.on(ev, cb); + return remove; + }; + unload = function unload2() { + if (!loaded || !processOk(global.process)) { + return; + } + loaded = false; + signals.forEach(function(sig) { + try { + process2.removeListener(sig, sigListeners[sig]); + } catch (er) { + } + }); + process2.emit = originalProcessEmit; + process2.reallyExit = originalProcessReallyExit; + emitter.count -= 1; + }; + module2.exports.unload = unload; + emit = function emit2(event, code, signal) { + if (emitter.emitted[event]) { + return; + } + emitter.emitted[event] = true; + emitter.emit(event, code, signal); + }; + sigListeners = {}; + signals.forEach(function(sig) { + sigListeners[sig] = function listener() { + if (!processOk(global.process)) { + return; + } + var listeners = process2.listeners(sig); + if (listeners.length === emitter.count) { + unload(); + emit("exit", null, sig); + emit("afterexit", null, sig); + if (isWin && sig === "SIGHUP") { + sig = "SIGINT"; + } + process2.kill(process2.pid, sig); + } + }; + }); + module2.exports.signals = function() { + return signals; + }; + loaded = false; + load = function load2() { + if (loaded || !processOk(global.process)) { + return; + } + loaded = true; + emitter.count += 1; + signals = signals.filter(function(sig) { + try { + process2.on(sig, sigListeners[sig]); + return true; + } catch (er) { + return false; + } + }); + process2.emit = processEmit; + process2.reallyExit = processReallyExit; + }; + module2.exports.load = load; + originalProcessReallyExit = process2.reallyExit; + processReallyExit = function processReallyExit2(code) { + if (!processOk(global.process)) { + return; + } + process2.exitCode = code || /* istanbul ignore next */ + 0; + emit("exit", process2.exitCode, null); + emit("afterexit", process2.exitCode, null); + originalProcessReallyExit.call(process2, process2.exitCode); + }; + originalProcessEmit = process2.emit; + processEmit = function processEmit2(ev, arg) { + if (ev === "exit" && processOk(global.process)) { + if (arg !== void 0) { + process2.exitCode = arg; + } + var ret = originalProcessEmit.apply(this, arguments); + emit("exit", process2.exitCode, null); + emit("afterexit", process2.exitCode, null); + return ret; + } else { + return originalProcessEmit.apply(this, arguments); + } + }; + } + var assert; + var signals; + var isWin; + var EE; + var emitter; + var unload; + var emit; + var sigListeners; + var loaded; + var load; + var originalProcessReallyExit; + var processReallyExit; + var originalProcessEmit; + var processEmit; + } +}); + +// ../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/lib/kill.js +var require_kill = __commonJS({ + "../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/lib/kill.js"(exports2, module2) { + "use strict"; + var os = require("os"); + var onExit = require_signal_exit(); + var DEFAULT_FORCE_KILL_TIMEOUT = 1e3 * 5; + var spawnedKill = (kill, signal = "SIGTERM", options = {}) => { + const killResult = kill(signal); + setKillTimeout(kill, signal, options, killResult); + return killResult; + }; + var setKillTimeout = (kill, signal, options, killResult) => { + if (!shouldForceKill(signal, options, killResult)) { + return; + } + const timeout = getForceKillAfterTimeout(options); + const t = setTimeout(() => { + kill("SIGKILL"); + }, timeout); + if (t.unref) { + t.unref(); + } + }; + var shouldForceKill = (signal, { forceKillAfterTimeout }, killResult) => { + return isSigterm(signal) && forceKillAfterTimeout !== false && killResult; + }; + var isSigterm = (signal) => { + return signal === os.constants.signals.SIGTERM || typeof signal === "string" && signal.toUpperCase() === "SIGTERM"; + }; + var getForceKillAfterTimeout = ({ forceKillAfterTimeout = true }) => { + if (forceKillAfterTimeout === true) { + return DEFAULT_FORCE_KILL_TIMEOUT; + } + if (!Number.isFinite(forceKillAfterTimeout) || forceKillAfterTimeout < 0) { + throw new TypeError(`Expected the \`forceKillAfterTimeout\` option to be a non-negative integer, got \`${forceKillAfterTimeout}\` (${typeof forceKillAfterTimeout})`); + } + return forceKillAfterTimeout; + }; + var spawnedCancel = (spawned, context) => { + const killResult = spawned.kill(); + if (killResult) { + context.isCanceled = true; + } + }; + var timeoutKill = (spawned, signal, reject) => { + spawned.kill(signal); + reject(Object.assign(new Error("Timed out"), { timedOut: true, signal })); + }; + var setupTimeout = (spawned, { timeout, killSignal = "SIGTERM" }, spawnedPromise) => { + if (timeout === 0 || timeout === void 0) { + return spawnedPromise; + } + let timeoutId; + const timeoutPromise = new Promise((resolve, reject) => { + timeoutId = setTimeout(() => { + timeoutKill(spawned, killSignal, reject); + }, timeout); + }); + const safeSpawnedPromise = spawnedPromise.finally(() => { + clearTimeout(timeoutId); + }); + return Promise.race([timeoutPromise, safeSpawnedPromise]); + }; + var validateTimeout = ({ timeout }) => { + if (timeout !== void 0 && (!Number.isFinite(timeout) || timeout < 0)) { + throw new TypeError(`Expected the \`timeout\` option to be a non-negative integer, got \`${timeout}\` (${typeof timeout})`); + } + }; + var setExitHandler = async (spawned, { cleanup, detached }, timedPromise) => { + if (!cleanup || detached) { + return timedPromise; + } + const removeExitHandler = onExit(() => { + spawned.kill(); + }); + return timedPromise.finally(() => { + removeExitHandler(); + }); + }; + module2.exports = { + spawnedKill, + spawnedCancel, + setupTimeout, + validateTimeout, + setExitHandler + }; + } +}); + +// ../../node_modules/.pnpm/is-stream@2.0.1/node_modules/is-stream/index.js +var require_is_stream = __commonJS({ + "../../node_modules/.pnpm/is-stream@2.0.1/node_modules/is-stream/index.js"(exports2, module2) { + "use strict"; + var isStream = (stream) => stream !== null && typeof stream === "object" && typeof stream.pipe === "function"; + isStream.writable = (stream) => isStream(stream) && stream.writable !== false && typeof stream._write === "function" && typeof stream._writableState === "object"; + isStream.readable = (stream) => isStream(stream) && stream.readable !== false && typeof stream._read === "function" && typeof stream._readableState === "object"; + isStream.duplex = (stream) => isStream.writable(stream) && isStream.readable(stream); + isStream.transform = (stream) => isStream.duplex(stream) && typeof stream._transform === "function"; + module2.exports = isStream; + } +}); + +// ../../node_modules/.pnpm/get-stream@6.0.1/node_modules/get-stream/buffer-stream.js +var require_buffer_stream = __commonJS({ + "../../node_modules/.pnpm/get-stream@6.0.1/node_modules/get-stream/buffer-stream.js"(exports2, module2) { + "use strict"; + var { PassThrough: PassThroughStream } = require("stream"); + module2.exports = (options) => { + options = { ...options }; + const { array } = options; + let { encoding } = options; + const isBuffer = encoding === "buffer"; + let objectMode = false; + if (array) { + objectMode = !(encoding || isBuffer); + } else { + encoding = encoding || "utf8"; + } + if (isBuffer) { + encoding = null; + } + const stream = new PassThroughStream({ objectMode }); + if (encoding) { + stream.setEncoding(encoding); + } + let length = 0; + const chunks = []; + stream.on("data", (chunk) => { + chunks.push(chunk); + if (objectMode) { + length = chunks.length; + } else { + length += chunk.length; + } + }); + stream.getBufferedValue = () => { + if (array) { + return chunks; + } + return isBuffer ? Buffer.concat(chunks, length) : chunks.join(""); + }; + stream.getBufferedLength = () => length; + return stream; + }; + } +}); + +// ../../node_modules/.pnpm/get-stream@6.0.1/node_modules/get-stream/index.js +var require_get_stream = __commonJS({ + "../../node_modules/.pnpm/get-stream@6.0.1/node_modules/get-stream/index.js"(exports2, module2) { + "use strict"; + var { constants: BufferConstants } = require("buffer"); + var stream = require("stream"); + var { promisify } = require("util"); + var bufferStream = require_buffer_stream(); + var streamPipelinePromisified = promisify(stream.pipeline); + var MaxBufferError = class extends Error { + constructor() { + super("maxBuffer exceeded"); + this.name = "MaxBufferError"; + } + }; + async function getStream(inputStream, options) { + if (!inputStream) { + throw new Error("Expected a stream"); + } + options = { + maxBuffer: Infinity, + ...options + }; + const { maxBuffer } = options; + const stream2 = bufferStream(options); + await new Promise((resolve, reject) => { + const rejectPromise = (error) => { + if (error && stream2.getBufferedLength() <= BufferConstants.MAX_LENGTH) { + error.bufferedData = stream2.getBufferedValue(); + } + reject(error); + }; + (async () => { + try { + await streamPipelinePromisified(inputStream, stream2); + resolve(); + } catch (error) { + rejectPromise(error); + } + })(); + stream2.on("data", () => { + if (stream2.getBufferedLength() > maxBuffer) { + rejectPromise(new MaxBufferError()); + } + }); + }); + return stream2.getBufferedValue(); + } + module2.exports = getStream; + module2.exports.buffer = (stream2, options) => getStream(stream2, { ...options, encoding: "buffer" }); + module2.exports.array = (stream2, options) => getStream(stream2, { ...options, array: true }); + module2.exports.MaxBufferError = MaxBufferError; + } +}); + +// ../../node_modules/.pnpm/merge-stream@2.0.0/node_modules/merge-stream/index.js +var require_merge_stream = __commonJS({ + "../../node_modules/.pnpm/merge-stream@2.0.0/node_modules/merge-stream/index.js"(exports2, module2) { + "use strict"; + var { PassThrough } = require("stream"); + module2.exports = function() { + var sources = []; + var output = new PassThrough({ objectMode: true }); + output.setMaxListeners(0); + output.add = add; + output.isEmpty = isEmpty; + output.on("unpipe", remove); + Array.prototype.slice.call(arguments).forEach(add); + return output; + function add(source) { + if (Array.isArray(source)) { + source.forEach(add); + return this; + } + sources.push(source); + source.once("end", remove.bind(null, source)); + source.once("error", output.emit.bind(output, "error")); + source.pipe(output, { end: false }); + return this; + } + function isEmpty() { + return sources.length == 0; + } + function remove(source) { + sources = sources.filter(function(it) { + return it !== source; + }); + if (!sources.length && output.readable) { + output.end(); + } + } + }; + } +}); + +// ../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/lib/stream.js +var require_stream = __commonJS({ + "../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/lib/stream.js"(exports2, module2) { + "use strict"; + var isStream = require_is_stream(); + var getStream = require_get_stream(); + var mergeStream = require_merge_stream(); + var handleInput = (spawned, input) => { + if (input === void 0 || spawned.stdin === void 0) { + return; + } + if (isStream(input)) { + input.pipe(spawned.stdin); + } else { + spawned.stdin.end(input); + } + }; + var makeAllStream = (spawned, { all }) => { + if (!all || !spawned.stdout && !spawned.stderr) { + return; + } + const mixed = mergeStream(); + if (spawned.stdout) { + mixed.add(spawned.stdout); + } + if (spawned.stderr) { + mixed.add(spawned.stderr); + } + return mixed; + }; + var getBufferedData = async (stream, streamPromise) => { + if (!stream) { + return; + } + stream.destroy(); + try { + return await streamPromise; + } catch (error) { + return error.bufferedData; + } + }; + var getStreamPromise = (stream, { encoding, buffer, maxBuffer }) => { + if (!stream || !buffer) { + return; + } + if (encoding) { + return getStream(stream, { encoding, maxBuffer }); + } + return getStream.buffer(stream, { maxBuffer }); + }; + var getSpawnedResult = async ({ stdout, stderr, all }, { encoding, buffer, maxBuffer }, processDone) => { + const stdoutPromise = getStreamPromise(stdout, { encoding, buffer, maxBuffer }); + const stderrPromise = getStreamPromise(stderr, { encoding, buffer, maxBuffer }); + const allPromise = getStreamPromise(all, { encoding, buffer, maxBuffer: maxBuffer * 2 }); + try { + return await Promise.all([processDone, stdoutPromise, stderrPromise, allPromise]); + } catch (error) { + return Promise.all([ + { error, signal: error.signal, timedOut: error.timedOut }, + getBufferedData(stdout, stdoutPromise), + getBufferedData(stderr, stderrPromise), + getBufferedData(all, allPromise) + ]); + } + }; + var validateInputSync = ({ input }) => { + if (isStream(input)) { + throw new TypeError("The `input` option cannot be a stream in sync mode"); + } + }; + module2.exports = { + handleInput, + makeAllStream, + getSpawnedResult, + validateInputSync + }; + } +}); + +// ../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/lib/promise.js +var require_promise = __commonJS({ + "../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/lib/promise.js"(exports2, module2) { + "use strict"; + var nativePromisePrototype = (async () => { + })().constructor.prototype; + var descriptors = ["then", "catch", "finally"].map((property) => [ + property, + Reflect.getOwnPropertyDescriptor(nativePromisePrototype, property) + ]); + var mergePromise = (spawned, promise) => { + for (const [property, descriptor] of descriptors) { + const value = typeof promise === "function" ? (...args) => Reflect.apply(descriptor.value, promise(), args) : descriptor.value.bind(promise); + Reflect.defineProperty(spawned, property, { ...descriptor, value }); + } + return spawned; + }; + var getSpawnedPromise = (spawned) => { + return new Promise((resolve, reject) => { + spawned.on("exit", (exitCode, signal) => { + resolve({ exitCode, signal }); + }); + spawned.on("error", (error) => { + reject(error); + }); + if (spawned.stdin) { + spawned.stdin.on("error", (error) => { + reject(error); + }); + } + }); + }; + module2.exports = { + mergePromise, + getSpawnedPromise + }; + } +}); + +// ../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/lib/command.js +var require_command = __commonJS({ + "../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/lib/command.js"(exports2, module2) { + "use strict"; + var normalizeArgs = (file, args = []) => { + if (!Array.isArray(args)) { + return [file]; + } + return [file, ...args]; + }; + var NO_ESCAPE_REGEXP = /^[\w.-]+$/; + var DOUBLE_QUOTES_REGEXP = /"/g; + var escapeArg = (arg) => { + if (typeof arg !== "string" || NO_ESCAPE_REGEXP.test(arg)) { + return arg; + } + return `"${arg.replace(DOUBLE_QUOTES_REGEXP, '\\"')}"`; + }; + var joinCommand = (file, args) => { + return normalizeArgs(file, args).join(" "); + }; + var getEscapedCommand = (file, args) => { + return normalizeArgs(file, args).map((arg) => escapeArg(arg)).join(" "); + }; + var SPACES_REGEXP = / +/g; + var parseCommand = (command) => { + const tokens = []; + for (const token of command.trim().split(SPACES_REGEXP)) { + const previousToken = tokens[tokens.length - 1]; + if (previousToken && previousToken.endsWith("\\")) { + tokens[tokens.length - 1] = `${previousToken.slice(0, -1)} ${token}`; + } else { + tokens.push(token); + } + } + return tokens; + }; + module2.exports = { + joinCommand, + getEscapedCommand, + parseCommand + }; + } +}); + +// ../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/index.js +var require_execa = __commonJS({ + "../../node_modules/.pnpm/execa@5.1.1/node_modules/execa/index.js"(exports2, module2) { + "use strict"; + var path2 = require("path"); + var childProcess = require("child_process"); + var crossSpawn = require_cross_spawn(); + var stripFinalNewline = require_strip_final_newline(); + var npmRunPath = require_npm_run_path(); + var onetime = require_onetime(); + var makeError = require_error(); + var normalizeStdio = require_stdio(); + var { spawnedKill, spawnedCancel, setupTimeout, validateTimeout, setExitHandler } = require_kill(); + var { handleInput, getSpawnedResult, makeAllStream, validateInputSync } = require_stream(); + var { mergePromise, getSpawnedPromise } = require_promise(); + var { joinCommand, parseCommand, getEscapedCommand } = require_command(); + var DEFAULT_MAX_BUFFER = 1e3 * 1e3 * 100; + var getEnv = ({ env: envOption, extendEnv, preferLocal, localDir, execPath }) => { + const env = extendEnv ? { ...process.env, ...envOption } : envOption; + if (preferLocal) { + return npmRunPath.env({ env, cwd: localDir, execPath }); + } + return env; + }; + var handleArguments = (file, args, options = {}) => { + const parsed = crossSpawn._parse(file, args, options); + file = parsed.command; + args = parsed.args; + options = parsed.options; + options = { + maxBuffer: DEFAULT_MAX_BUFFER, + buffer: true, + stripFinalNewline: true, + extendEnv: true, + preferLocal: false, + localDir: options.cwd || process.cwd(), + execPath: process.execPath, + encoding: "utf8", + reject: true, + cleanup: true, + all: false, + windowsHide: true, + ...options + }; + options.env = getEnv(options); + options.stdio = normalizeStdio(options); + if (process.platform === "win32" && path2.basename(file, ".exe") === "cmd") { + args.unshift("/q"); + } + return { file, args, options, parsed }; + }; + var handleOutput = (options, value, error) => { + if (typeof value !== "string" && !Buffer.isBuffer(value)) { + return error === void 0 ? void 0 : ""; + } + if (options.stripFinalNewline) { + return stripFinalNewline(value); + } + return value; + }; + var execa2 = (file, args, options) => { + const parsed = handleArguments(file, args, options); + const command = joinCommand(file, args); + const escapedCommand = getEscapedCommand(file, args); + validateTimeout(parsed.options); + let spawned; + try { + spawned = childProcess.spawn(parsed.file, parsed.args, parsed.options); + } catch (error) { + const dummySpawned = new childProcess.ChildProcess(); + const errorPromise = Promise.reject(makeError({ + error, + stdout: "", + stderr: "", + all: "", + command, + escapedCommand, + parsed, + timedOut: false, + isCanceled: false, + killed: false + })); + return mergePromise(dummySpawned, errorPromise); + } + const spawnedPromise = getSpawnedPromise(spawned); + const timedPromise = setupTimeout(spawned, parsed.options, spawnedPromise); + const processDone = setExitHandler(spawned, parsed.options, timedPromise); + const context = { isCanceled: false }; + spawned.kill = spawnedKill.bind(null, spawned.kill.bind(spawned)); + spawned.cancel = spawnedCancel.bind(null, spawned, context); + const handlePromise = async () => { + const [{ error, exitCode, signal, timedOut }, stdoutResult, stderrResult, allResult] = await getSpawnedResult(spawned, parsed.options, processDone); + const stdout = handleOutput(parsed.options, stdoutResult); + const stderr = handleOutput(parsed.options, stderrResult); + const all = handleOutput(parsed.options, allResult); + if (error || exitCode !== 0 || signal !== null) { + const returnedError = makeError({ + error, + exitCode, + signal, + stdout, + stderr, + all, + command, + escapedCommand, + parsed, + timedOut, + isCanceled: context.isCanceled, + killed: spawned.killed + }); + if (!parsed.options.reject) { + return returnedError; + } + throw returnedError; + } + return { + command, + escapedCommand, + exitCode: 0, + stdout, + stderr, + all, + failed: false, + timedOut: false, + isCanceled: false, + killed: false + }; + }; + const handlePromiseOnce = onetime(handlePromise); + handleInput(spawned, parsed.options.input); + spawned.all = makeAllStream(spawned, parsed.options); + return mergePromise(spawned, handlePromiseOnce); + }; + module2.exports = execa2; + module2.exports.sync = (file, args, options) => { + const parsed = handleArguments(file, args, options); + const command = joinCommand(file, args); + const escapedCommand = getEscapedCommand(file, args); + validateInputSync(parsed.options); + let result; + try { + result = childProcess.spawnSync(parsed.file, parsed.args, parsed.options); + } catch (error) { + throw makeError({ + error, + stdout: "", + stderr: "", + all: "", + command, + escapedCommand, + parsed, + timedOut: false, + isCanceled: false, + killed: false + }); + } + const stdout = handleOutput(parsed.options, result.stdout, result.error); + const stderr = handleOutput(parsed.options, result.stderr, result.error); + if (result.error || result.status !== 0 || result.signal !== null) { + const error = makeError({ + stdout, + stderr, + error: result.error, + signal: result.signal, + exitCode: result.status, + command, + escapedCommand, + parsed, + timedOut: result.error && result.error.code === "ETIMEDOUT", + isCanceled: false, + killed: result.signal !== null + }); + if (!parsed.options.reject) { + return error; + } + throw error; + } + return { + command, + escapedCommand, + exitCode: 0, + stdout, + stderr, + failed: false, + timedOut: false, + isCanceled: false, + killed: false + }; + }; + module2.exports.command = (command, options) => { + const [file, ...args] = parseCommand(command); + return execa2(file, args, options); + }; + module2.exports.commandSync = (command, options) => { + const [file, ...args] = parseCommand(command); + return execa2.sync(file, args, options); + }; + module2.exports.node = (scriptPath, args, options = {}) => { + if (args && !Array.isArray(args) && typeof args === "object") { + options = args; + args = []; + } + const stdio = normalizeStdio.node(options); + const defaultExecArgv = process.execArgv.filter((arg) => !arg.startsWith("--inspect")); + const { + nodePath = process.execPath, + nodeOptions = defaultExecArgv + } = options; + return execa2( + nodePath, + [ + ...nodeOptions, + scriptPath, + ...Array.isArray(args) ? args : [] + ], + { + ...options, + stdin: void 0, + stdout: void 0, + stderr: void 0, + stdio, + shell: false + } + ); + }; + } +}); + +// src/scripts/localinstall.ts +var import_fetch_engine = require("@prisma/fetch-engine"); +var import_package = require("@prisma/fetch-engine/package.json"); +var import_get_platform = require("@prisma/get-platform"); +var import_execa = __toESM(require_execa()); +var import_fs = __toESM(require("fs")); +var import_path = __toESM(require("path")); +var baseDir = import_path.default.join(__dirname, "..", ".."); +async function main() { + const binaryTarget = await (0, import_get_platform.getBinaryTargetForCurrentPlatform)(); + const cacheDir = await (0, import_fetch_engine.getCacheDir)("master", "_local_", binaryTarget); + const branch = import_package.enginesOverride?.["branch"]; + let folder = import_package.enginesOverride?.["folder"]; + const engineCachePaths = { + [import_fetch_engine.BinaryType.QueryEngineBinary]: import_path.default.join(cacheDir, import_fetch_engine.BinaryType.QueryEngineBinary), + [import_fetch_engine.BinaryType.QueryEngineLibrary]: import_path.default.join(cacheDir, import_fetch_engine.BinaryType.QueryEngineLibrary), + [import_fetch_engine.BinaryType.SchemaEngineBinary]: import_path.default.join(cacheDir, import_fetch_engine.BinaryType.SchemaEngineBinary) + }; + if (branch !== void 0) { + const enginesRepoUri = "git@github.com:prisma/prisma-engines.git"; + const enginesRepoDir = import_path.default.join(baseDir, "dist", "prisma-engines"); + const currentBranch = await (0, import_execa.default)("git", ["branch", "--show-current"], { + cwd: enginesRepoDir + }).catch(() => ({ failed: true, stdout: "" })); + if (currentBranch.failed === true || currentBranch.stdout !== branch) { + await import_fs.default.promises.rm(enginesRepoDir, { recursive: true, force: true }); + await (0, import_execa.default)("git", ["clone", enginesRepoUri, "--depth", "1", "--branch", branch], { + cwd: import_path.default.join(baseDir, "dist"), + stdio: "inherit" + }); + } + await (0, import_execa.default)("git", ["pull", "origin", branch], { + cwd: enginesRepoDir, + stdio: "inherit" + }); + await (0, import_execa.default)("cargo", ["build", "--release"], { + cwd: enginesRepoDir, + stdio: "inherit" + }); + folder = import_path.default.join(enginesRepoDir, "target", "release"); + } + if (folder !== void 0) { + folder = import_path.default.isAbsolute(folder) ? folder : import_path.default.join(baseDir, folder); + const libExt = binaryTarget.includes("windows") ? ".dll" : binaryTarget.includes("darwin") ? ".dylib" : ".so"; + const binExt = binaryTarget.includes("windows") ? ".exe" : ""; + const engineOutputPaths = { + [import_fetch_engine.BinaryType.QueryEngineLibrary]: import_path.default.join(folder, "libquery_engine".concat(libExt)), + [import_fetch_engine.BinaryType.QueryEngineBinary]: import_path.default.join(folder, import_fetch_engine.BinaryType.QueryEngineBinary.concat(binExt)), + [import_fetch_engine.BinaryType.SchemaEngineBinary]: import_path.default.join(folder, import_fetch_engine.BinaryType.SchemaEngineBinary.concat(binExt)) + }; + for (const [binaryType, outputPath] of Object.entries(engineOutputPaths)) { + await import_fs.default.promises.copyFile(outputPath, engineCachePaths[binaryType]); + } + } +} +main().catch((e) => { + console.log(e.message); + process.exit(1); +}); diff --git a/backend/node_modules/@prisma/engines/dist/scripts/postinstall.d.ts b/backend/node_modules/@prisma/engines/dist/scripts/postinstall.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb0ff5c3b541f646105198ee23ac0fc3d805023e --- /dev/null +++ b/backend/node_modules/@prisma/engines/dist/scripts/postinstall.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/backend/node_modules/@prisma/engines/dist/scripts/postinstall.js b/backend/node_modules/@prisma/engines/dist/scripts/postinstall.js new file mode 100644 index 0000000000000000000000000000000000000000..7f14ba80116eb6001fc97bd6ac0cd7adc1f1f408 --- /dev/null +++ b/backend/node_modules/@prisma/engines/dist/scripts/postinstall.js @@ -0,0 +1,122 @@ +"use strict"; +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); + +// src/scripts/postinstall.ts +var import_debug2 = __toESM(require("@prisma/debug")); +var import_engines_version3 = require("@prisma/engines-version"); +var import_fetch_engine2 = require("@prisma/fetch-engine"); +var import_fs = __toESM(require("fs")); +var import_path2 = __toESM(require("path")); + +// src/index.ts +var import_debug = require("@prisma/debug"); +var import_engines_version = require("@prisma/engines-version"); +var import_fetch_engine = require("@prisma/fetch-engine"); +var import_path = __toESM(require("path")); +var import_engines_version2 = require("@prisma/engines-version"); +var debug = (0, import_debug.Debug)("prisma:engines"); +var DEFAULT_CLI_QUERY_ENGINE_BINARY_TYPE = import_fetch_engine.BinaryType.QueryEngineLibrary; +function getCliQueryEngineBinaryType(clientEngineType = process.env.PRISMA_CLI_QUERY_ENGINE_TYPE) { + if (clientEngineType === "binary") { + return import_fetch_engine.BinaryType.QueryEngineBinary; + } + return DEFAULT_CLI_QUERY_ENGINE_BINARY_TYPE; +} +import_path.default.join(__dirname, "../query-engine-darwin"); +import_path.default.join(__dirname, "../query-engine-darwin-arm64"); +import_path.default.join(__dirname, "../query-engine-debian-openssl-1.0.x"); +import_path.default.join(__dirname, "../query-engine-debian-openssl-1.1.x"); +import_path.default.join(__dirname, "../query-engine-debian-openssl-3.0.x"); +import_path.default.join(__dirname, "../query-engine-linux-static-x64"); +import_path.default.join(__dirname, "../query-engine-linux-static-arm64"); +import_path.default.join(__dirname, "../query-engine-rhel-openssl-1.0.x"); +import_path.default.join(__dirname, "../query-engine-rhel-openssl-1.1.x"); +import_path.default.join(__dirname, "../query-engine-rhel-openssl-3.0.x"); +import_path.default.join(__dirname, "../libquery_engine-darwin.dylib.node"); +import_path.default.join(__dirname, "../libquery_engine-darwin-arm64.dylib.node"); +import_path.default.join(__dirname, "../libquery_engine-debian-openssl-1.0.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-debian-openssl-1.1.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-debian-openssl-3.0.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-linux-arm64-openssl-1.0.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-linux-arm64-openssl-1.1.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-linux-arm64-openssl-3.0.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-linux-musl.so.node"); +import_path.default.join(__dirname, "../libquery_engine-linux-musl-openssl-3.0.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-rhel-openssl-1.0.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-rhel-openssl-1.1.x.so.node"); +import_path.default.join(__dirname, "../libquery_engine-rhel-openssl-3.0.x.so.node"); +import_path.default.join(__dirname, "../query_engine-windows.dll.node"); + +// src/scripts/postinstall.ts +var debug2 = (0, import_debug2.default)("prisma:download"); +var baseDir = import_path2.default.join(__dirname, "../../"); +var lockFile = import_path2.default.join(baseDir, "download-lock"); +var createdLockFile = false; +async function main() { + if (import_fs.default.existsSync(lockFile) && parseInt(import_fs.default.readFileSync(lockFile, "utf-8"), 10) > Date.now() - 2e4) { + debug2(`Lock file already exists, so we're skipping the download of the prisma binaries`); + } else { + createLockFile(); + let binaryTargets; + if (process.env.PRISMA_CLI_BINARY_TARGETS) { + binaryTargets = process.env.PRISMA_CLI_BINARY_TARGETS.split(","); + } + const cliQueryEngineBinaryType = getCliQueryEngineBinaryType(); + const binaries = { + [cliQueryEngineBinaryType]: baseDir, + [import_fetch_engine2.BinaryType.SchemaEngineBinary]: baseDir + }; + await (0, import_fetch_engine2.download)({ + binaries, + version: import_engines_version3.enginesVersion, + showProgress: true, + failSilent: true, + binaryTargets + }).catch((e) => debug2(e)); + cleanupLockFile(); + } +} +function createLockFile() { + createdLockFile = true; + import_fs.default.writeFileSync(lockFile, Date.now().toString()); +} +function cleanupLockFile() { + if (createdLockFile) { + try { + if (import_fs.default.existsSync(lockFile)) { + import_fs.default.unlinkSync(lockFile); + } + } catch (e) { + debug2(e); + } + } +} +main().catch((e) => debug2(e)); +process.on("beforeExit", () => { + cleanupLockFile(); +}); +process.once("SIGINT", () => { + cleanupLockFile(); + process.exit(); +}); diff --git a/backend/node_modules/@prisma/engines/scripts/postinstall.js b/backend/node_modules/@prisma/engines/scripts/postinstall.js new file mode 100644 index 0000000000000000000000000000000000000000..3fa2e3ca2ac5ccbf13bbfac8d3f2e20735286510 --- /dev/null +++ b/backend/node_modules/@prisma/engines/scripts/postinstall.js @@ -0,0 +1,28 @@ +const path = require('path') + +const postInstallScriptPath = path.join(__dirname, '..', 'dist', 'scripts', 'postinstall.js') +const localInstallScriptPath = path.join(__dirname, '..', 'dist', 'scripts', 'localinstall.js') + +try { + // that's when we develop in the monorepo, `dist` does not exist yet + // so we compile postinstall script and trigger it immediately after + if (require('../package.json').version === '0.0.0') { + const execa = require('execa') + const buildScriptPath = path.join(__dirname, '..', 'helpers', 'build.ts') + + execa.sync('pnpm', ['tsx', buildScriptPath], { + // for the sake of simplicity, we IGNORE_EXTERNALS in our own setup + // ie. when the monorepo installs, the postinstall is self-contained + env: { DEV: true, IGNORE_EXTERNALS: true }, + stdio: 'inherit', + }) + + // if enabled, it will install engine overrides into the cache dir + execa.sync('node', [localInstallScriptPath], { + stdio: 'inherit', + }) + } +} catch {} + +// that's the normal path, when users get this package ready/installed +require(postInstallScriptPath) diff --git a/backend/node_modules/@prisma/fetch-engine/dist/chmodPlusX.js b/backend/node_modules/@prisma/fetch-engine/dist/chmodPlusX.js new file mode 100644 index 0000000000000000000000000000000000000000..5c64f7625a99b59171315a01db5bdeb67457ad85 --- /dev/null +++ b/backend/node_modules/@prisma/fetch-engine/dist/chmodPlusX.js @@ -0,0 +1,25 @@ +"use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var chmodPlusX_exports = {}; +__export(chmodPlusX_exports, { + chmodPlusX: () => import_chunk_7JLQJWOR.chmodPlusX +}); +module.exports = __toCommonJS(chmodPlusX_exports); +var import_chunk_7JLQJWOR = require("./chunk-7JLQJWOR.js"); +var import_chunk_QGM4M3NI = require("./chunk-QGM4M3NI.js"); diff --git a/backend/node_modules/@prisma/fetch-engine/dist/chunk-MWVY55RY.js b/backend/node_modules/@prisma/fetch-engine/dist/chunk-MWVY55RY.js new file mode 100644 index 0000000000000000000000000000000000000000..af1aac9ee75d00b916289c56665f0705a0092a82 --- /dev/null +++ b/backend/node_modules/@prisma/fetch-engine/dist/chunk-MWVY55RY.js @@ -0,0 +1,161 @@ +"use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var chunk_MWVY55RY_exports = {}; +__export(chunk_MWVY55RY_exports, { + getBar: () => getBar +}); +module.exports = __toCommonJS(chunk_MWVY55RY_exports); +var import_chunk_QGM4M3NI = require("./chunk-QGM4M3NI.js"); +var require_node_progress = (0, import_chunk_QGM4M3NI.__commonJS)({ + "../../node_modules/.pnpm/progress@2.0.3/node_modules/progress/lib/node-progress.js"(exports, module2) { + "use strict"; + exports = module2.exports = ProgressBar; + function ProgressBar(fmt, options) { + this.stream = options.stream || process.stderr; + if (typeof options == "number") { + var total = options; + options = {}; + options.total = total; + } else { + options = options || {}; + if ("string" != typeof fmt) throw new Error("format required"); + if ("number" != typeof options.total) throw new Error("total required"); + } + this.fmt = fmt; + this.curr = options.curr || 0; + this.total = options.total; + this.width = options.width || this.total; + this.clear = options.clear; + this.chars = { + complete: options.complete || "=", + incomplete: options.incomplete || "-", + head: options.head || (options.complete || "=") + }; + this.renderThrottle = options.renderThrottle !== 0 ? options.renderThrottle || 16 : 0; + this.lastRender = -Infinity; + this.callback = options.callback || function() { + }; + this.tokens = {}; + this.lastDraw = ""; + } + ProgressBar.prototype.tick = function(len, tokens) { + if (len !== 0) + len = len || 1; + if ("object" == typeof len) tokens = len, len = 1; + if (tokens) this.tokens = tokens; + if (0 == this.curr) this.start = /* @__PURE__ */ new Date(); + this.curr += len; + this.render(); + if (this.curr >= this.total) { + this.render(void 0, true); + this.complete = true; + this.terminate(); + this.callback(this); + return; + } + }; + ProgressBar.prototype.render = function(tokens, force) { + force = force !== void 0 ? force : false; + if (tokens) this.tokens = tokens; + if (!this.stream.isTTY) return; + var now = Date.now(); + var delta = now - this.lastRender; + if (!force && delta < this.renderThrottle) { + return; + } else { + this.lastRender = now; + } + var ratio = this.curr / this.total; + ratio = Math.min(Math.max(ratio, 0), 1); + var percent = Math.floor(ratio * 100); + var incomplete, complete, completeLength; + var elapsed = /* @__PURE__ */ new Date() - this.start; + var eta = percent == 100 ? 0 : elapsed * (this.total / this.curr - 1); + var rate = this.curr / (elapsed / 1e3); + var str = this.fmt.replace(":current", this.curr).replace(":total", this.total).replace(":elapsed", isNaN(elapsed) ? "0.0" : (elapsed / 1e3).toFixed(1)).replace(":eta", isNaN(eta) || !isFinite(eta) ? "0.0" : (eta / 1e3).toFixed(1)).replace(":percent", percent.toFixed(0) + "%").replace(":rate", Math.round(rate)); + var availableSpace = Math.max(0, this.stream.columns - str.replace(":bar", "").length); + if (availableSpace && process.platform === "win32") { + availableSpace = availableSpace - 1; + } + var width = Math.min(this.width, availableSpace); + completeLength = Math.round(width * ratio); + complete = Array(Math.max(0, completeLength + 1)).join(this.chars.complete); + incomplete = Array(Math.max(0, width - completeLength + 1)).join(this.chars.incomplete); + if (completeLength > 0) + complete = complete.slice(0, -1) + this.chars.head; + str = str.replace(":bar", complete + incomplete); + if (this.tokens) for (var key in this.tokens) str = str.replace(":" + key, this.tokens[key]); + if (this.lastDraw !== str) { + this.stream.cursorTo(0); + this.stream.write(str); + this.stream.clearLine(1); + this.lastDraw = str; + } + }; + ProgressBar.prototype.update = function(ratio, tokens) { + var goal = Math.floor(ratio * this.total); + var delta = goal - this.curr; + this.tick(delta, tokens); + }; + ProgressBar.prototype.interrupt = function(message) { + this.stream.clearLine(); + this.stream.cursorTo(0); + this.stream.write(message); + this.stream.write("\n"); + this.stream.write(this.lastDraw); + }; + ProgressBar.prototype.terminate = function() { + if (this.clear) { + if (this.stream.clearLine) { + this.stream.clearLine(); + this.stream.cursorTo(0); + } + } else { + this.stream.write("\n"); + } + }; + } +}); +var require_progress = (0, import_chunk_QGM4M3NI.__commonJS)({ + "../../node_modules/.pnpm/progress@2.0.3/node_modules/progress/index.js"(exports, module2) { + "use strict"; + module2.exports = require_node_progress(); + } +}); +var import_progress = (0, import_chunk_QGM4M3NI.__toESM)(require_progress()); +function getBar(text) { + return new import_progress.default(`> ${text} [:bar] :percent`, { + stream: process.stdout, + width: 20, + complete: "=", + incomplete: " ", + total: 100, + head: "", + clear: true + }); +} +/*! Bundled license information: + +progress/lib/node-progress.js: + (*! + * node-progress + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + *) +*/ diff --git a/backend/node_modules/@prisma/fetch-engine/dist/chunk-RXM4EBGR.js b/backend/node_modules/@prisma/fetch-engine/dist/chunk-RXM4EBGR.js new file mode 100644 index 0000000000000000000000000000000000000000..5df34f4deab23aab0c1ce0aab7efb9b73199b933 --- /dev/null +++ b/backend/node_modules/@prisma/fetch-engine/dist/chunk-RXM4EBGR.js @@ -0,0 +1,4230 @@ +"use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var chunk_RXM4EBGR_exports = {}; +__export(chunk_RXM4EBGR_exports, { + FormData: () => FormData, + fetch_blob_default: () => fetch_blob_default, + file_default: () => file_default, + formDataToBlob: () => formDataToBlob +}); +module.exports = __toCommonJS(chunk_RXM4EBGR_exports); +var import_chunk_QGM4M3NI = require("./chunk-QGM4M3NI.js"); +var import_node_fs = require("node:fs"); +var require_ponyfill_es2018 = (0, import_chunk_QGM4M3NI.__commonJS)({ + "../../node_modules/.pnpm/web-streams-polyfill@3.2.1/node_modules/web-streams-polyfill/dist/ponyfill.es2018.js"(exports, module2) { + "use strict"; + (function(global2, factory) { + typeof exports === "object" && typeof module2 !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global2 = typeof globalThis !== "undefined" ? globalThis : global2 || self, factory(global2.WebStreamsPolyfill = {})); + })(exports, function(exports2) { + "use strict"; + const SymbolPolyfill = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? Symbol : (description) => `Symbol(${description})`; + function noop() { + return void 0; + } + function getGlobals() { + if (typeof self !== "undefined") { + return self; + } else if (typeof window !== "undefined") { + return window; + } else if (typeof global !== "undefined") { + return global; + } + return void 0; + } + const globals = getGlobals(); + function typeIsObject(x2) { + return typeof x2 === "object" && x2 !== null || typeof x2 === "function"; + } + const rethrowAssertionErrorRejection = noop; + const originalPromise = Promise; + const originalPromiseThen = Promise.prototype.then; + const originalPromiseResolve = Promise.resolve.bind(originalPromise); + const originalPromiseReject = Promise.reject.bind(originalPromise); + function newPromise(executor) { + return new originalPromise(executor); + } + function promiseResolvedWith(value) { + return originalPromiseResolve(value); + } + function promiseRejectedWith(reason) { + return originalPromiseReject(reason); + } + function PerformPromiseThen(promise, onFulfilled, onRejected) { + return originalPromiseThen.call(promise, onFulfilled, onRejected); + } + function uponPromise(promise, onFulfilled, onRejected) { + PerformPromiseThen(PerformPromiseThen(promise, onFulfilled, onRejected), void 0, rethrowAssertionErrorRejection); + } + function uponFulfillment(promise, onFulfilled) { + uponPromise(promise, onFulfilled); + } + function uponRejection(promise, onRejected) { + uponPromise(promise, void 0, onRejected); + } + function transformPromiseWith(promise, fulfillmentHandler, rejectionHandler) { + return PerformPromiseThen(promise, fulfillmentHandler, rejectionHandler); + } + function setPromiseIsHandledToTrue(promise) { + PerformPromiseThen(promise, void 0, rethrowAssertionErrorRejection); + } + const queueMicrotask = (() => { + const globalQueueMicrotask = globals && globals.queueMicrotask; + if (typeof globalQueueMicrotask === "function") { + return globalQueueMicrotask; + } + const resolvedPromise = promiseResolvedWith(void 0); + return (fn) => PerformPromiseThen(resolvedPromise, fn); + })(); + function reflectCall(F, V, args) { + if (typeof F !== "function") { + throw new TypeError("Argument is not a function"); + } + return Function.prototype.apply.call(F, V, args); + } + function promiseCall(F, V, args) { + try { + return promiseResolvedWith(reflectCall(F, V, args)); + } catch (value) { + return promiseRejectedWith(value); + } + } + const QUEUE_MAX_ARRAY_SIZE = 16384; + class SimpleQueue { + constructor() { + this._cursor = 0; + this._size = 0; + this._front = { + _elements: [], + _next: void 0 + }; + this._back = this._front; + this._cursor = 0; + this._size = 0; + } + get length() { + return this._size; + } + // For exception safety, this method is structured in order: + // 1. Read state + // 2. Calculate required state mutations + // 3. Perform state mutations + push(element) { + const oldBack = this._back; + let newBack = oldBack; + if (oldBack._elements.length === QUEUE_MAX_ARRAY_SIZE - 1) { + newBack = { + _elements: [], + _next: void 0 + }; + } + oldBack._elements.push(element); + if (newBack !== oldBack) { + this._back = newBack; + oldBack._next = newBack; + } + ++this._size; + } + // Like push(), shift() follows the read -> calculate -> mutate pattern for + // exception safety. + shift() { + const oldFront = this._front; + let newFront = oldFront; + const oldCursor = this._cursor; + let newCursor = oldCursor + 1; + const elements = oldFront._elements; + const element = elements[oldCursor]; + if (newCursor === QUEUE_MAX_ARRAY_SIZE) { + newFront = oldFront._next; + newCursor = 0; + } + --this._size; + this._cursor = newCursor; + if (oldFront !== newFront) { + this._front = newFront; + } + elements[oldCursor] = void 0; + return element; + } + // The tricky thing about forEach() is that it can be called + // re-entrantly. The queue may be mutated inside the callback. It is easy to + // see that push() within the callback has no negative effects since the end + // of the queue is checked for on every iteration. If shift() is called + // repeatedly within the callback then the next iteration may return an + // element that has been removed. In this case the callback will be called + // with undefined values until we either "catch up" with elements that still + // exist or reach the back of the queue. + forEach(callback) { + let i2 = this._cursor; + let node = this._front; + let elements = node._elements; + while (i2 !== elements.length || node._next !== void 0) { + if (i2 === elements.length) { + node = node._next; + elements = node._elements; + i2 = 0; + if (elements.length === 0) { + break; + } + } + callback(elements[i2]); + ++i2; + } + } + // Return the element that would be returned if shift() was called now, + // without modifying the queue. + peek() { + const front = this._front; + const cursor = this._cursor; + return front._elements[cursor]; + } + } + function ReadableStreamReaderGenericInitialize(reader, stream) { + reader._ownerReadableStream = stream; + stream._reader = reader; + if (stream._state === "readable") { + defaultReaderClosedPromiseInitialize(reader); + } else if (stream._state === "closed") { + defaultReaderClosedPromiseInitializeAsResolved(reader); + } else { + defaultReaderClosedPromiseInitializeAsRejected(reader, stream._storedError); + } + } + function ReadableStreamReaderGenericCancel(reader, reason) { + const stream = reader._ownerReadableStream; + return ReadableStreamCancel(stream, reason); + } + function ReadableStreamReaderGenericRelease(reader) { + if (reader._ownerReadableStream._state === "readable") { + defaultReaderClosedPromiseReject(reader, new TypeError(`Reader was released and can no longer be used to monitor the stream's closedness`)); + } else { + defaultReaderClosedPromiseResetToRejected(reader, new TypeError(`Reader was released and can no longer be used to monitor the stream's closedness`)); + } + reader._ownerReadableStream._reader = void 0; + reader._ownerReadableStream = void 0; + } + function readerLockException(name) { + return new TypeError("Cannot " + name + " a stream using a released reader"); + } + function defaultReaderClosedPromiseInitialize(reader) { + reader._closedPromise = newPromise((resolve, reject) => { + reader._closedPromise_resolve = resolve; + reader._closedPromise_reject = reject; + }); + } + function defaultReaderClosedPromiseInitializeAsRejected(reader, reason) { + defaultReaderClosedPromiseInitialize(reader); + defaultReaderClosedPromiseReject(reader, reason); + } + function defaultReaderClosedPromiseInitializeAsResolved(reader) { + defaultReaderClosedPromiseInitialize(reader); + defaultReaderClosedPromiseResolve(reader); + } + function defaultReaderClosedPromiseReject(reader, reason) { + if (reader._closedPromise_reject === void 0) { + return; + } + setPromiseIsHandledToTrue(reader._closedPromise); + reader._closedPromise_reject(reason); + reader._closedPromise_resolve = void 0; + reader._closedPromise_reject = void 0; + } + function defaultReaderClosedPromiseResetToRejected(reader, reason) { + defaultReaderClosedPromiseInitializeAsRejected(reader, reason); + } + function defaultReaderClosedPromiseResolve(reader) { + if (reader._closedPromise_resolve === void 0) { + return; + } + reader._closedPromise_resolve(void 0); + reader._closedPromise_resolve = void 0; + reader._closedPromise_reject = void 0; + } + const AbortSteps = SymbolPolyfill("[[AbortSteps]]"); + const ErrorSteps = SymbolPolyfill("[[ErrorSteps]]"); + const CancelSteps = SymbolPolyfill("[[CancelSteps]]"); + const PullSteps = SymbolPolyfill("[[PullSteps]]"); + const NumberIsFinite = Number.isFinite || function(x2) { + return typeof x2 === "number" && isFinite(x2); + }; + const MathTrunc = Math.trunc || function(v) { + return v < 0 ? Math.ceil(v) : Math.floor(v); + }; + function isDictionary(x2) { + return typeof x2 === "object" || typeof x2 === "function"; + } + function assertDictionary(obj, context) { + if (obj !== void 0 && !isDictionary(obj)) { + throw new TypeError(`${context} is not an object.`); + } + } + function assertFunction(x2, context) { + if (typeof x2 !== "function") { + throw new TypeError(`${context} is not a function.`); + } + } + function isObject(x2) { + return typeof x2 === "object" && x2 !== null || typeof x2 === "function"; + } + function assertObject(x2, context) { + if (!isObject(x2)) { + throw new TypeError(`${context} is not an object.`); + } + } + function assertRequiredArgument(x2, position, context) { + if (x2 === void 0) { + throw new TypeError(`Parameter ${position} is required in '${context}'.`); + } + } + function assertRequiredField(x2, field, context) { + if (x2 === void 0) { + throw new TypeError(`${field} is required in '${context}'.`); + } + } + function convertUnrestrictedDouble(value) { + return Number(value); + } + function censorNegativeZero(x2) { + return x2 === 0 ? 0 : x2; + } + function integerPart(x2) { + return censorNegativeZero(MathTrunc(x2)); + } + function convertUnsignedLongLongWithEnforceRange(value, context) { + const lowerBound = 0; + const upperBound = Number.MAX_SAFE_INTEGER; + let x2 = Number(value); + x2 = censorNegativeZero(x2); + if (!NumberIsFinite(x2)) { + throw new TypeError(`${context} is not a finite number`); + } + x2 = integerPart(x2); + if (x2 < lowerBound || x2 > upperBound) { + throw new TypeError(`${context} is outside the accepted range of ${lowerBound} to ${upperBound}, inclusive`); + } + if (!NumberIsFinite(x2) || x2 === 0) { + return 0; + } + return x2; + } + function assertReadableStream(x2, context) { + if (!IsReadableStream(x2)) { + throw new TypeError(`${context} is not a ReadableStream.`); + } + } + function AcquireReadableStreamDefaultReader(stream) { + return new ReadableStreamDefaultReader(stream); + } + function ReadableStreamAddReadRequest(stream, readRequest) { + stream._reader._readRequests.push(readRequest); + } + function ReadableStreamFulfillReadRequest(stream, chunk, done) { + const reader = stream._reader; + const readRequest = reader._readRequests.shift(); + if (done) { + readRequest._closeSteps(); + } else { + readRequest._chunkSteps(chunk); + } + } + function ReadableStreamGetNumReadRequests(stream) { + return stream._reader._readRequests.length; + } + function ReadableStreamHasDefaultReader(stream) { + const reader = stream._reader; + if (reader === void 0) { + return false; + } + if (!IsReadableStreamDefaultReader(reader)) { + return false; + } + return true; + } + class ReadableStreamDefaultReader { + constructor(stream) { + assertRequiredArgument(stream, 1, "ReadableStreamDefaultReader"); + assertReadableStream(stream, "First parameter"); + if (IsReadableStreamLocked(stream)) { + throw new TypeError("This stream has already been locked for exclusive reading by another reader"); + } + ReadableStreamReaderGenericInitialize(this, stream); + this._readRequests = new SimpleQueue(); + } + /** + * Returns a promise that will be fulfilled when the stream becomes closed, + * or rejected if the stream ever errors or the reader's lock is released before the stream finishes closing. + */ + get closed() { + if (!IsReadableStreamDefaultReader(this)) { + return promiseRejectedWith(defaultReaderBrandCheckException("closed")); + } + return this._closedPromise; + } + /** + * If the reader is active, behaves the same as {@link ReadableStream.cancel | stream.cancel(reason)}. + */ + cancel(reason = void 0) { + if (!IsReadableStreamDefaultReader(this)) { + return promiseRejectedWith(defaultReaderBrandCheckException("cancel")); + } + if (this._ownerReadableStream === void 0) { + return promiseRejectedWith(readerLockException("cancel")); + } + return ReadableStreamReaderGenericCancel(this, reason); + } + /** + * Returns a promise that allows access to the next chunk from the stream's internal queue, if available. + * + * If reading a chunk causes the queue to become empty, more data will be pulled from the underlying source. + */ + read() { + if (!IsReadableStreamDefaultReader(this)) { + return promiseRejectedWith(defaultReaderBrandCheckException("read")); + } + if (this._ownerReadableStream === void 0) { + return promiseRejectedWith(readerLockException("read from")); + } + let resolvePromise; + let rejectPromise; + const promise = newPromise((resolve, reject) => { + resolvePromise = resolve; + rejectPromise = reject; + }); + const readRequest = { + _chunkSteps: (chunk) => resolvePromise({ value: chunk, done: false }), + _closeSteps: () => resolvePromise({ value: void 0, done: true }), + _errorSteps: (e2) => rejectPromise(e2) + }; + ReadableStreamDefaultReaderRead(this, readRequest); + return promise; + } + /** + * Releases the reader's lock on the corresponding stream. After the lock is released, the reader is no longer active. + * If the associated stream is errored when the lock is released, the reader will appear errored in the same way + * from now on; otherwise, the reader will appear closed. + * + * A reader's lock cannot be released while it still has a pending read request, i.e., if a promise returned by + * the reader's {@link ReadableStreamDefaultReader.read | read()} method has not yet been settled. Attempting to + * do so will throw a `TypeError` and leave the reader locked to the stream. + */ + releaseLock() { + if (!IsReadableStreamDefaultReader(this)) { + throw defaultReaderBrandCheckException("releaseLock"); + } + if (this._ownerReadableStream === void 0) { + return; + } + if (this._readRequests.length > 0) { + throw new TypeError("Tried to release a reader lock when that reader has pending read() calls un-settled"); + } + ReadableStreamReaderGenericRelease(this); + } + } + Object.defineProperties(ReadableStreamDefaultReader.prototype, { + cancel: { enumerable: true }, + read: { enumerable: true }, + releaseLock: { enumerable: true }, + closed: { enumerable: true } + }); + if (typeof SymbolPolyfill.toStringTag === "symbol") { + Object.defineProperty(ReadableStreamDefaultReader.prototype, SymbolPolyfill.toStringTag, { + value: "ReadableStreamDefaultReader", + configurable: true + }); + } + function IsReadableStreamDefaultReader(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_readRequests")) { + return false; + } + return x2 instanceof ReadableStreamDefaultReader; + } + function ReadableStreamDefaultReaderRead(reader, readRequest) { + const stream = reader._ownerReadableStream; + stream._disturbed = true; + if (stream._state === "closed") { + readRequest._closeSteps(); + } else if (stream._state === "errored") { + readRequest._errorSteps(stream._storedError); + } else { + stream._readableStreamController[PullSteps](readRequest); + } + } + function defaultReaderBrandCheckException(name) { + return new TypeError(`ReadableStreamDefaultReader.prototype.${name} can only be used on a ReadableStreamDefaultReader`); + } + const AsyncIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf(async function* () { + }).prototype); + class ReadableStreamAsyncIteratorImpl { + constructor(reader, preventCancel) { + this._ongoingPromise = void 0; + this._isFinished = false; + this._reader = reader; + this._preventCancel = preventCancel; + } + next() { + const nextSteps = () => this._nextSteps(); + this._ongoingPromise = this._ongoingPromise ? transformPromiseWith(this._ongoingPromise, nextSteps, nextSteps) : nextSteps(); + return this._ongoingPromise; + } + return(value) { + const returnSteps = () => this._returnSteps(value); + return this._ongoingPromise ? transformPromiseWith(this._ongoingPromise, returnSteps, returnSteps) : returnSteps(); + } + _nextSteps() { + if (this._isFinished) { + return Promise.resolve({ value: void 0, done: true }); + } + const reader = this._reader; + if (reader._ownerReadableStream === void 0) { + return promiseRejectedWith(readerLockException("iterate")); + } + let resolvePromise; + let rejectPromise; + const promise = newPromise((resolve, reject) => { + resolvePromise = resolve; + rejectPromise = reject; + }); + const readRequest = { + _chunkSteps: (chunk) => { + this._ongoingPromise = void 0; + queueMicrotask(() => resolvePromise({ value: chunk, done: false })); + }, + _closeSteps: () => { + this._ongoingPromise = void 0; + this._isFinished = true; + ReadableStreamReaderGenericRelease(reader); + resolvePromise({ value: void 0, done: true }); + }, + _errorSteps: (reason) => { + this._ongoingPromise = void 0; + this._isFinished = true; + ReadableStreamReaderGenericRelease(reader); + rejectPromise(reason); + } + }; + ReadableStreamDefaultReaderRead(reader, readRequest); + return promise; + } + _returnSteps(value) { + if (this._isFinished) { + return Promise.resolve({ value, done: true }); + } + this._isFinished = true; + const reader = this._reader; + if (reader._ownerReadableStream === void 0) { + return promiseRejectedWith(readerLockException("finish iterating")); + } + if (!this._preventCancel) { + const result = ReadableStreamReaderGenericCancel(reader, value); + ReadableStreamReaderGenericRelease(reader); + return transformPromiseWith(result, () => ({ value, done: true })); + } + ReadableStreamReaderGenericRelease(reader); + return promiseResolvedWith({ value, done: true }); + } + } + const ReadableStreamAsyncIteratorPrototype = { + next() { + if (!IsReadableStreamAsyncIterator(this)) { + return promiseRejectedWith(streamAsyncIteratorBrandCheckException("next")); + } + return this._asyncIteratorImpl.next(); + }, + return(value) { + if (!IsReadableStreamAsyncIterator(this)) { + return promiseRejectedWith(streamAsyncIteratorBrandCheckException("return")); + } + return this._asyncIteratorImpl.return(value); + } + }; + if (AsyncIteratorPrototype !== void 0) { + Object.setPrototypeOf(ReadableStreamAsyncIteratorPrototype, AsyncIteratorPrototype); + } + function AcquireReadableStreamAsyncIterator(stream, preventCancel) { + const reader = AcquireReadableStreamDefaultReader(stream); + const impl = new ReadableStreamAsyncIteratorImpl(reader, preventCancel); + const iterator = Object.create(ReadableStreamAsyncIteratorPrototype); + iterator._asyncIteratorImpl = impl; + return iterator; + } + function IsReadableStreamAsyncIterator(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_asyncIteratorImpl")) { + return false; + } + try { + return x2._asyncIteratorImpl instanceof ReadableStreamAsyncIteratorImpl; + } catch (_a) { + return false; + } + } + function streamAsyncIteratorBrandCheckException(name) { + return new TypeError(`ReadableStreamAsyncIterator.${name} can only be used on a ReadableSteamAsyncIterator`); + } + const NumberIsNaN = Number.isNaN || function(x2) { + return x2 !== x2; + }; + function CreateArrayFromList(elements) { + return elements.slice(); + } + function CopyDataBlockBytes(dest, destOffset, src, srcOffset, n) { + new Uint8Array(dest).set(new Uint8Array(src, srcOffset, n), destOffset); + } + function TransferArrayBuffer(O) { + return O; + } + function IsDetachedBuffer(O) { + return false; + } + function ArrayBufferSlice(buffer, begin, end) { + if (buffer.slice) { + return buffer.slice(begin, end); + } + const length = end - begin; + const slice = new ArrayBuffer(length); + CopyDataBlockBytes(slice, 0, buffer, begin, length); + return slice; + } + function IsNonNegativeNumber(v) { + if (typeof v !== "number") { + return false; + } + if (NumberIsNaN(v)) { + return false; + } + if (v < 0) { + return false; + } + return true; + } + function CloneAsUint8Array(O) { + const buffer = ArrayBufferSlice(O.buffer, O.byteOffset, O.byteOffset + O.byteLength); + return new Uint8Array(buffer); + } + function DequeueValue(container) { + const pair = container._queue.shift(); + container._queueTotalSize -= pair.size; + if (container._queueTotalSize < 0) { + container._queueTotalSize = 0; + } + return pair.value; + } + function EnqueueValueWithSize(container, value, size) { + if (!IsNonNegativeNumber(size) || size === Infinity) { + throw new RangeError("Size must be a finite, non-NaN, non-negative number."); + } + container._queue.push({ value, size }); + container._queueTotalSize += size; + } + function PeekQueueValue(container) { + const pair = container._queue.peek(); + return pair.value; + } + function ResetQueue(container) { + container._queue = new SimpleQueue(); + container._queueTotalSize = 0; + } + class ReadableStreamBYOBRequest { + constructor() { + throw new TypeError("Illegal constructor"); + } + /** + * Returns the view for writing in to, or `null` if the BYOB request has already been responded to. + */ + get view() { + if (!IsReadableStreamBYOBRequest(this)) { + throw byobRequestBrandCheckException("view"); + } + return this._view; + } + respond(bytesWritten) { + if (!IsReadableStreamBYOBRequest(this)) { + throw byobRequestBrandCheckException("respond"); + } + assertRequiredArgument(bytesWritten, 1, "respond"); + bytesWritten = convertUnsignedLongLongWithEnforceRange(bytesWritten, "First parameter"); + if (this._associatedReadableByteStreamController === void 0) { + throw new TypeError("This BYOB request has been invalidated"); + } + if (IsDetachedBuffer(this._view.buffer)) ; + ReadableByteStreamControllerRespond(this._associatedReadableByteStreamController, bytesWritten); + } + respondWithNewView(view) { + if (!IsReadableStreamBYOBRequest(this)) { + throw byobRequestBrandCheckException("respondWithNewView"); + } + assertRequiredArgument(view, 1, "respondWithNewView"); + if (!ArrayBuffer.isView(view)) { + throw new TypeError("You can only respond with array buffer views"); + } + if (this._associatedReadableByteStreamController === void 0) { + throw new TypeError("This BYOB request has been invalidated"); + } + if (IsDetachedBuffer(view.buffer)) ; + ReadableByteStreamControllerRespondWithNewView(this._associatedReadableByteStreamController, view); + } + } + Object.defineProperties(ReadableStreamBYOBRequest.prototype, { + respond: { enumerable: true }, + respondWithNewView: { enumerable: true }, + view: { enumerable: true } + }); + if (typeof SymbolPolyfill.toStringTag === "symbol") { + Object.defineProperty(ReadableStreamBYOBRequest.prototype, SymbolPolyfill.toStringTag, { + value: "ReadableStreamBYOBRequest", + configurable: true + }); + } + class ReadableByteStreamController { + constructor() { + throw new TypeError("Illegal constructor"); + } + /** + * Returns the current BYOB pull request, or `null` if there isn't one. + */ + get byobRequest() { + if (!IsReadableByteStreamController(this)) { + throw byteStreamControllerBrandCheckException("byobRequest"); + } + return ReadableByteStreamControllerGetBYOBRequest(this); + } + /** + * Returns the desired size to fill the controlled stream's internal queue. It can be negative, if the queue is + * over-full. An underlying byte source ought to use this information to determine when and how to apply backpressure. + */ + get desiredSize() { + if (!IsReadableByteStreamController(this)) { + throw byteStreamControllerBrandCheckException("desiredSize"); + } + return ReadableByteStreamControllerGetDesiredSize(this); + } + /** + * Closes the controlled readable stream. Consumers will still be able to read any previously-enqueued chunks from + * the stream, but once those are read, the stream will become closed. + */ + close() { + if (!IsReadableByteStreamController(this)) { + throw byteStreamControllerBrandCheckException("close"); + } + if (this._closeRequested) { + throw new TypeError("The stream has already been closed; do not close it again!"); + } + const state = this._controlledReadableByteStream._state; + if (state !== "readable") { + throw new TypeError(`The stream (in ${state} state) is not in the readable state and cannot be closed`); + } + ReadableByteStreamControllerClose(this); + } + enqueue(chunk) { + if (!IsReadableByteStreamController(this)) { + throw byteStreamControllerBrandCheckException("enqueue"); + } + assertRequiredArgument(chunk, 1, "enqueue"); + if (!ArrayBuffer.isView(chunk)) { + throw new TypeError("chunk must be an array buffer view"); + } + if (chunk.byteLength === 0) { + throw new TypeError("chunk must have non-zero byteLength"); + } + if (chunk.buffer.byteLength === 0) { + throw new TypeError(`chunk's buffer must have non-zero byteLength`); + } + if (this._closeRequested) { + throw new TypeError("stream is closed or draining"); + } + const state = this._controlledReadableByteStream._state; + if (state !== "readable") { + throw new TypeError(`The stream (in ${state} state) is not in the readable state and cannot be enqueued to`); + } + ReadableByteStreamControllerEnqueue(this, chunk); + } + /** + * Errors the controlled readable stream, making all future interactions with it fail with the given error `e`. + */ + error(e2 = void 0) { + if (!IsReadableByteStreamController(this)) { + throw byteStreamControllerBrandCheckException("error"); + } + ReadableByteStreamControllerError(this, e2); + } + /** @internal */ + [CancelSteps](reason) { + ReadableByteStreamControllerClearPendingPullIntos(this); + ResetQueue(this); + const result = this._cancelAlgorithm(reason); + ReadableByteStreamControllerClearAlgorithms(this); + return result; + } + /** @internal */ + [PullSteps](readRequest) { + const stream = this._controlledReadableByteStream; + if (this._queueTotalSize > 0) { + const entry = this._queue.shift(); + this._queueTotalSize -= entry.byteLength; + ReadableByteStreamControllerHandleQueueDrain(this); + const view = new Uint8Array(entry.buffer, entry.byteOffset, entry.byteLength); + readRequest._chunkSteps(view); + return; + } + const autoAllocateChunkSize = this._autoAllocateChunkSize; + if (autoAllocateChunkSize !== void 0) { + let buffer; + try { + buffer = new ArrayBuffer(autoAllocateChunkSize); + } catch (bufferE) { + readRequest._errorSteps(bufferE); + return; + } + const pullIntoDescriptor = { + buffer, + bufferByteLength: autoAllocateChunkSize, + byteOffset: 0, + byteLength: autoAllocateChunkSize, + bytesFilled: 0, + elementSize: 1, + viewConstructor: Uint8Array, + readerType: "default" + }; + this._pendingPullIntos.push(pullIntoDescriptor); + } + ReadableStreamAddReadRequest(stream, readRequest); + ReadableByteStreamControllerCallPullIfNeeded(this); + } + } + Object.defineProperties(ReadableByteStreamController.prototype, { + close: { enumerable: true }, + enqueue: { enumerable: true }, + error: { enumerable: true }, + byobRequest: { enumerable: true }, + desiredSize: { enumerable: true } + }); + if (typeof SymbolPolyfill.toStringTag === "symbol") { + Object.defineProperty(ReadableByteStreamController.prototype, SymbolPolyfill.toStringTag, { + value: "ReadableByteStreamController", + configurable: true + }); + } + function IsReadableByteStreamController(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_controlledReadableByteStream")) { + return false; + } + return x2 instanceof ReadableByteStreamController; + } + function IsReadableStreamBYOBRequest(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_associatedReadableByteStreamController")) { + return false; + } + return x2 instanceof ReadableStreamBYOBRequest; + } + function ReadableByteStreamControllerCallPullIfNeeded(controller) { + const shouldPull = ReadableByteStreamControllerShouldCallPull(controller); + if (!shouldPull) { + return; + } + if (controller._pulling) { + controller._pullAgain = true; + return; + } + controller._pulling = true; + const pullPromise = controller._pullAlgorithm(); + uponPromise(pullPromise, () => { + controller._pulling = false; + if (controller._pullAgain) { + controller._pullAgain = false; + ReadableByteStreamControllerCallPullIfNeeded(controller); + } + }, (e2) => { + ReadableByteStreamControllerError(controller, e2); + }); + } + function ReadableByteStreamControllerClearPendingPullIntos(controller) { + ReadableByteStreamControllerInvalidateBYOBRequest(controller); + controller._pendingPullIntos = new SimpleQueue(); + } + function ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor) { + let done = false; + if (stream._state === "closed") { + done = true; + } + const filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor); + if (pullIntoDescriptor.readerType === "default") { + ReadableStreamFulfillReadRequest(stream, filledView, done); + } else { + ReadableStreamFulfillReadIntoRequest(stream, filledView, done); + } + } + function ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor) { + const bytesFilled = pullIntoDescriptor.bytesFilled; + const elementSize = pullIntoDescriptor.elementSize; + return new pullIntoDescriptor.viewConstructor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, bytesFilled / elementSize); + } + function ReadableByteStreamControllerEnqueueChunkToQueue(controller, buffer, byteOffset, byteLength) { + controller._queue.push({ buffer, byteOffset, byteLength }); + controller._queueTotalSize += byteLength; + } + function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor) { + const elementSize = pullIntoDescriptor.elementSize; + const currentAlignedBytes = pullIntoDescriptor.bytesFilled - pullIntoDescriptor.bytesFilled % elementSize; + const maxBytesToCopy = Math.min(controller._queueTotalSize, pullIntoDescriptor.byteLength - pullIntoDescriptor.bytesFilled); + const maxBytesFilled = pullIntoDescriptor.bytesFilled + maxBytesToCopy; + const maxAlignedBytes = maxBytesFilled - maxBytesFilled % elementSize; + let totalBytesToCopyRemaining = maxBytesToCopy; + let ready = false; + if (maxAlignedBytes > currentAlignedBytes) { + totalBytesToCopyRemaining = maxAlignedBytes - pullIntoDescriptor.bytesFilled; + ready = true; + } + const queue = controller._queue; + while (totalBytesToCopyRemaining > 0) { + const headOfQueue = queue.peek(); + const bytesToCopy = Math.min(totalBytesToCopyRemaining, headOfQueue.byteLength); + const destStart = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled; + CopyDataBlockBytes(pullIntoDescriptor.buffer, destStart, headOfQueue.buffer, headOfQueue.byteOffset, bytesToCopy); + if (headOfQueue.byteLength === bytesToCopy) { + queue.shift(); + } else { + headOfQueue.byteOffset += bytesToCopy; + headOfQueue.byteLength -= bytesToCopy; + } + controller._queueTotalSize -= bytesToCopy; + ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesToCopy, pullIntoDescriptor); + totalBytesToCopyRemaining -= bytesToCopy; + } + return ready; + } + function ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, size, pullIntoDescriptor) { + pullIntoDescriptor.bytesFilled += size; + } + function ReadableByteStreamControllerHandleQueueDrain(controller) { + if (controller._queueTotalSize === 0 && controller._closeRequested) { + ReadableByteStreamControllerClearAlgorithms(controller); + ReadableStreamClose(controller._controlledReadableByteStream); + } else { + ReadableByteStreamControllerCallPullIfNeeded(controller); + } + } + function ReadableByteStreamControllerInvalidateBYOBRequest(controller) { + if (controller._byobRequest === null) { + return; + } + controller._byobRequest._associatedReadableByteStreamController = void 0; + controller._byobRequest._view = null; + controller._byobRequest = null; + } + function ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller) { + while (controller._pendingPullIntos.length > 0) { + if (controller._queueTotalSize === 0) { + return; + } + const pullIntoDescriptor = controller._pendingPullIntos.peek(); + if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor)) { + ReadableByteStreamControllerShiftPendingPullInto(controller); + ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableByteStream, pullIntoDescriptor); + } + } + } + function ReadableByteStreamControllerPullInto(controller, view, readIntoRequest) { + const stream = controller._controlledReadableByteStream; + let elementSize = 1; + if (view.constructor !== DataView) { + elementSize = view.constructor.BYTES_PER_ELEMENT; + } + const ctor = view.constructor; + const buffer = TransferArrayBuffer(view.buffer); + const pullIntoDescriptor = { + buffer, + bufferByteLength: buffer.byteLength, + byteOffset: view.byteOffset, + byteLength: view.byteLength, + bytesFilled: 0, + elementSize, + viewConstructor: ctor, + readerType: "byob" + }; + if (controller._pendingPullIntos.length > 0) { + controller._pendingPullIntos.push(pullIntoDescriptor); + ReadableStreamAddReadIntoRequest(stream, readIntoRequest); + return; + } + if (stream._state === "closed") { + const emptyView = new ctor(pullIntoDescriptor.buffer, pullIntoDescriptor.byteOffset, 0); + readIntoRequest._closeSteps(emptyView); + return; + } + if (controller._queueTotalSize > 0) { + if (ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller, pullIntoDescriptor)) { + const filledView = ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor); + ReadableByteStreamControllerHandleQueueDrain(controller); + readIntoRequest._chunkSteps(filledView); + return; + } + if (controller._closeRequested) { + const e2 = new TypeError("Insufficient bytes to fill elements in the given buffer"); + ReadableByteStreamControllerError(controller, e2); + readIntoRequest._errorSteps(e2); + return; + } + } + controller._pendingPullIntos.push(pullIntoDescriptor); + ReadableStreamAddReadIntoRequest(stream, readIntoRequest); + ReadableByteStreamControllerCallPullIfNeeded(controller); + } + function ReadableByteStreamControllerRespondInClosedState(controller, firstDescriptor) { + const stream = controller._controlledReadableByteStream; + if (ReadableStreamHasBYOBReader(stream)) { + while (ReadableStreamGetNumReadIntoRequests(stream) > 0) { + const pullIntoDescriptor = ReadableByteStreamControllerShiftPendingPullInto(controller); + ReadableByteStreamControllerCommitPullIntoDescriptor(stream, pullIntoDescriptor); + } + } + } + function ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, pullIntoDescriptor) { + ReadableByteStreamControllerFillHeadPullIntoDescriptor(controller, bytesWritten, pullIntoDescriptor); + if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) { + return; + } + ReadableByteStreamControllerShiftPendingPullInto(controller); + const remainderSize = pullIntoDescriptor.bytesFilled % pullIntoDescriptor.elementSize; + if (remainderSize > 0) { + const end = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled; + const remainder = ArrayBufferSlice(pullIntoDescriptor.buffer, end - remainderSize, end); + ReadableByteStreamControllerEnqueueChunkToQueue(controller, remainder, 0, remainder.byteLength); + } + pullIntoDescriptor.bytesFilled -= remainderSize; + ReadableByteStreamControllerCommitPullIntoDescriptor(controller._controlledReadableByteStream, pullIntoDescriptor); + ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller); + } + function ReadableByteStreamControllerRespondInternal(controller, bytesWritten) { + const firstDescriptor = controller._pendingPullIntos.peek(); + ReadableByteStreamControllerInvalidateBYOBRequest(controller); + const state = controller._controlledReadableByteStream._state; + if (state === "closed") { + ReadableByteStreamControllerRespondInClosedState(controller); + } else { + ReadableByteStreamControllerRespondInReadableState(controller, bytesWritten, firstDescriptor); + } + ReadableByteStreamControllerCallPullIfNeeded(controller); + } + function ReadableByteStreamControllerShiftPendingPullInto(controller) { + const descriptor = controller._pendingPullIntos.shift(); + return descriptor; + } + function ReadableByteStreamControllerShouldCallPull(controller) { + const stream = controller._controlledReadableByteStream; + if (stream._state !== "readable") { + return false; + } + if (controller._closeRequested) { + return false; + } + if (!controller._started) { + return false; + } + if (ReadableStreamHasDefaultReader(stream) && ReadableStreamGetNumReadRequests(stream) > 0) { + return true; + } + if (ReadableStreamHasBYOBReader(stream) && ReadableStreamGetNumReadIntoRequests(stream) > 0) { + return true; + } + const desiredSize = ReadableByteStreamControllerGetDesiredSize(controller); + if (desiredSize > 0) { + return true; + } + return false; + } + function ReadableByteStreamControllerClearAlgorithms(controller) { + controller._pullAlgorithm = void 0; + controller._cancelAlgorithm = void 0; + } + function ReadableByteStreamControllerClose(controller) { + const stream = controller._controlledReadableByteStream; + if (controller._closeRequested || stream._state !== "readable") { + return; + } + if (controller._queueTotalSize > 0) { + controller._closeRequested = true; + return; + } + if (controller._pendingPullIntos.length > 0) { + const firstPendingPullInto = controller._pendingPullIntos.peek(); + if (firstPendingPullInto.bytesFilled > 0) { + const e2 = new TypeError("Insufficient bytes to fill elements in the given buffer"); + ReadableByteStreamControllerError(controller, e2); + throw e2; + } + } + ReadableByteStreamControllerClearAlgorithms(controller); + ReadableStreamClose(stream); + } + function ReadableByteStreamControllerEnqueue(controller, chunk) { + const stream = controller._controlledReadableByteStream; + if (controller._closeRequested || stream._state !== "readable") { + return; + } + const buffer = chunk.buffer; + const byteOffset = chunk.byteOffset; + const byteLength = chunk.byteLength; + const transferredBuffer = TransferArrayBuffer(buffer); + if (controller._pendingPullIntos.length > 0) { + const firstPendingPullInto = controller._pendingPullIntos.peek(); + if (IsDetachedBuffer(firstPendingPullInto.buffer)) ; + firstPendingPullInto.buffer = TransferArrayBuffer(firstPendingPullInto.buffer); + } + ReadableByteStreamControllerInvalidateBYOBRequest(controller); + if (ReadableStreamHasDefaultReader(stream)) { + if (ReadableStreamGetNumReadRequests(stream) === 0) { + ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); + } else { + if (controller._pendingPullIntos.length > 0) { + ReadableByteStreamControllerShiftPendingPullInto(controller); + } + const transferredView = new Uint8Array(transferredBuffer, byteOffset, byteLength); + ReadableStreamFulfillReadRequest(stream, transferredView, false); + } + } else if (ReadableStreamHasBYOBReader(stream)) { + ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); + ReadableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(controller); + } else { + ReadableByteStreamControllerEnqueueChunkToQueue(controller, transferredBuffer, byteOffset, byteLength); + } + ReadableByteStreamControllerCallPullIfNeeded(controller); + } + function ReadableByteStreamControllerError(controller, e2) { + const stream = controller._controlledReadableByteStream; + if (stream._state !== "readable") { + return; + } + ReadableByteStreamControllerClearPendingPullIntos(controller); + ResetQueue(controller); + ReadableByteStreamControllerClearAlgorithms(controller); + ReadableStreamError(stream, e2); + } + function ReadableByteStreamControllerGetBYOBRequest(controller) { + if (controller._byobRequest === null && controller._pendingPullIntos.length > 0) { + const firstDescriptor = controller._pendingPullIntos.peek(); + const view = new Uint8Array(firstDescriptor.buffer, firstDescriptor.byteOffset + firstDescriptor.bytesFilled, firstDescriptor.byteLength - firstDescriptor.bytesFilled); + const byobRequest = Object.create(ReadableStreamBYOBRequest.prototype); + SetUpReadableStreamBYOBRequest(byobRequest, controller, view); + controller._byobRequest = byobRequest; + } + return controller._byobRequest; + } + function ReadableByteStreamControllerGetDesiredSize(controller) { + const state = controller._controlledReadableByteStream._state; + if (state === "errored") { + return null; + } + if (state === "closed") { + return 0; + } + return controller._strategyHWM - controller._queueTotalSize; + } + function ReadableByteStreamControllerRespond(controller, bytesWritten) { + const firstDescriptor = controller._pendingPullIntos.peek(); + const state = controller._controlledReadableByteStream._state; + if (state === "closed") { + if (bytesWritten !== 0) { + throw new TypeError("bytesWritten must be 0 when calling respond() on a closed stream"); + } + } else { + if (bytesWritten === 0) { + throw new TypeError("bytesWritten must be greater than 0 when calling respond() on a readable stream"); + } + if (firstDescriptor.bytesFilled + bytesWritten > firstDescriptor.byteLength) { + throw new RangeError("bytesWritten out of range"); + } + } + firstDescriptor.buffer = TransferArrayBuffer(firstDescriptor.buffer); + ReadableByteStreamControllerRespondInternal(controller, bytesWritten); + } + function ReadableByteStreamControllerRespondWithNewView(controller, view) { + const firstDescriptor = controller._pendingPullIntos.peek(); + const state = controller._controlledReadableByteStream._state; + if (state === "closed") { + if (view.byteLength !== 0) { + throw new TypeError("The view's length must be 0 when calling respondWithNewView() on a closed stream"); + } + } else { + if (view.byteLength === 0) { + throw new TypeError("The view's length must be greater than 0 when calling respondWithNewView() on a readable stream"); + } + } + if (firstDescriptor.byteOffset + firstDescriptor.bytesFilled !== view.byteOffset) { + throw new RangeError("The region specified by view does not match byobRequest"); + } + if (firstDescriptor.bufferByteLength !== view.buffer.byteLength) { + throw new RangeError("The buffer of view has different capacity than byobRequest"); + } + if (firstDescriptor.bytesFilled + view.byteLength > firstDescriptor.byteLength) { + throw new RangeError("The region specified by view is larger than byobRequest"); + } + const viewByteLength = view.byteLength; + firstDescriptor.buffer = TransferArrayBuffer(view.buffer); + ReadableByteStreamControllerRespondInternal(controller, viewByteLength); + } + function SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, autoAllocateChunkSize) { + controller._controlledReadableByteStream = stream; + controller._pullAgain = false; + controller._pulling = false; + controller._byobRequest = null; + controller._queue = controller._queueTotalSize = void 0; + ResetQueue(controller); + controller._closeRequested = false; + controller._started = false; + controller._strategyHWM = highWaterMark; + controller._pullAlgorithm = pullAlgorithm; + controller._cancelAlgorithm = cancelAlgorithm; + controller._autoAllocateChunkSize = autoAllocateChunkSize; + controller._pendingPullIntos = new SimpleQueue(); + stream._readableStreamController = controller; + const startResult = startAlgorithm(); + uponPromise(promiseResolvedWith(startResult), () => { + controller._started = true; + ReadableByteStreamControllerCallPullIfNeeded(controller); + }, (r2) => { + ReadableByteStreamControllerError(controller, r2); + }); + } + function SetUpReadableByteStreamControllerFromUnderlyingSource(stream, underlyingByteSource, highWaterMark) { + const controller = Object.create(ReadableByteStreamController.prototype); + let startAlgorithm = () => void 0; + let pullAlgorithm = () => promiseResolvedWith(void 0); + let cancelAlgorithm = () => promiseResolvedWith(void 0); + if (underlyingByteSource.start !== void 0) { + startAlgorithm = () => underlyingByteSource.start(controller); + } + if (underlyingByteSource.pull !== void 0) { + pullAlgorithm = () => underlyingByteSource.pull(controller); + } + if (underlyingByteSource.cancel !== void 0) { + cancelAlgorithm = (reason) => underlyingByteSource.cancel(reason); + } + const autoAllocateChunkSize = underlyingByteSource.autoAllocateChunkSize; + if (autoAllocateChunkSize === 0) { + throw new TypeError("autoAllocateChunkSize must be greater than 0"); + } + SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, autoAllocateChunkSize); + } + function SetUpReadableStreamBYOBRequest(request, controller, view) { + request._associatedReadableByteStreamController = controller; + request._view = view; + } + function byobRequestBrandCheckException(name) { + return new TypeError(`ReadableStreamBYOBRequest.prototype.${name} can only be used on a ReadableStreamBYOBRequest`); + } + function byteStreamControllerBrandCheckException(name) { + return new TypeError(`ReadableByteStreamController.prototype.${name} can only be used on a ReadableByteStreamController`); + } + function AcquireReadableStreamBYOBReader(stream) { + return new ReadableStreamBYOBReader(stream); + } + function ReadableStreamAddReadIntoRequest(stream, readIntoRequest) { + stream._reader._readIntoRequests.push(readIntoRequest); + } + function ReadableStreamFulfillReadIntoRequest(stream, chunk, done) { + const reader = stream._reader; + const readIntoRequest = reader._readIntoRequests.shift(); + if (done) { + readIntoRequest._closeSteps(chunk); + } else { + readIntoRequest._chunkSteps(chunk); + } + } + function ReadableStreamGetNumReadIntoRequests(stream) { + return stream._reader._readIntoRequests.length; + } + function ReadableStreamHasBYOBReader(stream) { + const reader = stream._reader; + if (reader === void 0) { + return false; + } + if (!IsReadableStreamBYOBReader(reader)) { + return false; + } + return true; + } + class ReadableStreamBYOBReader { + constructor(stream) { + assertRequiredArgument(stream, 1, "ReadableStreamBYOBReader"); + assertReadableStream(stream, "First parameter"); + if (IsReadableStreamLocked(stream)) { + throw new TypeError("This stream has already been locked for exclusive reading by another reader"); + } + if (!IsReadableByteStreamController(stream._readableStreamController)) { + throw new TypeError("Cannot construct a ReadableStreamBYOBReader for a stream not constructed with a byte source"); + } + ReadableStreamReaderGenericInitialize(this, stream); + this._readIntoRequests = new SimpleQueue(); + } + /** + * Returns a promise that will be fulfilled when the stream becomes closed, or rejected if the stream ever errors or + * the reader's lock is released before the stream finishes closing. + */ + get closed() { + if (!IsReadableStreamBYOBReader(this)) { + return promiseRejectedWith(byobReaderBrandCheckException("closed")); + } + return this._closedPromise; + } + /** + * If the reader is active, behaves the same as {@link ReadableStream.cancel | stream.cancel(reason)}. + */ + cancel(reason = void 0) { + if (!IsReadableStreamBYOBReader(this)) { + return promiseRejectedWith(byobReaderBrandCheckException("cancel")); + } + if (this._ownerReadableStream === void 0) { + return promiseRejectedWith(readerLockException("cancel")); + } + return ReadableStreamReaderGenericCancel(this, reason); + } + /** + * Attempts to reads bytes into view, and returns a promise resolved with the result. + * + * If reading a chunk causes the queue to become empty, more data will be pulled from the underlying source. + */ + read(view) { + if (!IsReadableStreamBYOBReader(this)) { + return promiseRejectedWith(byobReaderBrandCheckException("read")); + } + if (!ArrayBuffer.isView(view)) { + return promiseRejectedWith(new TypeError("view must be an array buffer view")); + } + if (view.byteLength === 0) { + return promiseRejectedWith(new TypeError("view must have non-zero byteLength")); + } + if (view.buffer.byteLength === 0) { + return promiseRejectedWith(new TypeError(`view's buffer must have non-zero byteLength`)); + } + if (IsDetachedBuffer(view.buffer)) ; + if (this._ownerReadableStream === void 0) { + return promiseRejectedWith(readerLockException("read from")); + } + let resolvePromise; + let rejectPromise; + const promise = newPromise((resolve, reject) => { + resolvePromise = resolve; + rejectPromise = reject; + }); + const readIntoRequest = { + _chunkSteps: (chunk) => resolvePromise({ value: chunk, done: false }), + _closeSteps: (chunk) => resolvePromise({ value: chunk, done: true }), + _errorSteps: (e2) => rejectPromise(e2) + }; + ReadableStreamBYOBReaderRead(this, view, readIntoRequest); + return promise; + } + /** + * Releases the reader's lock on the corresponding stream. After the lock is released, the reader is no longer active. + * If the associated stream is errored when the lock is released, the reader will appear errored in the same way + * from now on; otherwise, the reader will appear closed. + * + * A reader's lock cannot be released while it still has a pending read request, i.e., if a promise returned by + * the reader's {@link ReadableStreamBYOBReader.read | read()} method has not yet been settled. Attempting to + * do so will throw a `TypeError` and leave the reader locked to the stream. + */ + releaseLock() { + if (!IsReadableStreamBYOBReader(this)) { + throw byobReaderBrandCheckException("releaseLock"); + } + if (this._ownerReadableStream === void 0) { + return; + } + if (this._readIntoRequests.length > 0) { + throw new TypeError("Tried to release a reader lock when that reader has pending read() calls un-settled"); + } + ReadableStreamReaderGenericRelease(this); + } + } + Object.defineProperties(ReadableStreamBYOBReader.prototype, { + cancel: { enumerable: true }, + read: { enumerable: true }, + releaseLock: { enumerable: true }, + closed: { enumerable: true } + }); + if (typeof SymbolPolyfill.toStringTag === "symbol") { + Object.defineProperty(ReadableStreamBYOBReader.prototype, SymbolPolyfill.toStringTag, { + value: "ReadableStreamBYOBReader", + configurable: true + }); + } + function IsReadableStreamBYOBReader(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_readIntoRequests")) { + return false; + } + return x2 instanceof ReadableStreamBYOBReader; + } + function ReadableStreamBYOBReaderRead(reader, view, readIntoRequest) { + const stream = reader._ownerReadableStream; + stream._disturbed = true; + if (stream._state === "errored") { + readIntoRequest._errorSteps(stream._storedError); + } else { + ReadableByteStreamControllerPullInto(stream._readableStreamController, view, readIntoRequest); + } + } + function byobReaderBrandCheckException(name) { + return new TypeError(`ReadableStreamBYOBReader.prototype.${name} can only be used on a ReadableStreamBYOBReader`); + } + function ExtractHighWaterMark(strategy, defaultHWM) { + const { highWaterMark } = strategy; + if (highWaterMark === void 0) { + return defaultHWM; + } + if (NumberIsNaN(highWaterMark) || highWaterMark < 0) { + throw new RangeError("Invalid highWaterMark"); + } + return highWaterMark; + } + function ExtractSizeAlgorithm(strategy) { + const { size } = strategy; + if (!size) { + return () => 1; + } + return size; + } + function convertQueuingStrategy(init, context) { + assertDictionary(init, context); + const highWaterMark = init === null || init === void 0 ? void 0 : init.highWaterMark; + const size = init === null || init === void 0 ? void 0 : init.size; + return { + highWaterMark: highWaterMark === void 0 ? void 0 : convertUnrestrictedDouble(highWaterMark), + size: size === void 0 ? void 0 : convertQueuingStrategySize(size, `${context} has member 'size' that`) + }; + } + function convertQueuingStrategySize(fn, context) { + assertFunction(fn, context); + return (chunk) => convertUnrestrictedDouble(fn(chunk)); + } + function convertUnderlyingSink(original, context) { + assertDictionary(original, context); + const abort = original === null || original === void 0 ? void 0 : original.abort; + const close = original === null || original === void 0 ? void 0 : original.close; + const start = original === null || original === void 0 ? void 0 : original.start; + const type = original === null || original === void 0 ? void 0 : original.type; + const write = original === null || original === void 0 ? void 0 : original.write; + return { + abort: abort === void 0 ? void 0 : convertUnderlyingSinkAbortCallback(abort, original, `${context} has member 'abort' that`), + close: close === void 0 ? void 0 : convertUnderlyingSinkCloseCallback(close, original, `${context} has member 'close' that`), + start: start === void 0 ? void 0 : convertUnderlyingSinkStartCallback(start, original, `${context} has member 'start' that`), + write: write === void 0 ? void 0 : convertUnderlyingSinkWriteCallback(write, original, `${context} has member 'write' that`), + type + }; + } + function convertUnderlyingSinkAbortCallback(fn, original, context) { + assertFunction(fn, context); + return (reason) => promiseCall(fn, original, [reason]); + } + function convertUnderlyingSinkCloseCallback(fn, original, context) { + assertFunction(fn, context); + return () => promiseCall(fn, original, []); + } + function convertUnderlyingSinkStartCallback(fn, original, context) { + assertFunction(fn, context); + return (controller) => reflectCall(fn, original, [controller]); + } + function convertUnderlyingSinkWriteCallback(fn, original, context) { + assertFunction(fn, context); + return (chunk, controller) => promiseCall(fn, original, [chunk, controller]); + } + function assertWritableStream(x2, context) { + if (!IsWritableStream(x2)) { + throw new TypeError(`${context} is not a WritableStream.`); + } + } + function isAbortSignal(value) { + if (typeof value !== "object" || value === null) { + return false; + } + try { + return typeof value.aborted === "boolean"; + } catch (_a) { + return false; + } + } + const supportsAbortController = typeof AbortController === "function"; + function createAbortController() { + if (supportsAbortController) { + return new AbortController(); + } + return void 0; + } + class WritableStream { + constructor(rawUnderlyingSink = {}, rawStrategy = {}) { + if (rawUnderlyingSink === void 0) { + rawUnderlyingSink = null; + } else { + assertObject(rawUnderlyingSink, "First parameter"); + } + const strategy = convertQueuingStrategy(rawStrategy, "Second parameter"); + const underlyingSink = convertUnderlyingSink(rawUnderlyingSink, "First parameter"); + InitializeWritableStream(this); + const type = underlyingSink.type; + if (type !== void 0) { + throw new RangeError("Invalid type is specified"); + } + const sizeAlgorithm = ExtractSizeAlgorithm(strategy); + const highWaterMark = ExtractHighWaterMark(strategy, 1); + SetUpWritableStreamDefaultControllerFromUnderlyingSink(this, underlyingSink, highWaterMark, sizeAlgorithm); + } + /** + * Returns whether or not the writable stream is locked to a writer. + */ + get locked() { + if (!IsWritableStream(this)) { + throw streamBrandCheckException$2("locked"); + } + return IsWritableStreamLocked(this); + } + /** + * Aborts the stream, signaling that the producer can no longer successfully write to the stream and it is to be + * immediately moved to an errored state, with any queued-up writes discarded. This will also execute any abort + * mechanism of the underlying sink. + * + * The returned promise will fulfill if the stream shuts down successfully, or reject if the underlying sink signaled + * that there was an error doing so. Additionally, it will reject with a `TypeError` (without attempting to cancel + * the stream) if the stream is currently locked. + */ + abort(reason = void 0) { + if (!IsWritableStream(this)) { + return promiseRejectedWith(streamBrandCheckException$2("abort")); + } + if (IsWritableStreamLocked(this)) { + return promiseRejectedWith(new TypeError("Cannot abort a stream that already has a writer")); + } + return WritableStreamAbort(this, reason); + } + /** + * Closes the stream. The underlying sink will finish processing any previously-written chunks, before invoking its + * close behavior. During this time any further attempts to write will fail (without erroring the stream). + * + * The method returns a promise that will fulfill if all remaining chunks are successfully written and the stream + * successfully closes, or rejects if an error is encountered during this process. Additionally, it will reject with + * a `TypeError` (without attempting to cancel the stream) if the stream is currently locked. + */ + close() { + if (!IsWritableStream(this)) { + return promiseRejectedWith(streamBrandCheckException$2("close")); + } + if (IsWritableStreamLocked(this)) { + return promiseRejectedWith(new TypeError("Cannot close a stream that already has a writer")); + } + if (WritableStreamCloseQueuedOrInFlight(this)) { + return promiseRejectedWith(new TypeError("Cannot close an already-closing stream")); + } + return WritableStreamClose(this); + } + /** + * Creates a {@link WritableStreamDefaultWriter | writer} and locks the stream to the new writer. While the stream + * is locked, no other writer can be acquired until this one is released. + * + * This functionality is especially useful for creating abstractions that desire the ability to write to a stream + * without interruption or interleaving. By getting a writer for the stream, you can ensure nobody else can write at + * the same time, which would cause the resulting written data to be unpredictable and probably useless. + */ + getWriter() { + if (!IsWritableStream(this)) { + throw streamBrandCheckException$2("getWriter"); + } + return AcquireWritableStreamDefaultWriter(this); + } + } + Object.defineProperties(WritableStream.prototype, { + abort: { enumerable: true }, + close: { enumerable: true }, + getWriter: { enumerable: true }, + locked: { enumerable: true } + }); + if (typeof SymbolPolyfill.toStringTag === "symbol") { + Object.defineProperty(WritableStream.prototype, SymbolPolyfill.toStringTag, { + value: "WritableStream", + configurable: true + }); + } + function AcquireWritableStreamDefaultWriter(stream) { + return new WritableStreamDefaultWriter(stream); + } + function CreateWritableStream(startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark = 1, sizeAlgorithm = () => 1) { + const stream = Object.create(WritableStream.prototype); + InitializeWritableStream(stream); + const controller = Object.create(WritableStreamDefaultController.prototype); + SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm); + return stream; + } + function InitializeWritableStream(stream) { + stream._state = "writable"; + stream._storedError = void 0; + stream._writer = void 0; + stream._writableStreamController = void 0; + stream._writeRequests = new SimpleQueue(); + stream._inFlightWriteRequest = void 0; + stream._closeRequest = void 0; + stream._inFlightCloseRequest = void 0; + stream._pendingAbortRequest = void 0; + stream._backpressure = false; + } + function IsWritableStream(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_writableStreamController")) { + return false; + } + return x2 instanceof WritableStream; + } + function IsWritableStreamLocked(stream) { + if (stream._writer === void 0) { + return false; + } + return true; + } + function WritableStreamAbort(stream, reason) { + var _a; + if (stream._state === "closed" || stream._state === "errored") { + return promiseResolvedWith(void 0); + } + stream._writableStreamController._abortReason = reason; + (_a = stream._writableStreamController._abortController) === null || _a === void 0 ? void 0 : _a.abort(); + const state = stream._state; + if (state === "closed" || state === "errored") { + return promiseResolvedWith(void 0); + } + if (stream._pendingAbortRequest !== void 0) { + return stream._pendingAbortRequest._promise; + } + let wasAlreadyErroring = false; + if (state === "erroring") { + wasAlreadyErroring = true; + reason = void 0; + } + const promise = newPromise((resolve, reject) => { + stream._pendingAbortRequest = { + _promise: void 0, + _resolve: resolve, + _reject: reject, + _reason: reason, + _wasAlreadyErroring: wasAlreadyErroring + }; + }); + stream._pendingAbortRequest._promise = promise; + if (!wasAlreadyErroring) { + WritableStreamStartErroring(stream, reason); + } + return promise; + } + function WritableStreamClose(stream) { + const state = stream._state; + if (state === "closed" || state === "errored") { + return promiseRejectedWith(new TypeError(`The stream (in ${state} state) is not in the writable state and cannot be closed`)); + } + const promise = newPromise((resolve, reject) => { + const closeRequest = { + _resolve: resolve, + _reject: reject + }; + stream._closeRequest = closeRequest; + }); + const writer = stream._writer; + if (writer !== void 0 && stream._backpressure && state === "writable") { + defaultWriterReadyPromiseResolve(writer); + } + WritableStreamDefaultControllerClose(stream._writableStreamController); + return promise; + } + function WritableStreamAddWriteRequest(stream) { + const promise = newPromise((resolve, reject) => { + const writeRequest = { + _resolve: resolve, + _reject: reject + }; + stream._writeRequests.push(writeRequest); + }); + return promise; + } + function WritableStreamDealWithRejection(stream, error) { + const state = stream._state; + if (state === "writable") { + WritableStreamStartErroring(stream, error); + return; + } + WritableStreamFinishErroring(stream); + } + function WritableStreamStartErroring(stream, reason) { + const controller = stream._writableStreamController; + stream._state = "erroring"; + stream._storedError = reason; + const writer = stream._writer; + if (writer !== void 0) { + WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, reason); + } + if (!WritableStreamHasOperationMarkedInFlight(stream) && controller._started) { + WritableStreamFinishErroring(stream); + } + } + function WritableStreamFinishErroring(stream) { + stream._state = "errored"; + stream._writableStreamController[ErrorSteps](); + const storedError = stream._storedError; + stream._writeRequests.forEach((writeRequest) => { + writeRequest._reject(storedError); + }); + stream._writeRequests = new SimpleQueue(); + if (stream._pendingAbortRequest === void 0) { + WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + return; + } + const abortRequest = stream._pendingAbortRequest; + stream._pendingAbortRequest = void 0; + if (abortRequest._wasAlreadyErroring) { + abortRequest._reject(storedError); + WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + return; + } + const promise = stream._writableStreamController[AbortSteps](abortRequest._reason); + uponPromise(promise, () => { + abortRequest._resolve(); + WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + }, (reason) => { + abortRequest._reject(reason); + WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream); + }); + } + function WritableStreamFinishInFlightWrite(stream) { + stream._inFlightWriteRequest._resolve(void 0); + stream._inFlightWriteRequest = void 0; + } + function WritableStreamFinishInFlightWriteWithError(stream, error) { + stream._inFlightWriteRequest._reject(error); + stream._inFlightWriteRequest = void 0; + WritableStreamDealWithRejection(stream, error); + } + function WritableStreamFinishInFlightClose(stream) { + stream._inFlightCloseRequest._resolve(void 0); + stream._inFlightCloseRequest = void 0; + const state = stream._state; + if (state === "erroring") { + stream._storedError = void 0; + if (stream._pendingAbortRequest !== void 0) { + stream._pendingAbortRequest._resolve(); + stream._pendingAbortRequest = void 0; + } + } + stream._state = "closed"; + const writer = stream._writer; + if (writer !== void 0) { + defaultWriterClosedPromiseResolve(writer); + } + } + function WritableStreamFinishInFlightCloseWithError(stream, error) { + stream._inFlightCloseRequest._reject(error); + stream._inFlightCloseRequest = void 0; + if (stream._pendingAbortRequest !== void 0) { + stream._pendingAbortRequest._reject(error); + stream._pendingAbortRequest = void 0; + } + WritableStreamDealWithRejection(stream, error); + } + function WritableStreamCloseQueuedOrInFlight(stream) { + if (stream._closeRequest === void 0 && stream._inFlightCloseRequest === void 0) { + return false; + } + return true; + } + function WritableStreamHasOperationMarkedInFlight(stream) { + if (stream._inFlightWriteRequest === void 0 && stream._inFlightCloseRequest === void 0) { + return false; + } + return true; + } + function WritableStreamMarkCloseRequestInFlight(stream) { + stream._inFlightCloseRequest = stream._closeRequest; + stream._closeRequest = void 0; + } + function WritableStreamMarkFirstWriteRequestInFlight(stream) { + stream._inFlightWriteRequest = stream._writeRequests.shift(); + } + function WritableStreamRejectCloseAndClosedPromiseIfNeeded(stream) { + if (stream._closeRequest !== void 0) { + stream._closeRequest._reject(stream._storedError); + stream._closeRequest = void 0; + } + const writer = stream._writer; + if (writer !== void 0) { + defaultWriterClosedPromiseReject(writer, stream._storedError); + } + } + function WritableStreamUpdateBackpressure(stream, backpressure) { + const writer = stream._writer; + if (writer !== void 0 && backpressure !== stream._backpressure) { + if (backpressure) { + defaultWriterReadyPromiseReset(writer); + } else { + defaultWriterReadyPromiseResolve(writer); + } + } + stream._backpressure = backpressure; + } + class WritableStreamDefaultWriter { + constructor(stream) { + assertRequiredArgument(stream, 1, "WritableStreamDefaultWriter"); + assertWritableStream(stream, "First parameter"); + if (IsWritableStreamLocked(stream)) { + throw new TypeError("This stream has already been locked for exclusive writing by another writer"); + } + this._ownerWritableStream = stream; + stream._writer = this; + const state = stream._state; + if (state === "writable") { + if (!WritableStreamCloseQueuedOrInFlight(stream) && stream._backpressure) { + defaultWriterReadyPromiseInitialize(this); + } else { + defaultWriterReadyPromiseInitializeAsResolved(this); + } + defaultWriterClosedPromiseInitialize(this); + } else if (state === "erroring") { + defaultWriterReadyPromiseInitializeAsRejected(this, stream._storedError); + defaultWriterClosedPromiseInitialize(this); + } else if (state === "closed") { + defaultWriterReadyPromiseInitializeAsResolved(this); + defaultWriterClosedPromiseInitializeAsResolved(this); + } else { + const storedError = stream._storedError; + defaultWriterReadyPromiseInitializeAsRejected(this, storedError); + defaultWriterClosedPromiseInitializeAsRejected(this, storedError); + } + } + /** + * Returns a promise that will be fulfilled when the stream becomes closed, or rejected if the stream ever errors or + * the writer’s lock is released before the stream finishes closing. + */ + get closed() { + if (!IsWritableStreamDefaultWriter(this)) { + return promiseRejectedWith(defaultWriterBrandCheckException("closed")); + } + return this._closedPromise; + } + /** + * Returns the desired size to fill the stream’s internal queue. It can be negative, if the queue is over-full. + * A producer can use this information to determine the right amount of data to write. + * + * It will be `null` if the stream cannot be successfully written to (due to either being errored, or having an abort + * queued up). It will return zero if the stream is closed. And the getter will throw an exception if invoked when + * the writer’s lock is released. + */ + get desiredSize() { + if (!IsWritableStreamDefaultWriter(this)) { + throw defaultWriterBrandCheckException("desiredSize"); + } + if (this._ownerWritableStream === void 0) { + throw defaultWriterLockException("desiredSize"); + } + return WritableStreamDefaultWriterGetDesiredSize(this); + } + /** + * Returns a promise that will be fulfilled when the desired size to fill the stream’s internal queue transitions + * from non-positive to positive, signaling that it is no longer applying backpressure. Once the desired size dips + * back to zero or below, the getter will return a new promise that stays pending until the next transition. + * + * If the stream becomes errored or aborted, or the writer’s lock is released, the returned promise will become + * rejected. + */ + get ready() { + if (!IsWritableStreamDefaultWriter(this)) { + return promiseRejectedWith(defaultWriterBrandCheckException("ready")); + } + return this._readyPromise; + } + /** + * If the reader is active, behaves the same as {@link WritableStream.abort | stream.abort(reason)}. + */ + abort(reason = void 0) { + if (!IsWritableStreamDefaultWriter(this)) { + return promiseRejectedWith(defaultWriterBrandCheckException("abort")); + } + if (this._ownerWritableStream === void 0) { + return promiseRejectedWith(defaultWriterLockException("abort")); + } + return WritableStreamDefaultWriterAbort(this, reason); + } + /** + * If the reader is active, behaves the same as {@link WritableStream.close | stream.close()}. + */ + close() { + if (!IsWritableStreamDefaultWriter(this)) { + return promiseRejectedWith(defaultWriterBrandCheckException("close")); + } + const stream = this._ownerWritableStream; + if (stream === void 0) { + return promiseRejectedWith(defaultWriterLockException("close")); + } + if (WritableStreamCloseQueuedOrInFlight(stream)) { + return promiseRejectedWith(new TypeError("Cannot close an already-closing stream")); + } + return WritableStreamDefaultWriterClose(this); + } + /** + * Releases the writer’s lock on the corresponding stream. After the lock is released, the writer is no longer active. + * If the associated stream is errored when the lock is released, the writer will appear errored in the same way from + * now on; otherwise, the writer will appear closed. + * + * Note that the lock can still be released even if some ongoing writes have not yet finished (i.e. even if the + * promises returned from previous calls to {@link WritableStreamDefaultWriter.write | write()} have not yet settled). + * It’s not necessary to hold the lock on the writer for the duration of the write; the lock instead simply prevents + * other producers from writing in an interleaved manner. + */ + releaseLock() { + if (!IsWritableStreamDefaultWriter(this)) { + throw defaultWriterBrandCheckException("releaseLock"); + } + const stream = this._ownerWritableStream; + if (stream === void 0) { + return; + } + WritableStreamDefaultWriterRelease(this); + } + write(chunk = void 0) { + if (!IsWritableStreamDefaultWriter(this)) { + return promiseRejectedWith(defaultWriterBrandCheckException("write")); + } + if (this._ownerWritableStream === void 0) { + return promiseRejectedWith(defaultWriterLockException("write to")); + } + return WritableStreamDefaultWriterWrite(this, chunk); + } + } + Object.defineProperties(WritableStreamDefaultWriter.prototype, { + abort: { enumerable: true }, + close: { enumerable: true }, + releaseLock: { enumerable: true }, + write: { enumerable: true }, + closed: { enumerable: true }, + desiredSize: { enumerable: true }, + ready: { enumerable: true } + }); + if (typeof SymbolPolyfill.toStringTag === "symbol") { + Object.defineProperty(WritableStreamDefaultWriter.prototype, SymbolPolyfill.toStringTag, { + value: "WritableStreamDefaultWriter", + configurable: true + }); + } + function IsWritableStreamDefaultWriter(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_ownerWritableStream")) { + return false; + } + return x2 instanceof WritableStreamDefaultWriter; + } + function WritableStreamDefaultWriterAbort(writer, reason) { + const stream = writer._ownerWritableStream; + return WritableStreamAbort(stream, reason); + } + function WritableStreamDefaultWriterClose(writer) { + const stream = writer._ownerWritableStream; + return WritableStreamClose(stream); + } + function WritableStreamDefaultWriterCloseWithErrorPropagation(writer) { + const stream = writer._ownerWritableStream; + const state = stream._state; + if (WritableStreamCloseQueuedOrInFlight(stream) || state === "closed") { + return promiseResolvedWith(void 0); + } + if (state === "errored") { + return promiseRejectedWith(stream._storedError); + } + return WritableStreamDefaultWriterClose(writer); + } + function WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, error) { + if (writer._closedPromiseState === "pending") { + defaultWriterClosedPromiseReject(writer, error); + } else { + defaultWriterClosedPromiseResetToRejected(writer, error); + } + } + function WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error) { + if (writer._readyPromiseState === "pending") { + defaultWriterReadyPromiseReject(writer, error); + } else { + defaultWriterReadyPromiseResetToRejected(writer, error); + } + } + function WritableStreamDefaultWriterGetDesiredSize(writer) { + const stream = writer._ownerWritableStream; + const state = stream._state; + if (state === "errored" || state === "erroring") { + return null; + } + if (state === "closed") { + return 0; + } + return WritableStreamDefaultControllerGetDesiredSize(stream._writableStreamController); + } + function WritableStreamDefaultWriterRelease(writer) { + const stream = writer._ownerWritableStream; + const releasedError = new TypeError(`Writer was released and can no longer be used to monitor the stream's closedness`); + WritableStreamDefaultWriterEnsureReadyPromiseRejected(writer, releasedError); + WritableStreamDefaultWriterEnsureClosedPromiseRejected(writer, releasedError); + stream._writer = void 0; + writer._ownerWritableStream = void 0; + } + function WritableStreamDefaultWriterWrite(writer, chunk) { + const stream = writer._ownerWritableStream; + const controller = stream._writableStreamController; + const chunkSize = WritableStreamDefaultControllerGetChunkSize(controller, chunk); + if (stream !== writer._ownerWritableStream) { + return promiseRejectedWith(defaultWriterLockException("write to")); + } + const state = stream._state; + if (state === "errored") { + return promiseRejectedWith(stream._storedError); + } + if (WritableStreamCloseQueuedOrInFlight(stream) || state === "closed") { + return promiseRejectedWith(new TypeError("The stream is closing or closed and cannot be written to")); + } + if (state === "erroring") { + return promiseRejectedWith(stream._storedError); + } + const promise = WritableStreamAddWriteRequest(stream); + WritableStreamDefaultControllerWrite(controller, chunk, chunkSize); + return promise; + } + const closeSentinel = {}; + class WritableStreamDefaultController { + constructor() { + throw new TypeError("Illegal constructor"); + } + /** + * The reason which was passed to `WritableStream.abort(reason)` when the stream was aborted. + * + * @deprecated + * This property has been removed from the specification, see https://github.com/whatwg/streams/pull/1177. + * Use {@link WritableStreamDefaultController.signal}'s `reason` instead. + */ + get abortReason() { + if (!IsWritableStreamDefaultController(this)) { + throw defaultControllerBrandCheckException$2("abortReason"); + } + return this._abortReason; + } + /** + * An `AbortSignal` that can be used to abort the pending write or close operation when the stream is aborted. + */ + get signal() { + if (!IsWritableStreamDefaultController(this)) { + throw defaultControllerBrandCheckException$2("signal"); + } + if (this._abortController === void 0) { + throw new TypeError("WritableStreamDefaultController.prototype.signal is not supported"); + } + return this._abortController.signal; + } + /** + * Closes the controlled writable stream, making all future interactions with it fail with the given error `e`. + * + * This method is rarely used, since usually it suffices to return a rejected promise from one of the underlying + * sink's methods. However, it can be useful for suddenly shutting down a stream in response to an event outside the + * normal lifecycle of interactions with the underlying sink. + */ + error(e2 = void 0) { + if (!IsWritableStreamDefaultController(this)) { + throw defaultControllerBrandCheckException$2("error"); + } + const state = this._controlledWritableStream._state; + if (state !== "writable") { + return; + } + WritableStreamDefaultControllerError(this, e2); + } + /** @internal */ + [AbortSteps](reason) { + const result = this._abortAlgorithm(reason); + WritableStreamDefaultControllerClearAlgorithms(this); + return result; + } + /** @internal */ + [ErrorSteps]() { + ResetQueue(this); + } + } + Object.defineProperties(WritableStreamDefaultController.prototype, { + abortReason: { enumerable: true }, + signal: { enumerable: true }, + error: { enumerable: true } + }); + if (typeof SymbolPolyfill.toStringTag === "symbol") { + Object.defineProperty(WritableStreamDefaultController.prototype, SymbolPolyfill.toStringTag, { + value: "WritableStreamDefaultController", + configurable: true + }); + } + function IsWritableStreamDefaultController(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_controlledWritableStream")) { + return false; + } + return x2 instanceof WritableStreamDefaultController; + } + function SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm) { + controller._controlledWritableStream = stream; + stream._writableStreamController = controller; + controller._queue = void 0; + controller._queueTotalSize = void 0; + ResetQueue(controller); + controller._abortReason = void 0; + controller._abortController = createAbortController(); + controller._started = false; + controller._strategySizeAlgorithm = sizeAlgorithm; + controller._strategyHWM = highWaterMark; + controller._writeAlgorithm = writeAlgorithm; + controller._closeAlgorithm = closeAlgorithm; + controller._abortAlgorithm = abortAlgorithm; + const backpressure = WritableStreamDefaultControllerGetBackpressure(controller); + WritableStreamUpdateBackpressure(stream, backpressure); + const startResult = startAlgorithm(); + const startPromise = promiseResolvedWith(startResult); + uponPromise(startPromise, () => { + controller._started = true; + WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); + }, (r2) => { + controller._started = true; + WritableStreamDealWithRejection(stream, r2); + }); + } + function SetUpWritableStreamDefaultControllerFromUnderlyingSink(stream, underlyingSink, highWaterMark, sizeAlgorithm) { + const controller = Object.create(WritableStreamDefaultController.prototype); + let startAlgorithm = () => void 0; + let writeAlgorithm = () => promiseResolvedWith(void 0); + let closeAlgorithm = () => promiseResolvedWith(void 0); + let abortAlgorithm = () => promiseResolvedWith(void 0); + if (underlyingSink.start !== void 0) { + startAlgorithm = () => underlyingSink.start(controller); + } + if (underlyingSink.write !== void 0) { + writeAlgorithm = (chunk) => underlyingSink.write(chunk, controller); + } + if (underlyingSink.close !== void 0) { + closeAlgorithm = () => underlyingSink.close(); + } + if (underlyingSink.abort !== void 0) { + abortAlgorithm = (reason) => underlyingSink.abort(reason); + } + SetUpWritableStreamDefaultController(stream, controller, startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, highWaterMark, sizeAlgorithm); + } + function WritableStreamDefaultControllerClearAlgorithms(controller) { + controller._writeAlgorithm = void 0; + controller._closeAlgorithm = void 0; + controller._abortAlgorithm = void 0; + controller._strategySizeAlgorithm = void 0; + } + function WritableStreamDefaultControllerClose(controller) { + EnqueueValueWithSize(controller, closeSentinel, 0); + WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); + } + function WritableStreamDefaultControllerGetChunkSize(controller, chunk) { + try { + return controller._strategySizeAlgorithm(chunk); + } catch (chunkSizeE) { + WritableStreamDefaultControllerErrorIfNeeded(controller, chunkSizeE); + return 1; + } + } + function WritableStreamDefaultControllerGetDesiredSize(controller) { + return controller._strategyHWM - controller._queueTotalSize; + } + function WritableStreamDefaultControllerWrite(controller, chunk, chunkSize) { + try { + EnqueueValueWithSize(controller, chunk, chunkSize); + } catch (enqueueE) { + WritableStreamDefaultControllerErrorIfNeeded(controller, enqueueE); + return; + } + const stream = controller._controlledWritableStream; + if (!WritableStreamCloseQueuedOrInFlight(stream) && stream._state === "writable") { + const backpressure = WritableStreamDefaultControllerGetBackpressure(controller); + WritableStreamUpdateBackpressure(stream, backpressure); + } + WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); + } + function WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller) { + const stream = controller._controlledWritableStream; + if (!controller._started) { + return; + } + if (stream._inFlightWriteRequest !== void 0) { + return; + } + const state = stream._state; + if (state === "erroring") { + WritableStreamFinishErroring(stream); + return; + } + if (controller._queue.length === 0) { + return; + } + const value = PeekQueueValue(controller); + if (value === closeSentinel) { + WritableStreamDefaultControllerProcessClose(controller); + } else { + WritableStreamDefaultControllerProcessWrite(controller, value); + } + } + function WritableStreamDefaultControllerErrorIfNeeded(controller, error) { + if (controller._controlledWritableStream._state === "writable") { + WritableStreamDefaultControllerError(controller, error); + } + } + function WritableStreamDefaultControllerProcessClose(controller) { + const stream = controller._controlledWritableStream; + WritableStreamMarkCloseRequestInFlight(stream); + DequeueValue(controller); + const sinkClosePromise = controller._closeAlgorithm(); + WritableStreamDefaultControllerClearAlgorithms(controller); + uponPromise(sinkClosePromise, () => { + WritableStreamFinishInFlightClose(stream); + }, (reason) => { + WritableStreamFinishInFlightCloseWithError(stream, reason); + }); + } + function WritableStreamDefaultControllerProcessWrite(controller, chunk) { + const stream = controller._controlledWritableStream; + WritableStreamMarkFirstWriteRequestInFlight(stream); + const sinkWritePromise = controller._writeAlgorithm(chunk); + uponPromise(sinkWritePromise, () => { + WritableStreamFinishInFlightWrite(stream); + const state = stream._state; + DequeueValue(controller); + if (!WritableStreamCloseQueuedOrInFlight(stream) && state === "writable") { + const backpressure = WritableStreamDefaultControllerGetBackpressure(controller); + WritableStreamUpdateBackpressure(stream, backpressure); + } + WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller); + }, (reason) => { + if (stream._state === "writable") { + WritableStreamDefaultControllerClearAlgorithms(controller); + } + WritableStreamFinishInFlightWriteWithError(stream, reason); + }); + } + function WritableStreamDefaultControllerGetBackpressure(controller) { + const desiredSize = WritableStreamDefaultControllerGetDesiredSize(controller); + return desiredSize <= 0; + } + function WritableStreamDefaultControllerError(controller, error) { + const stream = controller._controlledWritableStream; + WritableStreamDefaultControllerClearAlgorithms(controller); + WritableStreamStartErroring(stream, error); + } + function streamBrandCheckException$2(name) { + return new TypeError(`WritableStream.prototype.${name} can only be used on a WritableStream`); + } + function defaultControllerBrandCheckException$2(name) { + return new TypeError(`WritableStreamDefaultController.prototype.${name} can only be used on a WritableStreamDefaultController`); + } + function defaultWriterBrandCheckException(name) { + return new TypeError(`WritableStreamDefaultWriter.prototype.${name} can only be used on a WritableStreamDefaultWriter`); + } + function defaultWriterLockException(name) { + return new TypeError("Cannot " + name + " a stream using a released writer"); + } + function defaultWriterClosedPromiseInitialize(writer) { + writer._closedPromise = newPromise((resolve, reject) => { + writer._closedPromise_resolve = resolve; + writer._closedPromise_reject = reject; + writer._closedPromiseState = "pending"; + }); + } + function defaultWriterClosedPromiseInitializeAsRejected(writer, reason) { + defaultWriterClosedPromiseInitialize(writer); + defaultWriterClosedPromiseReject(writer, reason); + } + function defaultWriterClosedPromiseInitializeAsResolved(writer) { + defaultWriterClosedPromiseInitialize(writer); + defaultWriterClosedPromiseResolve(writer); + } + function defaultWriterClosedPromiseReject(writer, reason) { + if (writer._closedPromise_reject === void 0) { + return; + } + setPromiseIsHandledToTrue(writer._closedPromise); + writer._closedPromise_reject(reason); + writer._closedPromise_resolve = void 0; + writer._closedPromise_reject = void 0; + writer._closedPromiseState = "rejected"; + } + function defaultWriterClosedPromiseResetToRejected(writer, reason) { + defaultWriterClosedPromiseInitializeAsRejected(writer, reason); + } + function defaultWriterClosedPromiseResolve(writer) { + if (writer._closedPromise_resolve === void 0) { + return; + } + writer._closedPromise_resolve(void 0); + writer._closedPromise_resolve = void 0; + writer._closedPromise_reject = void 0; + writer._closedPromiseState = "resolved"; + } + function defaultWriterReadyPromiseInitialize(writer) { + writer._readyPromise = newPromise((resolve, reject) => { + writer._readyPromise_resolve = resolve; + writer._readyPromise_reject = reject; + }); + writer._readyPromiseState = "pending"; + } + function defaultWriterReadyPromiseInitializeAsRejected(writer, reason) { + defaultWriterReadyPromiseInitialize(writer); + defaultWriterReadyPromiseReject(writer, reason); + } + function defaultWriterReadyPromiseInitializeAsResolved(writer) { + defaultWriterReadyPromiseInitialize(writer); + defaultWriterReadyPromiseResolve(writer); + } + function defaultWriterReadyPromiseReject(writer, reason) { + if (writer._readyPromise_reject === void 0) { + return; + } + setPromiseIsHandledToTrue(writer._readyPromise); + writer._readyPromise_reject(reason); + writer._readyPromise_resolve = void 0; + writer._readyPromise_reject = void 0; + writer._readyPromiseState = "rejected"; + } + function defaultWriterReadyPromiseReset(writer) { + defaultWriterReadyPromiseInitialize(writer); + } + function defaultWriterReadyPromiseResetToRejected(writer, reason) { + defaultWriterReadyPromiseInitializeAsRejected(writer, reason); + } + function defaultWriterReadyPromiseResolve(writer) { + if (writer._readyPromise_resolve === void 0) { + return; + } + writer._readyPromise_resolve(void 0); + writer._readyPromise_resolve = void 0; + writer._readyPromise_reject = void 0; + writer._readyPromiseState = "fulfilled"; + } + const NativeDOMException = typeof DOMException !== "undefined" ? DOMException : void 0; + function isDOMExceptionConstructor(ctor) { + if (!(typeof ctor === "function" || typeof ctor === "object")) { + return false; + } + try { + new ctor(); + return true; + } catch (_a) { + return false; + } + } + function createDOMExceptionPolyfill() { + const ctor = function DOMException3(message, name) { + this.message = message || ""; + this.name = name || "Error"; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + }; + ctor.prototype = Object.create(Error.prototype); + Object.defineProperty(ctor.prototype, "constructor", { value: ctor, writable: true, configurable: true }); + return ctor; + } + const DOMException$1 = isDOMExceptionConstructor(NativeDOMException) ? NativeDOMException : createDOMExceptionPolyfill(); + function ReadableStreamPipeTo(source, dest, preventClose, preventAbort, preventCancel, signal) { + const reader = AcquireReadableStreamDefaultReader(source); + const writer = AcquireWritableStreamDefaultWriter(dest); + source._disturbed = true; + let shuttingDown = false; + let currentWrite = promiseResolvedWith(void 0); + return newPromise((resolve, reject) => { + let abortAlgorithm; + if (signal !== void 0) { + abortAlgorithm = () => { + const error = new DOMException$1("Aborted", "AbortError"); + const actions = []; + if (!preventAbort) { + actions.push(() => { + if (dest._state === "writable") { + return WritableStreamAbort(dest, error); + } + return promiseResolvedWith(void 0); + }); + } + if (!preventCancel) { + actions.push(() => { + if (source._state === "readable") { + return ReadableStreamCancel(source, error); + } + return promiseResolvedWith(void 0); + }); + } + shutdownWithAction(() => Promise.all(actions.map((action) => action())), true, error); + }; + if (signal.aborted) { + abortAlgorithm(); + return; + } + signal.addEventListener("abort", abortAlgorithm); + } + function pipeLoop() { + return newPromise((resolveLoop, rejectLoop) => { + function next(done) { + if (done) { + resolveLoop(); + } else { + PerformPromiseThen(pipeStep(), next, rejectLoop); + } + } + next(false); + }); + } + function pipeStep() { + if (shuttingDown) { + return promiseResolvedWith(true); + } + return PerformPromiseThen(writer._readyPromise, () => { + return newPromise((resolveRead, rejectRead) => { + ReadableStreamDefaultReaderRead(reader, { + _chunkSteps: (chunk) => { + currentWrite = PerformPromiseThen(WritableStreamDefaultWriterWrite(writer, chunk), void 0, noop); + resolveRead(false); + }, + _closeSteps: () => resolveRead(true), + _errorSteps: rejectRead + }); + }); + }); + } + isOrBecomesErrored(source, reader._closedPromise, (storedError) => { + if (!preventAbort) { + shutdownWithAction(() => WritableStreamAbort(dest, storedError), true, storedError); + } else { + shutdown(true, storedError); + } + }); + isOrBecomesErrored(dest, writer._closedPromise, (storedError) => { + if (!preventCancel) { + shutdownWithAction(() => ReadableStreamCancel(source, storedError), true, storedError); + } else { + shutdown(true, storedError); + } + }); + isOrBecomesClosed(source, reader._closedPromise, () => { + if (!preventClose) { + shutdownWithAction(() => WritableStreamDefaultWriterCloseWithErrorPropagation(writer)); + } else { + shutdown(); + } + }); + if (WritableStreamCloseQueuedOrInFlight(dest) || dest._state === "closed") { + const destClosed = new TypeError("the destination writable stream closed before all data could be piped to it"); + if (!preventCancel) { + shutdownWithAction(() => ReadableStreamCancel(source, destClosed), true, destClosed); + } else { + shutdown(true, destClosed); + } + } + setPromiseIsHandledToTrue(pipeLoop()); + function waitForWritesToFinish() { + const oldCurrentWrite = currentWrite; + return PerformPromiseThen(currentWrite, () => oldCurrentWrite !== currentWrite ? waitForWritesToFinish() : void 0); + } + function isOrBecomesErrored(stream, promise, action) { + if (stream._state === "errored") { + action(stream._storedError); + } else { + uponRejection(promise, action); + } + } + function isOrBecomesClosed(stream, promise, action) { + if (stream._state === "closed") { + action(); + } else { + uponFulfillment(promise, action); + } + } + function shutdownWithAction(action, originalIsError, originalError) { + if (shuttingDown) { + return; + } + shuttingDown = true; + if (dest._state === "writable" && !WritableStreamCloseQueuedOrInFlight(dest)) { + uponFulfillment(waitForWritesToFinish(), doTheRest); + } else { + doTheRest(); + } + function doTheRest() { + uponPromise(action(), () => finalize(originalIsError, originalError), (newError) => finalize(true, newError)); + } + } + function shutdown(isError, error) { + if (shuttingDown) { + return; + } + shuttingDown = true; + if (dest._state === "writable" && !WritableStreamCloseQueuedOrInFlight(dest)) { + uponFulfillment(waitForWritesToFinish(), () => finalize(isError, error)); + } else { + finalize(isError, error); + } + } + function finalize(isError, error) { + WritableStreamDefaultWriterRelease(writer); + ReadableStreamReaderGenericRelease(reader); + if (signal !== void 0) { + signal.removeEventListener("abort", abortAlgorithm); + } + if (isError) { + reject(error); + } else { + resolve(void 0); + } + } + }); + } + class ReadableStreamDefaultController { + constructor() { + throw new TypeError("Illegal constructor"); + } + /** + * Returns the desired size to fill the controlled stream's internal queue. It can be negative, if the queue is + * over-full. An underlying source ought to use this information to determine when and how to apply backpressure. + */ + get desiredSize() { + if (!IsReadableStreamDefaultController(this)) { + throw defaultControllerBrandCheckException$1("desiredSize"); + } + return ReadableStreamDefaultControllerGetDesiredSize(this); + } + /** + * Closes the controlled readable stream. Consumers will still be able to read any previously-enqueued chunks from + * the stream, but once those are read, the stream will become closed. + */ + close() { + if (!IsReadableStreamDefaultController(this)) { + throw defaultControllerBrandCheckException$1("close"); + } + if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(this)) { + throw new TypeError("The stream is not in a state that permits close"); + } + ReadableStreamDefaultControllerClose(this); + } + enqueue(chunk = void 0) { + if (!IsReadableStreamDefaultController(this)) { + throw defaultControllerBrandCheckException$1("enqueue"); + } + if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(this)) { + throw new TypeError("The stream is not in a state that permits enqueue"); + } + return ReadableStreamDefaultControllerEnqueue(this, chunk); + } + /** + * Errors the controlled readable stream, making all future interactions with it fail with the given error `e`. + */ + error(e2 = void 0) { + if (!IsReadableStreamDefaultController(this)) { + throw defaultControllerBrandCheckException$1("error"); + } + ReadableStreamDefaultControllerError(this, e2); + } + /** @internal */ + [CancelSteps](reason) { + ResetQueue(this); + const result = this._cancelAlgorithm(reason); + ReadableStreamDefaultControllerClearAlgorithms(this); + return result; + } + /** @internal */ + [PullSteps](readRequest) { + const stream = this._controlledReadableStream; + if (this._queue.length > 0) { + const chunk = DequeueValue(this); + if (this._closeRequested && this._queue.length === 0) { + ReadableStreamDefaultControllerClearAlgorithms(this); + ReadableStreamClose(stream); + } else { + ReadableStreamDefaultControllerCallPullIfNeeded(this); + } + readRequest._chunkSteps(chunk); + } else { + ReadableStreamAddReadRequest(stream, readRequest); + ReadableStreamDefaultControllerCallPullIfNeeded(this); + } + } + } + Object.defineProperties(ReadableStreamDefaultController.prototype, { + close: { enumerable: true }, + enqueue: { enumerable: true }, + error: { enumerable: true }, + desiredSize: { enumerable: true } + }); + if (typeof SymbolPolyfill.toStringTag === "symbol") { + Object.defineProperty(ReadableStreamDefaultController.prototype, SymbolPolyfill.toStringTag, { + value: "ReadableStreamDefaultController", + configurable: true + }); + } + function IsReadableStreamDefaultController(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_controlledReadableStream")) { + return false; + } + return x2 instanceof ReadableStreamDefaultController; + } + function ReadableStreamDefaultControllerCallPullIfNeeded(controller) { + const shouldPull = ReadableStreamDefaultControllerShouldCallPull(controller); + if (!shouldPull) { + return; + } + if (controller._pulling) { + controller._pullAgain = true; + return; + } + controller._pulling = true; + const pullPromise = controller._pullAlgorithm(); + uponPromise(pullPromise, () => { + controller._pulling = false; + if (controller._pullAgain) { + controller._pullAgain = false; + ReadableStreamDefaultControllerCallPullIfNeeded(controller); + } + }, (e2) => { + ReadableStreamDefaultControllerError(controller, e2); + }); + } + function ReadableStreamDefaultControllerShouldCallPull(controller) { + const stream = controller._controlledReadableStream; + if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(controller)) { + return false; + } + if (!controller._started) { + return false; + } + if (IsReadableStreamLocked(stream) && ReadableStreamGetNumReadRequests(stream) > 0) { + return true; + } + const desiredSize = ReadableStreamDefaultControllerGetDesiredSize(controller); + if (desiredSize > 0) { + return true; + } + return false; + } + function ReadableStreamDefaultControllerClearAlgorithms(controller) { + controller._pullAlgorithm = void 0; + controller._cancelAlgorithm = void 0; + controller._strategySizeAlgorithm = void 0; + } + function ReadableStreamDefaultControllerClose(controller) { + if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(controller)) { + return; + } + const stream = controller._controlledReadableStream; + controller._closeRequested = true; + if (controller._queue.length === 0) { + ReadableStreamDefaultControllerClearAlgorithms(controller); + ReadableStreamClose(stream); + } + } + function ReadableStreamDefaultControllerEnqueue(controller, chunk) { + if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(controller)) { + return; + } + const stream = controller._controlledReadableStream; + if (IsReadableStreamLocked(stream) && ReadableStreamGetNumReadRequests(stream) > 0) { + ReadableStreamFulfillReadRequest(stream, chunk, false); + } else { + let chunkSize; + try { + chunkSize = controller._strategySizeAlgorithm(chunk); + } catch (chunkSizeE) { + ReadableStreamDefaultControllerError(controller, chunkSizeE); + throw chunkSizeE; + } + try { + EnqueueValueWithSize(controller, chunk, chunkSize); + } catch (enqueueE) { + ReadableStreamDefaultControllerError(controller, enqueueE); + throw enqueueE; + } + } + ReadableStreamDefaultControllerCallPullIfNeeded(controller); + } + function ReadableStreamDefaultControllerError(controller, e2) { + const stream = controller._controlledReadableStream; + if (stream._state !== "readable") { + return; + } + ResetQueue(controller); + ReadableStreamDefaultControllerClearAlgorithms(controller); + ReadableStreamError(stream, e2); + } + function ReadableStreamDefaultControllerGetDesiredSize(controller) { + const state = controller._controlledReadableStream._state; + if (state === "errored") { + return null; + } + if (state === "closed") { + return 0; + } + return controller._strategyHWM - controller._queueTotalSize; + } + function ReadableStreamDefaultControllerHasBackpressure(controller) { + if (ReadableStreamDefaultControllerShouldCallPull(controller)) { + return false; + } + return true; + } + function ReadableStreamDefaultControllerCanCloseOrEnqueue(controller) { + const state = controller._controlledReadableStream._state; + if (!controller._closeRequested && state === "readable") { + return true; + } + return false; + } + function SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm) { + controller._controlledReadableStream = stream; + controller._queue = void 0; + controller._queueTotalSize = void 0; + ResetQueue(controller); + controller._started = false; + controller._closeRequested = false; + controller._pullAgain = false; + controller._pulling = false; + controller._strategySizeAlgorithm = sizeAlgorithm; + controller._strategyHWM = highWaterMark; + controller._pullAlgorithm = pullAlgorithm; + controller._cancelAlgorithm = cancelAlgorithm; + stream._readableStreamController = controller; + const startResult = startAlgorithm(); + uponPromise(promiseResolvedWith(startResult), () => { + controller._started = true; + ReadableStreamDefaultControllerCallPullIfNeeded(controller); + }, (r2) => { + ReadableStreamDefaultControllerError(controller, r2); + }); + } + function SetUpReadableStreamDefaultControllerFromUnderlyingSource(stream, underlyingSource, highWaterMark, sizeAlgorithm) { + const controller = Object.create(ReadableStreamDefaultController.prototype); + let startAlgorithm = () => void 0; + let pullAlgorithm = () => promiseResolvedWith(void 0); + let cancelAlgorithm = () => promiseResolvedWith(void 0); + if (underlyingSource.start !== void 0) { + startAlgorithm = () => underlyingSource.start(controller); + } + if (underlyingSource.pull !== void 0) { + pullAlgorithm = () => underlyingSource.pull(controller); + } + if (underlyingSource.cancel !== void 0) { + cancelAlgorithm = (reason) => underlyingSource.cancel(reason); + } + SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm); + } + function defaultControllerBrandCheckException$1(name) { + return new TypeError(`ReadableStreamDefaultController.prototype.${name} can only be used on a ReadableStreamDefaultController`); + } + function ReadableStreamTee(stream, cloneForBranch2) { + if (IsReadableByteStreamController(stream._readableStreamController)) { + return ReadableByteStreamTee(stream); + } + return ReadableStreamDefaultTee(stream); + } + function ReadableStreamDefaultTee(stream, cloneForBranch2) { + const reader = AcquireReadableStreamDefaultReader(stream); + let reading = false; + let readAgain = false; + let canceled1 = false; + let canceled2 = false; + let reason1; + let reason2; + let branch1; + let branch2; + let resolveCancelPromise; + const cancelPromise = newPromise((resolve) => { + resolveCancelPromise = resolve; + }); + function pullAlgorithm() { + if (reading) { + readAgain = true; + return promiseResolvedWith(void 0); + } + reading = true; + const readRequest = { + _chunkSteps: (chunk) => { + queueMicrotask(() => { + readAgain = false; + const chunk1 = chunk; + const chunk2 = chunk; + if (!canceled1) { + ReadableStreamDefaultControllerEnqueue(branch1._readableStreamController, chunk1); + } + if (!canceled2) { + ReadableStreamDefaultControllerEnqueue(branch2._readableStreamController, chunk2); + } + reading = false; + if (readAgain) { + pullAlgorithm(); + } + }); + }, + _closeSteps: () => { + reading = false; + if (!canceled1) { + ReadableStreamDefaultControllerClose(branch1._readableStreamController); + } + if (!canceled2) { + ReadableStreamDefaultControllerClose(branch2._readableStreamController); + } + if (!canceled1 || !canceled2) { + resolveCancelPromise(void 0); + } + }, + _errorSteps: () => { + reading = false; + } + }; + ReadableStreamDefaultReaderRead(reader, readRequest); + return promiseResolvedWith(void 0); + } + function cancel1Algorithm(reason) { + canceled1 = true; + reason1 = reason; + if (canceled2) { + const compositeReason = CreateArrayFromList([reason1, reason2]); + const cancelResult = ReadableStreamCancel(stream, compositeReason); + resolveCancelPromise(cancelResult); + } + return cancelPromise; + } + function cancel2Algorithm(reason) { + canceled2 = true; + reason2 = reason; + if (canceled1) { + const compositeReason = CreateArrayFromList([reason1, reason2]); + const cancelResult = ReadableStreamCancel(stream, compositeReason); + resolveCancelPromise(cancelResult); + } + return cancelPromise; + } + function startAlgorithm() { + } + branch1 = CreateReadableStream(startAlgorithm, pullAlgorithm, cancel1Algorithm); + branch2 = CreateReadableStream(startAlgorithm, pullAlgorithm, cancel2Algorithm); + uponRejection(reader._closedPromise, (r2) => { + ReadableStreamDefaultControllerError(branch1._readableStreamController, r2); + ReadableStreamDefaultControllerError(branch2._readableStreamController, r2); + if (!canceled1 || !canceled2) { + resolveCancelPromise(void 0); + } + }); + return [branch1, branch2]; + } + function ReadableByteStreamTee(stream) { + let reader = AcquireReadableStreamDefaultReader(stream); + let reading = false; + let readAgainForBranch1 = false; + let readAgainForBranch2 = false; + let canceled1 = false; + let canceled2 = false; + let reason1; + let reason2; + let branch1; + let branch2; + let resolveCancelPromise; + const cancelPromise = newPromise((resolve) => { + resolveCancelPromise = resolve; + }); + function forwardReaderError(thisReader) { + uponRejection(thisReader._closedPromise, (r2) => { + if (thisReader !== reader) { + return; + } + ReadableByteStreamControllerError(branch1._readableStreamController, r2); + ReadableByteStreamControllerError(branch2._readableStreamController, r2); + if (!canceled1 || !canceled2) { + resolveCancelPromise(void 0); + } + }); + } + function pullWithDefaultReader() { + if (IsReadableStreamBYOBReader(reader)) { + ReadableStreamReaderGenericRelease(reader); + reader = AcquireReadableStreamDefaultReader(stream); + forwardReaderError(reader); + } + const readRequest = { + _chunkSteps: (chunk) => { + queueMicrotask(() => { + readAgainForBranch1 = false; + readAgainForBranch2 = false; + const chunk1 = chunk; + let chunk2 = chunk; + if (!canceled1 && !canceled2) { + try { + chunk2 = CloneAsUint8Array(chunk); + } catch (cloneE) { + ReadableByteStreamControllerError(branch1._readableStreamController, cloneE); + ReadableByteStreamControllerError(branch2._readableStreamController, cloneE); + resolveCancelPromise(ReadableStreamCancel(stream, cloneE)); + return; + } + } + if (!canceled1) { + ReadableByteStreamControllerEnqueue(branch1._readableStreamController, chunk1); + } + if (!canceled2) { + ReadableByteStreamControllerEnqueue(branch2._readableStreamController, chunk2); + } + reading = false; + if (readAgainForBranch1) { + pull1Algorithm(); + } else if (readAgainForBranch2) { + pull2Algorithm(); + } + }); + }, + _closeSteps: () => { + reading = false; + if (!canceled1) { + ReadableByteStreamControllerClose(branch1._readableStreamController); + } + if (!canceled2) { + ReadableByteStreamControllerClose(branch2._readableStreamController); + } + if (branch1._readableStreamController._pendingPullIntos.length > 0) { + ReadableByteStreamControllerRespond(branch1._readableStreamController, 0); + } + if (branch2._readableStreamController._pendingPullIntos.length > 0) { + ReadableByteStreamControllerRespond(branch2._readableStreamController, 0); + } + if (!canceled1 || !canceled2) { + resolveCancelPromise(void 0); + } + }, + _errorSteps: () => { + reading = false; + } + }; + ReadableStreamDefaultReaderRead(reader, readRequest); + } + function pullWithBYOBReader(view, forBranch2) { + if (IsReadableStreamDefaultReader(reader)) { + ReadableStreamReaderGenericRelease(reader); + reader = AcquireReadableStreamBYOBReader(stream); + forwardReaderError(reader); + } + const byobBranch = forBranch2 ? branch2 : branch1; + const otherBranch = forBranch2 ? branch1 : branch2; + const readIntoRequest = { + _chunkSteps: (chunk) => { + queueMicrotask(() => { + readAgainForBranch1 = false; + readAgainForBranch2 = false; + const byobCanceled = forBranch2 ? canceled2 : canceled1; + const otherCanceled = forBranch2 ? canceled1 : canceled2; + if (!otherCanceled) { + let clonedChunk; + try { + clonedChunk = CloneAsUint8Array(chunk); + } catch (cloneE) { + ReadableByteStreamControllerError(byobBranch._readableStreamController, cloneE); + ReadableByteStreamControllerError(otherBranch._readableStreamController, cloneE); + resolveCancelPromise(ReadableStreamCancel(stream, cloneE)); + return; + } + if (!byobCanceled) { + ReadableByteStreamControllerRespondWithNewView(byobBranch._readableStreamController, chunk); + } + ReadableByteStreamControllerEnqueue(otherBranch._readableStreamController, clonedChunk); + } else if (!byobCanceled) { + ReadableByteStreamControllerRespondWithNewView(byobBranch._readableStreamController, chunk); + } + reading = false; + if (readAgainForBranch1) { + pull1Algorithm(); + } else if (readAgainForBranch2) { + pull2Algorithm(); + } + }); + }, + _closeSteps: (chunk) => { + reading = false; + const byobCanceled = forBranch2 ? canceled2 : canceled1; + const otherCanceled = forBranch2 ? canceled1 : canceled2; + if (!byobCanceled) { + ReadableByteStreamControllerClose(byobBranch._readableStreamController); + } + if (!otherCanceled) { + ReadableByteStreamControllerClose(otherBranch._readableStreamController); + } + if (chunk !== void 0) { + if (!byobCanceled) { + ReadableByteStreamControllerRespondWithNewView(byobBranch._readableStreamController, chunk); + } + if (!otherCanceled && otherBranch._readableStreamController._pendingPullIntos.length > 0) { + ReadableByteStreamControllerRespond(otherBranch._readableStreamController, 0); + } + } + if (!byobCanceled || !otherCanceled) { + resolveCancelPromise(void 0); + } + }, + _errorSteps: () => { + reading = false; + } + }; + ReadableStreamBYOBReaderRead(reader, view, readIntoRequest); + } + function pull1Algorithm() { + if (reading) { + readAgainForBranch1 = true; + return promiseResolvedWith(void 0); + } + reading = true; + const byobRequest = ReadableByteStreamControllerGetBYOBRequest(branch1._readableStreamController); + if (byobRequest === null) { + pullWithDefaultReader(); + } else { + pullWithBYOBReader(byobRequest._view, false); + } + return promiseResolvedWith(void 0); + } + function pull2Algorithm() { + if (reading) { + readAgainForBranch2 = true; + return promiseResolvedWith(void 0); + } + reading = true; + const byobRequest = ReadableByteStreamControllerGetBYOBRequest(branch2._readableStreamController); + if (byobRequest === null) { + pullWithDefaultReader(); + } else { + pullWithBYOBReader(byobRequest._view, true); + } + return promiseResolvedWith(void 0); + } + function cancel1Algorithm(reason) { + canceled1 = true; + reason1 = reason; + if (canceled2) { + const compositeReason = CreateArrayFromList([reason1, reason2]); + const cancelResult = ReadableStreamCancel(stream, compositeReason); + resolveCancelPromise(cancelResult); + } + return cancelPromise; + } + function cancel2Algorithm(reason) { + canceled2 = true; + reason2 = reason; + if (canceled1) { + const compositeReason = CreateArrayFromList([reason1, reason2]); + const cancelResult = ReadableStreamCancel(stream, compositeReason); + resolveCancelPromise(cancelResult); + } + return cancelPromise; + } + function startAlgorithm() { + return; + } + branch1 = CreateReadableByteStream(startAlgorithm, pull1Algorithm, cancel1Algorithm); + branch2 = CreateReadableByteStream(startAlgorithm, pull2Algorithm, cancel2Algorithm); + forwardReaderError(reader); + return [branch1, branch2]; + } + function convertUnderlyingDefaultOrByteSource(source, context) { + assertDictionary(source, context); + const original = source; + const autoAllocateChunkSize = original === null || original === void 0 ? void 0 : original.autoAllocateChunkSize; + const cancel = original === null || original === void 0 ? void 0 : original.cancel; + const pull = original === null || original === void 0 ? void 0 : original.pull; + const start = original === null || original === void 0 ? void 0 : original.start; + const type = original === null || original === void 0 ? void 0 : original.type; + return { + autoAllocateChunkSize: autoAllocateChunkSize === void 0 ? void 0 : convertUnsignedLongLongWithEnforceRange(autoAllocateChunkSize, `${context} has member 'autoAllocateChunkSize' that`), + cancel: cancel === void 0 ? void 0 : convertUnderlyingSourceCancelCallback(cancel, original, `${context} has member 'cancel' that`), + pull: pull === void 0 ? void 0 : convertUnderlyingSourcePullCallback(pull, original, `${context} has member 'pull' that`), + start: start === void 0 ? void 0 : convertUnderlyingSourceStartCallback(start, original, `${context} has member 'start' that`), + type: type === void 0 ? void 0 : convertReadableStreamType(type, `${context} has member 'type' that`) + }; + } + function convertUnderlyingSourceCancelCallback(fn, original, context) { + assertFunction(fn, context); + return (reason) => promiseCall(fn, original, [reason]); + } + function convertUnderlyingSourcePullCallback(fn, original, context) { + assertFunction(fn, context); + return (controller) => promiseCall(fn, original, [controller]); + } + function convertUnderlyingSourceStartCallback(fn, original, context) { + assertFunction(fn, context); + return (controller) => reflectCall(fn, original, [controller]); + } + function convertReadableStreamType(type, context) { + type = `${type}`; + if (type !== "bytes") { + throw new TypeError(`${context} '${type}' is not a valid enumeration value for ReadableStreamType`); + } + return type; + } + function convertReaderOptions(options, context) { + assertDictionary(options, context); + const mode = options === null || options === void 0 ? void 0 : options.mode; + return { + mode: mode === void 0 ? void 0 : convertReadableStreamReaderMode(mode, `${context} has member 'mode' that`) + }; + } + function convertReadableStreamReaderMode(mode, context) { + mode = `${mode}`; + if (mode !== "byob") { + throw new TypeError(`${context} '${mode}' is not a valid enumeration value for ReadableStreamReaderMode`); + } + return mode; + } + function convertIteratorOptions(options, context) { + assertDictionary(options, context); + const preventCancel = options === null || options === void 0 ? void 0 : options.preventCancel; + return { preventCancel: Boolean(preventCancel) }; + } + function convertPipeOptions(options, context) { + assertDictionary(options, context); + const preventAbort = options === null || options === void 0 ? void 0 : options.preventAbort; + const preventCancel = options === null || options === void 0 ? void 0 : options.preventCancel; + const preventClose = options === null || options === void 0 ? void 0 : options.preventClose; + const signal = options === null || options === void 0 ? void 0 : options.signal; + if (signal !== void 0) { + assertAbortSignal(signal, `${context} has member 'signal' that`); + } + return { + preventAbort: Boolean(preventAbort), + preventCancel: Boolean(preventCancel), + preventClose: Boolean(preventClose), + signal + }; + } + function assertAbortSignal(signal, context) { + if (!isAbortSignal(signal)) { + throw new TypeError(`${context} is not an AbortSignal.`); + } + } + function convertReadableWritablePair(pair, context) { + assertDictionary(pair, context); + const readable = pair === null || pair === void 0 ? void 0 : pair.readable; + assertRequiredField(readable, "readable", "ReadableWritablePair"); + assertReadableStream(readable, `${context} has member 'readable' that`); + const writable = pair === null || pair === void 0 ? void 0 : pair.writable; + assertRequiredField(writable, "writable", "ReadableWritablePair"); + assertWritableStream(writable, `${context} has member 'writable' that`); + return { readable, writable }; + } + class ReadableStream2 { + constructor(rawUnderlyingSource = {}, rawStrategy = {}) { + if (rawUnderlyingSource === void 0) { + rawUnderlyingSource = null; + } else { + assertObject(rawUnderlyingSource, "First parameter"); + } + const strategy = convertQueuingStrategy(rawStrategy, "Second parameter"); + const underlyingSource = convertUnderlyingDefaultOrByteSource(rawUnderlyingSource, "First parameter"); + InitializeReadableStream(this); + if (underlyingSource.type === "bytes") { + if (strategy.size !== void 0) { + throw new RangeError("The strategy for a byte stream cannot have a size function"); + } + const highWaterMark = ExtractHighWaterMark(strategy, 0); + SetUpReadableByteStreamControllerFromUnderlyingSource(this, underlyingSource, highWaterMark); + } else { + const sizeAlgorithm = ExtractSizeAlgorithm(strategy); + const highWaterMark = ExtractHighWaterMark(strategy, 1); + SetUpReadableStreamDefaultControllerFromUnderlyingSource(this, underlyingSource, highWaterMark, sizeAlgorithm); + } + } + /** + * Whether or not the readable stream is locked to a {@link ReadableStreamDefaultReader | reader}. + */ + get locked() { + if (!IsReadableStream(this)) { + throw streamBrandCheckException$1("locked"); + } + return IsReadableStreamLocked(this); + } + /** + * Cancels the stream, signaling a loss of interest in the stream by a consumer. + * + * The supplied `reason` argument will be given to the underlying source's {@link UnderlyingSource.cancel | cancel()} + * method, which might or might not use it. + */ + cancel(reason = void 0) { + if (!IsReadableStream(this)) { + return promiseRejectedWith(streamBrandCheckException$1("cancel")); + } + if (IsReadableStreamLocked(this)) { + return promiseRejectedWith(new TypeError("Cannot cancel a stream that already has a reader")); + } + return ReadableStreamCancel(this, reason); + } + getReader(rawOptions = void 0) { + if (!IsReadableStream(this)) { + throw streamBrandCheckException$1("getReader"); + } + const options = convertReaderOptions(rawOptions, "First parameter"); + if (options.mode === void 0) { + return AcquireReadableStreamDefaultReader(this); + } + return AcquireReadableStreamBYOBReader(this); + } + pipeThrough(rawTransform, rawOptions = {}) { + if (!IsReadableStream(this)) { + throw streamBrandCheckException$1("pipeThrough"); + } + assertRequiredArgument(rawTransform, 1, "pipeThrough"); + const transform = convertReadableWritablePair(rawTransform, "First parameter"); + const options = convertPipeOptions(rawOptions, "Second parameter"); + if (IsReadableStreamLocked(this)) { + throw new TypeError("ReadableStream.prototype.pipeThrough cannot be used on a locked ReadableStream"); + } + if (IsWritableStreamLocked(transform.writable)) { + throw new TypeError("ReadableStream.prototype.pipeThrough cannot be used on a locked WritableStream"); + } + const promise = ReadableStreamPipeTo(this, transform.writable, options.preventClose, options.preventAbort, options.preventCancel, options.signal); + setPromiseIsHandledToTrue(promise); + return transform.readable; + } + pipeTo(destination, rawOptions = {}) { + if (!IsReadableStream(this)) { + return promiseRejectedWith(streamBrandCheckException$1("pipeTo")); + } + if (destination === void 0) { + return promiseRejectedWith(`Parameter 1 is required in 'pipeTo'.`); + } + if (!IsWritableStream(destination)) { + return promiseRejectedWith(new TypeError(`ReadableStream.prototype.pipeTo's first argument must be a WritableStream`)); + } + let options; + try { + options = convertPipeOptions(rawOptions, "Second parameter"); + } catch (e2) { + return promiseRejectedWith(e2); + } + if (IsReadableStreamLocked(this)) { + return promiseRejectedWith(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked ReadableStream")); + } + if (IsWritableStreamLocked(destination)) { + return promiseRejectedWith(new TypeError("ReadableStream.prototype.pipeTo cannot be used on a locked WritableStream")); + } + return ReadableStreamPipeTo(this, destination, options.preventClose, options.preventAbort, options.preventCancel, options.signal); + } + /** + * Tees this readable stream, returning a two-element array containing the two resulting branches as + * new {@link ReadableStream} instances. + * + * Teeing a stream will lock it, preventing any other consumer from acquiring a reader. + * To cancel the stream, cancel both of the resulting branches; a composite cancellation reason will then be + * propagated to the stream's underlying source. + * + * Note that the chunks seen in each branch will be the same object. If the chunks are not immutable, + * this could allow interference between the two branches. + */ + tee() { + if (!IsReadableStream(this)) { + throw streamBrandCheckException$1("tee"); + } + const branches = ReadableStreamTee(this); + return CreateArrayFromList(branches); + } + values(rawOptions = void 0) { + if (!IsReadableStream(this)) { + throw streamBrandCheckException$1("values"); + } + const options = convertIteratorOptions(rawOptions, "First parameter"); + return AcquireReadableStreamAsyncIterator(this, options.preventCancel); + } + } + Object.defineProperties(ReadableStream2.prototype, { + cancel: { enumerable: true }, + getReader: { enumerable: true }, + pipeThrough: { enumerable: true }, + pipeTo: { enumerable: true }, + tee: { enumerable: true }, + values: { enumerable: true }, + locked: { enumerable: true } + }); + if (typeof SymbolPolyfill.toStringTag === "symbol") { + Object.defineProperty(ReadableStream2.prototype, SymbolPolyfill.toStringTag, { + value: "ReadableStream", + configurable: true + }); + } + if (typeof SymbolPolyfill.asyncIterator === "symbol") { + Object.defineProperty(ReadableStream2.prototype, SymbolPolyfill.asyncIterator, { + value: ReadableStream2.prototype.values, + writable: true, + configurable: true + }); + } + function CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark = 1, sizeAlgorithm = () => 1) { + const stream = Object.create(ReadableStream2.prototype); + InitializeReadableStream(stream); + const controller = Object.create(ReadableStreamDefaultController.prototype); + SetUpReadableStreamDefaultController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, highWaterMark, sizeAlgorithm); + return stream; + } + function CreateReadableByteStream(startAlgorithm, pullAlgorithm, cancelAlgorithm) { + const stream = Object.create(ReadableStream2.prototype); + InitializeReadableStream(stream); + const controller = Object.create(ReadableByteStreamController.prototype); + SetUpReadableByteStreamController(stream, controller, startAlgorithm, pullAlgorithm, cancelAlgorithm, 0, void 0); + return stream; + } + function InitializeReadableStream(stream) { + stream._state = "readable"; + stream._reader = void 0; + stream._storedError = void 0; + stream._disturbed = false; + } + function IsReadableStream(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_readableStreamController")) { + return false; + } + return x2 instanceof ReadableStream2; + } + function IsReadableStreamLocked(stream) { + if (stream._reader === void 0) { + return false; + } + return true; + } + function ReadableStreamCancel(stream, reason) { + stream._disturbed = true; + if (stream._state === "closed") { + return promiseResolvedWith(void 0); + } + if (stream._state === "errored") { + return promiseRejectedWith(stream._storedError); + } + ReadableStreamClose(stream); + const reader = stream._reader; + if (reader !== void 0 && IsReadableStreamBYOBReader(reader)) { + reader._readIntoRequests.forEach((readIntoRequest) => { + readIntoRequest._closeSteps(void 0); + }); + reader._readIntoRequests = new SimpleQueue(); + } + const sourceCancelPromise = stream._readableStreamController[CancelSteps](reason); + return transformPromiseWith(sourceCancelPromise, noop); + } + function ReadableStreamClose(stream) { + stream._state = "closed"; + const reader = stream._reader; + if (reader === void 0) { + return; + } + defaultReaderClosedPromiseResolve(reader); + if (IsReadableStreamDefaultReader(reader)) { + reader._readRequests.forEach((readRequest) => { + readRequest._closeSteps(); + }); + reader._readRequests = new SimpleQueue(); + } + } + function ReadableStreamError(stream, e2) { + stream._state = "errored"; + stream._storedError = e2; + const reader = stream._reader; + if (reader === void 0) { + return; + } + defaultReaderClosedPromiseReject(reader, e2); + if (IsReadableStreamDefaultReader(reader)) { + reader._readRequests.forEach((readRequest) => { + readRequest._errorSteps(e2); + }); + reader._readRequests = new SimpleQueue(); + } else { + reader._readIntoRequests.forEach((readIntoRequest) => { + readIntoRequest._errorSteps(e2); + }); + reader._readIntoRequests = new SimpleQueue(); + } + } + function streamBrandCheckException$1(name) { + return new TypeError(`ReadableStream.prototype.${name} can only be used on a ReadableStream`); + } + function convertQueuingStrategyInit(init, context) { + assertDictionary(init, context); + const highWaterMark = init === null || init === void 0 ? void 0 : init.highWaterMark; + assertRequiredField(highWaterMark, "highWaterMark", "QueuingStrategyInit"); + return { + highWaterMark: convertUnrestrictedDouble(highWaterMark) + }; + } + const byteLengthSizeFunction = (chunk) => { + return chunk.byteLength; + }; + try { + Object.defineProperty(byteLengthSizeFunction, "name", { + value: "size", + configurable: true + }); + } catch (_a) { + } + class ByteLengthQueuingStrategy { + constructor(options) { + assertRequiredArgument(options, 1, "ByteLengthQueuingStrategy"); + options = convertQueuingStrategyInit(options, "First parameter"); + this._byteLengthQueuingStrategyHighWaterMark = options.highWaterMark; + } + /** + * Returns the high water mark provided to the constructor. + */ + get highWaterMark() { + if (!IsByteLengthQueuingStrategy(this)) { + throw byteLengthBrandCheckException("highWaterMark"); + } + return this._byteLengthQueuingStrategyHighWaterMark; + } + /** + * Measures the size of `chunk` by returning the value of its `byteLength` property. + */ + get size() { + if (!IsByteLengthQueuingStrategy(this)) { + throw byteLengthBrandCheckException("size"); + } + return byteLengthSizeFunction; + } + } + Object.defineProperties(ByteLengthQueuingStrategy.prototype, { + highWaterMark: { enumerable: true }, + size: { enumerable: true } + }); + if (typeof SymbolPolyfill.toStringTag === "symbol") { + Object.defineProperty(ByteLengthQueuingStrategy.prototype, SymbolPolyfill.toStringTag, { + value: "ByteLengthQueuingStrategy", + configurable: true + }); + } + function byteLengthBrandCheckException(name) { + return new TypeError(`ByteLengthQueuingStrategy.prototype.${name} can only be used on a ByteLengthQueuingStrategy`); + } + function IsByteLengthQueuingStrategy(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_byteLengthQueuingStrategyHighWaterMark")) { + return false; + } + return x2 instanceof ByteLengthQueuingStrategy; + } + const countSizeFunction = () => { + return 1; + }; + try { + Object.defineProperty(countSizeFunction, "name", { + value: "size", + configurable: true + }); + } catch (_a) { + } + class CountQueuingStrategy { + constructor(options) { + assertRequiredArgument(options, 1, "CountQueuingStrategy"); + options = convertQueuingStrategyInit(options, "First parameter"); + this._countQueuingStrategyHighWaterMark = options.highWaterMark; + } + /** + * Returns the high water mark provided to the constructor. + */ + get highWaterMark() { + if (!IsCountQueuingStrategy(this)) { + throw countBrandCheckException("highWaterMark"); + } + return this._countQueuingStrategyHighWaterMark; + } + /** + * Measures the size of `chunk` by always returning 1. + * This ensures that the total queue size is a count of the number of chunks in the queue. + */ + get size() { + if (!IsCountQueuingStrategy(this)) { + throw countBrandCheckException("size"); + } + return countSizeFunction; + } + } + Object.defineProperties(CountQueuingStrategy.prototype, { + highWaterMark: { enumerable: true }, + size: { enumerable: true } + }); + if (typeof SymbolPolyfill.toStringTag === "symbol") { + Object.defineProperty(CountQueuingStrategy.prototype, SymbolPolyfill.toStringTag, { + value: "CountQueuingStrategy", + configurable: true + }); + } + function countBrandCheckException(name) { + return new TypeError(`CountQueuingStrategy.prototype.${name} can only be used on a CountQueuingStrategy`); + } + function IsCountQueuingStrategy(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_countQueuingStrategyHighWaterMark")) { + return false; + } + return x2 instanceof CountQueuingStrategy; + } + function convertTransformer(original, context) { + assertDictionary(original, context); + const flush = original === null || original === void 0 ? void 0 : original.flush; + const readableType = original === null || original === void 0 ? void 0 : original.readableType; + const start = original === null || original === void 0 ? void 0 : original.start; + const transform = original === null || original === void 0 ? void 0 : original.transform; + const writableType = original === null || original === void 0 ? void 0 : original.writableType; + return { + flush: flush === void 0 ? void 0 : convertTransformerFlushCallback(flush, original, `${context} has member 'flush' that`), + readableType, + start: start === void 0 ? void 0 : convertTransformerStartCallback(start, original, `${context} has member 'start' that`), + transform: transform === void 0 ? void 0 : convertTransformerTransformCallback(transform, original, `${context} has member 'transform' that`), + writableType + }; + } + function convertTransformerFlushCallback(fn, original, context) { + assertFunction(fn, context); + return (controller) => promiseCall(fn, original, [controller]); + } + function convertTransformerStartCallback(fn, original, context) { + assertFunction(fn, context); + return (controller) => reflectCall(fn, original, [controller]); + } + function convertTransformerTransformCallback(fn, original, context) { + assertFunction(fn, context); + return (chunk, controller) => promiseCall(fn, original, [chunk, controller]); + } + class TransformStream { + constructor(rawTransformer = {}, rawWritableStrategy = {}, rawReadableStrategy = {}) { + if (rawTransformer === void 0) { + rawTransformer = null; + } + const writableStrategy = convertQueuingStrategy(rawWritableStrategy, "Second parameter"); + const readableStrategy = convertQueuingStrategy(rawReadableStrategy, "Third parameter"); + const transformer = convertTransformer(rawTransformer, "First parameter"); + if (transformer.readableType !== void 0) { + throw new RangeError("Invalid readableType specified"); + } + if (transformer.writableType !== void 0) { + throw new RangeError("Invalid writableType specified"); + } + const readableHighWaterMark = ExtractHighWaterMark(readableStrategy, 0); + const readableSizeAlgorithm = ExtractSizeAlgorithm(readableStrategy); + const writableHighWaterMark = ExtractHighWaterMark(writableStrategy, 1); + const writableSizeAlgorithm = ExtractSizeAlgorithm(writableStrategy); + let startPromise_resolve; + const startPromise = newPromise((resolve) => { + startPromise_resolve = resolve; + }); + InitializeTransformStream(this, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm); + SetUpTransformStreamDefaultControllerFromTransformer(this, transformer); + if (transformer.start !== void 0) { + startPromise_resolve(transformer.start(this._transformStreamController)); + } else { + startPromise_resolve(void 0); + } + } + /** + * The readable side of the transform stream. + */ + get readable() { + if (!IsTransformStream(this)) { + throw streamBrandCheckException("readable"); + } + return this._readable; + } + /** + * The writable side of the transform stream. + */ + get writable() { + if (!IsTransformStream(this)) { + throw streamBrandCheckException("writable"); + } + return this._writable; + } + } + Object.defineProperties(TransformStream.prototype, { + readable: { enumerable: true }, + writable: { enumerable: true } + }); + if (typeof SymbolPolyfill.toStringTag === "symbol") { + Object.defineProperty(TransformStream.prototype, SymbolPolyfill.toStringTag, { + value: "TransformStream", + configurable: true + }); + } + function InitializeTransformStream(stream, startPromise, writableHighWaterMark, writableSizeAlgorithm, readableHighWaterMark, readableSizeAlgorithm) { + function startAlgorithm() { + return startPromise; + } + function writeAlgorithm(chunk) { + return TransformStreamDefaultSinkWriteAlgorithm(stream, chunk); + } + function abortAlgorithm(reason) { + return TransformStreamDefaultSinkAbortAlgorithm(stream, reason); + } + function closeAlgorithm() { + return TransformStreamDefaultSinkCloseAlgorithm(stream); + } + stream._writable = CreateWritableStream(startAlgorithm, writeAlgorithm, closeAlgorithm, abortAlgorithm, writableHighWaterMark, writableSizeAlgorithm); + function pullAlgorithm() { + return TransformStreamDefaultSourcePullAlgorithm(stream); + } + function cancelAlgorithm(reason) { + TransformStreamErrorWritableAndUnblockWrite(stream, reason); + return promiseResolvedWith(void 0); + } + stream._readable = CreateReadableStream(startAlgorithm, pullAlgorithm, cancelAlgorithm, readableHighWaterMark, readableSizeAlgorithm); + stream._backpressure = void 0; + stream._backpressureChangePromise = void 0; + stream._backpressureChangePromise_resolve = void 0; + TransformStreamSetBackpressure(stream, true); + stream._transformStreamController = void 0; + } + function IsTransformStream(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_transformStreamController")) { + return false; + } + return x2 instanceof TransformStream; + } + function TransformStreamError(stream, e2) { + ReadableStreamDefaultControllerError(stream._readable._readableStreamController, e2); + TransformStreamErrorWritableAndUnblockWrite(stream, e2); + } + function TransformStreamErrorWritableAndUnblockWrite(stream, e2) { + TransformStreamDefaultControllerClearAlgorithms(stream._transformStreamController); + WritableStreamDefaultControllerErrorIfNeeded(stream._writable._writableStreamController, e2); + if (stream._backpressure) { + TransformStreamSetBackpressure(stream, false); + } + } + function TransformStreamSetBackpressure(stream, backpressure) { + if (stream._backpressureChangePromise !== void 0) { + stream._backpressureChangePromise_resolve(); + } + stream._backpressureChangePromise = newPromise((resolve) => { + stream._backpressureChangePromise_resolve = resolve; + }); + stream._backpressure = backpressure; + } + class TransformStreamDefaultController { + constructor() { + throw new TypeError("Illegal constructor"); + } + /** + * Returns the desired size to fill the readable side’s internal queue. It can be negative, if the queue is over-full. + */ + get desiredSize() { + if (!IsTransformStreamDefaultController(this)) { + throw defaultControllerBrandCheckException("desiredSize"); + } + const readableController = this._controlledTransformStream._readable._readableStreamController; + return ReadableStreamDefaultControllerGetDesiredSize(readableController); + } + enqueue(chunk = void 0) { + if (!IsTransformStreamDefaultController(this)) { + throw defaultControllerBrandCheckException("enqueue"); + } + TransformStreamDefaultControllerEnqueue(this, chunk); + } + /** + * Errors both the readable side and the writable side of the controlled transform stream, making all future + * interactions with it fail with the given error `e`. Any chunks queued for transformation will be discarded. + */ + error(reason = void 0) { + if (!IsTransformStreamDefaultController(this)) { + throw defaultControllerBrandCheckException("error"); + } + TransformStreamDefaultControllerError(this, reason); + } + /** + * Closes the readable side and errors the writable side of the controlled transform stream. This is useful when the + * transformer only needs to consume a portion of the chunks written to the writable side. + */ + terminate() { + if (!IsTransformStreamDefaultController(this)) { + throw defaultControllerBrandCheckException("terminate"); + } + TransformStreamDefaultControllerTerminate(this); + } + } + Object.defineProperties(TransformStreamDefaultController.prototype, { + enqueue: { enumerable: true }, + error: { enumerable: true }, + terminate: { enumerable: true }, + desiredSize: { enumerable: true } + }); + if (typeof SymbolPolyfill.toStringTag === "symbol") { + Object.defineProperty(TransformStreamDefaultController.prototype, SymbolPolyfill.toStringTag, { + value: "TransformStreamDefaultController", + configurable: true + }); + } + function IsTransformStreamDefaultController(x2) { + if (!typeIsObject(x2)) { + return false; + } + if (!Object.prototype.hasOwnProperty.call(x2, "_controlledTransformStream")) { + return false; + } + return x2 instanceof TransformStreamDefaultController; + } + function SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm) { + controller._controlledTransformStream = stream; + stream._transformStreamController = controller; + controller._transformAlgorithm = transformAlgorithm; + controller._flushAlgorithm = flushAlgorithm; + } + function SetUpTransformStreamDefaultControllerFromTransformer(stream, transformer) { + const controller = Object.create(TransformStreamDefaultController.prototype); + let transformAlgorithm = (chunk) => { + try { + TransformStreamDefaultControllerEnqueue(controller, chunk); + return promiseResolvedWith(void 0); + } catch (transformResultE) { + return promiseRejectedWith(transformResultE); + } + }; + let flushAlgorithm = () => promiseResolvedWith(void 0); + if (transformer.transform !== void 0) { + transformAlgorithm = (chunk) => transformer.transform(chunk, controller); + } + if (transformer.flush !== void 0) { + flushAlgorithm = () => transformer.flush(controller); + } + SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm); + } + function TransformStreamDefaultControllerClearAlgorithms(controller) { + controller._transformAlgorithm = void 0; + controller._flushAlgorithm = void 0; + } + function TransformStreamDefaultControllerEnqueue(controller, chunk) { + const stream = controller._controlledTransformStream; + const readableController = stream._readable._readableStreamController; + if (!ReadableStreamDefaultControllerCanCloseOrEnqueue(readableController)) { + throw new TypeError("Readable side is not in a state that permits enqueue"); + } + try { + ReadableStreamDefaultControllerEnqueue(readableController, chunk); + } catch (e2) { + TransformStreamErrorWritableAndUnblockWrite(stream, e2); + throw stream._readable._storedError; + } + const backpressure = ReadableStreamDefaultControllerHasBackpressure(readableController); + if (backpressure !== stream._backpressure) { + TransformStreamSetBackpressure(stream, true); + } + } + function TransformStreamDefaultControllerError(controller, e2) { + TransformStreamError(controller._controlledTransformStream, e2); + } + function TransformStreamDefaultControllerPerformTransform(controller, chunk) { + const transformPromise = controller._transformAlgorithm(chunk); + return transformPromiseWith(transformPromise, void 0, (r2) => { + TransformStreamError(controller._controlledTransformStream, r2); + throw r2; + }); + } + function TransformStreamDefaultControllerTerminate(controller) { + const stream = controller._controlledTransformStream; + const readableController = stream._readable._readableStreamController; + ReadableStreamDefaultControllerClose(readableController); + const error = new TypeError("TransformStream terminated"); + TransformStreamErrorWritableAndUnblockWrite(stream, error); + } + function TransformStreamDefaultSinkWriteAlgorithm(stream, chunk) { + const controller = stream._transformStreamController; + if (stream._backpressure) { + const backpressureChangePromise = stream._backpressureChangePromise; + return transformPromiseWith(backpressureChangePromise, () => { + const writable = stream._writable; + const state = writable._state; + if (state === "erroring") { + throw writable._storedError; + } + return TransformStreamDefaultControllerPerformTransform(controller, chunk); + }); + } + return TransformStreamDefaultControllerPerformTransform(controller, chunk); + } + function TransformStreamDefaultSinkAbortAlgorithm(stream, reason) { + TransformStreamError(stream, reason); + return promiseResolvedWith(void 0); + } + function TransformStreamDefaultSinkCloseAlgorithm(stream) { + const readable = stream._readable; + const controller = stream._transformStreamController; + const flushPromise = controller._flushAlgorithm(); + TransformStreamDefaultControllerClearAlgorithms(controller); + return transformPromiseWith(flushPromise, () => { + if (readable._state === "errored") { + throw readable._storedError; + } + ReadableStreamDefaultControllerClose(readable._readableStreamController); + }, (r2) => { + TransformStreamError(stream, r2); + throw readable._storedError; + }); + } + function TransformStreamDefaultSourcePullAlgorithm(stream) { + TransformStreamSetBackpressure(stream, false); + return stream._backpressureChangePromise; + } + function defaultControllerBrandCheckException(name) { + return new TypeError(`TransformStreamDefaultController.prototype.${name} can only be used on a TransformStreamDefaultController`); + } + function streamBrandCheckException(name) { + return new TypeError(`TransformStream.prototype.${name} can only be used on a TransformStream`); + } + exports2.ByteLengthQueuingStrategy = ByteLengthQueuingStrategy; + exports2.CountQueuingStrategy = CountQueuingStrategy; + exports2.ReadableByteStreamController = ReadableByteStreamController; + exports2.ReadableStream = ReadableStream2; + exports2.ReadableStreamBYOBReader = ReadableStreamBYOBReader; + exports2.ReadableStreamBYOBRequest = ReadableStreamBYOBRequest; + exports2.ReadableStreamDefaultController = ReadableStreamDefaultController; + exports2.ReadableStreamDefaultReader = ReadableStreamDefaultReader; + exports2.TransformStream = TransformStream; + exports2.TransformStreamDefaultController = TransformStreamDefaultController; + exports2.WritableStream = WritableStream; + exports2.WritableStreamDefaultController = WritableStreamDefaultController; + exports2.WritableStreamDefaultWriter = WritableStreamDefaultWriter; + Object.defineProperty(exports2, "__esModule", { value: true }); + }); + } +}); +var require_streams = (0, import_chunk_QGM4M3NI.__commonJS)({ + "../../node_modules/.pnpm/fetch-blob@3.2.0/node_modules/fetch-blob/streams.cjs"() { + "use strict"; + var POOL_SIZE2 = 65536; + if (!globalThis.ReadableStream) { + try { + const process = (0, import_chunk_QGM4M3NI.__require)("node:process"); + const { emitWarning } = process; + try { + process.emitWarning = () => { + }; + Object.assign(globalThis, (0, import_chunk_QGM4M3NI.__require)("node:stream/web")); + process.emitWarning = emitWarning; + } catch (error) { + process.emitWarning = emitWarning; + throw error; + } + } catch (error) { + Object.assign(globalThis, require_ponyfill_es2018()); + } + } + try { + const { Blob: Blob3 } = (0, import_chunk_QGM4M3NI.__require)("buffer"); + if (Blob3 && !Blob3.prototype.stream) { + Blob3.prototype.stream = function name(params) { + let position = 0; + const blob = this; + return new ReadableStream({ + type: "bytes", + async pull(ctrl) { + const chunk = blob.slice(position, Math.min(blob.size, position + POOL_SIZE2)); + const buffer = await chunk.arrayBuffer(); + position += buffer.byteLength; + ctrl.enqueue(new Uint8Array(buffer)); + if (position === blob.size) { + ctrl.close(); + } + } + }); + }; + } + } catch (error) { + } + } +}); +var require_node_domexception = (0, import_chunk_QGM4M3NI.__commonJS)({ + "../../node_modules/.pnpm/node-domexception@1.0.0/node_modules/node-domexception/index.js"(exports, module2) { + "use strict"; + if (!globalThis.DOMException) { + try { + const { MessageChannel } = (0, import_chunk_QGM4M3NI.__require)("worker_threads"), port = new MessageChannel().port1, ab = new ArrayBuffer(); + port.postMessage(ab, [ab, ab]); + } catch (err) { + err.constructor.name === "DOMException" && (globalThis.DOMException = err.constructor); + } + } + module2.exports = globalThis.DOMException; + } +}); +var import_streams = (0, import_chunk_QGM4M3NI.__toESM)(require_streams(), 1); +var POOL_SIZE = 65536; +async function* toIterator(parts, clone = true) { + for (const part of parts) { + if ("stream" in part) { + yield* ( + /** @type {AsyncIterableIterator} */ + part.stream() + ); + } else if (ArrayBuffer.isView(part)) { + if (clone) { + let position = part.byteOffset; + const end = part.byteOffset + part.byteLength; + while (position !== end) { + const size = Math.min(end - position, POOL_SIZE); + const chunk = part.buffer.slice(position, position + size); + position += chunk.byteLength; + yield new Uint8Array(chunk); + } + } else { + yield part; + } + } else { + let position = 0, b = ( + /** @type {Blob} */ + part + ); + while (position !== b.size) { + const chunk = b.slice(position, Math.min(b.size, position + POOL_SIZE)); + const buffer = await chunk.arrayBuffer(); + position += buffer.byteLength; + yield new Uint8Array(buffer); + } + } + } +} +var _Blob = class Blob { + /** @type {Array.<(Blob|Uint8Array)>} */ + #parts = []; + #type = ""; + #size = 0; + #endings = "transparent"; + /** + * The Blob() constructor returns a new Blob object. The content + * of the blob consists of the concatenation of the values given + * in the parameter array. + * + * @param {*} blobParts + * @param {{ type?: string, endings?: string }} [options] + */ + constructor(blobParts = [], options = {}) { + if (typeof blobParts !== "object" || blobParts === null) { + throw new TypeError("Failed to construct 'Blob': The provided value cannot be converted to a sequence."); + } + if (typeof blobParts[Symbol.iterator] !== "function") { + throw new TypeError("Failed to construct 'Blob': The object must have a callable @@iterator property."); + } + if (typeof options !== "object" && typeof options !== "function") { + throw new TypeError("Failed to construct 'Blob': parameter 2 cannot convert to dictionary."); + } + if (options === null) options = {}; + const encoder = new TextEncoder(); + for (const element of blobParts) { + let part; + if (ArrayBuffer.isView(element)) { + part = new Uint8Array(element.buffer.slice(element.byteOffset, element.byteOffset + element.byteLength)); + } else if (element instanceof ArrayBuffer) { + part = new Uint8Array(element.slice(0)); + } else if (element instanceof Blob) { + part = element; + } else { + part = encoder.encode(`${element}`); + } + this.#size += ArrayBuffer.isView(part) ? part.byteLength : part.size; + this.#parts.push(part); + } + this.#endings = `${options.endings === void 0 ? "transparent" : options.endings}`; + const type = options.type === void 0 ? "" : String(options.type); + this.#type = /^[\x20-\x7E]*$/.test(type) ? type : ""; + } + /** + * The Blob interface's size property returns the + * size of the Blob in bytes. + */ + get size() { + return this.#size; + } + /** + * The type property of a Blob object returns the MIME type of the file. + */ + get type() { + return this.#type; + } + /** + * The text() method in the Blob interface returns a Promise + * that resolves with a string containing the contents of + * the blob, interpreted as UTF-8. + * + * @return {Promise} + */ + async text() { + const decoder = new TextDecoder(); + let str = ""; + for await (const part of toIterator(this.#parts, false)) { + str += decoder.decode(part, { stream: true }); + } + str += decoder.decode(); + return str; + } + /** + * The arrayBuffer() method in the Blob interface returns a + * Promise that resolves with the contents of the blob as + * binary data contained in an ArrayBuffer. + * + * @return {Promise} + */ + async arrayBuffer() { + const data = new Uint8Array(this.size); + let offset = 0; + for await (const chunk of toIterator(this.#parts, false)) { + data.set(chunk, offset); + offset += chunk.length; + } + return data.buffer; + } + stream() { + const it = toIterator(this.#parts, true); + return new globalThis.ReadableStream({ + // @ts-ignore + type: "bytes", + async pull(ctrl) { + const chunk = await it.next(); + chunk.done ? ctrl.close() : ctrl.enqueue(chunk.value); + }, + async cancel() { + await it.return(); + } + }); + } + /** + * The Blob interface's slice() method creates and returns a + * new Blob object which contains data from a subset of the + * blob on which it's called. + * + * @param {number} [start] + * @param {number} [end] + * @param {string} [type] + */ + slice(start = 0, end = this.size, type = "") { + const { size } = this; + let relativeStart = start < 0 ? Math.max(size + start, 0) : Math.min(start, size); + let relativeEnd = end < 0 ? Math.max(size + end, 0) : Math.min(end, size); + const span = Math.max(relativeEnd - relativeStart, 0); + const parts = this.#parts; + const blobParts = []; + let added = 0; + for (const part of parts) { + if (added >= span) { + break; + } + const size2 = ArrayBuffer.isView(part) ? part.byteLength : part.size; + if (relativeStart && size2 <= relativeStart) { + relativeStart -= size2; + relativeEnd -= size2; + } else { + let chunk; + if (ArrayBuffer.isView(part)) { + chunk = part.subarray(relativeStart, Math.min(size2, relativeEnd)); + added += chunk.byteLength; + } else { + chunk = part.slice(relativeStart, Math.min(size2, relativeEnd)); + added += chunk.size; + } + relativeEnd -= size2; + blobParts.push(chunk); + relativeStart = 0; + } + } + const blob = new Blob([], { type: String(type).toLowerCase() }); + blob.#size = span; + blob.#parts = blobParts; + return blob; + } + get [Symbol.toStringTag]() { + return "Blob"; + } + static [Symbol.hasInstance](object) { + return object && typeof object === "object" && typeof object.constructor === "function" && (typeof object.stream === "function" || typeof object.arrayBuffer === "function") && /^(Blob|File)$/.test(object[Symbol.toStringTag]); + } +}; +Object.defineProperties(_Blob.prototype, { + size: { enumerable: true }, + type: { enumerable: true }, + slice: { enumerable: true } +}); +var Blob2 = _Blob; +var fetch_blob_default = Blob2; +var _File = class File extends fetch_blob_default { + #lastModified = 0; + #name = ""; + /** + * @param {*[]} fileBits + * @param {string} fileName + * @param {{lastModified?: number, type?: string}} options + */ + // @ts-ignore + constructor(fileBits, fileName, options = {}) { + if (arguments.length < 2) { + throw new TypeError(`Failed to construct 'File': 2 arguments required, but only ${arguments.length} present.`); + } + super(fileBits, options); + if (options === null) options = {}; + const lastModified = options.lastModified === void 0 ? Date.now() : Number(options.lastModified); + if (!Number.isNaN(lastModified)) { + this.#lastModified = lastModified; + } + this.#name = String(fileName); + } + get name() { + return this.#name; + } + get lastModified() { + return this.#lastModified; + } + get [Symbol.toStringTag]() { + return "File"; + } + static [Symbol.hasInstance](object) { + return !!object && object instanceof fetch_blob_default && /^(File)$/.test(object[Symbol.toStringTag]); + } +}; +var File2 = _File; +var file_default = File2; +var { toStringTag: t, iterator: i, hasInstance: h } = Symbol; +var r = Math.random; +var m = "append,set,get,getAll,delete,keys,values,entries,forEach,constructor".split(","); +var f = (a, b, c) => (a += "", /^(Blob|File)$/.test(b && b[t]) ? [(c = c !== void 0 ? c + "" : b[t] == "File" ? b.name : "blob", a), b.name !== c || b[t] == "blob" ? new file_default([b], c, b) : b] : [a, b + ""]); +var e = (c, f2) => (f2 ? c : c.replace(/\r?\n|\r/g, "\r\n")).replace(/\n/g, "%0A").replace(/\r/g, "%0D").replace(/"/g, "%22"); +var x = (n, a, e2) => { + if (a.length < e2) { + throw new TypeError(`Failed to execute '${n}' on 'FormData': ${e2} arguments required, but only ${a.length} present.`); + } +}; +var FormData = class FormData2 { + #d = []; + constructor(...a) { + if (a.length) throw new TypeError(`Failed to construct 'FormData': parameter 1 is not of type 'HTMLFormElement'.`); + } + get [t]() { + return "FormData"; + } + [i]() { + return this.entries(); + } + static [h](o) { + return o && typeof o === "object" && o[t] === "FormData" && !m.some((m2) => typeof o[m2] != "function"); + } + append(...a) { + x("append", arguments, 2); + this.#d.push(f(...a)); + } + delete(a) { + x("delete", arguments, 1); + a += ""; + this.#d = this.#d.filter(([b]) => b !== a); + } + get(a) { + x("get", arguments, 1); + a += ""; + for (var b = this.#d, l = b.length, c = 0; c < l; c++) if (b[c][0] === a) return b[c][1]; + return null; + } + getAll(a, b) { + x("getAll", arguments, 1); + b = []; + a += ""; + this.#d.forEach((c) => c[0] === a && b.push(c[1])); + return b; + } + has(a) { + x("has", arguments, 1); + a += ""; + return this.#d.some((b) => b[0] === a); + } + forEach(a, b) { + x("forEach", arguments, 1); + for (var [c, d] of this) a.call(b, d, c, this); + } + set(...a) { + x("set", arguments, 2); + var b = [], c = true; + a = f(...a); + this.#d.forEach((d) => { + d[0] === a[0] ? c && (c = !b.push(a)) : b.push(d); + }); + c && b.push(a); + this.#d = b; + } + *entries() { + yield* this.#d; + } + *keys() { + for (var [a] of this) yield a; + } + *values() { + for (var [, a] of this) yield a; + } +}; +function formDataToBlob(F, B = fetch_blob_default) { + var b = `${r()}${r()}`.replace(/\./g, "").slice(-28).padStart(32, "-"), c = [], p = `--${b}\r +Content-Disposition: form-data; name="`; + F.forEach((v, n) => typeof v == "string" ? c.push(p + e(n) + `"\r +\r +${v.replace(/\r(?!\n)|(? *) + +fetch-blob/index.js: + (*! fetch-blob. MIT License. Jimmy Wärting *) + +formdata-polyfill/esm.min.js: + (*! formdata-polyfill. MIT License. Jimmy Wärting *) +*/ diff --git a/backend/node_modules/@prisma/fetch-engine/dist/downloadZip.js b/backend/node_modules/@prisma/fetch-engine/dist/downloadZip.js new file mode 100644 index 0000000000000000000000000000000000000000..ff1e4814709ce4e5db9c7236920d03a33b517b0d --- /dev/null +++ b/backend/node_modules/@prisma/fetch-engine/dist/downloadZip.js @@ -0,0 +1,30 @@ +"use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var downloadZip_exports = {}; +__export(downloadZip_exports, { + downloadZip: () => import_chunk_CY52DY2B.downloadZip +}); +module.exports = __toCommonJS(downloadZip_exports); +var import_chunk_CY52DY2B = require("./chunk-CY52DY2B.js"); +var import_chunk_RXM4EBGR = require("./chunk-RXM4EBGR.js"); +var import_chunk_FSAAZH62 = require("./chunk-FSAAZH62.js"); +var import_chunk_LONQL55G = require("./chunk-LONQL55G.js"); +var import_chunk_X37PZICB = require("./chunk-X37PZICB.js"); +var import_chunk_VAPNG6TS = require("./chunk-VAPNG6TS.js"); +var import_chunk_QGM4M3NI = require("./chunk-QGM4M3NI.js"); diff --git a/backend/node_modules/@prisma/fetch-engine/dist/getHash.d.ts b/backend/node_modules/@prisma/fetch-engine/dist/getHash.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..4149af035f702e2ccc52b909a44ff6b11329d2b2 --- /dev/null +++ b/backend/node_modules/@prisma/fetch-engine/dist/getHash.d.ts @@ -0,0 +1 @@ +export declare function getHash(filePath: string): Promise; diff --git a/backend/node_modules/@prisma/fetch-engine/dist/index.d.ts b/backend/node_modules/@prisma/fetch-engine/dist/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..73f139de54aa53dc7b2dcb3fb347060e00c17725 --- /dev/null +++ b/backend/node_modules/@prisma/fetch-engine/dist/index.d.ts @@ -0,0 +1,5 @@ +export * from './BinaryType'; +export * from './download'; +export * from './env'; +export { getProxyAgent } from './getProxyAgent'; +export { getCacheDir, overwriteFile } from './utils'; diff --git a/backend/node_modules/@prisma/fetch-engine/dist/utils.js b/backend/node_modules/@prisma/fetch-engine/dist/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..a0b4421fcd5e98559792e7128ba3b248f7e1a511 --- /dev/null +++ b/backend/node_modules/@prisma/fetch-engine/dist/utils.js @@ -0,0 +1,29 @@ +"use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var utils_exports = {}; +__export(utils_exports, { + getCacheDir: () => import_chunk_LONQL55G.getCacheDir, + getDownloadUrl: () => import_chunk_LONQL55G.getDownloadUrl, + getRootCacheDir: () => import_chunk_LONQL55G.getRootCacheDir, + overwriteFile: () => import_chunk_LONQL55G.overwriteFile +}); +module.exports = __toCommonJS(utils_exports); +var import_chunk_LONQL55G = require("./chunk-LONQL55G.js"); +var import_chunk_X37PZICB = require("./chunk-X37PZICB.js"); +var import_chunk_QGM4M3NI = require("./chunk-QGM4M3NI.js"); diff --git a/backend/node_modules/effect/BigInt/package.json b/backend/node_modules/effect/BigInt/package.json new file mode 100644 index 0000000000000000000000000000000000000000..57dfb76f5e87ac28f510ebab3ff5f5a6025bcd82 --- /dev/null +++ b/backend/node_modules/effect/BigInt/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/BigInt.js", + "module": "../dist/esm/BigInt.js", + "types": "../dist/dts/BigInt.d.ts" +} diff --git a/backend/node_modules/effect/Clock/package.json b/backend/node_modules/effect/Clock/package.json new file mode 100644 index 0000000000000000000000000000000000000000..8583ad02bd88cf7c0c6d9a9fcd158d36e64c01f6 --- /dev/null +++ b/backend/node_modules/effect/Clock/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Clock.js", + "module": "../dist/esm/Clock.js", + "types": "../dist/dts/Clock.d.ts" +} diff --git a/backend/node_modules/effect/ConfigProvider/package.json b/backend/node_modules/effect/ConfigProvider/package.json new file mode 100644 index 0000000000000000000000000000000000000000..2c346d08cdd1d898ad0d3f509f69804394c8b3d4 --- /dev/null +++ b/backend/node_modules/effect/ConfigProvider/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/ConfigProvider.js", + "module": "../dist/esm/ConfigProvider.js", + "types": "../dist/dts/ConfigProvider.d.ts" +} diff --git a/backend/node_modules/effect/ConfigProviderPathPatch/package.json b/backend/node_modules/effect/ConfigProviderPathPatch/package.json new file mode 100644 index 0000000000000000000000000000000000000000..0227f84c0a4373e0839105392db506e44c39c289 --- /dev/null +++ b/backend/node_modules/effect/ConfigProviderPathPatch/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/ConfigProviderPathPatch.js", + "module": "../dist/esm/ConfigProviderPathPatch.js", + "types": "../dist/dts/ConfigProviderPathPatch.d.ts" +} diff --git a/backend/node_modules/effect/Console/package.json b/backend/node_modules/effect/Console/package.json new file mode 100644 index 0000000000000000000000000000000000000000..32496c47721f66f2a6634004e772c3db9d48ad1e --- /dev/null +++ b/backend/node_modules/effect/Console/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Console.js", + "module": "../dist/esm/Console.js", + "types": "../dist/dts/Console.d.ts" +} diff --git a/backend/node_modules/effect/Context/package.json b/backend/node_modules/effect/Context/package.json new file mode 100644 index 0000000000000000000000000000000000000000..4bec6eb3b71749fee6dd9ebb9cb25c33c17a645b --- /dev/null +++ b/backend/node_modules/effect/Context/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Context.js", + "module": "../dist/esm/Context.js", + "types": "../dist/dts/Context.d.ts" +} diff --git a/backend/node_modules/effect/Cron/package.json b/backend/node_modules/effect/Cron/package.json new file mode 100644 index 0000000000000000000000000000000000000000..a9255c91da8a9d5a3b7589c2d80befc34b8bb457 --- /dev/null +++ b/backend/node_modules/effect/Cron/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Cron.js", + "module": "../dist/esm/Cron.js", + "types": "../dist/dts/Cron.d.ts" +} diff --git a/backend/node_modules/effect/Data/package.json b/backend/node_modules/effect/Data/package.json new file mode 100644 index 0000000000000000000000000000000000000000..100942637f7e29d758ac277de6863247111bcdda --- /dev/null +++ b/backend/node_modules/effect/Data/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Data.js", + "module": "../dist/esm/Data.js", + "types": "../dist/dts/Data.d.ts" +} diff --git a/backend/node_modules/effect/Duration/package.json b/backend/node_modules/effect/Duration/package.json new file mode 100644 index 0000000000000000000000000000000000000000..0d454bf974f0d0d5f1e0f4484fef157058a319ad --- /dev/null +++ b/backend/node_modules/effect/Duration/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Duration.js", + "module": "../dist/esm/Duration.js", + "types": "../dist/dts/Duration.d.ts" +} diff --git a/backend/node_modules/effect/Effectable/package.json b/backend/node_modules/effect/Effectable/package.json new file mode 100644 index 0000000000000000000000000000000000000000..8ba926460e6bacea52355b5e2fab85a30decf57c --- /dev/null +++ b/backend/node_modules/effect/Effectable/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Effectable.js", + "module": "../dist/esm/Effectable.js", + "types": "../dist/dts/Effectable.d.ts" +} diff --git a/backend/node_modules/effect/Either/package.json b/backend/node_modules/effect/Either/package.json new file mode 100644 index 0000000000000000000000000000000000000000..4d6d9735e75b60701f13e0f913c12ff8fe2b78be --- /dev/null +++ b/backend/node_modules/effect/Either/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Either.js", + "module": "../dist/esm/Either.js", + "types": "../dist/dts/Either.d.ts" +} diff --git a/backend/node_modules/effect/Equal/package.json b/backend/node_modules/effect/Equal/package.json new file mode 100644 index 0000000000000000000000000000000000000000..3728a423ae97370a3f8003761f9d11618fb905ac --- /dev/null +++ b/backend/node_modules/effect/Equal/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Equal.js", + "module": "../dist/esm/Equal.js", + "types": "../dist/dts/Equal.d.ts" +} diff --git a/backend/node_modules/effect/ExecutionStrategy/package.json b/backend/node_modules/effect/ExecutionStrategy/package.json new file mode 100644 index 0000000000000000000000000000000000000000..a523befcd43f9958bcb99d95c62a1135a30ce4a1 --- /dev/null +++ b/backend/node_modules/effect/ExecutionStrategy/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/ExecutionStrategy.js", + "module": "../dist/esm/ExecutionStrategy.js", + "types": "../dist/dts/ExecutionStrategy.d.ts" +} diff --git a/backend/node_modules/effect/Exit/package.json b/backend/node_modules/effect/Exit/package.json new file mode 100644 index 0000000000000000000000000000000000000000..c2bb3753602f6ed142ddde457cc434436830d5b4 --- /dev/null +++ b/backend/node_modules/effect/Exit/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Exit.js", + "module": "../dist/esm/Exit.js", + "types": "../dist/dts/Exit.d.ts" +} diff --git a/backend/node_modules/effect/Fiber/package.json b/backend/node_modules/effect/Fiber/package.json new file mode 100644 index 0000000000000000000000000000000000000000..0d936843c6b69831cca4a938e65b31f4965a3db0 --- /dev/null +++ b/backend/node_modules/effect/Fiber/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Fiber.js", + "module": "../dist/esm/Fiber.js", + "types": "../dist/dts/Fiber.d.ts" +} diff --git a/backend/node_modules/effect/FiberHandle/package.json b/backend/node_modules/effect/FiberHandle/package.json new file mode 100644 index 0000000000000000000000000000000000000000..682aca05e8269bf07cc472da6bf249f3bc30d369 --- /dev/null +++ b/backend/node_modules/effect/FiberHandle/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/FiberHandle.js", + "module": "../dist/esm/FiberHandle.js", + "types": "../dist/dts/FiberHandle.d.ts" +} diff --git a/backend/node_modules/effect/FiberId/package.json b/backend/node_modules/effect/FiberId/package.json new file mode 100644 index 0000000000000000000000000000000000000000..77ee2294df02f9bbea4307d1178d9dc257202fb5 --- /dev/null +++ b/backend/node_modules/effect/FiberId/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/FiberId.js", + "module": "../dist/esm/FiberId.js", + "types": "../dist/dts/FiberId.d.ts" +} diff --git a/backend/node_modules/effect/FiberMap/package.json b/backend/node_modules/effect/FiberMap/package.json new file mode 100644 index 0000000000000000000000000000000000000000..4aa5602daa329997c4bf4586badbacfa92f8acb9 --- /dev/null +++ b/backend/node_modules/effect/FiberMap/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/FiberMap.js", + "module": "../dist/esm/FiberMap.js", + "types": "../dist/dts/FiberMap.d.ts" +} diff --git a/backend/node_modules/effect/FiberRefsPatch/package.json b/backend/node_modules/effect/FiberRefsPatch/package.json new file mode 100644 index 0000000000000000000000000000000000000000..b7083d75a16b561866c68be06652c37c47cf9ed3 --- /dev/null +++ b/backend/node_modules/effect/FiberRefsPatch/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/FiberRefsPatch.js", + "module": "../dist/esm/FiberRefsPatch.js", + "types": "../dist/dts/FiberRefsPatch.d.ts" +} diff --git a/backend/node_modules/effect/GlobalValue/package.json b/backend/node_modules/effect/GlobalValue/package.json new file mode 100644 index 0000000000000000000000000000000000000000..8e256ea133c9f17f3f1ccb29ef451b22a96dbf4e --- /dev/null +++ b/backend/node_modules/effect/GlobalValue/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/GlobalValue.js", + "module": "../dist/esm/GlobalValue.js", + "types": "../dist/dts/GlobalValue.d.ts" +} diff --git a/backend/node_modules/effect/HKT/package.json b/backend/node_modules/effect/HKT/package.json new file mode 100644 index 0000000000000000000000000000000000000000..7d86e1227502b4ff82524917ab0ba834de3282df --- /dev/null +++ b/backend/node_modules/effect/HKT/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/HKT.js", + "module": "../dist/esm/HKT.js", + "types": "../dist/dts/HKT.d.ts" +} diff --git a/backend/node_modules/effect/Inspectable/package.json b/backend/node_modules/effect/Inspectable/package.json new file mode 100644 index 0000000000000000000000000000000000000000..11e1f347e948da490b5f77a0c2c66dd7da44cd7d --- /dev/null +++ b/backend/node_modules/effect/Inspectable/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Inspectable.js", + "module": "../dist/esm/Inspectable.js", + "types": "../dist/dts/Inspectable.d.ts" +} diff --git a/backend/node_modules/effect/Iterable/package.json b/backend/node_modules/effect/Iterable/package.json new file mode 100644 index 0000000000000000000000000000000000000000..146c0d3ebc4ad4c09e650a9256cba1c455133a02 --- /dev/null +++ b/backend/node_modules/effect/Iterable/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Iterable.js", + "module": "../dist/esm/Iterable.js", + "types": "../dist/dts/Iterable.d.ts" +} diff --git a/backend/node_modules/effect/KeyedPool/package.json b/backend/node_modules/effect/KeyedPool/package.json new file mode 100644 index 0000000000000000000000000000000000000000..97f906540b24c993f27c9ac0f5cb7c15e21a37fb --- /dev/null +++ b/backend/node_modules/effect/KeyedPool/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/KeyedPool.js", + "module": "../dist/esm/KeyedPool.js", + "types": "../dist/dts/KeyedPool.d.ts" +} diff --git a/backend/node_modules/effect/LogSpan/package.json b/backend/node_modules/effect/LogSpan/package.json new file mode 100644 index 0000000000000000000000000000000000000000..5435dfe71d6a3fa25866a93c00c61fe034698178 --- /dev/null +++ b/backend/node_modules/effect/LogSpan/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/LogSpan.js", + "module": "../dist/esm/LogSpan.js", + "types": "../dist/dts/LogSpan.d.ts" +} diff --git a/backend/node_modules/effect/Metric/package.json b/backend/node_modules/effect/Metric/package.json new file mode 100644 index 0000000000000000000000000000000000000000..de59dd4f9e5b59c9c9833b815dadef85bf27ef5b --- /dev/null +++ b/backend/node_modules/effect/Metric/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Metric.js", + "module": "../dist/esm/Metric.js", + "types": "../dist/dts/Metric.d.ts" +} diff --git a/backend/node_modules/effect/MetricBoundaries/package.json b/backend/node_modules/effect/MetricBoundaries/package.json new file mode 100644 index 0000000000000000000000000000000000000000..c10d0e3fa82c391583d7d76c7ca9f9662b2ede20 --- /dev/null +++ b/backend/node_modules/effect/MetricBoundaries/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/MetricBoundaries.js", + "module": "../dist/esm/MetricBoundaries.js", + "types": "../dist/dts/MetricBoundaries.d.ts" +} diff --git a/backend/node_modules/effect/MetricHook/package.json b/backend/node_modules/effect/MetricHook/package.json new file mode 100644 index 0000000000000000000000000000000000000000..62e1111d380b6238b2c3a50ddee49f0f1ac92002 --- /dev/null +++ b/backend/node_modules/effect/MetricHook/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/MetricHook.js", + "module": "../dist/esm/MetricHook.js", + "types": "../dist/dts/MetricHook.d.ts" +} diff --git a/backend/node_modules/effect/MetricPair/package.json b/backend/node_modules/effect/MetricPair/package.json new file mode 100644 index 0000000000000000000000000000000000000000..1e103fc5f31d8d5974b5886e0736ad5e999b675a --- /dev/null +++ b/backend/node_modules/effect/MetricPair/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/MetricPair.js", + "module": "../dist/esm/MetricPair.js", + "types": "../dist/dts/MetricPair.d.ts" +} diff --git a/backend/node_modules/effect/MetricRegistry/package.json b/backend/node_modules/effect/MetricRegistry/package.json new file mode 100644 index 0000000000000000000000000000000000000000..66706b6405481b552fe8f5c7f7cc6532ac2da6a0 --- /dev/null +++ b/backend/node_modules/effect/MetricRegistry/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/MetricRegistry.js", + "module": "../dist/esm/MetricRegistry.js", + "types": "../dist/dts/MetricRegistry.d.ts" +} diff --git a/backend/node_modules/effect/Micro/package.json b/backend/node_modules/effect/Micro/package.json new file mode 100644 index 0000000000000000000000000000000000000000..0e21ca3fa494d3b9aaa21378f99f64b955e120c8 --- /dev/null +++ b/backend/node_modules/effect/Micro/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Micro.js", + "module": "../dist/esm/Micro.js", + "types": "../dist/dts/Micro.d.ts" +} diff --git a/backend/node_modules/effect/MutableHashMap/package.json b/backend/node_modules/effect/MutableHashMap/package.json new file mode 100644 index 0000000000000000000000000000000000000000..c5497d6e3b4758987070928bec3468095e0c4336 --- /dev/null +++ b/backend/node_modules/effect/MutableHashMap/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/MutableHashMap.js", + "module": "../dist/esm/MutableHashMap.js", + "types": "../dist/dts/MutableHashMap.d.ts" +} diff --git a/backend/node_modules/effect/MutableHashSet/package.json b/backend/node_modules/effect/MutableHashSet/package.json new file mode 100644 index 0000000000000000000000000000000000000000..b9d3edcc6da2c645ff15a757301fdc9b2beac40a --- /dev/null +++ b/backend/node_modules/effect/MutableHashSet/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/MutableHashSet.js", + "module": "../dist/esm/MutableHashSet.js", + "types": "../dist/dts/MutableHashSet.d.ts" +} diff --git a/backend/node_modules/effect/MutableList/package.json b/backend/node_modules/effect/MutableList/package.json new file mode 100644 index 0000000000000000000000000000000000000000..04d45af80b4708866f56e9bf5b91f5996be0efff --- /dev/null +++ b/backend/node_modules/effect/MutableList/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/MutableList.js", + "module": "../dist/esm/MutableList.js", + "types": "../dist/dts/MutableList.d.ts" +} diff --git a/backend/node_modules/effect/NonEmptyIterable/package.json b/backend/node_modules/effect/NonEmptyIterable/package.json new file mode 100644 index 0000000000000000000000000000000000000000..3b77501758de08184f2d61c176e6d647900bcf58 --- /dev/null +++ b/backend/node_modules/effect/NonEmptyIterable/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/NonEmptyIterable.js", + "module": "../dist/esm/NonEmptyIterable.js", + "types": "../dist/dts/NonEmptyIterable.d.ts" +} diff --git a/backend/node_modules/effect/Order/package.json b/backend/node_modules/effect/Order/package.json new file mode 100644 index 0000000000000000000000000000000000000000..cc24fde6ebfad37fce5e3359f17a59b30049e4c9 --- /dev/null +++ b/backend/node_modules/effect/Order/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Order.js", + "module": "../dist/esm/Order.js", + "types": "../dist/dts/Order.d.ts" +} diff --git a/backend/node_modules/effect/PartitionedSemaphore/package.json b/backend/node_modules/effect/PartitionedSemaphore/package.json new file mode 100644 index 0000000000000000000000000000000000000000..8574f20f414b067b320ba1661a65ba3f06cf1900 --- /dev/null +++ b/backend/node_modules/effect/PartitionedSemaphore/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/PartitionedSemaphore.js", + "module": "../dist/esm/PartitionedSemaphore.js", + "types": "../dist/dts/PartitionedSemaphore.d.ts" +} diff --git a/backend/node_modules/effect/Pool/package.json b/backend/node_modules/effect/Pool/package.json new file mode 100644 index 0000000000000000000000000000000000000000..9fcccef8078b6a9d99718c3800bf40a6037bf366 --- /dev/null +++ b/backend/node_modules/effect/Pool/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Pool.js", + "module": "../dist/esm/Pool.js", + "types": "../dist/dts/Pool.d.ts" +} diff --git a/backend/node_modules/effect/Predicate/package.json b/backend/node_modules/effect/Predicate/package.json new file mode 100644 index 0000000000000000000000000000000000000000..2aa0f02c7479708cdf8d45b5a9c8dbfb995ab937 --- /dev/null +++ b/backend/node_modules/effect/Predicate/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Predicate.js", + "module": "../dist/esm/Predicate.js", + "types": "../dist/dts/Predicate.d.ts" +} diff --git a/backend/node_modules/effect/Pretty/package.json b/backend/node_modules/effect/Pretty/package.json new file mode 100644 index 0000000000000000000000000000000000000000..2acf24e55c40ac20a9ca016a756b80f895d265d0 --- /dev/null +++ b/backend/node_modules/effect/Pretty/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Pretty.js", + "module": "../dist/esm/Pretty.js", + "types": "../dist/dts/Pretty.d.ts" +} diff --git a/backend/node_modules/effect/PrimaryKey/package.json b/backend/node_modules/effect/PrimaryKey/package.json new file mode 100644 index 0000000000000000000000000000000000000000..9b850dc72a0b05526d84f50595309387013d586c --- /dev/null +++ b/backend/node_modules/effect/PrimaryKey/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/PrimaryKey.js", + "module": "../dist/esm/PrimaryKey.js", + "types": "../dist/dts/PrimaryKey.d.ts" +} diff --git a/backend/node_modules/effect/PubSub/package.json b/backend/node_modules/effect/PubSub/package.json new file mode 100644 index 0000000000000000000000000000000000000000..68df20060e405b2ccd5c0fbcf3080d5ac3f09621 --- /dev/null +++ b/backend/node_modules/effect/PubSub/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/PubSub.js", + "module": "../dist/esm/PubSub.js", + "types": "../dist/dts/PubSub.d.ts" +} diff --git a/backend/node_modules/effect/Queue/package.json b/backend/node_modules/effect/Queue/package.json new file mode 100644 index 0000000000000000000000000000000000000000..53ed2d9d7bbcda1fc1e81a9b09b9dca7c9dd8417 --- /dev/null +++ b/backend/node_modules/effect/Queue/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Queue.js", + "module": "../dist/esm/Queue.js", + "types": "../dist/dts/Queue.d.ts" +} diff --git a/backend/node_modules/effect/Random/package.json b/backend/node_modules/effect/Random/package.json new file mode 100644 index 0000000000000000000000000000000000000000..cf92ff6d1fe2668640c2bc06f93800e18afff8f5 --- /dev/null +++ b/backend/node_modules/effect/Random/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Random.js", + "module": "../dist/esm/Random.js", + "types": "../dist/dts/Random.d.ts" +} diff --git a/backend/node_modules/effect/RcMap/package.json b/backend/node_modules/effect/RcMap/package.json new file mode 100644 index 0000000000000000000000000000000000000000..1d76cb41fe0acbb66e389d5910c678772462921f --- /dev/null +++ b/backend/node_modules/effect/RcMap/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/RcMap.js", + "module": "../dist/esm/RcMap.js", + "types": "../dist/dts/RcMap.d.ts" +} diff --git a/backend/node_modules/effect/Readable/package.json b/backend/node_modules/effect/Readable/package.json new file mode 100644 index 0000000000000000000000000000000000000000..ef07438eda233fe937e92b0df5b9de5b976d72b4 --- /dev/null +++ b/backend/node_modules/effect/Readable/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Readable.js", + "module": "../dist/esm/Readable.js", + "types": "../dist/dts/Readable.d.ts" +} diff --git a/backend/node_modules/effect/Ref/package.json b/backend/node_modules/effect/Ref/package.json new file mode 100644 index 0000000000000000000000000000000000000000..abe4d44c9ce6304099a0427033a5801d097b8615 --- /dev/null +++ b/backend/node_modules/effect/Ref/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Ref.js", + "module": "../dist/esm/Ref.js", + "types": "../dist/dts/Ref.d.ts" +} diff --git a/backend/node_modules/effect/RegExp/package.json b/backend/node_modules/effect/RegExp/package.json new file mode 100644 index 0000000000000000000000000000000000000000..f0a3019c3ad55372fe92815728c43b6bd575310c --- /dev/null +++ b/backend/node_modules/effect/RegExp/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/RegExp.js", + "module": "../dist/esm/RegExp.js", + "types": "../dist/dts/RegExp.d.ts" +} diff --git a/backend/node_modules/effect/Request/package.json b/backend/node_modules/effect/Request/package.json new file mode 100644 index 0000000000000000000000000000000000000000..494c3b92b316436e4ee0e758b3c48ca54b0cfd8e --- /dev/null +++ b/backend/node_modules/effect/Request/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Request.js", + "module": "../dist/esm/Request.js", + "types": "../dist/dts/Request.d.ts" +} diff --git a/backend/node_modules/effect/RequestBlock/package.json b/backend/node_modules/effect/RequestBlock/package.json new file mode 100644 index 0000000000000000000000000000000000000000..4d1b358578ddbd9af7327fd257e201f9f3e99821 --- /dev/null +++ b/backend/node_modules/effect/RequestBlock/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/RequestBlock.js", + "module": "../dist/esm/RequestBlock.js", + "types": "../dist/dts/RequestBlock.d.ts" +} diff --git a/backend/node_modules/effect/RequestResolver/package.json b/backend/node_modules/effect/RequestResolver/package.json new file mode 100644 index 0000000000000000000000000000000000000000..713acd49db06e55e19458732628fd33e914ee375 --- /dev/null +++ b/backend/node_modules/effect/RequestResolver/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/RequestResolver.js", + "module": "../dist/esm/RequestResolver.js", + "types": "../dist/dts/RequestResolver.d.ts" +} diff --git a/backend/node_modules/effect/Resource/package.json b/backend/node_modules/effect/Resource/package.json new file mode 100644 index 0000000000000000000000000000000000000000..4c590faa29b16ea6e23f425568118479898053a3 --- /dev/null +++ b/backend/node_modules/effect/Resource/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Resource.js", + "module": "../dist/esm/Resource.js", + "types": "../dist/dts/Resource.d.ts" +} diff --git a/backend/node_modules/effect/RuntimeFlags/package.json b/backend/node_modules/effect/RuntimeFlags/package.json new file mode 100644 index 0000000000000000000000000000000000000000..85d0932a3dbe201b527ee1326b66990f22500671 --- /dev/null +++ b/backend/node_modules/effect/RuntimeFlags/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/RuntimeFlags.js", + "module": "../dist/esm/RuntimeFlags.js", + "types": "../dist/dts/RuntimeFlags.d.ts" +} diff --git a/backend/node_modules/effect/Schedule/package.json b/backend/node_modules/effect/Schedule/package.json new file mode 100644 index 0000000000000000000000000000000000000000..ca9a997c0804abc705a556bf87710d7d85415945 --- /dev/null +++ b/backend/node_modules/effect/Schedule/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Schedule.js", + "module": "../dist/esm/Schedule.js", + "types": "../dist/dts/Schedule.d.ts" +} diff --git a/backend/node_modules/effect/ScheduleInterval/package.json b/backend/node_modules/effect/ScheduleInterval/package.json new file mode 100644 index 0000000000000000000000000000000000000000..998efaf07a2699844414efdee8e928b9f2170aa5 --- /dev/null +++ b/backend/node_modules/effect/ScheduleInterval/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/ScheduleInterval.js", + "module": "../dist/esm/ScheduleInterval.js", + "types": "../dist/dts/ScheduleInterval.d.ts" +} diff --git a/backend/node_modules/effect/SchemaAST/package.json b/backend/node_modules/effect/SchemaAST/package.json new file mode 100644 index 0000000000000000000000000000000000000000..37d2a332a73455370c3b3a399c7416b2a1a3355b --- /dev/null +++ b/backend/node_modules/effect/SchemaAST/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/SchemaAST.js", + "module": "../dist/esm/SchemaAST.js", + "types": "../dist/dts/SchemaAST.d.ts" +} diff --git a/backend/node_modules/effect/ScopedCache/package.json b/backend/node_modules/effect/ScopedCache/package.json new file mode 100644 index 0000000000000000000000000000000000000000..ec5af2a1c4b213345de44e492effd0827b72b8d3 --- /dev/null +++ b/backend/node_modules/effect/ScopedCache/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/ScopedCache.js", + "module": "../dist/esm/ScopedCache.js", + "types": "../dist/dts/ScopedCache.d.ts" +} diff --git a/backend/node_modules/effect/ScopedRef/package.json b/backend/node_modules/effect/ScopedRef/package.json new file mode 100644 index 0000000000000000000000000000000000000000..10886760b12af1ff0c791ccbbbaf22aa5a79bcac --- /dev/null +++ b/backend/node_modules/effect/ScopedRef/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/ScopedRef.js", + "module": "../dist/esm/ScopedRef.js", + "types": "../dist/dts/ScopedRef.d.ts" +} diff --git a/backend/node_modules/effect/Secret/package.json b/backend/node_modules/effect/Secret/package.json new file mode 100644 index 0000000000000000000000000000000000000000..daded8a97ee28259a2cc6e276ac9e0b7f46c2972 --- /dev/null +++ b/backend/node_modules/effect/Secret/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Secret.js", + "module": "../dist/esm/Secret.js", + "types": "../dist/dts/Secret.d.ts" +} diff --git a/backend/node_modules/effect/StreamEmit/package.json b/backend/node_modules/effect/StreamEmit/package.json new file mode 100644 index 0000000000000000000000000000000000000000..125b0d61d4f4a6939f9022ad88ba29ebd65a6c95 --- /dev/null +++ b/backend/node_modules/effect/StreamEmit/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/StreamEmit.js", + "module": "../dist/esm/StreamEmit.js", + "types": "../dist/dts/StreamEmit.d.ts" +} diff --git a/backend/node_modules/effect/String/package.json b/backend/node_modules/effect/String/package.json new file mode 100644 index 0000000000000000000000000000000000000000..1fc9445594de2270b3ba7344b934d173180a3b27 --- /dev/null +++ b/backend/node_modules/effect/String/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/String.js", + "module": "../dist/esm/String.js", + "types": "../dist/dts/String.d.ts" +} diff --git a/backend/node_modules/effect/Supervisor/package.json b/backend/node_modules/effect/Supervisor/package.json new file mode 100644 index 0000000000000000000000000000000000000000..eab2cacb0fdcbe92284727595901eabddd7e8893 --- /dev/null +++ b/backend/node_modules/effect/Supervisor/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Supervisor.js", + "module": "../dist/esm/Supervisor.js", + "types": "../dist/dts/Supervisor.d.ts" +} diff --git a/backend/node_modules/effect/SynchronizedRef/package.json b/backend/node_modules/effect/SynchronizedRef/package.json new file mode 100644 index 0000000000000000000000000000000000000000..d2716fcee2dd3f8a3daef86ab113548bc25e8883 --- /dev/null +++ b/backend/node_modules/effect/SynchronizedRef/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/SynchronizedRef.js", + "module": "../dist/esm/SynchronizedRef.js", + "types": "../dist/dts/SynchronizedRef.d.ts" +} diff --git a/backend/node_modules/effect/TArray/package.json b/backend/node_modules/effect/TArray/package.json new file mode 100644 index 0000000000000000000000000000000000000000..5ae856ee2d46334a764e35f65e6f13e404cd7ba9 --- /dev/null +++ b/backend/node_modules/effect/TArray/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/TArray.js", + "module": "../dist/esm/TArray.js", + "types": "../dist/dts/TArray.d.ts" +} diff --git a/backend/node_modules/effect/TMap/package.json b/backend/node_modules/effect/TMap/package.json new file mode 100644 index 0000000000000000000000000000000000000000..ae1a6a4e771fc230e34efd6cedcee518925a7688 --- /dev/null +++ b/backend/node_modules/effect/TMap/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/TMap.js", + "module": "../dist/esm/TMap.js", + "types": "../dist/dts/TMap.d.ts" +} diff --git a/backend/node_modules/effect/TPriorityQueue/package.json b/backend/node_modules/effect/TPriorityQueue/package.json new file mode 100644 index 0000000000000000000000000000000000000000..463d61a54edabd964c25bd83305f74cd55f84c5c --- /dev/null +++ b/backend/node_modules/effect/TPriorityQueue/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/TPriorityQueue.js", + "module": "../dist/esm/TPriorityQueue.js", + "types": "../dist/dts/TPriorityQueue.d.ts" +} diff --git a/backend/node_modules/effect/TPubSub/package.json b/backend/node_modules/effect/TPubSub/package.json new file mode 100644 index 0000000000000000000000000000000000000000..9ec78916f94b41b3f37b2481e64b368839517243 --- /dev/null +++ b/backend/node_modules/effect/TPubSub/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/TPubSub.js", + "module": "../dist/esm/TPubSub.js", + "types": "../dist/dts/TPubSub.d.ts" +} diff --git a/backend/node_modules/effect/TSubscriptionRef/package.json b/backend/node_modules/effect/TSubscriptionRef/package.json new file mode 100644 index 0000000000000000000000000000000000000000..2884414d39aab9c1b0a0c5110ec484b0a4210b3d --- /dev/null +++ b/backend/node_modules/effect/TSubscriptionRef/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/TSubscriptionRef.js", + "module": "../dist/esm/TSubscriptionRef.js", + "types": "../dist/dts/TSubscriptionRef.d.ts" +} diff --git a/backend/node_modules/effect/TestAnnotation/package.json b/backend/node_modules/effect/TestAnnotation/package.json new file mode 100644 index 0000000000000000000000000000000000000000..503cf9b3122abe5b385345f77caa66a8832cf135 --- /dev/null +++ b/backend/node_modules/effect/TestAnnotation/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/TestAnnotation.js", + "module": "../dist/esm/TestAnnotation.js", + "types": "../dist/dts/TestAnnotation.d.ts" +} diff --git a/backend/node_modules/effect/TestAnnotationMap/package.json b/backend/node_modules/effect/TestAnnotationMap/package.json new file mode 100644 index 0000000000000000000000000000000000000000..9d64d2c20615d06e894ad958ad5158b98ded3ef4 --- /dev/null +++ b/backend/node_modules/effect/TestAnnotationMap/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/TestAnnotationMap.js", + "module": "../dist/esm/TestAnnotationMap.js", + "types": "../dist/dts/TestAnnotationMap.d.ts" +} diff --git a/backend/node_modules/effect/TestAnnotations/package.json b/backend/node_modules/effect/TestAnnotations/package.json new file mode 100644 index 0000000000000000000000000000000000000000..e6f6cf8b2c93a7a94fdb5be18ee41c37e264d9d1 --- /dev/null +++ b/backend/node_modules/effect/TestAnnotations/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/TestAnnotations.js", + "module": "../dist/esm/TestAnnotations.js", + "types": "../dist/dts/TestAnnotations.d.ts" +} diff --git a/backend/node_modules/effect/TestServices/package.json b/backend/node_modules/effect/TestServices/package.json new file mode 100644 index 0000000000000000000000000000000000000000..2661125b7a08a9602318661ced421466e49fbccd --- /dev/null +++ b/backend/node_modules/effect/TestServices/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/TestServices.js", + "module": "../dist/esm/TestServices.js", + "types": "../dist/dts/TestServices.d.ts" +} diff --git a/backend/node_modules/effect/Tracer/package.json b/backend/node_modules/effect/Tracer/package.json new file mode 100644 index 0000000000000000000000000000000000000000..3f3fb094327b39083ec5c51a212df8f83d55f670 --- /dev/null +++ b/backend/node_modules/effect/Tracer/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Tracer.js", + "module": "../dist/esm/Tracer.js", + "types": "../dist/dts/Tracer.d.ts" +} diff --git a/backend/node_modules/effect/Types/package.json b/backend/node_modules/effect/Types/package.json new file mode 100644 index 0000000000000000000000000000000000000000..1164c5332c0bdd411444eaafcf72b5b72d452093 --- /dev/null +++ b/backend/node_modules/effect/Types/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/Types.js", + "module": "../dist/esm/Types.js", + "types": "../dist/dts/Types.d.ts" +} diff --git a/backend/node_modules/effect/UpstreamPullRequest/package.json b/backend/node_modules/effect/UpstreamPullRequest/package.json new file mode 100644 index 0000000000000000000000000000000000000000..ff8e3f2c393db50f99376ccc2951c4f262fad4d2 --- /dev/null +++ b/backend/node_modules/effect/UpstreamPullRequest/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/UpstreamPullRequest.js", + "module": "../dist/esm/UpstreamPullRequest.js", + "types": "../dist/dts/UpstreamPullRequest.d.ts" +} diff --git a/backend/node_modules/effect/UpstreamPullStrategy/package.json b/backend/node_modules/effect/UpstreamPullStrategy/package.json new file mode 100644 index 0000000000000000000000000000000000000000..fda9f86b946fe06f50f2730393909ee88efc6648 --- /dev/null +++ b/backend/node_modules/effect/UpstreamPullStrategy/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/UpstreamPullStrategy.js", + "module": "../dist/esm/UpstreamPullStrategy.js", + "types": "../dist/dts/UpstreamPullStrategy.d.ts" +} diff --git a/backend/node_modules/effect/index/package.json b/backend/node_modules/effect/index/package.json new file mode 100644 index 0000000000000000000000000000000000000000..e405185f21eeaeb59f65d92b2a1430b635217694 --- /dev/null +++ b/backend/node_modules/effect/index/package.json @@ -0,0 +1,6 @@ +{ + "sideEffects": [], + "main": "../dist/cjs/index.js", + "module": "../dist/esm/index.js", + "types": "../dist/dts/index.d.ts" +} diff --git a/backend/node_modules/effect/src/Array.ts b/backend/node_modules/effect/src/Array.ts new file mode 100644 index 0000000000000000000000000000000000000000..415c8b31931c84d39f32fcccf79ec8a8c76dcd5c --- /dev/null +++ b/backend/node_modules/effect/src/Array.ts @@ -0,0 +1,6854 @@ +/** + * This module provides utility functions for working with arrays in TypeScript. + * + * @since 2.0.0 + */ + +import * as Either from "./Either.js" +import * as Equal from "./Equal.js" +import * as Equivalence from "./Equivalence.js" +import type { LazyArg } from "./Function.js" +import { dual, identity } from "./Function.js" +import type { TypeLambda } from "./HKT.js" +import * as internalArray from "./internal/array.js" +import * as internalDoNotation from "./internal/doNotation.js" +import * as moduleIterable from "./Iterable.js" +import * as Option from "./Option.js" +import * as Order from "./Order.js" +import * as Predicate from "./Predicate.js" +import * as Record from "./Record.js" +import * as Tuple from "./Tuple.js" +import type { NoInfer, TupleOf } from "./Types.js" + +/** + * @category type lambdas + * @since 2.0.0 + */ +export interface ReadonlyArrayTypeLambda extends TypeLambda { + readonly type: ReadonlyArray +} + +/** + * @category models + * @since 2.0.0 + */ +export type NonEmptyReadonlyArray = readonly [A, ...Array] + +/** + * @category models + * @since 2.0.0 + */ +export type NonEmptyArray = [A, ...Array] + +/** + * Builds a `NonEmptyArray` from an non-empty collection of elements. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.make(1, 2, 3) + * console.log(result) // [1, 2, 3] + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const make = >( + ...elements: Elements +): NonEmptyArray => elements + +/** + * Creates a new `Array` of the specified length. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.allocate(3) + * console.log(result) // [ <3 empty items> ] + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const allocate = (n: number): Array => new Array(n) + +/** + * Return a `NonEmptyArray` of length `n` with element `i` initialized with `f(i)`. + * + * **Note**. `n` is normalized to an integer >= 1. + * + * **Example** + * + * ```ts + * import { makeBy } from "effect/Array" + * + * const result = makeBy(5, n => n * 2) + * console.log(result) // [0, 2, 4, 6, 8] + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const makeBy: { + /** + * Return a `NonEmptyArray` of length `n` with element `i` initialized with `f(i)`. + * + * **Note**. `n` is normalized to an integer >= 1. + * + * **Example** + * + * ```ts + * import { makeBy } from "effect/Array" + * + * const result = makeBy(5, n => n * 2) + * console.log(result) // [0, 2, 4, 6, 8] + * ``` + * + * @category constructors + * @since 2.0.0 + */ + (f: (i: number) => A): (n: number) => NonEmptyArray + /** + * Return a `NonEmptyArray` of length `n` with element `i` initialized with `f(i)`. + * + * **Note**. `n` is normalized to an integer >= 1. + * + * **Example** + * + * ```ts + * import { makeBy } from "effect/Array" + * + * const result = makeBy(5, n => n * 2) + * console.log(result) // [0, 2, 4, 6, 8] + * ``` + * + * @category constructors + * @since 2.0.0 + */ + (n: number, f: (i: number) => A): NonEmptyArray +} = dual(2, (n: number, f: (i: number) => A) => { + const max = Math.max(1, Math.floor(n)) + const out = new Array(max) + for (let i = 0; i < max; i++) { + out[i] = f(i) + } + return out as NonEmptyArray +}) + +/** + * Return a `NonEmptyArray` containing a range of integers, including both endpoints. + * + * **Example** + * + * ```ts + * import { range } from "effect/Array" + * + * const result = range(1, 3) + * console.log(result) // [1, 2, 3] + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const range = (start: number, end: number): NonEmptyArray => + start <= end ? makeBy(end - start + 1, (i) => start + i) : [start] + +/** + * Return a `NonEmptyArray` containing a value repeated the specified number of times. + * + * **Note**. `n` is normalized to an integer >= 1. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.replicate("a", 3) + * console.log(result) // ["a", "a", "a"] + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const replicate: { + /** + * Return a `NonEmptyArray` containing a value repeated the specified number of times. + * + * **Note**. `n` is normalized to an integer >= 1. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.replicate("a", 3) + * console.log(result) // ["a", "a", "a"] + * ``` + * + * @category constructors + * @since 2.0.0 + */ + (n: number): (a: A) => NonEmptyArray + /** + * Return a `NonEmptyArray` containing a value repeated the specified number of times. + * + * **Note**. `n` is normalized to an integer >= 1. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.replicate("a", 3) + * console.log(result) // ["a", "a", "a"] + * ``` + * + * @category constructors + * @since 2.0.0 + */ + (a: A, n: number): NonEmptyArray +} = dual(2, (a: A, n: number): NonEmptyArray => makeBy(n, () => a)) + +/** + * Creates a new `Array` from an iterable collection of values. + * If the input is already an array, it returns the input as-is. + * Otherwise, it converts the iterable collection to an array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.fromIterable(new Set([1, 2, 3])) + * console.log(result) // [1, 2, 3] + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const fromIterable = (collection: Iterable): Array => + Array.isArray(collection) ? collection : Array.from(collection) + +/** + * Creates a new `Array` from a value that might not be an iterable. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * console.log(Array.ensure("a")) // ["a"] + * console.log(Array.ensure(["a"])) // ["a"] + * console.log(Array.ensure(["a", "b", "c"])) // ["a", "b", "c"] + * ``` + * + * @category constructors + * @since 3.3.0 + */ +export const ensure = (self: ReadonlyArray | A): Array => Array.isArray(self) ? self : [self as A] + +/** + * Takes a record and returns an array of tuples containing its keys and values. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.fromRecord({ a: 1, b: 2, c: 3 }) + * console.log(result) // [["a", 1], ["b", 2], ["c", 3]] + * ``` + * + * @category conversions + * @since 2.0.0 + */ +export const fromRecord: (self: Readonly>) => Array<[K, A]> = Record.toEntries + +/** + * Converts an `Option` to an array. + * + * **Example** + * + * ```ts + * import { Array, Option } from "effect" + * + * console.log(Array.fromOption(Option.some(1))) // [1] + * console.log(Array.fromOption(Option.none())) // [] + * ``` + * + * @category conversions + * @since 2.0.0 + */ +export const fromOption: (self: Option.Option) => Array = Option.toArray + +/** + * Matches the elements of an array, applying functions to cases of empty and non-empty arrays. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const match = Array.match({ + * onEmpty: () => "empty", + * onNonEmpty: ([head, ...tail]) => `head: ${head}, tail: ${tail.length}` + * }) + * console.log(match([])) // "empty" + * console.log(match([1, 2, 3])) // "head: 1, tail: 2" + * ``` + * + * @category pattern matching + * @since 2.0.0 + */ +export const match: { + /** + * Matches the elements of an array, applying functions to cases of empty and non-empty arrays. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const match = Array.match({ + * onEmpty: () => "empty", + * onNonEmpty: ([head, ...tail]) => `head: ${head}, tail: ${tail.length}` + * }) + * console.log(match([])) // "empty" + * console.log(match([1, 2, 3])) // "head: 1, tail: 2" + * ``` + * + * @category pattern matching + * @since 2.0.0 + */ + ( + options: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (self: NonEmptyReadonlyArray) => C + } + ): (self: ReadonlyArray) => B | C + /** + * Matches the elements of an array, applying functions to cases of empty and non-empty arrays. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const match = Array.match({ + * onEmpty: () => "empty", + * onNonEmpty: ([head, ...tail]) => `head: ${head}, tail: ${tail.length}` + * }) + * console.log(match([])) // "empty" + * console.log(match([1, 2, 3])) // "head: 1, tail: 2" + * ``` + * + * @category pattern matching + * @since 2.0.0 + */ + ( + self: ReadonlyArray, + options: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (self: NonEmptyReadonlyArray) => C + } + ): B | C +} = dual(2, ( + self: ReadonlyArray, + { onEmpty, onNonEmpty }: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (self: NonEmptyReadonlyArray) => C + } +): B | C => isNonEmptyReadonlyArray(self) ? onNonEmpty(self) : onEmpty()) + +/** + * Matches the elements of an array from the left, applying functions to cases of empty and non-empty arrays. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const matchLeft = Array.matchLeft({ + * onEmpty: () => "empty", + * onNonEmpty: (head, tail) => `head: ${head}, tail: ${tail.length}` + * }) + * console.log(matchLeft([])) // "empty" + * console.log(matchLeft([1, 2, 3])) // "head: 1, tail: 2" + * ``` + * + * @category pattern matching + * @since 2.0.0 + */ +export const matchLeft: { + /** + * Matches the elements of an array from the left, applying functions to cases of empty and non-empty arrays. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const matchLeft = Array.matchLeft({ + * onEmpty: () => "empty", + * onNonEmpty: (head, tail) => `head: ${head}, tail: ${tail.length}` + * }) + * console.log(matchLeft([])) // "empty" + * console.log(matchLeft([1, 2, 3])) // "head: 1, tail: 2" + * ``` + * + * @category pattern matching + * @since 2.0.0 + */ + ( + options: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (head: A, tail: Array) => C + } + ): (self: ReadonlyArray) => B | C + /** + * Matches the elements of an array from the left, applying functions to cases of empty and non-empty arrays. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const matchLeft = Array.matchLeft({ + * onEmpty: () => "empty", + * onNonEmpty: (head, tail) => `head: ${head}, tail: ${tail.length}` + * }) + * console.log(matchLeft([])) // "empty" + * console.log(matchLeft([1, 2, 3])) // "head: 1, tail: 2" + * ``` + * + * @category pattern matching + * @since 2.0.0 + */ + ( + self: ReadonlyArray, + options: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (head: A, tail: Array) => C + } + ): B | C +} = dual(2, ( + self: ReadonlyArray, + { onEmpty, onNonEmpty }: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (head: A, tail: Array) => C + } +): B | C => isNonEmptyReadonlyArray(self) ? onNonEmpty(headNonEmpty(self), tailNonEmpty(self)) : onEmpty()) + +/** + * Matches the elements of an array from the right, applying functions to cases of empty and non-empty arrays. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const matchRight = Array.matchRight({ + * onEmpty: () => "empty", + * onNonEmpty: (init, last) => `init: ${init.length}, last: ${last}` + * }) + * console.log(matchRight([])) // "empty" + * console.log(matchRight([1, 2, 3])) // "init: 2, last: 3" + * ``` + * + * @category pattern matching + * @since 2.0.0 + */ +export const matchRight: { + /** + * Matches the elements of an array from the right, applying functions to cases of empty and non-empty arrays. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const matchRight = Array.matchRight({ + * onEmpty: () => "empty", + * onNonEmpty: (init, last) => `init: ${init.length}, last: ${last}` + * }) + * console.log(matchRight([])) // "empty" + * console.log(matchRight([1, 2, 3])) // "init: 2, last: 3" + * ``` + * + * @category pattern matching + * @since 2.0.0 + */ + ( + options: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (init: Array, last: A) => C + } + ): (self: ReadonlyArray) => B | C + /** + * Matches the elements of an array from the right, applying functions to cases of empty and non-empty arrays. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const matchRight = Array.matchRight({ + * onEmpty: () => "empty", + * onNonEmpty: (init, last) => `init: ${init.length}, last: ${last}` + * }) + * console.log(matchRight([])) // "empty" + * console.log(matchRight([1, 2, 3])) // "init: 2, last: 3" + * ``` + * + * @category pattern matching + * @since 2.0.0 + */ + ( + self: ReadonlyArray, + options: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (init: Array, last: A) => C + } + ): B | C +} = dual(2, ( + self: ReadonlyArray, + { onEmpty, onNonEmpty }: { + readonly onEmpty: LazyArg + readonly onNonEmpty: (init: Array, last: A) => C + } +): B | C => + isNonEmptyReadonlyArray(self) ? + onNonEmpty(initNonEmpty(self), lastNonEmpty(self)) : + onEmpty()) + +/** + * Prepend an element to the front of an `Iterable`, creating a new `NonEmptyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.prepend([2, 3, 4], 1) + * console.log(result) // [1, 2, 3, 4] + * ``` + * + * @category concatenating + * @since 2.0.0 + */ +export const prepend: { + /** + * Prepend an element to the front of an `Iterable`, creating a new `NonEmptyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.prepend([2, 3, 4], 1) + * console.log(result) // [1, 2, 3, 4] + * ``` + * + * @category concatenating + * @since 2.0.0 + */ + (head: B): (self: Iterable) => NonEmptyArray + /** + * Prepend an element to the front of an `Iterable`, creating a new `NonEmptyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.prepend([2, 3, 4], 1) + * console.log(result) // [1, 2, 3, 4] + * ``` + * + * @category concatenating + * @since 2.0.0 + */ + (self: Iterable, head: B): NonEmptyArray +} = dual(2, (self: Iterable, head: B): NonEmptyArray => [head, ...self]) + +/** + * Prepends the specified prefix array (or iterable) to the beginning of the specified array (or iterable). + * If either array is non-empty, the result is also a non-empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.prependAll([2, 3], [0, 1]) + * console.log(result) // [0, 1, 2, 3] + * ``` + * + * @category concatenating + * @since 2.0.0 + */ +export const prependAll: { + /** + * Prepends the specified prefix array (or iterable) to the beginning of the specified array (or iterable). + * If either array is non-empty, the result is also a non-empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.prependAll([2, 3], [0, 1]) + * console.log(result) // [0, 1, 2, 3] + * ``` + * + * @category concatenating + * @since 2.0.0 + */ + , T extends Iterable>(that: T): (self: S) => ReadonlyArray.OrNonEmpty | ReadonlyArray.Infer> + /** + * Prepends the specified prefix array (or iterable) to the beginning of the specified array (or iterable). + * If either array is non-empty, the result is also a non-empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.prependAll([2, 3], [0, 1]) + * console.log(result) // [0, 1, 2, 3] + * ``` + * + * @category concatenating + * @since 2.0.0 + */ + (self: Iterable, that: NonEmptyReadonlyArray): NonEmptyArray + /** + * Prepends the specified prefix array (or iterable) to the beginning of the specified array (or iterable). + * If either array is non-empty, the result is also a non-empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.prependAll([2, 3], [0, 1]) + * console.log(result) // [0, 1, 2, 3] + * ``` + * + * @category concatenating + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, that: Iterable): NonEmptyArray + /** + * Prepends the specified prefix array (or iterable) to the beginning of the specified array (or iterable). + * If either array is non-empty, the result is also a non-empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.prependAll([2, 3], [0, 1]) + * console.log(result) // [0, 1, 2, 3] + * ``` + * + * @category concatenating + * @since 2.0.0 + */ + (self: Iterable, that: Iterable): Array +} = dual( + 2, + (self: Iterable, that: Iterable): Array => fromIterable(that).concat(fromIterable(self)) +) + +/** + * Append an element to the end of an `Iterable`, creating a new `NonEmptyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.append([1, 2, 3], 4); + * console.log(result) // [1, 2, 3, 4] + * ``` + * + * @category concatenating + * @since 2.0.0 + */ +export const append: { + /** + * Append an element to the end of an `Iterable`, creating a new `NonEmptyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.append([1, 2, 3], 4); + * console.log(result) // [1, 2, 3, 4] + * ``` + * + * @category concatenating + * @since 2.0.0 + */ + (last: B): (self: Iterable) => NonEmptyArray + /** + * Append an element to the end of an `Iterable`, creating a new `NonEmptyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.append([1, 2, 3], 4); + * console.log(result) // [1, 2, 3, 4] + * ``` + * + * @category concatenating + * @since 2.0.0 + */ + (self: Iterable, last: B): NonEmptyArray +} = dual(2, (self: Iterable, last: B): Array => [...self, last]) + +/** + * Concatenates two arrays (or iterables), combining their elements. + * If either array is non-empty, the result is also a non-empty array. + * + * @category concatenating + * @since 2.0.0 + */ +export const appendAll: { + /** + * Concatenates two arrays (or iterables), combining their elements. + * If either array is non-empty, the result is also a non-empty array. + * + * @category concatenating + * @since 2.0.0 + */ + , T extends Iterable>(that: T): (self: S) => ReadonlyArray.OrNonEmpty | ReadonlyArray.Infer> + /** + * Concatenates two arrays (or iterables), combining their elements. + * If either array is non-empty, the result is also a non-empty array. + * + * @category concatenating + * @since 2.0.0 + */ + (self: Iterable, that: NonEmptyReadonlyArray): NonEmptyArray + /** + * Concatenates two arrays (or iterables), combining their elements. + * If either array is non-empty, the result is also a non-empty array. + * + * @category concatenating + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, that: Iterable): NonEmptyArray + /** + * Concatenates two arrays (or iterables), combining their elements. + * If either array is non-empty, the result is also a non-empty array. + * + * @category concatenating + * @since 2.0.0 + */ + (self: Iterable, that: Iterable): Array +} = dual( + 2, + (self: Iterable, that: Iterable): Array => fromIterable(self).concat(fromIterable(that)) +) + +/** + * Accumulates values from an `Iterable` starting from the left, storing + * each intermediate result in an array. Useful for tracking the progression of + * a value through a series of transformations. + * + * **Example** + * + * ```ts + * import { Array } from "effect"; + * + * const result = Array.scan([1, 2, 3, 4], 0, (acc, value) => acc + value) + * console.log(result) // [0, 1, 3, 6, 10] + * + * // Explanation: + * // This function starts with the initial value (0 in this case) + * // and adds each element of the array to this accumulator one by one, + * // keeping track of the cumulative sum after each addition. + * // Each of these sums is captured in the resulting array. + * ``` + * + * @category folding + * @since 2.0.0 + */ +export const scan: { + /** + * Accumulates values from an `Iterable` starting from the left, storing + * each intermediate result in an array. Useful for tracking the progression of + * a value through a series of transformations. + * + * **Example** + * + * ```ts + * import { Array } from "effect"; + * + * const result = Array.scan([1, 2, 3, 4], 0, (acc, value) => acc + value) + * console.log(result) // [0, 1, 3, 6, 10] + * + * // Explanation: + * // This function starts with the initial value (0 in this case) + * // and adds each element of the array to this accumulator one by one, + * // keeping track of the cumulative sum after each addition. + * // Each of these sums is captured in the resulting array. + * ``` + * + * @category folding + * @since 2.0.0 + */ + (b: B, f: (b: B, a: A) => B): (self: Iterable) => NonEmptyArray + /** + * Accumulates values from an `Iterable` starting from the left, storing + * each intermediate result in an array. Useful for tracking the progression of + * a value through a series of transformations. + * + * **Example** + * + * ```ts + * import { Array } from "effect"; + * + * const result = Array.scan([1, 2, 3, 4], 0, (acc, value) => acc + value) + * console.log(result) // [0, 1, 3, 6, 10] + * + * // Explanation: + * // This function starts with the initial value (0 in this case) + * // and adds each element of the array to this accumulator one by one, + * // keeping track of the cumulative sum after each addition. + * // Each of these sums is captured in the resulting array. + * ``` + * + * @category folding + * @since 2.0.0 + */ + (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray +} = dual(3, (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray => { + const out: NonEmptyArray = [b] + let i = 0 + for (const a of self) { + out[i + 1] = f(out[i], a) + i++ + } + return out +}) + +/** + * Accumulates values from an `Iterable` starting from the right, storing + * each intermediate result in an array. Useful for tracking the progression of + * a value through a series of transformations. + * + * **Example** + * + * ```ts + * import { Array } from "effect"; + * + * const result = Array.scanRight([1, 2, 3, 4], 0, (acc, value) => acc + value) + * console.log(result) // [10, 9, 7, 4, 0] + * ``` + * + * @category folding + * @since 2.0.0 + */ +export const scanRight: { + /** + * Accumulates values from an `Iterable` starting from the right, storing + * each intermediate result in an array. Useful for tracking the progression of + * a value through a series of transformations. + * + * **Example** + * + * ```ts + * import { Array } from "effect"; + * + * const result = Array.scanRight([1, 2, 3, 4], 0, (acc, value) => acc + value) + * console.log(result) // [10, 9, 7, 4, 0] + * ``` + * + * @category folding + * @since 2.0.0 + */ + (b: B, f: (b: B, a: A) => B): (self: Iterable) => NonEmptyArray + /** + * Accumulates values from an `Iterable` starting from the right, storing + * each intermediate result in an array. Useful for tracking the progression of + * a value through a series of transformations. + * + * **Example** + * + * ```ts + * import { Array } from "effect"; + * + * const result = Array.scanRight([1, 2, 3, 4], 0, (acc, value) => acc + value) + * console.log(result) // [10, 9, 7, 4, 0] + * ``` + * + * @category folding + * @since 2.0.0 + */ + (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray +} = dual(3, (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray => { + const input = fromIterable(self) + const out: NonEmptyArray = new Array(input.length + 1) as any + out[input.length] = b + for (let i = input.length - 1; i >= 0; i--) { + out[i] = f(out[i + 1], input[i]) + } + return out +}) + +/** + * Determine if `unknown` is an Array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * console.log(Array.isArray(null)) // false + * console.log(Array.isArray([1, 2, 3])) // true + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isArray: { + /** + * Determine if `unknown` is an Array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * console.log(Array.isArray(null)) // false + * console.log(Array.isArray([1, 2, 3])) // true + * ``` + * + * @category guards + * @since 2.0.0 + */ + (self: unknown): self is Array + /** + * Determine if `unknown` is an Array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * console.log(Array.isArray(null)) // false + * console.log(Array.isArray([1, 2, 3])) // true + * ``` + * + * @category guards + * @since 2.0.0 + */ + (self: T): self is Extract> +} = Array.isArray + +/** + * Determine if an `Array` is empty narrowing down the type to `[]`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * console.log(Array.isEmptyArray([])) // true + * console.log(Array.isEmptyArray([1, 2, 3])) // false + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isEmptyArray = (self: Array): self is [] => self.length === 0 + +/** + * Determine if a `ReadonlyArray` is empty narrowing down the type to `readonly []`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * console.log(Array.isEmptyReadonlyArray([])) // true + * console.log(Array.isEmptyReadonlyArray([1, 2, 3])) // false + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isEmptyReadonlyArray: (self: ReadonlyArray) => self is readonly [] = isEmptyArray as any + +/** + * Determine if an `Array` is non empty narrowing down the type to `NonEmptyArray`. + * + * An `Array` is considered to be a `NonEmptyArray` if it contains at least one element. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * console.log(Array.isNonEmptyArray([])) // false + * console.log(Array.isNonEmptyArray([1, 2, 3])) // true + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isNonEmptyArray: (self: Array) => self is NonEmptyArray = internalArray.isNonEmptyArray + +/** + * Determine if a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyReadonlyArray`. + * + * A `ReadonlyArray` is considered to be a `NonEmptyReadonlyArray` if it contains at least one element. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * console.log(Array.isNonEmptyReadonlyArray([])) // false + * console.log(Array.isNonEmptyReadonlyArray([1, 2, 3])) // true + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isNonEmptyReadonlyArray: (self: ReadonlyArray) => self is NonEmptyReadonlyArray = + internalArray.isNonEmptyArray + +/** + * Return the number of elements in a `ReadonlyArray`. + * + * @category getters + * @since 2.0.0 + */ +export const length = (self: ReadonlyArray): number => self.length + +const isOutOfBounds = (i: number, as: ReadonlyArray): boolean => i < 0 || i >= as.length + +const clamp = (i: number, as: ReadonlyArray): number => Math.floor(Math.min(Math.max(0, i), as.length)) + +/** + * This function provides a safe way to read a value at a particular index from a `ReadonlyArray`. + * + * @category getters + * @since 2.0.0 + */ +export const get: { + /** + * This function provides a safe way to read a value at a particular index from a `ReadonlyArray`. + * + * @category getters + * @since 2.0.0 + */ + (index: number): (self: ReadonlyArray) => Option.Option + /** + * This function provides a safe way to read a value at a particular index from a `ReadonlyArray`. + * + * @category getters + * @since 2.0.0 + */ + (self: ReadonlyArray, index: number): Option.Option +} = dual(2, (self: ReadonlyArray, index: number): Option.Option => { + const i = Math.floor(index) + return isOutOfBounds(i, self) ? Option.none() : Option.some(self[i]) +}) + +/** + * Gets an element unsafely, will throw on out of bounds. + * + * @since 2.0.0 + * @category unsafe + */ +export const unsafeGet: { + /** + * Gets an element unsafely, will throw on out of bounds. + * + * @since 2.0.0 + * @category unsafe + */ + (index: number): (self: ReadonlyArray) => A + /** + * Gets an element unsafely, will throw on out of bounds. + * + * @since 2.0.0 + * @category unsafe + */ + (self: ReadonlyArray, index: number): A +} = dual(2, (self: ReadonlyArray, index: number): A => { + const i = Math.floor(index) + if (isOutOfBounds(i, self)) { + throw new Error(`Index ${i} out of bounds`) + } + return self[i] +}) + +/** + * Return a tuple containing the first element, and a new `Array` of the remaining elements, if any. + * + * **Example** + * + * ```ts + * import { Array } from "effect"; + * + * const result = Array.unprepend([1, 2, 3, 4]) + * console.log(result) // [1, [2, 3, 4]] + * ``` + * + * @category splitting + * @since 2.0.0 + */ +export const unprepend = ( + self: NonEmptyReadonlyArray +): [firstElement: A, remainingElements: Array] => [headNonEmpty(self), tailNonEmpty(self)] + +/** + * Return a tuple containing a copy of the `NonEmptyReadonlyArray` without its last element, and that last element. + * + * **Example** + * + * ```ts + * import { Array } from "effect"; + * + * const result = Array.unappend([1, 2, 3, 4]) + * console.log(result) // [[1, 2, 3], 4] + * ``` + * + * @category splitting + * @since 2.0.0 + */ +export const unappend = ( + self: NonEmptyReadonlyArray +): [arrayWithoutLastElement: Array, lastElement: A] => [initNonEmpty(self), lastNonEmpty(self)] + +/** + * Get the first element of a `ReadonlyArray`, or `None` if the `ReadonlyArray` is empty. + * + * @category getters + * @since 2.0.0 + */ +export const head: (self: ReadonlyArray) => Option.Option = get(0) + +/** + * Get the first element of a non empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.headNonEmpty([1, 2, 3, 4]) + * console.log(result) // 1 + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const headNonEmpty: (self: NonEmptyReadonlyArray) => A = unsafeGet(0) + +/** + * Get the last element in a `ReadonlyArray`, or `None` if the `ReadonlyArray` is empty. + * + * @category getters + * @since 2.0.0 + */ +export const last = (self: ReadonlyArray): Option.Option => + isNonEmptyReadonlyArray(self) ? Option.some(lastNonEmpty(self)) : Option.none() + +/** + * Get the last element of a non empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.lastNonEmpty([1, 2, 3, 4]) + * console.log(result) // 4 + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const lastNonEmpty = (self: NonEmptyReadonlyArray): A => self[self.length - 1] + +/** + * Get all but the first element of an `Iterable`, creating a new `Array`, or `None` if the `Iterable` is empty. + * + * @category getters + * @since 2.0.0 + */ +export const tail = (self: Iterable): Option.Option> => { + const input = fromIterable(self) + return isNonEmptyReadonlyArray(input) ? Option.some(tailNonEmpty(input)) : Option.none() +} + +/** + * Get all but the first element of a `NonEmptyReadonlyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.tailNonEmpty([1, 2, 3, 4]) + * console.log(result) // [2, 3, 4] + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const tailNonEmpty = (self: NonEmptyReadonlyArray): Array => self.slice(1) + +/** + * Get all but the last element of an `Iterable`, creating a new `Array`, or `None` if the `Iterable` is empty. + * + * @category getters + * @since 2.0.0 + */ +export const init = (self: Iterable): Option.Option> => { + const input = fromIterable(self) + return isNonEmptyReadonlyArray(input) ? Option.some(initNonEmpty(input)) : Option.none() +} + +/** + * Get all but the last element of a non empty array, creating a new array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.initNonEmpty([1, 2, 3, 4]) + * console.log(result) // [1, 2, 3] + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const initNonEmpty = (self: NonEmptyReadonlyArray): Array => self.slice(0, -1) + +/** + * Keep only a max number of elements from the start of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.take([1, 2, 3, 4, 5], 3) + * console.log(result) // [1, 2, 3] + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const take: { + /** + * Keep only a max number of elements from the start of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.take([1, 2, 3, 4, 5], 3) + * console.log(result) // [1, 2, 3] + * ``` + * + * @category getters + * @since 2.0.0 + */ + (n: number): (self: Iterable) => Array + /** + * Keep only a max number of elements from the start of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.take([1, 2, 3, 4, 5], 3) + * console.log(result) // [1, 2, 3] + * ``` + * + * @category getters + * @since 2.0.0 + */ + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + return input.slice(0, clamp(n, input)) +}) + +/** + * Keep only a max number of elements from the end of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.takeRight([1, 2, 3, 4, 5], 3) + * console.log(result) // [3, 4, 5] + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const takeRight: { + /** + * Keep only a max number of elements from the end of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.takeRight([1, 2, 3, 4, 5], 3) + * console.log(result) // [3, 4, 5] + * ``` + * + * @category getters + * @since 2.0.0 + */ + (n: number): (self: Iterable) => Array + /** + * Keep only a max number of elements from the end of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.takeRight([1, 2, 3, 4, 5], 3) + * console.log(result) // [3, 4, 5] + * ``` + * + * @category getters + * @since 2.0.0 + */ + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + const i = clamp(n, input) + return i === 0 ? [] : input.slice(-i) +}) + +/** + * Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.takeWhile([1, 3, 2, 4, 1, 2], x => x < 4) + * console.log(result) // [1, 3, 2] + * + * // Explanation: + * // - The function starts with the first element (`1`), which is less than `4`, so it adds `1` to the result. + * // - The next element (`3`) is also less than `4`, so it adds `3`. + * // - The next element (`2`) is again less than `4`, so it adds `2`. + * // - The function then encounters `4`, which is not less than `4`. At this point, it stops checking further elements and finalizes the result. + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const takeWhile: { + /** + * Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.takeWhile([1, 3, 2, 4, 1, 2], x => x < 4) + * console.log(result) // [1, 3, 2] + * + * // Explanation: + * // - The function starts with the first element (`1`), which is less than `4`, so it adds `1` to the result. + * // - The next element (`3`) is also less than `4`, so it adds `3`. + * // - The next element (`2`) is again less than `4`, so it adds `2`. + * // - The function then encounters `4`, which is not less than `4`. At this point, it stops checking further elements and finalizes the result. + * ``` + * + * @category getters + * @since 2.0.0 + */ + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Array + /** + * Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.takeWhile([1, 3, 2, 4, 1, 2], x => x < 4) + * console.log(result) // [1, 3, 2] + * + * // Explanation: + * // - The function starts with the first element (`1`), which is less than `4`, so it adds `1` to the result. + * // - The next element (`3`) is also less than `4`, so it adds `3`. + * // - The next element (`2`) is again less than `4`, so it adds `2`. + * // - The function then encounters `4`, which is not less than `4`. At this point, it stops checking further elements and finalizes the result. + * ``` + * + * @category getters + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Array + /** + * Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.takeWhile([1, 3, 2, 4, 1, 2], x => x < 4) + * console.log(result) // [1, 3, 2] + * + * // Explanation: + * // - The function starts with the first element (`1`), which is less than `4`, so it adds `1` to the result. + * // - The next element (`3`) is also less than `4`, so it adds `3`. + * // - The next element (`2`) is again less than `4`, so it adds `2`. + * // - The function then encounters `4`, which is not less than `4`. At this point, it stops checking further elements and finalizes the result. + * ``` + * + * @category getters + * @since 2.0.0 + */ + (self: Iterable, refinement: (a: A, i: number) => a is B): Array + /** + * Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.takeWhile([1, 3, 2, 4, 1, 2], x => x < 4) + * console.log(result) // [1, 3, 2] + * + * // Explanation: + * // - The function starts with the first element (`1`), which is less than `4`, so it adds `1` to the result. + * // - The next element (`3`) is also less than `4`, so it adds `3`. + * // - The next element (`2`) is again less than `4`, so it adds `2`. + * // - The function then encounters `4`, which is not less than `4`. At this point, it stops checking further elements and finalizes the result. + * ``` + * + * @category getters + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): Array +} = dual(2, (self: Iterable, predicate: (a: A, i: number) => boolean): Array => { + let i = 0 + const out: Array = [] + for (const a of self) { + if (!predicate(a, i)) { + break + } + out.push(a) + i++ + } + return out +}) + +const spanIndex = (self: Iterable, predicate: (a: A, i: number) => boolean): number => { + let i = 0 + for (const a of self) { + if (!predicate(a, i)) { + break + } + i++ + } + return i +} + +/** + * Split an `Iterable` into two parts: + * + * 1. the longest initial subarray for which all elements satisfy the specified predicate + * 2. the remaining elements + * + * @category splitting + * @since 2.0.0 + */ +export const span: { + /** + * Split an `Iterable` into two parts: + * + * 1. the longest initial subarray for which all elements satisfy the specified predicate + * 2. the remaining elements + * + * @category splitting + * @since 2.0.0 + */ + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => [init: Array, rest: Array>] + /** + * Split an `Iterable` into two parts: + * + * 1. the longest initial subarray for which all elements satisfy the specified predicate + * 2. the remaining elements + * + * @category splitting + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => [init: Array, rest: Array] + /** + * Split an `Iterable` into two parts: + * + * 1. the longest initial subarray for which all elements satisfy the specified predicate + * 2. the remaining elements + * + * @category splitting + * @since 2.0.0 + */ + (self: Iterable, refinement: (a: A, i: number) => a is B): [init: Array, rest: Array>] + /** + * Split an `Iterable` into two parts: + * + * 1. the longest initial subarray for which all elements satisfy the specified predicate + * 2. the remaining elements + * + * @category splitting + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): [init: Array, rest: Array] +} = dual( + 2, + (self: Iterable, predicate: (a: A, i: number) => boolean): [init: Array, rest: Array] => + splitAt(self, spanIndex(self, predicate)) +) + +/** + * Drop a max number of elements from the start of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.drop([1, 2, 3, 4, 5], 2) + * console.log(result) // [3, 4, 5] + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const drop: { + /** + * Drop a max number of elements from the start of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.drop([1, 2, 3, 4, 5], 2) + * console.log(result) // [3, 4, 5] + * ``` + * + * @category getters + * @since 2.0.0 + */ + (n: number): (self: Iterable) => Array + /** + * Drop a max number of elements from the start of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.drop([1, 2, 3, 4, 5], 2) + * console.log(result) // [3, 4, 5] + * ``` + * + * @category getters + * @since 2.0.0 + */ + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + return input.slice(clamp(n, input), input.length) +}) + +/** + * Drop a max number of elements from the end of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dropRight([1, 2, 3, 4, 5], 2) + * console.log(result) // [1, 2, 3] + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const dropRight: { + /** + * Drop a max number of elements from the end of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dropRight([1, 2, 3, 4, 5], 2) + * console.log(result) // [1, 2, 3] + * ``` + * + * @category getters + * @since 2.0.0 + */ + (n: number): (self: Iterable) => Array + /** + * Drop a max number of elements from the end of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dropRight([1, 2, 3, 4, 5], 2) + * console.log(result) // [1, 2, 3] + * ``` + * + * @category getters + * @since 2.0.0 + */ + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + return input.slice(0, input.length - clamp(n, input)) +}) + +/** + * Remove the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dropWhile([1, 2, 3, 4, 5], x => x < 4) + * console.log(result) // [4, 5] + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const dropWhile: { + /** + * Remove the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dropWhile([1, 2, 3, 4, 5], x => x < 4) + * console.log(result) // [4, 5] + * ``` + * + * @category getters + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Array + /** + * Remove the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dropWhile([1, 2, 3, 4, 5], x => x < 4) + * console.log(result) // [4, 5] + * ``` + * + * @category getters + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): Array +} = dual( + 2, + (self: Iterable, predicate: (a: A, i: number) => boolean): Array => + fromIterable(self).slice(spanIndex(self, predicate)) +) + +/** + * Return the first index for which a predicate holds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirstIndex([5, 3, 8, 9], x => x > 5) + * console.log(result) // Option.some(2) + * ``` + * + * @category elements + * @since 2.0.0 + */ +export const findFirstIndex: { + /** + * Return the first index for which a predicate holds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirstIndex([5, 3, 8, 9], x => x > 5) + * console.log(result) // Option.some(2) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option + /** + * Return the first index for which a predicate holds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirstIndex([5, 3, 8, 9], x => x > 5) + * console.log(result) // Option.some(2) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option +} = dual(2, (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option => { + let i = 0 + for (const a of self) { + if (predicate(a, i)) { + return Option.some(i) + } + i++ + } + return Option.none() +}) + +/** + * Return the last index for which a predicate holds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findLastIndex([1, 3, 8, 9], x => x < 5) + * console.log(result) // Option.some(1) + * ``` + * + * @category elements + * @since 2.0.0 + */ +export const findLastIndex: { + /** + * Return the last index for which a predicate holds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findLastIndex([1, 3, 8, 9], x => x < 5) + * console.log(result) // Option.some(1) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option + /** + * Return the last index for which a predicate holds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findLastIndex([1, 3, 8, 9], x => x < 5) + * console.log(result) // Option.some(1) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option +} = dual(2, (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option => { + const input = fromIterable(self) + for (let i = input.length - 1; i >= 0; i--) { + if (predicate(input[i], i)) { + return Option.some(i) + } + } + return Option.none() +}) + +/** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirst([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ +export const findFirst: { + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirst([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (f: (a: NoInfer, i: number) => Option.Option): (self: Iterable) => Option.Option + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirst([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Option.Option + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirst([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirst([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, f: (a: A, i: number) => Option.Option): Option.Option + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirst([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, refinement: (a: A, i: number) => a is B): Option.Option + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirst([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option +} = moduleIterable.findFirst + +/** + * Finds the last element in an iterable collection that satisfies the given predicate or refinement. + * Returns an `Option` containing the found element, or `Option.none` if no element matches. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findLast([1, 2, 3, 4, 5], n => n % 2 === 0) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ +export const findLast: { + /** + * Finds the last element in an iterable collection that satisfies the given predicate or refinement. + * Returns an `Option` containing the found element, or `Option.none` if no element matches. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findLast([1, 2, 3, 4, 5], n => n % 2 === 0) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (f: (a: NoInfer, i: number) => Option.Option): (self: Iterable) => Option.Option + /** + * Finds the last element in an iterable collection that satisfies the given predicate or refinement. + * Returns an `Option` containing the found element, or `Option.none` if no element matches. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findLast([1, 2, 3, 4, 5], n => n % 2 === 0) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Option.Option + /** + * Finds the last element in an iterable collection that satisfies the given predicate or refinement. + * Returns an `Option` containing the found element, or `Option.none` if no element matches. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findLast([1, 2, 3, 4, 5], n => n % 2 === 0) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option + /** + * Finds the last element in an iterable collection that satisfies the given predicate or refinement. + * Returns an `Option` containing the found element, or `Option.none` if no element matches. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findLast([1, 2, 3, 4, 5], n => n % 2 === 0) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, f: (a: A, i: number) => Option.Option): Option.Option + /** + * Finds the last element in an iterable collection that satisfies the given predicate or refinement. + * Returns an `Option` containing the found element, or `Option.none` if no element matches. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findLast([1, 2, 3, 4, 5], n => n % 2 === 0) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, refinement: (a: A, i: number) => a is B): Option.Option + /** + * Finds the last element in an iterable collection that satisfies the given predicate or refinement. + * Returns an `Option` containing the found element, or `Option.none` if no element matches. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findLast([1, 2, 3, 4, 5], n => n % 2 === 0) + * console.log(result) // Option.some(4) + * ``` + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option +} = dual( + 2, + ( + self: Iterable, + f: ((a: A, i: number) => boolean) | ((a: A, i: number) => Option.Option) + ): Option.Option => { + const input = fromIterable(self) + for (let i = input.length - 1; i >= 0; i--) { + const a = input[i] + const o = f(a, i) + if (Predicate.isBoolean(o)) { + if (o) { + return Option.some(a) + } + } else { + if (Option.isSome(o)) { + return o + } + } + } + return Option.none() + } +) + +/** + * Returns a tuple of the first element that satisfies the specified + * predicate and its index, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirstWithIndex([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some([4, 3]) + * ``` + * + * @category elements + * @since 3.17.0 + */ +export const findFirstWithIndex: { + /** + * Returns a tuple of the first element that satisfies the specified + * predicate and its index, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirstWithIndex([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some([4, 3]) + * ``` + * + * @category elements + * @since 3.17.0 + */ + (f: (a: NoInfer, i: number) => Option.Option): (self: Iterable) => Option.Option<[B, number]> + /** + * Returns a tuple of the first element that satisfies the specified + * predicate and its index, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirstWithIndex([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some([4, 3]) + * ``` + * + * @category elements + * @since 3.17.0 + */ + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Option.Option<[B, number]> + /** + * Returns a tuple of the first element that satisfies the specified + * predicate and its index, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirstWithIndex([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some([4, 3]) + * ``` + * + * @category elements + * @since 3.17.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option.Option<[A, number]> + /** + * Returns a tuple of the first element that satisfies the specified + * predicate and its index, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirstWithIndex([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some([4, 3]) + * ``` + * + * @category elements + * @since 3.17.0 + */ + (self: Iterable, f: (a: A, i: number) => Option.Option): Option.Option<[B, number]> + /** + * Returns a tuple of the first element that satisfies the specified + * predicate and its index, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirstWithIndex([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some([4, 3]) + * ``` + * + * @category elements + * @since 3.17.0 + */ + (self: Iterable, refinement: (a: A, i: number) => a is B): Option.Option<[B, number]> + /** + * Returns a tuple of the first element that satisfies the specified + * predicate and its index, or `None` if no such element exists. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.findFirstWithIndex([1, 2, 3, 4, 5], x => x > 3) + * console.log(result) // Option.some([4, 3]) + * ``` + * + * @category elements + * @since 3.17.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): Option.Option<[A, number]> +} = dual( + 2, + ( + self: Iterable, + f: ((a: A, i: number) => boolean) | ((a: A, i: number) => Option.Option) + ): Option.Option<[A, number]> => { + let i = 0 + for (const a of self) { + const o = f(a, i) + if (Predicate.isBoolean(o)) { + if (o) { + return Option.some([a, i]) + } + } else { + if (Option.isSome(o)) { + return Option.some([o.value, i]) + } + } + i++ + } + return Option.none() + } +) + +/** + * Counts all the element of the given array that pass the given predicate + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.countBy([1, 2, 3, 4, 5], n => n % 2 === 0) + * console.log(result) // 2 + * ``` + * + * @category folding + * @since 3.16.0 + */ +export const countBy: { + /** + * Counts all the element of the given array that pass the given predicate + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.countBy([1, 2, 3, 4, 5], n => n % 2 === 0) + * console.log(result) // 2 + * ``` + * + * @category folding + * @since 3.16.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => number + /** + * Counts all the element of the given array that pass the given predicate + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.countBy([1, 2, 3, 4, 5], n => n % 2 === 0) + * console.log(result) // 2 + * ``` + * + * @category folding + * @since 3.16.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): number +} = dual( + 2, + ( + self: Iterable, + f: (a: A, i: number) => boolean + ): number => { + let count = 0 + const as = fromIterable(self) + for (let i = 0; i < as.length; i++) { + const a = as[i] + if (f(a, i)) { + count++ + } + } + return count + } +) + +/** + * Insert an element at the specified index, creating a new `NonEmptyArray`, + * or return `None` if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.insertAt(['a', 'b', 'c', 'e'], 3, 'd') + * console.log(result) // Option.some(['a', 'b', 'c', 'd', 'e']) + * ``` + * + * @since 2.0.0 + */ +export const insertAt: { + /** + * Insert an element at the specified index, creating a new `NonEmptyArray`, + * or return `None` if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.insertAt(['a', 'b', 'c', 'e'], 3, 'd') + * console.log(result) // Option.some(['a', 'b', 'c', 'd', 'e']) + * ``` + * + * @since 2.0.0 + */ + (i: number, b: B): (self: Iterable) => Option.Option> + /** + * Insert an element at the specified index, creating a new `NonEmptyArray`, + * or return `None` if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.insertAt(['a', 'b', 'c', 'e'], 3, 'd') + * console.log(result) // Option.some(['a', 'b', 'c', 'd', 'e']) + * ``` + * + * @since 2.0.0 + */ + (self: Iterable, i: number, b: B): Option.Option> +} = dual(3, (self: Iterable, i: number, b: B): Option.Option> => { + const out: Array = Array.from(self) + // v--- `= self.length` is ok, it means inserting in last position + if (i < 0 || i > out.length) { + return Option.none() + } + out.splice(i, 0, b) + return Option.some(out) as any +}) + +/** + * Change the element at the specified index, creating a new `Array`, + * or return a copy of the input if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.replace(['a', 'b', 'c', 'd'], 1, 'z') + * console.log(result) // ['a', 'z', 'c', 'd'] + * ``` + * + * @since 2.0.0 + */ +export const replace: { + /** + * Change the element at the specified index, creating a new `Array`, + * or return a copy of the input if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.replace(['a', 'b', 'c', 'd'], 1, 'z') + * console.log(result) // ['a', 'z', 'c', 'd'] + * ``` + * + * @since 2.0.0 + */ + (i: number, b: B): = Iterable>( + self: S + ) => ReadonlyArray.With | B> + /** + * Change the element at the specified index, creating a new `Array`, + * or return a copy of the input if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.replace(['a', 'b', 'c', 'd'], 1, 'z') + * console.log(result) // ['a', 'z', 'c', 'd'] + * ``` + * + * @since 2.0.0 + */ + = Iterable>(self: S, i: number, b: B): ReadonlyArray.With | B> +} = dual(3, (self: Iterable, i: number, b: B): Array => modify(self, i, () => b)) + +/** + * Replaces an element in an array with the given value, returning an option of the updated array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.replaceOption([1, 2, 3], 1, 4) + * console.log(result) // Option.some([1, 4, 3]) + * ``` + * + * @since 2.0.0 + */ +export const replaceOption: { + /** + * Replaces an element in an array with the given value, returning an option of the updated array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.replaceOption([1, 2, 3], 1, 4) + * console.log(result) // Option.some([1, 4, 3]) + * ``` + * + * @since 2.0.0 + */ + (i: number, b: B): = Iterable>( + self: S + ) => Option.Option | B>> + /** + * Replaces an element in an array with the given value, returning an option of the updated array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.replaceOption([1, 2, 3], 1, 4) + * console.log(result) // Option.some([1, 4, 3]) + * ``` + * + * @since 2.0.0 + */ + = Iterable>(self: S, i: number, b: B): Option.Option | B>> +} = dual( + 3, + (self: Iterable, i: number, b: B): Option.Option> => modifyOption(self, i, () => b) +) + +/** + * Apply a function to the element at the specified index, creating a new `Array`, + * or return a copy of the input if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.modify([1, 2, 3, 4], 2, (n) => n * 2) + * console.log(result) // [1, 2, 6, 4] + * ``` + * + * @since 2.0.0 + */ +export const modify: { + /** + * Apply a function to the element at the specified index, creating a new `Array`, + * or return a copy of the input if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.modify([1, 2, 3, 4], 2, (n) => n * 2) + * console.log(result) // [1, 2, 6, 4] + * ``` + * + * @since 2.0.0 + */ + = Iterable>(i: number, f: (a: ReadonlyArray.Infer) => B): (self: S) => ReadonlyArray.With | B> + /** + * Apply a function to the element at the specified index, creating a new `Array`, + * or return a copy of the input if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.modify([1, 2, 3, 4], 2, (n) => n * 2) + * console.log(result) // [1, 2, 6, 4] + * ``` + * + * @since 2.0.0 + */ + = Iterable>(self: S, i: number, f: (a: ReadonlyArray.Infer) => B): ReadonlyArray.With | B> +} = dual( + 3, + (self: Iterable, i: number, f: (a: A) => B): Array => { + const out: Array = Array.from(self) + if (isOutOfBounds(i, out)) { + return out + } + const b = f(out[i] as A) + out[i] = b + return out + } +) + +/** + * Apply a function to the element at the specified index, creating a new `Array`, + * or return `None` if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const input = [1, 2, 3, 4] + * const result = Array.modifyOption(input, 2, (n) => n * 2) + * console.log(result) // Option.some([1, 2, 6, 4]) + * + * const outOfBoundsResult = Array.modifyOption(input, 5, (n) => n * 2) + * console.log(outOfBoundsResult) // Option.none() + * ``` + * + * @since 2.0.0 + */ +export const modifyOption: { + /** + * Apply a function to the element at the specified index, creating a new `Array`, + * or return `None` if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const input = [1, 2, 3, 4] + * const result = Array.modifyOption(input, 2, (n) => n * 2) + * console.log(result) // Option.some([1, 2, 6, 4]) + * + * const outOfBoundsResult = Array.modifyOption(input, 5, (n) => n * 2) + * console.log(outOfBoundsResult) // Option.none() + * ``` + * + * @since 2.0.0 + */ + = Iterable>(i: number, f: (a: ReadonlyArray.Infer) => B): (self: S) => Option.Option | B>> + /** + * Apply a function to the element at the specified index, creating a new `Array`, + * or return `None` if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const input = [1, 2, 3, 4] + * const result = Array.modifyOption(input, 2, (n) => n * 2) + * console.log(result) // Option.some([1, 2, 6, 4]) + * + * const outOfBoundsResult = Array.modifyOption(input, 5, (n) => n * 2) + * console.log(outOfBoundsResult) // Option.none() + * ``` + * + * @since 2.0.0 + */ + = Iterable>(self: S, i: number, f: (a: ReadonlyArray.Infer) => B): Option.Option | B>> +} = dual(3, (self: Iterable, i: number, f: (a: A) => B): Option.Option> => { + const arr = fromIterable(self) + if (isOutOfBounds(i, arr)) { + return Option.none() + } + const out: Array = Array.isArray(self) ? self.slice() : arr + const b = f(arr[i]) + out[i] = b + return Option.some(out) +}) + +/** + * Delete the element at the specified index, creating a new `Array`, + * or return a copy of the input if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const input = [1, 2, 3, 4] + * const result = Array.remove(input, 2) + * console.log(result) // [1, 2, 4] + * + * const outOfBoundsResult = Array.remove(input, 5) + * console.log(outOfBoundsResult) // [1, 2, 3, 4] + * ``` + * + * @since 2.0.0 + */ +export const remove: { + /** + * Delete the element at the specified index, creating a new `Array`, + * or return a copy of the input if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const input = [1, 2, 3, 4] + * const result = Array.remove(input, 2) + * console.log(result) // [1, 2, 4] + * + * const outOfBoundsResult = Array.remove(input, 5) + * console.log(outOfBoundsResult) // [1, 2, 3, 4] + * ``` + * + * @since 2.0.0 + */ + (i: number): (self: Iterable) => Array + /** + * Delete the element at the specified index, creating a new `Array`, + * or return a copy of the input if the index is out of bounds. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const input = [1, 2, 3, 4] + * const result = Array.remove(input, 2) + * console.log(result) // [1, 2, 4] + * + * const outOfBoundsResult = Array.remove(input, 5) + * console.log(outOfBoundsResult) // [1, 2, 3, 4] + * ``` + * + * @since 2.0.0 + */ + (self: Iterable, i: number): Array +} = dual(2, (self: Iterable, i: number): Array => { + const out = Array.from(self) + if (isOutOfBounds(i, out)) { + return out + } + out.splice(i, 1) + return out +}) + +/** + * Delete the element at the specified index, creating a new `Array`, + * or return `None` if the index is out of bounds. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Array, Option } from "effect" + * + * const numbers = [1, 2, 3, 4] + * const result = Array.removeOption(numbers, 2) + * assert.deepStrictEqual(result, Option.some([1, 2, 4])) + * + * const outOfBoundsResult = Array.removeOption(numbers, 5) + * assert.deepStrictEqual(outOfBoundsResult, Option.none()) + * ``` + * + * @since 3.16.0 + */ +export const removeOption: { + /** + * Delete the element at the specified index, creating a new `Array`, + * or return `None` if the index is out of bounds. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Array, Option } from "effect" + * + * const numbers = [1, 2, 3, 4] + * const result = Array.removeOption(numbers, 2) + * assert.deepStrictEqual(result, Option.some([1, 2, 4])) + * + * const outOfBoundsResult = Array.removeOption(numbers, 5) + * assert.deepStrictEqual(outOfBoundsResult, Option.none()) + * ``` + * + * @since 3.16.0 + */ + (i: number): (self: Iterable) => Option.Option> + /** + * Delete the element at the specified index, creating a new `Array`, + * or return `None` if the index is out of bounds. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Array, Option } from "effect" + * + * const numbers = [1, 2, 3, 4] + * const result = Array.removeOption(numbers, 2) + * assert.deepStrictEqual(result, Option.some([1, 2, 4])) + * + * const outOfBoundsResult = Array.removeOption(numbers, 5) + * assert.deepStrictEqual(outOfBoundsResult, Option.none()) + * ``` + * + * @since 3.16.0 + */ + (self: Iterable, i: number): Option.Option> +} = dual(2, (self: Iterable, i: number): Option.Option> => { + const arr = fromIterable(self) + if (isOutOfBounds(i, arr)) { + return Option.none() + } + const out = Array.isArray(self) ? self.slice() : arr + out.splice(i, 1) + return Option.some(out) +}) + +/** + * Reverse an `Iterable`, creating a new `Array`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.reverse([1, 2, 3, 4]) + * console.log(result) // [4, 3, 2, 1] + * ``` + * + * @category elements + * @since 2.0.0 + */ +export const reverse = >( + self: S +): S extends NonEmptyReadonlyArray ? NonEmptyArray : S extends Iterable ? Array : never => + Array.from(self).reverse() as any + +/** + * Create a new array with elements sorted in increasing order based on the specified comparator. + * If the input is a `NonEmptyReadonlyArray`, the output will also be a `NonEmptyReadonlyArray`. + * + * @category sorting + * @since 2.0.0 + */ +export const sort: { + /** + * Create a new array with elements sorted in increasing order based on the specified comparator. + * If the input is a `NonEmptyReadonlyArray`, the output will also be a `NonEmptyReadonlyArray`. + * + * @category sorting + * @since 2.0.0 + */ + (O: Order.Order): >(self: S) => ReadonlyArray.With> + /** + * Create a new array with elements sorted in increasing order based on the specified comparator. + * If the input is a `NonEmptyReadonlyArray`, the output will also be a `NonEmptyReadonlyArray`. + * + * @category sorting + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, O: Order.Order): NonEmptyArray + /** + * Create a new array with elements sorted in increasing order based on the specified comparator. + * If the input is a `NonEmptyReadonlyArray`, the output will also be a `NonEmptyReadonlyArray`. + * + * @category sorting + * @since 2.0.0 + */ + (self: Iterable, O: Order.Order): Array +} = dual(2, (self: Iterable, O: Order.Order): Array => { + const out = Array.from(self) + out.sort(O) + return out +}) + +/** + * Sorts an array based on a provided mapping function and order. The mapping + * function transforms the elements into a value that can be compared, and the + * order defines how those values should be sorted. + * + * **Example** + * + * ```ts + * import { Array, Order } from "effect" + * + * const result = Array.sortWith(["aaa", "b", "cc"], (s) => s.length, Order.number) + * console.log(result) // ["b", "cc", "aaa"] + * + * // Explanation: + * // The array of strings is sorted based on their lengths. The mapping function `(s) => s.length` + * // converts each string into its length, and the `Order.number` specifies that the lengths should + * // be sorted in ascending order. + * ``` + * + * @since 2.0.0 + * @category elements + */ +export const sortWith: { + /** + * Sorts an array based on a provided mapping function and order. The mapping + * function transforms the elements into a value that can be compared, and the + * order defines how those values should be sorted. + * + * **Example** + * + * ```ts + * import { Array, Order } from "effect" + * + * const result = Array.sortWith(["aaa", "b", "cc"], (s) => s.length, Order.number) + * console.log(result) // ["b", "cc", "aaa"] + * + * // Explanation: + * // The array of strings is sorted based on their lengths. The mapping function `(s) => s.length` + * // converts each string into its length, and the `Order.number` specifies that the lengths should + * // be sorted in ascending order. + * ``` + * + * @since 2.0.0 + * @category elements + */ + , B>(f: (a: ReadonlyArray.Infer) => B, order: Order.Order): (self: S) => ReadonlyArray.With> + /** + * Sorts an array based on a provided mapping function and order. The mapping + * function transforms the elements into a value that can be compared, and the + * order defines how those values should be sorted. + * + * **Example** + * + * ```ts + * import { Array, Order } from "effect" + * + * const result = Array.sortWith(["aaa", "b", "cc"], (s) => s.length, Order.number) + * console.log(result) // ["b", "cc", "aaa"] + * + * // Explanation: + * // The array of strings is sorted based on their lengths. The mapping function `(s) => s.length` + * // converts each string into its length, and the `Order.number` specifies that the lengths should + * // be sorted in ascending order. + * ``` + * + * @since 2.0.0 + * @category elements + */ + (self: NonEmptyReadonlyArray, f: (a: A) => B, O: Order.Order): NonEmptyArray + /** + * Sorts an array based on a provided mapping function and order. The mapping + * function transforms the elements into a value that can be compared, and the + * order defines how those values should be sorted. + * + * **Example** + * + * ```ts + * import { Array, Order } from "effect" + * + * const result = Array.sortWith(["aaa", "b", "cc"], (s) => s.length, Order.number) + * console.log(result) // ["b", "cc", "aaa"] + * + * // Explanation: + * // The array of strings is sorted based on their lengths. The mapping function `(s) => s.length` + * // converts each string into its length, and the `Order.number` specifies that the lengths should + * // be sorted in ascending order. + * ``` + * + * @since 2.0.0 + * @category elements + */ + (self: Iterable, f: (a: A) => B, order: Order.Order): Array +} = dual( + 3, + (self: Iterable, f: (a: A) => B, order: Order.Order): Array => + Array.from(self).map((a) => [a, f(a)] as const).sort(([, a], [, b]) => order(a, b)).map(([_]) => _) +) + +/** + * Sorts the elements of an `Iterable` in increasing order based on the provided + * orders. The elements are compared using the first order in `orders`, then the + * second order if the first comparison is equal, and so on. + * + * **Example** + * + * ```ts + * import { Array, Order, pipe } from "effect" + * + * const users = [ + * { name: "Alice", age: 30 }, + * { name: "Bob", age: 25 }, + * { name: "Charlie", age: 30 } + * ] + * + * const result = pipe( + * users, + * Array.sortBy( + * Order.mapInput(Order.number, (user: (typeof users)[number]) => user.age), + * Order.mapInput(Order.string, (user: (typeof users)[number]) => user.name) + * ) + * ) + * + * console.log(result) + * // [ + * // { name: "Bob", age: 25 }, + * // { name: "Alice", age: 30 }, + * // { name: "Charlie", age: 30 } + * // ] + * + * // Explanation: + * // The array of users is sorted first by age in ascending order. When ages are equal, + * // the users are further sorted by name in ascending order. + * ``` + * + * @category sorting + * @since 2.0.0 + */ +export const sortBy = >( + ...orders: ReadonlyArray>> +) => { + const sortByAll = sort(Order.combineAll(orders)) + return ( + self: S + ): S extends NonEmptyReadonlyArray ? NonEmptyArray : S extends Iterable ? Array : never => { + const input = fromIterable(self) + if (isNonEmptyReadonlyArray(input)) { + return sortByAll(input) as any + } + return [] as any + } +} + +/** + * Takes two `Iterable`s and returns an `Array` of corresponding pairs. + * If one input `Iterable` is short, excess elements of the + * longer `Iterable` are discarded. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.zip([1, 2, 3], ['a', 'b']) + * console.log(result) // [[1, 'a'], [2, 'b']] + * ``` + * + * @category zipping + * @since 2.0.0 + */ +export const zip: { + /** + * Takes two `Iterable`s and returns an `Array` of corresponding pairs. + * If one input `Iterable` is short, excess elements of the + * longer `Iterable` are discarded. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.zip([1, 2, 3], ['a', 'b']) + * console.log(result) // [[1, 'a'], [2, 'b']] + * ``` + * + * @category zipping + * @since 2.0.0 + */ + (that: NonEmptyReadonlyArray): (self: NonEmptyReadonlyArray) => NonEmptyArray<[A, B]> + /** + * Takes two `Iterable`s and returns an `Array` of corresponding pairs. + * If one input `Iterable` is short, excess elements of the + * longer `Iterable` are discarded. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.zip([1, 2, 3], ['a', 'b']) + * console.log(result) // [[1, 'a'], [2, 'b']] + * ``` + * + * @category zipping + * @since 2.0.0 + */ + (that: Iterable): (self: Iterable) => Array<[A, B]> + /** + * Takes two `Iterable`s and returns an `Array` of corresponding pairs. + * If one input `Iterable` is short, excess elements of the + * longer `Iterable` are discarded. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.zip([1, 2, 3], ['a', 'b']) + * console.log(result) // [[1, 'a'], [2, 'b']] + * ``` + * + * @category zipping + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, that: NonEmptyReadonlyArray): NonEmptyArray<[A, B]> + /** + * Takes two `Iterable`s and returns an `Array` of corresponding pairs. + * If one input `Iterable` is short, excess elements of the + * longer `Iterable` are discarded. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.zip([1, 2, 3], ['a', 'b']) + * console.log(result) // [[1, 'a'], [2, 'b']] + * ``` + * + * @category zipping + * @since 2.0.0 + */ + (self: Iterable, that: Iterable): Array<[A, B]> +} = dual( + 2, + (self: Iterable, that: Iterable): Array<[A, B]> => zipWith(self, that, Tuple.make) +) + +/** + * Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results in a new `Array`. If one + * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b) + * console.log(result) // [5, 7, 9] + * ``` + * + * @category zipping + * @since 2.0.0 + */ +export const zipWith: { + /** + * Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results in a new `Array`. If one + * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b) + * console.log(result) // [5, 7, 9] + * ``` + * + * @category zipping + * @since 2.0.0 + */ + (that: NonEmptyReadonlyArray, f: (a: A, b: B) => C): (self: NonEmptyReadonlyArray) => NonEmptyArray + /** + * Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results in a new `Array`. If one + * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b) + * console.log(result) // [5, 7, 9] + * ``` + * + * @category zipping + * @since 2.0.0 + */ + (that: Iterable, f: (a: A, b: B) => C): (self: Iterable) => Array + /** + * Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results in a new `Array`. If one + * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b) + * console.log(result) // [5, 7, 9] + * ``` + * + * @category zipping + * @since 2.0.0 + */ + ( + self: NonEmptyReadonlyArray, + that: NonEmptyReadonlyArray, + f: (a: A, b: B) => C + ): NonEmptyArray + /** + * Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results in a new `Array`. If one + * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.zipWith([1, 2, 3], [4, 5, 6], (a, b) => a + b) + * console.log(result) // [5, 7, 9] + * ``` + * + * @category zipping + * @since 2.0.0 + */ + (self: Iterable, that: Iterable, f: (a: A, b: B) => C): Array +} = dual(3, (self: Iterable, that: Iterable, f: (a: A, b: B) => C): Array => { + const as = fromIterable(self) + const bs = fromIterable(that) + if (isNonEmptyReadonlyArray(as) && isNonEmptyReadonlyArray(bs)) { + const out: NonEmptyArray = [f(headNonEmpty(as), headNonEmpty(bs))] + const len = Math.min(as.length, bs.length) + for (let i = 1; i < len; i++) { + out[i] = f(as[i], bs[i]) + } + return out + } + return [] +}) + +/** + * This function is the inverse of `zip`. Takes an `Iterable` of pairs and return two corresponding `Array`s. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.unzip([[1, "a"], [2, "b"], [3, "c"]]) + * console.log(result) // [[1, 2, 3], ['a', 'b', 'c']] + * ``` + * + * @since 2.0.0 + */ +export const unzip: >( + self: S +) => S extends NonEmptyReadonlyArray ? [NonEmptyArray, NonEmptyArray] + : S extends Iterable ? [Array, Array] + : never = ((self: Iterable): [Array, Array] => { + const input = fromIterable(self) + if (isNonEmptyReadonlyArray(input)) { + const fa: NonEmptyArray = [input[0][0]] + const fb: NonEmptyArray = [input[0][1]] + for (let i = 1; i < input.length; i++) { + fa[i] = input[i][0] + fb[i] = input[i][1] + } + return [fa, fb] + } + return [[], []] + }) as any + +/** + * Places an element in between members of an `Iterable`. + * If the input is a non-empty array, the result is also a non-empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.intersperse([1, 2, 3], 0) + * console.log(result) // [1, 0, 2, 0, 3] + * ``` + * + * @since 2.0.0 + */ +export const intersperse: { + /** + * Places an element in between members of an `Iterable`. + * If the input is a non-empty array, the result is also a non-empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.intersperse([1, 2, 3], 0) + * console.log(result) // [1, 0, 2, 0, 3] + * ``` + * + * @since 2.0.0 + */ + (middle: B): >(self: S) => ReadonlyArray.With | B> + /** + * Places an element in between members of an `Iterable`. + * If the input is a non-empty array, the result is also a non-empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.intersperse([1, 2, 3], 0) + * console.log(result) // [1, 0, 2, 0, 3] + * ``` + * + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, middle: B): NonEmptyArray + /** + * Places an element in between members of an `Iterable`. + * If the input is a non-empty array, the result is also a non-empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.intersperse([1, 2, 3], 0) + * console.log(result) // [1, 0, 2, 0, 3] + * ``` + * + * @since 2.0.0 + */ + (self: Iterable, middle: B): Array +} = dual(2, (self: Iterable, middle: B): Array => { + const input = fromIterable(self) + if (isNonEmptyReadonlyArray(input)) { + const out: NonEmptyArray = [headNonEmpty(input)] + const tail = tailNonEmpty(input) + for (let i = 0; i < tail.length; i++) { + if (i < tail.length) { + out.push(middle) + } + out.push(tail[i]) + } + return out + } + return [] +}) + +/** + * Apply a function to the head, creating a new `NonEmptyReadonlyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.modifyNonEmptyHead([1, 2, 3], n => n * 10) + * console.log(result) // [10, 2, 3] + * ``` + * + * @since 2.0.0 + */ +export const modifyNonEmptyHead: { + /** + * Apply a function to the head, creating a new `NonEmptyReadonlyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.modifyNonEmptyHead([1, 2, 3], n => n * 10) + * console.log(result) // [10, 2, 3] + * ``` + * + * @since 2.0.0 + */ + (f: (a: A) => B): (self: NonEmptyReadonlyArray) => NonEmptyArray + /** + * Apply a function to the head, creating a new `NonEmptyReadonlyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.modifyNonEmptyHead([1, 2, 3], n => n * 10) + * console.log(result) // [10, 2, 3] + * ``` + * + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray +} = dual( + 2, + ( + self: NonEmptyReadonlyArray, + f: (a: A) => B + ): NonEmptyArray => [f(headNonEmpty(self)), ...tailNonEmpty(self)] +) + +/** + * Change the head, creating a new `NonEmptyReadonlyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.setNonEmptyHead([1, 2, 3], 10) + * console.log(result) // [10, 2, 3] + * ``` + * + * @since 2.0.0 + */ +export const setNonEmptyHead: { + /** + * Change the head, creating a new `NonEmptyReadonlyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.setNonEmptyHead([1, 2, 3], 10) + * console.log(result) // [10, 2, 3] + * ``` + * + * @since 2.0.0 + */ + (b: B): (self: NonEmptyReadonlyArray) => NonEmptyArray + /** + * Change the head, creating a new `NonEmptyReadonlyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.setNonEmptyHead([1, 2, 3], 10) + * console.log(result) // [10, 2, 3] + * ``` + * + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, b: B): NonEmptyArray +} = dual( + 2, + (self: NonEmptyReadonlyArray, b: B): NonEmptyArray => modifyNonEmptyHead(self, () => b) +) + +/** + * Apply a function to the last element, creating a new `NonEmptyReadonlyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.modifyNonEmptyLast([1, 2, 3], n => n * 2) + * console.log(result) // [1, 2, 6] + * ``` + * + * @since 2.0.0 + */ +export const modifyNonEmptyLast: { + /** + * Apply a function to the last element, creating a new `NonEmptyReadonlyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.modifyNonEmptyLast([1, 2, 3], n => n * 2) + * console.log(result) // [1, 2, 6] + * ``` + * + * @since 2.0.0 + */ + (f: (a: A) => B): (self: NonEmptyReadonlyArray) => NonEmptyArray + /** + * Apply a function to the last element, creating a new `NonEmptyReadonlyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.modifyNonEmptyLast([1, 2, 3], n => n * 2) + * console.log(result) // [1, 2, 6] + * ``` + * + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray +} = dual( + 2, + (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray => + append(initNonEmpty(self), f(lastNonEmpty(self))) +) + +/** + * Change the last element, creating a new `NonEmptyReadonlyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.setNonEmptyLast([1, 2, 3], 4) + * console.log(result) // [1, 2, 4] + * ``` + * + * @since 2.0.0 + */ +export const setNonEmptyLast: { + /** + * Change the last element, creating a new `NonEmptyReadonlyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.setNonEmptyLast([1, 2, 3], 4) + * console.log(result) // [1, 2, 4] + * ``` + * + * @since 2.0.0 + */ + (b: B): (self: NonEmptyReadonlyArray) => NonEmptyArray + /** + * Change the last element, creating a new `NonEmptyReadonlyArray`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.setNonEmptyLast([1, 2, 3], 4) + * console.log(result) // [1, 2, 4] + * ``` + * + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, b: B): NonEmptyArray +} = dual( + 2, + (self: NonEmptyReadonlyArray, b: B): NonEmptyArray => modifyNonEmptyLast(self, () => b) +) + +/** + * Rotate an `Iterable` by `n` steps. + * If the input is a non-empty array, the result is also a non-empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.rotate(['a', 'b', 'c', 'd', 'e'], 2) + * console.log(result) // [ 'd', 'e', 'a', 'b', 'c' ] + * ``` + * + * @since 2.0.0 + */ +export const rotate: { + /** + * Rotate an `Iterable` by `n` steps. + * If the input is a non-empty array, the result is also a non-empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.rotate(['a', 'b', 'c', 'd', 'e'], 2) + * console.log(result) // [ 'd', 'e', 'a', 'b', 'c' ] + * ``` + * + * @since 2.0.0 + */ + (n: number): >(self: S) => ReadonlyArray.With> + /** + * Rotate an `Iterable` by `n` steps. + * If the input is a non-empty array, the result is also a non-empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.rotate(['a', 'b', 'c', 'd', 'e'], 2) + * console.log(result) // [ 'd', 'e', 'a', 'b', 'c' ] + * ``` + * + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, n: number): NonEmptyArray + /** + * Rotate an `Iterable` by `n` steps. + * If the input is a non-empty array, the result is also a non-empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.rotate(['a', 'b', 'c', 'd', 'e'], 2) + * console.log(result) // [ 'd', 'e', 'a', 'b', 'c' ] + * ``` + * + * @since 2.0.0 + */ + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + if (isNonEmptyReadonlyArray(input)) { + const len = input.length + const m = Math.round(n) % len + if (isOutOfBounds(Math.abs(m), input) || m === 0) { + return copy(input) + } + if (m < 0) { + const [f, s] = splitNonEmptyAt(input, -m) + return appendAll(s, f) + } else { + return rotate(self, m - len) + } + } + return [] +}) + +/** + * Returns a function that checks if a `ReadonlyArray` contains a given value using a provided `isEquivalent` function. + * + * **Example** + * + * ```ts + * import { Array, pipe } from "effect" + * + * const isEquivalent = (a: number, b: number) => a === b + * const containsNumber = Array.containsWith(isEquivalent) + * const result = pipe([1, 2, 3, 4], containsNumber(3)) + * console.log(result) // true + * ``` + * + * @category elements + * @since 2.0.0 + */ +export const containsWith = (isEquivalent: (self: A, that: A) => boolean): { + (a: A): (self: Iterable) => boolean + (self: Iterable, a: A): boolean +} => + dual(2, (self: Iterable, a: A): boolean => { + for (const i of self) { + if (isEquivalent(a, i)) { + return true + } + } + return false + }) + +const _equivalence = Equal.equivalence() + +/** + * Returns a function that checks if a `ReadonlyArray` contains a given value using the default `Equivalence`. + * + * **Example** + * + * ```ts + * import { Array, pipe } from "effect" + * + * const result = pipe(['a', 'b', 'c', 'd'], Array.contains('c')) + * console.log(result) // true + * ``` + * + * @category elements + * @since 2.0.0 + */ +export const contains: { + /** + * Returns a function that checks if a `ReadonlyArray` contains a given value using the default `Equivalence`. + * + * **Example** + * + * ```ts + * import { Array, pipe } from "effect" + * + * const result = pipe(['a', 'b', 'c', 'd'], Array.contains('c')) + * console.log(result) // true + * ``` + * + * @category elements + * @since 2.0.0 + */ + (a: A): (self: Iterable) => boolean + /** + * Returns a function that checks if a `ReadonlyArray` contains a given value using the default `Equivalence`. + * + * **Example** + * + * ```ts + * import { Array, pipe } from "effect" + * + * const result = pipe(['a', 'b', 'c', 'd'], Array.contains('c')) + * console.log(result) // true + * ``` + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, a: A): boolean +} = containsWith(_equivalence) + +/** + * A useful recursion pattern for processing an `Iterable` to produce a new `Array`, often used for "chopping" up the input + * `Iterable`. Typically chop is called with some function that will consume an initial prefix of the `Iterable` and produce a + * value and the rest of the `Array`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.chop([1, 2, 3, 4, 5], (as): [number, Array] => [as[0] * 2, as.slice(1)]) + * console.log(result) // [2, 4, 6, 8, 10] + * + * // Explanation: + * // The `chopFunction` takes the first element of the array, doubles it, and then returns it along with the rest of the array. + * // The `chop` function applies this `chopFunction` recursively to the input array `[1, 2, 3, 4, 5]`, + * // resulting in a new array `[2, 4, 6, 8, 10]`. + * ``` + * + * @since 2.0.0 + */ +export const chop: { + /** + * A useful recursion pattern for processing an `Iterable` to produce a new `Array`, often used for "chopping" up the input + * `Iterable`. Typically chop is called with some function that will consume an initial prefix of the `Iterable` and produce a + * value and the rest of the `Array`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.chop([1, 2, 3, 4, 5], (as): [number, Array] => [as[0] * 2, as.slice(1)]) + * console.log(result) // [2, 4, 6, 8, 10] + * + * // Explanation: + * // The `chopFunction` takes the first element of the array, doubles it, and then returns it along with the rest of the array. + * // The `chop` function applies this `chopFunction` recursively to the input array `[1, 2, 3, 4, 5]`, + * // resulting in a new array `[2, 4, 6, 8, 10]`. + * ``` + * + * @since 2.0.0 + */ + , B>( + f: (as: NonEmptyReadonlyArray>) => readonly [B, ReadonlyArray>] + ): (self: S) => ReadonlyArray.With> + /** + * A useful recursion pattern for processing an `Iterable` to produce a new `Array`, often used for "chopping" up the input + * `Iterable`. Typically chop is called with some function that will consume an initial prefix of the `Iterable` and produce a + * value and the rest of the `Array`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.chop([1, 2, 3, 4, 5], (as): [number, Array] => [as[0] * 2, as.slice(1)]) + * console.log(result) // [2, 4, 6, 8, 10] + * + * // Explanation: + * // The `chopFunction` takes the first element of the array, doubles it, and then returns it along with the rest of the array. + * // The `chop` function applies this `chopFunction` recursively to the input array `[1, 2, 3, 4, 5]`, + * // resulting in a new array `[2, 4, 6, 8, 10]`. + * ``` + * + * @since 2.0.0 + */ + ( + self: NonEmptyReadonlyArray, + f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] + ): NonEmptyArray + /** + * A useful recursion pattern for processing an `Iterable` to produce a new `Array`, often used for "chopping" up the input + * `Iterable`. Typically chop is called with some function that will consume an initial prefix of the `Iterable` and produce a + * value and the rest of the `Array`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.chop([1, 2, 3, 4, 5], (as): [number, Array] => [as[0] * 2, as.slice(1)]) + * console.log(result) // [2, 4, 6, 8, 10] + * + * // Explanation: + * // The `chopFunction` takes the first element of the array, doubles it, and then returns it along with the rest of the array. + * // The `chop` function applies this `chopFunction` recursively to the input array `[1, 2, 3, 4, 5]`, + * // resulting in a new array `[2, 4, 6, 8, 10]`. + * ``` + * + * @since 2.0.0 + */ + ( + self: Iterable, + f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] + ): Array +} = dual(2, ( + self: Iterable, + f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] +): Array => { + const input = fromIterable(self) + if (isNonEmptyReadonlyArray(input)) { + const [b, rest] = f(input) + const out: NonEmptyArray = [b] + let next: ReadonlyArray = rest + while (internalArray.isNonEmptyArray(next)) { + const [b, rest] = f(next) + out.push(b) + next = rest + } + return out + } + return [] +}) + +/** + * Splits an `Iterable` into two segments, with the first segment containing a maximum of `n` elements. + * The value of `n` can be `0`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.splitAt([1, 2, 3, 4, 5], 3) + * console.log(result) // [[1, 2, 3], [4, 5]] + * ``` + * + * @category splitting + * @since 2.0.0 + */ +export const splitAt: { + /** + * Splits an `Iterable` into two segments, with the first segment containing a maximum of `n` elements. + * The value of `n` can be `0`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.splitAt([1, 2, 3, 4, 5], 3) + * console.log(result) // [[1, 2, 3], [4, 5]] + * ``` + * + * @category splitting + * @since 2.0.0 + */ + (n: number): (self: Iterable) => [beforeIndex: Array, fromIndex: Array] + /** + * Splits an `Iterable` into two segments, with the first segment containing a maximum of `n` elements. + * The value of `n` can be `0`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.splitAt([1, 2, 3, 4, 5], 3) + * console.log(result) // [[1, 2, 3], [4, 5]] + * ``` + * + * @category splitting + * @since 2.0.0 + */ + (self: Iterable, n: number): [beforeIndex: Array, fromIndex: Array] +} = dual(2, (self: Iterable, n: number): [Array, Array] => { + const input = Array.from(self) + const _n = Math.floor(n) + if (isNonEmptyReadonlyArray(input)) { + if (_n >= 1) { + return splitNonEmptyAt(input, _n) + } + return [[], input] + } + return [input, []] +}) + +/** + * Splits a `NonEmptyReadonlyArray` into two segments, with the first segment containing a maximum of `n` elements. + * The value of `n` must be `>= 1`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.splitNonEmptyAt(["a", "b", "c", "d", "e"], 3) + * console.log(result) // [["a", "b", "c"], ["d", "e"]] + * ``` + * + * @category splitting + * @since 2.0.0 + */ +export const splitNonEmptyAt: { + /** + * Splits a `NonEmptyReadonlyArray` into two segments, with the first segment containing a maximum of `n` elements. + * The value of `n` must be `>= 1`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.splitNonEmptyAt(["a", "b", "c", "d", "e"], 3) + * console.log(result) // [["a", "b", "c"], ["d", "e"]] + * ``` + * + * @category splitting + * @since 2.0.0 + */ + (n: number): (self: NonEmptyReadonlyArray) => [beforeIndex: NonEmptyArray, fromIndex: Array] + /** + * Splits a `NonEmptyReadonlyArray` into two segments, with the first segment containing a maximum of `n` elements. + * The value of `n` must be `>= 1`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.splitNonEmptyAt(["a", "b", "c", "d", "e"], 3) + * console.log(result) // [["a", "b", "c"], ["d", "e"]] + * ``` + * + * @category splitting + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, n: number): [beforeIndex: NonEmptyArray, fromIndex: Array] +} = dual(2, (self: NonEmptyReadonlyArray, n: number): [NonEmptyArray, Array] => { + const _n = Math.max(1, Math.floor(n)) + return _n >= self.length ? + [copy(self), []] : + [prepend(self.slice(1, _n), headNonEmpty(self)), self.slice(_n)] +}) + +/** + * Splits this iterable into `n` equally sized arrays. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.split([1, 2, 3, 4, 5, 6, 7, 8], 3) + * console.log(result) // [[1, 2, 3], [4, 5, 6], [7, 8]] + * ``` + * + * @since 2.0.0 + * @category splitting + */ +export const split: { + /** + * Splits this iterable into `n` equally sized arrays. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.split([1, 2, 3, 4, 5, 6, 7, 8], 3) + * console.log(result) // [[1, 2, 3], [4, 5, 6], [7, 8]] + * ``` + * + * @since 2.0.0 + * @category splitting + */ + (n: number): (self: Iterable) => Array> + /** + * Splits this iterable into `n` equally sized arrays. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.split([1, 2, 3, 4, 5, 6, 7, 8], 3) + * console.log(result) // [[1, 2, 3], [4, 5, 6], [7, 8]] + * ``` + * + * @since 2.0.0 + * @category splitting + */ + (self: Iterable, n: number): Array> +} = dual(2, (self: Iterable, n: number) => { + const input = fromIterable(self) + return chunksOf(input, Math.ceil(input.length / Math.floor(n))) +}) + +/** + * Splits this iterable on the first element that matches this predicate. + * Returns a tuple containing two arrays: the first one is before the match, and the second one is from the match onward. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.splitWhere([1, 2, 3, 4, 5], n => n > 3) + * console.log(result) // [[1, 2, 3], [4, 5]] + * ``` + * + * @category splitting + * @since 2.0.0 + */ +export const splitWhere: { + /** + * Splits this iterable on the first element that matches this predicate. + * Returns a tuple containing two arrays: the first one is before the match, and the second one is from the match onward. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.splitWhere([1, 2, 3, 4, 5], n => n > 3) + * console.log(result) // [[1, 2, 3], [4, 5]] + * ``` + * + * @category splitting + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => [beforeMatch: Array, fromMatch: Array] + /** + * Splits this iterable on the first element that matches this predicate. + * Returns a tuple containing two arrays: the first one is before the match, and the second one is from the match onward. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.splitWhere([1, 2, 3, 4, 5], n => n > 3) + * console.log(result) // [[1, 2, 3], [4, 5]] + * ``` + * + * @category splitting + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): [beforeMatch: Array, fromMatch: Array] +} = dual( + 2, + (self: Iterable, predicate: (a: A, i: number) => boolean): [beforeMatch: Array, fromMatch: Array] => + span(self, (a: A, i: number) => !predicate(a, i)) +) + +/** + * Copies an array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.copy([1, 2, 3]) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ +export const copy: { + /** + * Copies an array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.copy([1, 2, 3]) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray): NonEmptyArray + /** + * Copies an array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.copy([1, 2, 3]) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + (self: ReadonlyArray): Array +} = ((self: ReadonlyArray): Array => self.slice()) as any + +/** + * Pads an array. + * Returns a new array of length `n` with the elements of `array` followed by `fill` elements if `array` is shorter than `n`. + * If `array` is longer than `n`, the returned array will be a slice of `array` containing the `n` first elements of `array`. + * If `n` is less than or equal to 0, the returned array will be an empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.pad([1, 2, 3], 6, 0) + * console.log(result) // [1, 2, 3, 0, 0, 0] + * ``` + * + * @since 3.8.4 + */ +export const pad: { + /** + * Pads an array. + * Returns a new array of length `n` with the elements of `array` followed by `fill` elements if `array` is shorter than `n`. + * If `array` is longer than `n`, the returned array will be a slice of `array` containing the `n` first elements of `array`. + * If `n` is less than or equal to 0, the returned array will be an empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.pad([1, 2, 3], 6, 0) + * console.log(result) // [1, 2, 3, 0, 0, 0] + * ``` + * + * @since 3.8.4 + */ + (n: number, fill: T): ( + self: Array + ) => Array + /** + * Pads an array. + * Returns a new array of length `n` with the elements of `array` followed by `fill` elements if `array` is shorter than `n`. + * If `array` is longer than `n`, the returned array will be a slice of `array` containing the `n` first elements of `array`. + * If `n` is less than or equal to 0, the returned array will be an empty array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.pad([1, 2, 3], 6, 0) + * console.log(result) // [1, 2, 3, 0, 0, 0] + * ``` + * + * @since 3.8.4 + */ + (self: Array, n: number, fill: T): Array +} = dual(3, (self: Array, n: number, fill: T): Array => { + if (self.length >= n) { + return take(self, n) + } + return appendAll( + self, + makeBy(n - self.length, () => fill) + ) +}) + +/** + * Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of + * the `Iterable`. Note that `chunksOf(n)([])` is `[]`, not `[[]]`. This is intentional, and is consistent with a recursive + * definition of `chunksOf`; it satisfies the property that + * + * ```ts skip-type-checking + * chunksOf(n)(xs).concat(chunksOf(n)(ys)) == chunksOf(n)(xs.concat(ys))) + * ``` + * + * whenever `n` evenly divides the length of `self`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.chunksOf([1, 2, 3, 4, 5], 2) + * console.log(result) // [[1, 2], [3, 4], [5]] + * + * // Explanation: + * // The `chunksOf` function takes an array of numbers `[1, 2, 3, 4, 5]` and a number `2`. + * // It splits the array into chunks of length 2. Since the array length is not evenly divisible by 2, + * // the last chunk contains the remaining elements. + * // The result is `[[1, 2], [3, 4], [5]]`. + * ``` + * + * @category splitting + * @since 2.0.0 + */ +export const chunksOf: { + /** + * Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of + * the `Iterable`. Note that `chunksOf(n)([])` is `[]`, not `[[]]`. This is intentional, and is consistent with a recursive + * definition of `chunksOf`; it satisfies the property that + * + * ```ts skip-type-checking + * chunksOf(n)(xs).concat(chunksOf(n)(ys)) == chunksOf(n)(xs.concat(ys))) + * ``` + * + * whenever `n` evenly divides the length of `self`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.chunksOf([1, 2, 3, 4, 5], 2) + * console.log(result) // [[1, 2], [3, 4], [5]] + * + * // Explanation: + * // The `chunksOf` function takes an array of numbers `[1, 2, 3, 4, 5]` and a number `2`. + * // It splits the array into chunks of length 2. Since the array length is not evenly divisible by 2, + * // the last chunk contains the remaining elements. + * // The result is `[[1, 2], [3, 4], [5]]`. + * ``` + * + * @category splitting + * @since 2.0.0 + */ + (n: number): >( + self: S + ) => ReadonlyArray.With>> + /** + * Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of + * the `Iterable`. Note that `chunksOf(n)([])` is `[]`, not `[[]]`. This is intentional, and is consistent with a recursive + * definition of `chunksOf`; it satisfies the property that + * + * ```ts skip-type-checking + * chunksOf(n)(xs).concat(chunksOf(n)(ys)) == chunksOf(n)(xs.concat(ys))) + * ``` + * + * whenever `n` evenly divides the length of `self`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.chunksOf([1, 2, 3, 4, 5], 2) + * console.log(result) // [[1, 2], [3, 4], [5]] + * + * // Explanation: + * // The `chunksOf` function takes an array of numbers `[1, 2, 3, 4, 5]` and a number `2`. + * // It splits the array into chunks of length 2. Since the array length is not evenly divisible by 2, + * // the last chunk contains the remaining elements. + * // The result is `[[1, 2], [3, 4], [5]]`. + * ``` + * + * @category splitting + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, n: number): NonEmptyArray> + /** + * Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of + * the `Iterable`. Note that `chunksOf(n)([])` is `[]`, not `[[]]`. This is intentional, and is consistent with a recursive + * definition of `chunksOf`; it satisfies the property that + * + * ```ts skip-type-checking + * chunksOf(n)(xs).concat(chunksOf(n)(ys)) == chunksOf(n)(xs.concat(ys))) + * ``` + * + * whenever `n` evenly divides the length of `self`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.chunksOf([1, 2, 3, 4, 5], 2) + * console.log(result) // [[1, 2], [3, 4], [5]] + * + * // Explanation: + * // The `chunksOf` function takes an array of numbers `[1, 2, 3, 4, 5]` and a number `2`. + * // It splits the array into chunks of length 2. Since the array length is not evenly divisible by 2, + * // the last chunk contains the remaining elements. + * // The result is `[[1, 2], [3, 4], [5]]`. + * ``` + * + * @category splitting + * @since 2.0.0 + */ + (self: Iterable, n: number): Array> +} = dual(2, (self: Iterable, n: number): Array> => { + const input = fromIterable(self) + if (isNonEmptyReadonlyArray(input)) { + return chop(input, splitNonEmptyAt(n)) + } + return [] +}) + +/** + * Creates sliding windows of size `n` from an `Iterable`. + * If the number of elements is less than `n` or if `n` is not greater than zero, + * an empty array is returned. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Array } from "effect" + * + * const numbers = [1, 2, 3, 4, 5] + * assert.deepStrictEqual(Array.window(numbers, 3), [[1, 2, 3], [2, 3, 4], [3, 4, 5]]) + * assert.deepStrictEqual(Array.window(numbers, 6), []) + * ``` + * + * @category splitting + * @since 3.13.2 + */ +export const window: { + /** + * Creates sliding windows of size `n` from an `Iterable`. + * If the number of elements is less than `n` or if `n` is not greater than zero, + * an empty array is returned. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Array } from "effect" + * + * const numbers = [1, 2, 3, 4, 5] + * assert.deepStrictEqual(Array.window(numbers, 3), [[1, 2, 3], [2, 3, 4], [3, 4, 5]]) + * assert.deepStrictEqual(Array.window(numbers, 6), []) + * ``` + * + * @category splitting + * @since 3.13.2 + */ + (n: N): (self: Iterable) => Array> + /** + * Creates sliding windows of size `n` from an `Iterable`. + * If the number of elements is less than `n` or if `n` is not greater than zero, + * an empty array is returned. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Array } from "effect" + * + * const numbers = [1, 2, 3, 4, 5] + * assert.deepStrictEqual(Array.window(numbers, 3), [[1, 2, 3], [2, 3, 4], [3, 4, 5]]) + * assert.deepStrictEqual(Array.window(numbers, 6), []) + * ``` + * + * @category splitting + * @since 3.13.2 + */ + (self: Iterable, n: N): Array> +} = dual(2, (self: Iterable, n: N): Array> => { + const input = fromIterable(self) + if (n > 0 && isNonEmptyReadonlyArray(input)) { + return Array.from( + { length: input.length - (n - 1) }, + (_, index) => input.slice(index, index + n) + ) + } + return [] +}) + +/** + * Group equal, consecutive elements of a `NonEmptyReadonlyArray` into `NonEmptyArray`s using the provided `isEquivalent` function. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.groupWith(["a", "a", "b", "b", "b", "c", "a"], (x, y) => x === y) + * console.log(result) // [["a", "a"], ["b", "b", "b"], ["c"], ["a"]] + * ``` + * + * @category grouping + * @since 2.0.0 + */ +export const groupWith: { + /** + * Group equal, consecutive elements of a `NonEmptyReadonlyArray` into `NonEmptyArray`s using the provided `isEquivalent` function. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.groupWith(["a", "a", "b", "b", "b", "c", "a"], (x, y) => x === y) + * console.log(result) // [["a", "a"], ["b", "b", "b"], ["c"], ["a"]] + * ``` + * + * @category grouping + * @since 2.0.0 + */ + (isEquivalent: (self: A, that: A) => boolean): (self: NonEmptyReadonlyArray) => NonEmptyArray> + /** + * Group equal, consecutive elements of a `NonEmptyReadonlyArray` into `NonEmptyArray`s using the provided `isEquivalent` function. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.groupWith(["a", "a", "b", "b", "b", "c", "a"], (x, y) => x === y) + * console.log(result) // [["a", "a"], ["b", "b", "b"], ["c"], ["a"]] + * ``` + * + * @category grouping + * @since 2.0.0 + */ + ( + self: NonEmptyReadonlyArray, + isEquivalent: (self: A, that: A) => boolean + ): NonEmptyArray> +} = dual( + 2, + (self: NonEmptyReadonlyArray, isEquivalent: (self: A, that: A) => boolean): NonEmptyArray> => + chop(self, (as) => { + const h = headNonEmpty(as) + const out: NonEmptyArray = [h] + let i = 1 + for (; i < as.length; i++) { + const a = as[i] + if (isEquivalent(a, h)) { + out.push(a) + } else { + break + } + } + return [out, as.slice(i)] + }) +) + +/** + * Group equal, consecutive elements of a `NonEmptyReadonlyArray` into `NonEmptyArray`s. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.group([1, 1, 2, 2, 2, 3, 1]) + * console.log(result) // [[1, 1], [2, 2, 2], [3], [1]] + * ``` + * + * @category grouping + * @since 2.0.0 + */ +export const group: (self: NonEmptyReadonlyArray) => NonEmptyArray> = groupWith( + Equal.equivalence() +) + +/** + * Splits an `Iterable` into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning + * function on each element, and grouping the results according to values returned + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const people = [ + * { name: "Alice", group: "A" }, + * { name: "Bob", group: "B" }, + * { name: "Charlie", group: "A" } + * ] + * + * const result = Array.groupBy(people, person => person.group) + * console.log(result) + * // { + * // A: [{ name: "Alice", group: "A" }, { name: "Charlie", group: "A" }], + * // B: [{ name: "Bob", group: "B" }] + * // } + * ``` + * + * @category grouping + * @since 2.0.0 + */ +export const groupBy: { + /** + * Splits an `Iterable` into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning + * function on each element, and grouping the results according to values returned + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const people = [ + * { name: "Alice", group: "A" }, + * { name: "Bob", group: "B" }, + * { name: "Charlie", group: "A" } + * ] + * + * const result = Array.groupBy(people, person => person.group) + * console.log(result) + * // { + * // A: [{ name: "Alice", group: "A" }, { name: "Charlie", group: "A" }], + * // B: [{ name: "Bob", group: "B" }] + * // } + * ``` + * + * @category grouping + * @since 2.0.0 + */ + (f: (a: A) => K): (self: Iterable) => Record, NonEmptyArray> + /** + * Splits an `Iterable` into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning + * function on each element, and grouping the results according to values returned + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const people = [ + * { name: "Alice", group: "A" }, + * { name: "Bob", group: "B" }, + * { name: "Charlie", group: "A" } + * ] + * + * const result = Array.groupBy(people, person => person.group) + * console.log(result) + * // { + * // A: [{ name: "Alice", group: "A" }, { name: "Charlie", group: "A" }], + * // B: [{ name: "Bob", group: "B" }] + * // } + * ``` + * + * @category grouping + * @since 2.0.0 + */ + (self: Iterable, f: (a: A) => K): Record, NonEmptyArray> +} = dual(2, ( + self: Iterable, + f: (a: A) => K +): Record, NonEmptyArray> => { + const out: Record> = {} + for (const a of self) { + const k = f(a) + if (Object.prototype.hasOwnProperty.call(out, k)) { + out[k].push(a) + } else { + out[k] = [a] + } + } + return out +}) + +/** + * Calculates the union of two arrays using the provided equivalence relation. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const union = Array.unionWith([1, 2], [2, 3], (a, b) => a === b) + * console.log(union) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ +export const unionWith: { + /** + * Calculates the union of two arrays using the provided equivalence relation. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const union = Array.unionWith([1, 2], [2, 3], (a, b) => a === b) + * console.log(union) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + , T extends Iterable>( + that: T, + isEquivalent: (self: ReadonlyArray.Infer, that: ReadonlyArray.Infer) => boolean + ): (self: S) => ReadonlyArray.OrNonEmpty | ReadonlyArray.Infer> + /** + * Calculates the union of two arrays using the provided equivalence relation. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const union = Array.unionWith([1, 2], [2, 3], (a, b) => a === b) + * console.log(union) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + ( + self: NonEmptyReadonlyArray, + that: Iterable, + isEquivalent: (self: A, that: B) => boolean + ): NonEmptyArray + /** + * Calculates the union of two arrays using the provided equivalence relation. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const union = Array.unionWith([1, 2], [2, 3], (a, b) => a === b) + * console.log(union) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + ( + self: Iterable, + that: NonEmptyReadonlyArray, + isEquivalent: (self: A, that: B) => boolean + ): NonEmptyArray + /** + * Calculates the union of two arrays using the provided equivalence relation. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const union = Array.unionWith([1, 2], [2, 3], (a, b) => a === b) + * console.log(union) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + ( + self: Iterable, + that: Iterable, + isEquivalent: (self: A, that: B) => boolean + ): Array +} = dual(3, (self: Iterable, that: Iterable, isEquivalent: (self: A, that: A) => boolean): Array => { + const a = fromIterable(self) + const b = fromIterable(that) + if (isNonEmptyReadonlyArray(a)) { + if (isNonEmptyReadonlyArray(b)) { + const dedupe = dedupeWith(isEquivalent) + return dedupe(appendAll(a, b)) + } + return a + } + return b +}) + +/** + * Creates a union of two arrays, removing duplicates. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.union([1, 2], [2, 3]) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ +export const union: { + /** + * Creates a union of two arrays, removing duplicates. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.union([1, 2], [2, 3]) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + >(that: T): >( + self: S + ) => ReadonlyArray.OrNonEmpty | ReadonlyArray.Infer> + /** + * Creates a union of two arrays, removing duplicates. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.union([1, 2], [2, 3]) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, that: ReadonlyArray): NonEmptyArray + /** + * Creates a union of two arrays, removing duplicates. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.union([1, 2], [2, 3]) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + (self: ReadonlyArray, that: NonEmptyReadonlyArray): NonEmptyArray + /** + * Creates a union of two arrays, removing duplicates. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.union([1, 2], [2, 3]) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + (self: Iterable, that: Iterable): Array +} = dual(2, (self: Iterable, that: Iterable): Array => unionWith(self, that, _equivalence)) + +/** + * Creates an `Array` of unique values that are included in all given `Iterable`s using the provided `isEquivalent` function. + * The order and references of result values are determined by the first `Iterable`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const array1 = [{ id: 1 }, { id: 2 }, { id: 3 }] + * const array2 = [{ id: 3 }, { id: 4 }, { id: 1 }] + * const isEquivalent = (a: { id: number }, b: { id: number }) => a.id === b.id + * const result = Array.intersectionWith(isEquivalent)(array2)(array1) + * console.log(result) // [{ id: 1 }, { id: 3 }] + * ``` + * + * @since 2.0.0 + */ +export const intersectionWith = (isEquivalent: (self: A, that: A) => boolean): { + (that: Iterable): (self: Iterable) => Array + (self: Iterable, that: Iterable): Array +} => { + const has = containsWith(isEquivalent) + return dual( + 2, + (self: Iterable, that: Iterable): Array => { + const bs = fromIterable(that) + return fromIterable(self).filter((a) => has(bs, a)) + } + ) +} + +/** + * Creates an `Array` of unique values that are included in all given `Iterable`s. + * The order and references of result values are determined by the first `Iterable`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.intersection([1, 2, 3], [3, 4, 1]) + * console.log(result) // [1, 3] + * ``` + * + * @since 2.0.0 + */ +export const intersection: { + /** + * Creates an `Array` of unique values that are included in all given `Iterable`s. + * The order and references of result values are determined by the first `Iterable`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.intersection([1, 2, 3], [3, 4, 1]) + * console.log(result) // [1, 3] + * ``` + * + * @since 2.0.0 + */ + (that: Iterable): (self: Iterable) => Array + /** + * Creates an `Array` of unique values that are included in all given `Iterable`s. + * The order and references of result values are determined by the first `Iterable`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.intersection([1, 2, 3], [3, 4, 1]) + * console.log(result) // [1, 3] + * ``` + * + * @since 2.0.0 + */ + (self: Iterable, that: Iterable): Array +} = intersectionWith(_equivalence) + +/** + * Creates a `Array` of values not included in the other given `Iterable` using the provided `isEquivalent` function. + * The order and references of result values are determined by the first `Iterable`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const array1 = [1, 2, 3] + * const array2 = [2, 3, 4] + * const difference = Array.differenceWith((a, b) => a === b)(array1, array2) + * console.log(difference) // [1] + * ``` + * + * @since 2.0.0 + */ +export const differenceWith = (isEquivalent: (self: A, that: A) => boolean): { + (that: Iterable): (self: Iterable) => Array + (self: Iterable, that: Iterable): Array +} => { + const has = containsWith(isEquivalent) + return dual( + 2, + (self: Iterable, that: Iterable): Array => { + const bs = fromIterable(that) + return fromIterable(self).filter((a) => !has(bs, a)) + } + ) +} + +/** + * Creates a `Array` of values not included in the other given `Iterable`. + * The order and references of result values are determined by the first `Iterable`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const difference = Array.difference([1, 2, 3], [2, 3, 4]) + * console.log(difference) // [1] + * ``` + * + * @since 2.0.0 + */ +export const difference: { + /** + * Creates a `Array` of values not included in the other given `Iterable`. + * The order and references of result values are determined by the first `Iterable`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const difference = Array.difference([1, 2, 3], [2, 3, 4]) + * console.log(difference) // [1] + * ``` + * + * @since 2.0.0 + */ + (that: Iterable): (self: Iterable) => Array + /** + * Creates a `Array` of values not included in the other given `Iterable`. + * The order and references of result values are determined by the first `Iterable`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const difference = Array.difference([1, 2, 3], [2, 3, 4]) + * console.log(difference) // [1] + * ``` + * + * @since 2.0.0 + */ + (self: Iterable, that: Iterable): Array +} = differenceWith(_equivalence) + +/** + * @category constructors + * @since 2.0.0 + */ +export const empty: () => Array = () => [] + +/** + * Constructs a new `NonEmptyArray` from the specified value. + * + * @category constructors + * @since 2.0.0 + */ +export const of = (a: A): NonEmptyArray => [a] + +/** + * @since 2.0.0 + */ +export declare namespace ReadonlyArray { + /** + * @since 2.0.0 + */ + export type Infer> = S extends ReadonlyArray ? A + : S extends Iterable ? A + : never + + /** + * @since 2.0.0 + */ + export type With, A> = S extends NonEmptyReadonlyArray ? NonEmptyArray + : Array + + /** + * @since 2.0.0 + */ + export type OrNonEmpty< + S extends Iterable, + T extends Iterable, + A + > = S extends NonEmptyReadonlyArray ? NonEmptyArray + : T extends NonEmptyReadonlyArray ? NonEmptyArray + : Array + + /** + * @since 2.0.0 + */ + export type AndNonEmpty< + S extends Iterable, + T extends Iterable, + A + > = S extends NonEmptyReadonlyArray ? T extends NonEmptyReadonlyArray ? NonEmptyArray + : Array + : Array + + /** + * @since 2.0.0 + */ + export type Flatten>> = T extends + NonEmptyReadonlyArray> ? NonEmptyArray + : Array +} + +/** + * @category mapping + * @since 2.0.0 + */ +export const map: { + /** + * @category mapping + * @since 2.0.0 + */ + , B>(f: (a: ReadonlyArray.Infer, i: number) => B): (self: S) => ReadonlyArray.With + /** + * @category mapping + * @since 2.0.0 + */ + , B>(self: S, f: (a: ReadonlyArray.Infer, i: number) => B): ReadonlyArray.With +} = dual(2, (self: ReadonlyArray, f: (a: A, i: number) => B): Array => self.map(f)) + +/** + * Applies a function to each element in an array and returns a new array containing the concatenated mapped elements. + * + * @category sequencing + * @since 2.0.0 + */ +export const flatMap: { + /** + * Applies a function to each element in an array and returns a new array containing the concatenated mapped elements. + * + * @category sequencing + * @since 2.0.0 + */ + , T extends ReadonlyArray>(f: (a: ReadonlyArray.Infer, i: number) => T): (self: S) => ReadonlyArray.AndNonEmpty> + /** + * Applies a function to each element in an array and returns a new array containing the concatenated mapped elements. + * + * @category sequencing + * @since 2.0.0 + */ + ( + self: NonEmptyReadonlyArray, + f: (a: A, i: number) => NonEmptyReadonlyArray + ): NonEmptyArray + /** + * Applies a function to each element in an array and returns a new array containing the concatenated mapped elements. + * + * @category sequencing + * @since 2.0.0 + */ + (self: ReadonlyArray, f: (a: A, i: number) => ReadonlyArray): Array +} = dual( + 2, + (self: ReadonlyArray, f: (a: A, i: number) => ReadonlyArray): Array => { + if (isEmptyReadonlyArray(self)) { + return [] + } + const out: Array = [] + for (let i = 0; i < self.length; i++) { + const inner = f(self[i], i) + for (let j = 0; j < inner.length; j++) { + out.push(inner[j]) + } + } + return out + } +) + +/** + * Combines multiple arrays into a single array by concatenating all elements + * from each nested array. This function ensures that the structure of nested + * arrays is collapsed into a single, flat array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.flatten([[1, 2], [], [3, 4], [], [5, 6]]) + * console.log(result) // [1, 2, 3, 4, 5, 6] + * ``` + * + * @category sequencing + * @since 2.0.0 + */ +export const flatten: >>( + self: S +) => ReadonlyArray.Flatten = flatMap( + identity +) as any + +/** + * Applies a function to each element of the `Iterable` and filters based on the result, keeping the transformed values where the function returns `Some`. + * This method combines filtering and mapping functionalities, allowing transformations and filtering of elements based on a single function pass. + * + * **Example** + * + * ```ts + * import { Array, Option } from "effect" + * + * const evenSquares = (x: number) => x % 2 === 0 ? Option.some(x * x) : Option.none() + * + * const result = Array.filterMap([1, 2, 3, 4, 5], evenSquares); + * console.log(result) // [4, 16] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const filterMap: { + /** + * Applies a function to each element of the `Iterable` and filters based on the result, keeping the transformed values where the function returns `Some`. + * This method combines filtering and mapping functionalities, allowing transformations and filtering of elements based on a single function pass. + * + * **Example** + * + * ```ts + * import { Array, Option } from "effect" + * + * const evenSquares = (x: number) => x % 2 === 0 ? Option.some(x * x) : Option.none() + * + * const result = Array.filterMap([1, 2, 3, 4, 5], evenSquares); + * console.log(result) // [4, 16] + * ``` + * + * @category filtering + * @since 2.0.0 + */ + (f: (a: A, i: number) => Option.Option): (self: Iterable) => Array + /** + * Applies a function to each element of the `Iterable` and filters based on the result, keeping the transformed values where the function returns `Some`. + * This method combines filtering and mapping functionalities, allowing transformations and filtering of elements based on a single function pass. + * + * **Example** + * + * ```ts + * import { Array, Option } from "effect" + * + * const evenSquares = (x: number) => x % 2 === 0 ? Option.some(x * x) : Option.none() + * + * const result = Array.filterMap([1, 2, 3, 4, 5], evenSquares); + * console.log(result) // [4, 16] + * ``` + * + * @category filtering + * @since 2.0.0 + */ + (self: Iterable, f: (a: A, i: number) => Option.Option): Array +} = dual( + 2, + (self: Iterable, f: (a: A, i: number) => Option.Option): Array => { + const as = fromIterable(self) + const out: Array = [] + for (let i = 0; i < as.length; i++) { + const o = f(as[i], i) + if (Option.isSome(o)) { + out.push(o.value) + } + } + return out + } +) + +/** + * Applies a function to each element of the array and filters based on the result, stopping when a condition is not met. + * This method combines filtering and mapping in a single pass, and short-circuits, i.e., stops processing, as soon as the function returns `None`. + * This is useful when you need to transform an array but only up to the point where a certain condition holds true. + * + * **Example** + * + * ```ts + * import { Array, Option } from "effect" + * + * const toSquareTillOdd = (x: number) => x % 2 === 0 ? Option.some(x * x) : Option.none() + * + * const result = Array.filterMapWhile([2, 4, 5], toSquareTillOdd) + * console.log(result) // [4, 16] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const filterMapWhile: { + /** + * Applies a function to each element of the array and filters based on the result, stopping when a condition is not met. + * This method combines filtering and mapping in a single pass, and short-circuits, i.e., stops processing, as soon as the function returns `None`. + * This is useful when you need to transform an array but only up to the point where a certain condition holds true. + * + * **Example** + * + * ```ts + * import { Array, Option } from "effect" + * + * const toSquareTillOdd = (x: number) => x % 2 === 0 ? Option.some(x * x) : Option.none() + * + * const result = Array.filterMapWhile([2, 4, 5], toSquareTillOdd) + * console.log(result) // [4, 16] + * ``` + * + * @category filtering + * @since 2.0.0 + */ + (f: (a: A, i: number) => Option.Option): (self: Iterable) => Array + /** + * Applies a function to each element of the array and filters based on the result, stopping when a condition is not met. + * This method combines filtering and mapping in a single pass, and short-circuits, i.e., stops processing, as soon as the function returns `None`. + * This is useful when you need to transform an array but only up to the point where a certain condition holds true. + * + * **Example** + * + * ```ts + * import { Array, Option } from "effect" + * + * const toSquareTillOdd = (x: number) => x % 2 === 0 ? Option.some(x * x) : Option.none() + * + * const result = Array.filterMapWhile([2, 4, 5], toSquareTillOdd) + * console.log(result) // [4, 16] + * ``` + * + * @category filtering + * @since 2.0.0 + */ + (self: Iterable, f: (a: A, i: number) => Option.Option): Array +} = dual(2, (self: Iterable, f: (a: A, i: number) => Option.Option) => { + let i = 0 + const out: Array = [] + for (const a of self) { + const b = f(a, i) + if (Option.isSome(b)) { + out.push(b.value) + } else { + break + } + i++ + } + return out +}) + +/** + * Applies a function to each element of the `Iterable`, categorizing the results into two separate arrays. + * This function is particularly useful for operations where each element can result in two possible types, + * and you want to separate these types into different collections. For instance, separating validation results + * into successes and failures. + * + * **Example** + * + * ```ts + * import { Array, Either } from "effect"; + * + * const isEven = (x: number) => x % 2 === 0 + * + * const result = Array.partitionMap([1, 2, 3, 4, 5], x => + * isEven(x) ? Either.right(x) : Either.left(x) + * ) + * console.log(result) + * // [ + * // [1, 3, 5], + * // [2, 4] + * // ] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const partitionMap: { + /** + * Applies a function to each element of the `Iterable`, categorizing the results into two separate arrays. + * This function is particularly useful for operations where each element can result in two possible types, + * and you want to separate these types into different collections. For instance, separating validation results + * into successes and failures. + * + * **Example** + * + * ```ts + * import { Array, Either } from "effect"; + * + * const isEven = (x: number) => x % 2 === 0 + * + * const result = Array.partitionMap([1, 2, 3, 4, 5], x => + * isEven(x) ? Either.right(x) : Either.left(x) + * ) + * console.log(result) + * // [ + * // [1, 3, 5], + * // [2, 4] + * // ] + * ``` + * + * @category filtering + * @since 2.0.0 + */ + (f: (a: A, i: number) => Either.Either): (self: Iterable) => [left: Array, right: Array] + /** + * Applies a function to each element of the `Iterable`, categorizing the results into two separate arrays. + * This function is particularly useful for operations where each element can result in two possible types, + * and you want to separate these types into different collections. For instance, separating validation results + * into successes and failures. + * + * **Example** + * + * ```ts + * import { Array, Either } from "effect"; + * + * const isEven = (x: number) => x % 2 === 0 + * + * const result = Array.partitionMap([1, 2, 3, 4, 5], x => + * isEven(x) ? Either.right(x) : Either.left(x) + * ) + * console.log(result) + * // [ + * // [1, 3, 5], + * // [2, 4] + * // ] + * ``` + * + * @category filtering + * @since 2.0.0 + */ + (self: Iterable, f: (a: A, i: number) => Either.Either): [left: Array, right: Array] +} = dual( + 2, + (self: Iterable, f: (a: A, i: number) => Either.Either): [left: Array, right: Array] => { + const left: Array = [] + const right: Array = [] + const as = fromIterable(self) + for (let i = 0; i < as.length; i++) { + const e = f(as[i], i) + if (Either.isLeft(e)) { + left.push(e.left) + } else { + right.push(e.right) + } + } + return [left, right] + } +) + +/** + * Retrieves the `Some` values from an `Iterable` of `Option`s, collecting them into an array. + * + * **Example** + * + * ```ts + * import { Array, Option } from "effect" + * + * const result = Array.getSomes([Option.some(1), Option.none(), Option.some(2)]) + * console.log(result) // [1, 2] + * ``` + * + * @category filtering + * @since 2.0.0 + */ + +export const getSomes: >, X = any>( + self: T +) => Array>> = filterMap(identity as any) + +/** + * Retrieves the `Left` values from an `Iterable` of `Either`s, collecting them into an array. + * + * **Example** + * + * ```ts + * import { Array, Either } from "effect" + * + * const result = Array.getLefts([Either.right(1), Either.left("err"), Either.right(2)]) + * console.log(result) // ["err"] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const getLefts = >>( + self: T +): Array>> => { + const out: Array = [] + for (const a of self) { + if (Either.isLeft(a)) { + out.push(a.left) + } + } + + return out +} + +/** + * Retrieves the `Right` values from an `Iterable` of `Either`s, collecting them into an array. + * + * **Example** + * + * ```ts + * import { Array, Either } from "effect" + * + * const result = Array.getRights([Either.right(1), Either.left("err"), Either.right(2)]) + * console.log(result) // [1, 2] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const getRights = >>( + self: T +): Array>> => { + const out: Array = [] + for (const a of self) { + if (Either.isRight(a)) { + out.push(a.right) + } + } + + return out +} + +/** + * @category filtering + * @since 2.0.0 + */ +export const filter: { + /** + * @category filtering + * @since 2.0.0 + */ + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Array + /** + * @category filtering + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Array + /** + * @category filtering + * @since 2.0.0 + */ + (self: Iterable, refinement: (a: A, i: number) => a is B): Array + /** + * @category filtering + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): Array +} = dual( + 2, + (self: Iterable, predicate: (a: A, i: number) => boolean): Array => { + const as = fromIterable(self) + const out: Array = [] + for (let i = 0; i < as.length; i++) { + if (predicate(as[i], i)) { + out.push(as[i]) + } + } + return out + } +) + +/** + * Separate elements based on a predicate that also exposes the index of the element. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.partition([1, 2, 3, 4], n => n % 2 === 0) + * console.log(result) // [[1, 3], [2, 4]] + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const partition: { + /** + * Separate elements based on a predicate that also exposes the index of the element. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.partition([1, 2, 3, 4], n => n % 2 === 0) + * console.log(result) // [[1, 3], [2, 4]] + * ``` + * + * @category filtering + * @since 2.0.0 + */ + (refinement: (a: NoInfer, i: number) => a is B): ( + self: Iterable + ) => [excluded: Array>, satisfying: Array] + /** + * Separate elements based on a predicate that also exposes the index of the element. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.partition([1, 2, 3, 4], n => n % 2 === 0) + * console.log(result) // [[1, 3], [2, 4]] + * ``` + * + * @category filtering + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => [excluded: Array, satisfying: Array] + /** + * Separate elements based on a predicate that also exposes the index of the element. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.partition([1, 2, 3, 4], n => n % 2 === 0) + * console.log(result) // [[1, 3], [2, 4]] + * ``` + * + * @category filtering + * @since 2.0.0 + */ + (self: Iterable, refinement: (a: A, i: number) => a is B): [excluded: Array>, satisfying: Array] + /** + * Separate elements based on a predicate that also exposes the index of the element. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.partition([1, 2, 3, 4], n => n % 2 === 0) + * console.log(result) // [[1, 3], [2, 4]] + * ``` + * + * @category filtering + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): [excluded: Array, satisfying: Array] +} = dual( + 2, + (self: Iterable, predicate: (a: A, i: number) => boolean): [excluded: Array, satisfying: Array] => { + const left: Array = [] + const right: Array = [] + const as = fromIterable(self) + for (let i = 0; i < as.length; i++) { + if (predicate(as[i], i)) { + right.push(as[i]) + } else { + left.push(as[i]) + } + } + return [left, right] + } +) + +/** + * Separates an `Iterable` into two arrays based on a predicate. + * + * @category filtering + * @since 2.0.0 + */ +export const separate: >>( + self: T +) => [Array>>, Array>>] = + partitionMap(identity) + +/** + * Reduces an array from the left. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.reduce([1, 2, 3], 0, (acc, n) => acc + n) + * console.log(result) // 6 + * ``` + * + * @category folding + * @since 2.0.0 + */ +export const reduce: { + /** + * Reduces an array from the left. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.reduce([1, 2, 3], 0, (acc, n) => acc + n) + * console.log(result) // 6 + * ``` + * + * @category folding + * @since 2.0.0 + */ + (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B + /** + * Reduces an array from the left. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.reduce([1, 2, 3], 0, (acc, n) => acc + n) + * console.log(result) // 6 + * ``` + * + * @category folding + * @since 2.0.0 + */ + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B +} = dual( + 3, + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B => + fromIterable(self).reduce((b, a, i) => f(b, a, i), b) +) + +/** + * Reduces an array from the right. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.reduceRight([1, 2, 3], 0, (acc, n) => acc + n) + * console.log(result) // 6 + * ``` + * + * @category folding + * @since 2.0.0 + */ +export const reduceRight: { + /** + * Reduces an array from the right. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.reduceRight([1, 2, 3], 0, (acc, n) => acc + n) + * console.log(result) // 6 + * ``` + * + * @category folding + * @since 2.0.0 + */ + (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B + /** + * Reduces an array from the right. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.reduceRight([1, 2, 3], 0, (acc, n) => acc + n) + * console.log(result) // 6 + * ``` + * + * @category folding + * @since 2.0.0 + */ + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B +} = dual( + 3, + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B => + fromIterable(self).reduceRight((b, a, i) => f(b, a, i), b) +) + +/** + * Lifts a predicate into an array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const isEven = (n: number) => n % 2 === 0 + * const to = Array.liftPredicate(isEven) + * console.log(to(1)) // [] + * console.log(to(2)) // [2] + * ``` + * + * @category lifting + * @since 2.0.0 + */ +export const liftPredicate: { // Note: I intentionally avoid using the NoInfer pattern here. + (refinement: Predicate.Refinement): (a: A) => Array + /** + * Lifts a predicate into an array. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const isEven = (n: number) => n % 2 === 0 + * const to = Array.liftPredicate(isEven) + * console.log(to(1)) // [] + * console.log(to(2)) // [2] + * ``` + * + * @category lifting + * @since 2.0.0 + */ + (predicate: Predicate.Predicate): (b: B) => Array +} = (predicate: Predicate.Predicate) => (b: B): Array => predicate(b) ? [b] : [] + +/** + * @category lifting + * @since 2.0.0 + */ +export const liftOption = , B>( + f: (...a: A) => Option.Option +) => +(...a: A): Array => fromOption(f(...a)) + +/** + * @category conversions + * @since 2.0.0 + */ +export const fromNullable = (a: A): Array> => a == null ? empty() : [a as NonNullable] + +/** + * @category lifting + * @since 2.0.0 + */ +export const liftNullable = , B>( + f: (...a: A) => B | null | undefined +): (...a: A) => Array> => +(...a) => fromNullable(f(...a)) + +/** + * Maps over an array and flattens the result, removing null and undefined values. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.flatMapNullable([1, 2, 3], n => (n % 2 === 0 ? null : n)) + * console.log(result) // [1, 3] + * + * // Explanation: + * // The array of numbers [1, 2, 3] is mapped with a function that returns null for even numbers + * // and the number itself for odd numbers. The resulting array [1, null, 3] is then flattened + * // to remove null values, resulting in [1, 3]. + * ``` + * + * @category sequencing + * @since 2.0.0 + */ +export const flatMapNullable: { + /** + * Maps over an array and flattens the result, removing null and undefined values. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.flatMapNullable([1, 2, 3], n => (n % 2 === 0 ? null : n)) + * console.log(result) // [1, 3] + * + * // Explanation: + * // The array of numbers [1, 2, 3] is mapped with a function that returns null for even numbers + * // and the number itself for odd numbers. The resulting array [1, null, 3] is then flattened + * // to remove null values, resulting in [1, 3]. + * ``` + * + * @category sequencing + * @since 2.0.0 + */ + (f: (a: A) => B | null | undefined): (self: ReadonlyArray) => Array> + /** + * Maps over an array and flattens the result, removing null and undefined values. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.flatMapNullable([1, 2, 3], n => (n % 2 === 0 ? null : n)) + * console.log(result) // [1, 3] + * + * // Explanation: + * // The array of numbers [1, 2, 3] is mapped with a function that returns null for even numbers + * // and the number itself for odd numbers. The resulting array [1, null, 3] is then flattened + * // to remove null values, resulting in [1, 3]. + * ``` + * + * @category sequencing + * @since 2.0.0 + */ + (self: ReadonlyArray, f: (a: A) => B | null | undefined): Array> +} = dual( + 2, + (self: ReadonlyArray, f: (a: A) => B | null | undefined): Array> => + flatMap(self, (a) => fromNullable(f(a))) +) + +/** + * Lifts a function that returns an `Either` into a function that returns an array. + * If the `Either` is a left, it returns an empty array. + * If the `Either` is a right, it returns an array with the right value. + * + * **Example** + * + * ```ts + * import { Array, Either } from "effect" + * + * const parseNumber = (s: string): Either.Either => + * isNaN(Number(s)) ? Either.left(new Error("Not a number")) : Either.right(Number(s)) + * + * const liftedParseNumber = Array.liftEither(parseNumber) + * + * const result1 = liftedParseNumber("42") + * console.log(result1) // [42] + * + * const result2 = liftedParseNumber("not a number") + * console.log(result2) // [] + * + * // Explanation: + * // The function parseNumber is lifted to return an array. + * // When parsing "42", it returns an Either.left with the number 42, resulting in [42]. + * // When parsing "not a number", it returns an Either.right with an error, resulting in an empty array []. + * ``` + * + * @category lifting + * @since 2.0.0 + */ +export const liftEither = , E, B>( + f: (...a: A) => Either.Either +) => +(...a: A): Array => { + const e = f(...a) + return Either.isLeft(e) ? [] : [e.right] +} + +/** + * Check if a predicate holds true for every `ReadonlyArray` element. + * + * @category elements + * @since 2.0.0 + */ +export const every: { + /** + * Check if a predicate holds true for every `ReadonlyArray` element. + * + * @category elements + * @since 2.0.0 + */ + (refinement: (a: NoInfer, i: number) => a is B): (self: ReadonlyArray) => self is ReadonlyArray + /** + * Check if a predicate holds true for every `ReadonlyArray` element. + * + * @category elements + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: ReadonlyArray) => boolean + /** + * Check if a predicate holds true for every `ReadonlyArray` element. + * + * @category elements + * @since 2.0.0 + */ + (self: ReadonlyArray, refinement: (a: A, i: number) => a is B): self is ReadonlyArray + /** + * Check if a predicate holds true for every `ReadonlyArray` element. + * + * @category elements + * @since 2.0.0 + */ + (self: ReadonlyArray, predicate: (a: A, i: number) => boolean): boolean +} = dual( + 2, + (self: ReadonlyArray, refinement: (a: A, i: number) => a is B): self is ReadonlyArray => + self.every(refinement) +) + +/** + * Check if a predicate holds true for some `ReadonlyArray` element. + * + * @category elements + * @since 2.0.0 + */ +export const some: { + /** + * Check if a predicate holds true for some `ReadonlyArray` element. + * + * @category elements + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: ReadonlyArray) => self is NonEmptyReadonlyArray + /** + * Check if a predicate holds true for some `ReadonlyArray` element. + * + * @category elements + * @since 2.0.0 + */ + (self: ReadonlyArray, predicate: (a: A, i: number) => boolean): self is NonEmptyReadonlyArray +} = dual( + 2, + (self: ReadonlyArray, predicate: (a: A, i: number) => boolean): self is NonEmptyReadonlyArray => + self.some(predicate) +) + +/** + * Extends an array with a function that maps each subarray to a value. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.extend([1, 2, 3], as => as.length) + * console.log(result) // [3, 2, 1] + * + * // Explanation: + * // The function maps each subarray starting from each element to its length. + * // The subarrays are: [1, 2, 3], [2, 3], [3]. + * // The lengths are: 3, 2, 1. + * // Therefore, the result is [3, 2, 1]. + * ``` + * + * @since 2.0.0 + */ +export const extend: { + /** + * Extends an array with a function that maps each subarray to a value. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.extend([1, 2, 3], as => as.length) + * console.log(result) // [3, 2, 1] + * + * // Explanation: + * // The function maps each subarray starting from each element to its length. + * // The subarrays are: [1, 2, 3], [2, 3], [3]. + * // The lengths are: 3, 2, 1. + * // Therefore, the result is [3, 2, 1]. + * ``` + * + * @since 2.0.0 + */ + (f: (as: ReadonlyArray) => B): (self: ReadonlyArray) => Array + /** + * Extends an array with a function that maps each subarray to a value. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.extend([1, 2, 3], as => as.length) + * console.log(result) // [3, 2, 1] + * + * // Explanation: + * // The function maps each subarray starting from each element to its length. + * // The subarrays are: [1, 2, 3], [2, 3], [3]. + * // The lengths are: 3, 2, 1. + * // Therefore, the result is [3, 2, 1]. + * ``` + * + * @since 2.0.0 + */ + (self: ReadonlyArray, f: (as: ReadonlyArray) => B): Array +} = dual( + 2, + (self: ReadonlyArray, f: (as: ReadonlyArray) => B): Array => self.map((_, i, as) => f(as.slice(i))) +) + +/** + * Finds the minimum element in an array based on a comparator. + * + * **Example** + * + * ```ts + * import { Array, Order } from "effect" + * + * const result = Array.min([3, 1, 2], Order.number) + * console.log(result) // 1 + * ``` + * + * @since 2.0.0 + */ +export const min: { + /** + * Finds the minimum element in an array based on a comparator. + * + * **Example** + * + * ```ts + * import { Array, Order } from "effect" + * + * const result = Array.min([3, 1, 2], Order.number) + * console.log(result) // 1 + * ``` + * + * @since 2.0.0 + */ + (O: Order.Order): (self: NonEmptyReadonlyArray) => A + /** + * Finds the minimum element in an array based on a comparator. + * + * **Example** + * + * ```ts + * import { Array, Order } from "effect" + * + * const result = Array.min([3, 1, 2], Order.number) + * console.log(result) // 1 + * ``` + * + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, O: Order.Order): A +} = dual(2, (self: NonEmptyReadonlyArray, O: Order.Order): A => self.reduce(Order.min(O))) + +/** + * Finds the maximum element in an array based on a comparator. + * + * **Example** + * + * ```ts + * import { Array, Order } from "effect" + * + * const result = Array.max([3, 1, 2], Order.number) + * console.log(result) // 3 + * ``` + * + * @since 2.0.0 + */ +export const max: { + /** + * Finds the maximum element in an array based on a comparator. + * + * **Example** + * + * ```ts + * import { Array, Order } from "effect" + * + * const result = Array.max([3, 1, 2], Order.number) + * console.log(result) // 3 + * ``` + * + * @since 2.0.0 + */ + (O: Order.Order): (self: NonEmptyReadonlyArray) => A + /** + * Finds the maximum element in an array based on a comparator. + * + * **Example** + * + * ```ts + * import { Array, Order } from "effect" + * + * const result = Array.max([3, 1, 2], Order.number) + * console.log(result) // 3 + * ``` + * + * @since 2.0.0 + */ + (self: NonEmptyReadonlyArray, O: Order.Order): A +} = dual(2, (self: NonEmptyReadonlyArray, O: Order.Order): A => self.reduce(Order.max(O))) + +/** + * @category constructors + * @since 2.0.0 + */ +export const unfold = (b: B, f: (b: B) => Option.Option): Array => { + const out: Array = [] + let next: B = b + let o: Option.Option + while (Option.isSome(o = f(next))) { + const [a, b] = o.value + out.push(a) + next = b + } + return out +} + +/** + * This function creates and returns a new `Order` for an array of values based on a given `Order` for the elements of the array. + * The returned `Order` compares two arrays by applying the given `Order` to each element in the arrays. + * If all elements are equal, the arrays are then compared based on their length. + * It is useful when you need to compare two arrays of the same type and you have a specific way of comparing each element of the array. + * + * @category instances + * @since 2.0.0 + */ +export const getOrder: (O: Order.Order) => Order.Order> = Order.array + +/** + * Creates an equivalence relation for arrays. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const eq = Array.getEquivalence((a, b) => a === b) + * console.log(eq([1, 2, 3], [1, 2, 3])) // true + * ``` + * + * @category instances + * @since 2.0.0 + */ +export const getEquivalence: ( + isEquivalent: Equivalence.Equivalence +) => Equivalence.Equivalence> = Equivalence.array + +/** + * Performs a side-effect for each element of the `Iterable`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * Array.forEach([1, 2, 3], n => console.log(n)) // 1, 2, 3 + * ``` + * + * @since 2.0.0 + */ +export const forEach: { + /** + * Performs a side-effect for each element of the `Iterable`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * Array.forEach([1, 2, 3], n => console.log(n)) // 1, 2, 3 + * ``` + * + * @since 2.0.0 + */ + (f: (a: A, i: number) => void): (self: Iterable) => void + /** + * Performs a side-effect for each element of the `Iterable`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * Array.forEach([1, 2, 3], n => console.log(n)) // 1, 2, 3 + * ``` + * + * @since 2.0.0 + */ + (self: Iterable, f: (a: A, i: number) => void): void +} = dual(2, (self: Iterable, f: (a: A, i: number) => void): void => fromIterable(self).forEach((a, i) => f(a, i))) + +/** + * Remove duplicates from an `Iterable` using the provided `isEquivalent` function, + * preserving the order of the first occurrence of each element. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dedupeWith([1, 2, 2, 3, 3, 3], (a, b) => a === b) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ +export const dedupeWith: { + /** + * Remove duplicates from an `Iterable` using the provided `isEquivalent` function, + * preserving the order of the first occurrence of each element. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dedupeWith([1, 2, 2, 3, 3, 3], (a, b) => a === b) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + >( + isEquivalent: (self: ReadonlyArray.Infer, that: ReadonlyArray.Infer) => boolean + ): (self: S) => ReadonlyArray.With> + /** + * Remove duplicates from an `Iterable` using the provided `isEquivalent` function, + * preserving the order of the first occurrence of each element. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dedupeWith([1, 2, 2, 3, 3, 3], (a, b) => a === b) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + ( + self: NonEmptyReadonlyArray, + isEquivalent: (self: A, that: A) => boolean + ): NonEmptyArray + /** + * Remove duplicates from an `Iterable` using the provided `isEquivalent` function, + * preserving the order of the first occurrence of each element. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dedupeWith([1, 2, 2, 3, 3, 3], (a, b) => a === b) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + (self: Iterable, isEquivalent: (self: A, that: A) => boolean): Array +} = dual( + 2, + (self: Iterable, isEquivalent: (self: A, that: A) => boolean): Array => { + const input = fromIterable(self) + if (isNonEmptyReadonlyArray(input)) { + const out: NonEmptyArray = [headNonEmpty(input)] + const rest = tailNonEmpty(input) + for (const r of rest) { + if (out.every((a) => !isEquivalent(r, a))) { + out.push(r) + } + } + return out + } + return [] + } +) + +/** + * Remove duplicates from an `Iterable`, preserving the order of the first occurrence of each element. + * The equivalence used to compare elements is provided by `Equal.equivalence()` from the `Equal` module. + * + * @since 2.0.0 + */ +export const dedupe = >( + self: S +): S extends NonEmptyReadonlyArray ? NonEmptyArray : S extends Iterable ? Array : never => + dedupeWith(self, Equal.equivalence()) as any + +/** + * Deduplicates adjacent elements that are identical using the provided `isEquivalent` function. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dedupeAdjacentWith([1, 1, 2, 2, 3, 3], (a, b) => a === b) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ +export const dedupeAdjacentWith: { + /** + * Deduplicates adjacent elements that are identical using the provided `isEquivalent` function. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dedupeAdjacentWith([1, 1, 2, 2, 3, 3], (a, b) => a === b) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + (isEquivalent: (self: A, that: A) => boolean): (self: Iterable) => Array + /** + * Deduplicates adjacent elements that are identical using the provided `isEquivalent` function. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dedupeAdjacentWith([1, 1, 2, 2, 3, 3], (a, b) => a === b) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ + (self: Iterable, isEquivalent: (self: A, that: A) => boolean): Array +} = dual(2, (self: Iterable, isEquivalent: (self: A, that: A) => boolean): Array => { + const out: Array = [] + let lastA: Option.Option = Option.none() + for (const a of self) { + if (Option.isNone(lastA) || !isEquivalent(a, lastA.value)) { + out.push(a) + lastA = Option.some(a) + } + } + return out +}) + +/** + * Deduplicates adjacent elements that are identical. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.dedupeAdjacent([1, 1, 2, 2, 3, 3]) + * console.log(result) // [1, 2, 3] + * ``` + * + * @since 2.0.0 + */ +export const dedupeAdjacent: (self: Iterable) => Array = dedupeAdjacentWith(Equal.equivalence()) + +/** + * Joins the elements together with "sep" in the middle. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const strings = ["a", "b", "c"] + * const joined = Array.join(strings, "-") + * console.log(joined) // "a-b-c" + * ``` + * + * @since 2.0.0 + * @category folding + */ +export const join: { + /** + * Joins the elements together with "sep" in the middle. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const strings = ["a", "b", "c"] + * const joined = Array.join(strings, "-") + * console.log(joined) // "a-b-c" + * ``` + * + * @since 2.0.0 + * @category folding + */ + (sep: string): (self: Iterable) => string + /** + * Joins the elements together with "sep" in the middle. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const strings = ["a", "b", "c"] + * const joined = Array.join(strings, "-") + * console.log(joined) // "a-b-c" + * ``` + * + * @since 2.0.0 + * @category folding + */ + (self: Iterable, sep: string): string +} = dual(2, (self: Iterable, sep: string): string => fromIterable(self).join(sep)) + +/** + * Statefully maps over the chunk, producing new elements of type `B`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.mapAccum([1, 2, 3], 0, (acc, n) => [acc + n, acc + n]) + * console.log(result) // [6, [1, 3, 6]] + * ``` + * + * @since 2.0.0 + * @category folding + */ +export const mapAccum: { + /** + * Statefully maps over the chunk, producing new elements of type `B`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.mapAccum([1, 2, 3], 0, (acc, n) => [acc + n, acc + n]) + * console.log(result) // [6, [1, 3, 6]] + * ``` + * + * @since 2.0.0 + * @category folding + */ + = Iterable>(s: S, f: (s: S, a: ReadonlyArray.Infer, i: number) => readonly [S, B]): (self: I) => [state: S, mappedArray: ReadonlyArray.With] + /** + * Statefully maps over the chunk, producing new elements of type `B`. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.mapAccum([1, 2, 3], 0, (acc, n) => [acc + n, acc + n]) + * console.log(result) // [6, [1, 3, 6]] + * ``` + * + * @since 2.0.0 + * @category folding + */ + = Iterable>( + self: I, + s: S, + f: (s: S, a: ReadonlyArray.Infer, i: number) => readonly [S, B] + ): [state: S, mappedArray: ReadonlyArray.With] +} = dual( + 3, + (self: Iterable, s: S, f: (s: S, a: A, i: number) => [S, B]): [state: S, mappedArray: Array] => { + let i = 0 + let s1 = s + const out: Array = [] + for (const a of self) { + const r = f(s1, a, i) + s1 = r[0] + out.push(r[1]) + i++ + } + return [s1, out] + } +) + +/** + * Zips this chunk crosswise with the specified chunk using the specified combiner. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.cartesianWith([1, 2], ["a", "b"], (a, b) => `${a}-${b}`) + * console.log(result) // ["1-a", "1-b", "2-a", "2-b"] + * ``` + * + * @since 2.0.0 + * @category elements + */ +export const cartesianWith: { + /** + * Zips this chunk crosswise with the specified chunk using the specified combiner. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.cartesianWith([1, 2], ["a", "b"], (a, b) => `${a}-${b}`) + * console.log(result) // ["1-a", "1-b", "2-a", "2-b"] + * ``` + * + * @since 2.0.0 + * @category elements + */ + (that: ReadonlyArray, f: (a: A, b: B) => C): (self: ReadonlyArray) => Array + /** + * Zips this chunk crosswise with the specified chunk using the specified combiner. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.cartesianWith([1, 2], ["a", "b"], (a, b) => `${a}-${b}`) + * console.log(result) // ["1-a", "1-b", "2-a", "2-b"] + * ``` + * + * @since 2.0.0 + * @category elements + */ + (self: ReadonlyArray, that: ReadonlyArray, f: (a: A, b: B) => C): Array +} = dual( + 3, + (self: ReadonlyArray, that: ReadonlyArray, f: (a: A, b: B) => C): Array => + flatMap(self, (a) => map(that, (b) => f(a, b))) +) + +/** + * Zips this chunk crosswise with the specified chunk. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.cartesian([1, 2], ["a", "b"]) + * console.log(result) // [[1, "a"], [1, "b"], [2, "a"], [2, "b"]] + * ``` + * + * @since 2.0.0 + * @category elements + */ +export const cartesian: { + /** + * Zips this chunk crosswise with the specified chunk. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.cartesian([1, 2], ["a", "b"]) + * console.log(result) // [[1, "a"], [1, "b"], [2, "a"], [2, "b"]] + * ``` + * + * @since 2.0.0 + * @category elements + */ + (that: ReadonlyArray): (self: ReadonlyArray) => Array<[A, B]> + /** + * Zips this chunk crosswise with the specified chunk. + * + * **Example** + * + * ```ts + * import { Array } from "effect" + * + * const result = Array.cartesian([1, 2], ["a", "b"]) + * console.log(result) // [[1, "a"], [1, "b"], [2, "a"], [2, "b"]] + * ``` + * + * @since 2.0.0 + * @category elements + */ + (self: ReadonlyArray, that: ReadonlyArray): Array<[A, B]> +} = dual( + 2, + (self: ReadonlyArray, that: ReadonlyArray): Array<[A, B]> => cartesianWith(self, that, (a, b) => [a, b]) +) + +// ------------------------------------------------------------------------------------- +// do notation +// ------------------------------------------------------------------------------------- + +/** + * The "do simulation" for array allows you to sequentially apply operations to the elements of arrays, just as nested loops allow you to go through all combinations of elements in an arrays. + * + * It can be used to simulate "array comprehension". + * It's a technique that allows you to create new arrays by iterating over existing ones and applying specific **conditions** or **transformations** to the elements. It's like assembling a new collection from pieces of other collections based on certain rules. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Array` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * 5. Regular `Array` functions like `map` and `filter` can still be used within the do simulation. These functions will receive the accumulated variables as arguments within the scope + * + * **Example** + * + * ```ts + * import { Array, pipe } from "effect" + * + * const doResult = pipe( + * Array.Do, + * Array.bind("x", () => [1, 3, 5]), + * Array.bind("y", () => [2, 4, 6]), + * Array.filter(({ x, y }) => x < y), // condition + * Array.map(({ x, y }) => [x, y] as const) // transformation + * ) + * console.log(doResult) // [[1, 2], [1, 4], [1, 6], [3, 4], [3, 6], [5, 6]] + * + * // equivalent + * const x = [1, 3, 5], + * y = [2, 4, 6], + * result = []; + * for(let i = 0; i < x.length; i++) { + * for(let j = 0; j < y.length; j++) { + * const _x = x[i], _y = y[j]; + * if(_x < _y) result.push([_x, _y] as const) + * } + * } + * ``` + * + * @see {@link bindTo} + * @see {@link bind} + * @see {@link let_ let} + * + * @category do notation + * @since 3.2.0 + */ +export const Do: ReadonlyArray<{}> = of({}) + +/** + * The "do simulation" for array allows you to sequentially apply operations to the elements of arrays, just as nested loops allow you to go through all combinations of elements in an arrays. + * + * It can be used to simulate "array comprehension". + * It's a technique that allows you to create new arrays by iterating over existing ones and applying specific **conditions** or **transformations** to the elements. It's like assembling a new collection from pieces of other collections based on certain rules. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Array` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * 5. Regular `Array` functions like `map` and `filter` can still be used within the do simulation. These functions will receive the accumulated variables as arguments within the scope + * + * **Example** + * + * ```ts + * import { Array, pipe } from "effect" + * + * const doResult = pipe( + * Array.Do, + * Array.bind("x", () => [1, 3, 5]), + * Array.bind("y", () => [2, 4, 6]), + * Array.filter(({ x, y }) => x < y), // condition + * Array.map(({ x, y }) => [x, y] as const) // transformation + * ) + * console.log(doResult) // [[1, 2], [1, 4], [1, 6], [3, 4], [3, 6], [5, 6]] + * + * // equivalent + * const x = [1, 3, 5], + * y = [2, 4, 6], + * result = []; + * for(let i = 0; i < x.length; i++) { + * for(let j = 0; j < y.length; j++) { + * const _x = x[i], _y = y[j]; + * if(_x < _y) result.push([_x, _y] as const) + * } + * } + * ``` + * + * @see {@link bindTo} + * @see {@link Do} + * @see {@link let_ let} + * + * @category do notation + * @since 3.2.0 + */ +export const bind: { + /** + * The "do simulation" for array allows you to sequentially apply operations to the elements of arrays, just as nested loops allow you to go through all combinations of elements in an arrays. + * + * It can be used to simulate "array comprehension". + * It's a technique that allows you to create new arrays by iterating over existing ones and applying specific **conditions** or **transformations** to the elements. It's like assembling a new collection from pieces of other collections based on certain rules. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Array` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * 5. Regular `Array` functions like `map` and `filter` can still be used within the do simulation. These functions will receive the accumulated variables as arguments within the scope + * + * **Example** + * + * ```ts + * import { Array, pipe } from "effect" + * + * const doResult = pipe( + * Array.Do, + * Array.bind("x", () => [1, 3, 5]), + * Array.bind("y", () => [2, 4, 6]), + * Array.filter(({ x, y }) => x < y), // condition + * Array.map(({ x, y }) => [x, y] as const) // transformation + * ) + * console.log(doResult) // [[1, 2], [1, 4], [1, 6], [3, 4], [3, 6], [5, 6]] + * + * // equivalent + * const x = [1, 3, 5], + * y = [2, 4, 6], + * result = []; + * for(let i = 0; i < x.length; i++) { + * for(let j = 0; j < y.length; j++) { + * const _x = x[i], _y = y[j]; + * if(_x < _y) result.push([_x, _y] as const) + * } + * } + * ``` + * + * @see {@link bindTo} + * @see {@link Do} + * @see {@link let_ let} + * + * @category do notation + * @since 3.2.0 + */ + (tag: Exclude, f: (a: NoInfer) => ReadonlyArray): ( + self: ReadonlyArray + ) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + /** + * The "do simulation" for array allows you to sequentially apply operations to the elements of arrays, just as nested loops allow you to go through all combinations of elements in an arrays. + * + * It can be used to simulate "array comprehension". + * It's a technique that allows you to create new arrays by iterating over existing ones and applying specific **conditions** or **transformations** to the elements. It's like assembling a new collection from pieces of other collections based on certain rules. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Array` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * 5. Regular `Array` functions like `map` and `filter` can still be used within the do simulation. These functions will receive the accumulated variables as arguments within the scope + * + * **Example** + * + * ```ts + * import { Array, pipe } from "effect" + * + * const doResult = pipe( + * Array.Do, + * Array.bind("x", () => [1, 3, 5]), + * Array.bind("y", () => [2, 4, 6]), + * Array.filter(({ x, y }) => x < y), // condition + * Array.map(({ x, y }) => [x, y] as const) // transformation + * ) + * console.log(doResult) // [[1, 2], [1, 4], [1, 6], [3, 4], [3, 6], [5, 6]] + * + * // equivalent + * const x = [1, 3, 5], + * y = [2, 4, 6], + * result = []; + * for(let i = 0; i < x.length; i++) { + * for(let j = 0; j < y.length; j++) { + * const _x = x[i], _y = y[j]; + * if(_x < _y) result.push([_x, _y] as const) + * } + * } + * ``` + * + * @see {@link bindTo} + * @see {@link Do} + * @see {@link let_ let} + * + * @category do notation + * @since 3.2.0 + */ + ( + self: ReadonlyArray, + tag: Exclude, + f: (a: NoInfer) => ReadonlyArray + ): Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = internalDoNotation.bind(map, flatMap) as any + +/** + * The "do simulation" for array allows you to sequentially apply operations to the elements of arrays, just as nested loops allow you to go through all combinations of elements in an arrays. + * + * It can be used to simulate "array comprehension". + * It's a technique that allows you to create new arrays by iterating over existing ones and applying specific **conditions** or **transformations** to the elements. It's like assembling a new collection from pieces of other collections based on certain rules. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Array` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * 5. Regular `Array` functions like `map` and `filter` can still be used within the do simulation. These functions will receive the accumulated variables as arguments within the scope + * + * **Example** + * + * ```ts + * import { Array, pipe } from "effect" + * + * const doResult = pipe( + * Array.Do, + * Array.bind("x", () => [1, 3, 5]), + * Array.bind("y", () => [2, 4, 6]), + * Array.filter(({ x, y }) => x < y), // condition + * Array.map(({ x, y }) => [x, y] as const) // transformation + * ) + * console.log(doResult) // [[1, 2], [1, 4], [1, 6], [3, 4], [3, 6], [5, 6]] + * + * // equivalent + * const x = [1, 3, 5], + * y = [2, 4, 6], + * result = []; + * for(let i = 0; i < x.length; i++) { + * for(let j = 0; j < y.length; j++) { + * const _x = x[i], _y = y[j]; + * if(_x < _y) result.push([_x, _y] as const) + * } + * } + * ``` + * + * @see {@link bindTo} + * @see {@link Do} + * @see {@link let_ let} + * + * @category do notation + * @since 3.2.0 + */ +export const bindTo: { + /** + * The "do simulation" for array allows you to sequentially apply operations to the elements of arrays, just as nested loops allow you to go through all combinations of elements in an arrays. + * + * It can be used to simulate "array comprehension". + * It's a technique that allows you to create new arrays by iterating over existing ones and applying specific **conditions** or **transformations** to the elements. It's like assembling a new collection from pieces of other collections based on certain rules. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Array` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * 5. Regular `Array` functions like `map` and `filter` can still be used within the do simulation. These functions will receive the accumulated variables as arguments within the scope + * + * **Example** + * + * ```ts + * import { Array, pipe } from "effect" + * + * const doResult = pipe( + * Array.Do, + * Array.bind("x", () => [1, 3, 5]), + * Array.bind("y", () => [2, 4, 6]), + * Array.filter(({ x, y }) => x < y), // condition + * Array.map(({ x, y }) => [x, y] as const) // transformation + * ) + * console.log(doResult) // [[1, 2], [1, 4], [1, 6], [3, 4], [3, 6], [5, 6]] + * + * // equivalent + * const x = [1, 3, 5], + * y = [2, 4, 6], + * result = []; + * for(let i = 0; i < x.length; i++) { + * for(let j = 0; j < y.length; j++) { + * const _x = x[i], _y = y[j]; + * if(_x < _y) result.push([_x, _y] as const) + * } + * } + * ``` + * + * @see {@link bindTo} + * @see {@link Do} + * @see {@link let_ let} + * + * @category do notation + * @since 3.2.0 + */ + (tag: N): (self: ReadonlyArray) => Array<{ [K in N]: A }> + /** + * The "do simulation" for array allows you to sequentially apply operations to the elements of arrays, just as nested loops allow you to go through all combinations of elements in an arrays. + * + * It can be used to simulate "array comprehension". + * It's a technique that allows you to create new arrays by iterating over existing ones and applying specific **conditions** or **transformations** to the elements. It's like assembling a new collection from pieces of other collections based on certain rules. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Array` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * 5. Regular `Array` functions like `map` and `filter` can still be used within the do simulation. These functions will receive the accumulated variables as arguments within the scope + * + * **Example** + * + * ```ts + * import { Array, pipe } from "effect" + * + * const doResult = pipe( + * Array.Do, + * Array.bind("x", () => [1, 3, 5]), + * Array.bind("y", () => [2, 4, 6]), + * Array.filter(({ x, y }) => x < y), // condition + * Array.map(({ x, y }) => [x, y] as const) // transformation + * ) + * console.log(doResult) // [[1, 2], [1, 4], [1, 6], [3, 4], [3, 6], [5, 6]] + * + * // equivalent + * const x = [1, 3, 5], + * y = [2, 4, 6], + * result = []; + * for(let i = 0; i < x.length; i++) { + * for(let j = 0; j < y.length; j++) { + * const _x = x[i], _y = y[j]; + * if(_x < _y) result.push([_x, _y] as const) + * } + * } + * ``` + * + * @see {@link bindTo} + * @see {@link Do} + * @see {@link let_ let} + * + * @category do notation + * @since 3.2.0 + */ + (self: ReadonlyArray, tag: N): Array<{ [K in N]: A }> +} = internalDoNotation.bindTo(map) as any + +const let_: { + ( + tag: Exclude, + f: (a: NoInfer) => B + ): (self: ReadonlyArray) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: ReadonlyArray, + tag: Exclude, + f: (a: NoInfer) => B + ): Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = internalDoNotation.let_(map) as any + +export { + /** + * The "do simulation" for array allows you to sequentially apply operations to the elements of arrays, just as nested loops allow you to go through all combinations of elements in an arrays. + * + * It can be used to simulate "array comprehension". + * It's a technique that allows you to create new arrays by iterating over existing ones and applying specific **conditions** or **transformations** to the elements. It's like assembling a new collection from pieces of other collections based on certain rules. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Array` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * 5. Regular `Array` functions like `map` and `filter` can still be used within the do simulation. These functions will receive the accumulated variables as arguments within the scope + * + * **Example** + * + * ```ts + * import { Array, pipe } from "effect" + * + * const doResult = pipe( + * Array.Do, + * Array.bind("x", () => [1, 3, 5]), + * Array.bind("y", () => [2, 4, 6]), + * Array.filter(({ x, y }) => x < y), // condition + * Array.map(({ x, y }) => [x, y] as const) // transformation + * ) + * console.log(doResult) // [[1, 2], [1, 4], [1, 6], [3, 4], [3, 6], [5, 6]] + * + * // equivalent + * const x = [1, 3, 5], + * y = [2, 4, 6], + * result = []; + * for(let i = 0; i < x.length; i++) { + * for(let j = 0; j < y.length; j++) { + * const _x = x[i], _y = y[j]; + * if(_x < _y) result.push([_x, _y] as const) + * } + * } + * + * ``` + * + * @see {@link bindTo} + * @see {@link bind} + * @see {@link Do} + * + * @category do notation + * @since 3.2.0 + */ + let_ as let +} diff --git a/backend/node_modules/effect/src/BigDecimal.ts b/backend/node_modules/effect/src/BigDecimal.ts new file mode 100644 index 0000000000000000000000000000000000000000..6ec880dc0837dd879f13ad4f54b644946bf22323 --- /dev/null +++ b/backend/node_modules/effect/src/BigDecimal.ts @@ -0,0 +1,2037 @@ +/** + * This module provides utility functions and type class instances for working with the `BigDecimal` type in TypeScript. + * It includes functions for basic arithmetic operations, as well as type class instances for `Equivalence` and `Order`. + * + * A `BigDecimal` allows storing any real number to arbitrary precision; which avoids common floating point errors + * (such as 0.1 + 0.2 ≠ 0.3) at the cost of complexity. + * + * Internally, `BigDecimal` uses a `BigInt` object, paired with a 64-bit integer which determines the position of the + * decimal point. Therefore, the precision *is not* actually arbitrary, but limited to 263 decimal places. + * + * It is not recommended to convert a floating point number to a decimal directly, as the floating point representation + * may be unexpected. + * + * @module BigDecimal + * @since 2.0.0 + * @see {@link module:BigInt} for more similar operations on `bigint` types + * @see {@link module:Number} for more similar operations on `number` types + */ + +import * as Equal from "./Equal.js" +import * as equivalence from "./Equivalence.js" +import { dual, pipe } from "./Function.js" +import * as Hash from "./Hash.js" +import { type Inspectable, NodeInspectSymbol } from "./Inspectable.js" +import * as Option from "./Option.js" +import * as order from "./Order.js" +import type { Ordering } from "./Ordering.js" +import { type Pipeable, pipeArguments } from "./Pipeable.js" +import { hasProperty } from "./Predicate.js" + +const DEFAULT_PRECISION = 100 +const FINITE_INT_REGEX = /^[+-]?\d+$/ + +/** + * @since 2.0.0 + * @category symbols + */ +export const TypeId: unique symbol = Symbol.for("effect/BigDecimal") + +/** + * @since 2.0.0 + * @category symbol + */ +export type TypeId = typeof TypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface BigDecimal extends Equal.Equal, Pipeable, Inspectable { + readonly [TypeId]: TypeId + readonly value: bigint + readonly scale: number + /** @internal */ + normalized?: BigDecimal +} + +const BigDecimalProto: Omit = { + [TypeId]: TypeId, + [Hash.symbol](this: BigDecimal): number { + const normalized = normalize(this) + return pipe( + Hash.hash(normalized.value), + Hash.combine(Hash.number(normalized.scale)), + Hash.cached(this) + ) + }, + [Equal.symbol](this: BigDecimal, that: unknown): boolean { + return isBigDecimal(that) && equals(this, that) + }, + toString(this: BigDecimal) { + return `BigDecimal(${format(this)})` + }, + toJSON(this: BigDecimal) { + return { + _id: "BigDecimal", + value: String(this.value), + scale: this.scale + } + }, + [NodeInspectSymbol](this: BigDecimal) { + return this.toJSON() + }, + pipe() { + return pipeArguments(this, arguments) + } +} as const + +/** + * Checks if a given value is a `BigDecimal`. + * + * @since 2.0.0 + * @category guards + */ +export const isBigDecimal = (u: unknown): u is BigDecimal => hasProperty(u, TypeId) + +/** + * Creates a `BigDecimal` from a `bigint` value and a scale. + * + * @since 2.0.0 + * @category constructors + */ +export const make = (value: bigint, scale: number): BigDecimal => { + const o = Object.create(BigDecimalProto) + o.value = value + o.scale = scale + return o +} + +/** + * Internal function used to create pre-normalized `BigDecimal`s. + * + * @internal + */ +export const unsafeMakeNormalized = (value: bigint, scale: number): BigDecimal => { + if (value !== bigint0 && value % bigint10 === bigint0) { + throw new RangeError("Value must be normalized") + } + + const o = make(value, scale) + o.normalized = o + return o +} + +const bigint0 = BigInt(0) +const bigint1 = BigInt(1) +const bigint10 = BigInt(10) +const zero = unsafeMakeNormalized(bigint0, 0) + +/** + * Normalizes a given `BigDecimal` by removing trailing zeros. + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { normalize, make, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(normalize(unsafeFromString("123.00000")), normalize(make(123n, 0))) + * assert.deepStrictEqual(normalize(unsafeFromString("12300000")), normalize(make(123n, -5))) + * ``` + * + * @since 2.0.0 + * @category scaling + */ +export const normalize = (self: BigDecimal): BigDecimal => { + if (self.normalized === undefined) { + if (self.value === bigint0) { + self.normalized = zero + } else { + const digits = `${self.value}` + + let trail = 0 + for (let i = digits.length - 1; i >= 0; i--) { + if (digits[i] === "0") { + trail++ + } else { + break + } + } + + if (trail === 0) { + self.normalized = self + } + + const value = BigInt(digits.substring(0, digits.length - trail)) + const scale = self.scale - trail + self.normalized = unsafeMakeNormalized(value, scale) + } + } + + return self.normalized +} + +/** + * Scales a given `BigDecimal` to the specified scale. + * + * If the given scale is smaller than the current scale, the value will be rounded down to + * the nearest integer. + * + * @since 2.0.0 + * @category scaling + */ +export const scale: { + /** + * Scales a given `BigDecimal` to the specified scale. + * + * If the given scale is smaller than the current scale, the value will be rounded down to + * the nearest integer. + * + * @since 2.0.0 + * @category scaling + */ + (scale: number): (self: BigDecimal) => BigDecimal + /** + * Scales a given `BigDecimal` to the specified scale. + * + * If the given scale is smaller than the current scale, the value will be rounded down to + * the nearest integer. + * + * @since 2.0.0 + * @category scaling + */ + (self: BigDecimal, scale: number): BigDecimal +} = dual(2, (self: BigDecimal, scale: number): BigDecimal => { + if (scale > self.scale) { + return make(self.value * bigint10 ** BigInt(scale - self.scale), scale) + } + + if (scale < self.scale) { + return make(self.value / bigint10 ** BigInt(self.scale - scale), scale) + } + + return self +}) + +/** + * Provides an addition operation on `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { sum, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(sum(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("5")) + * ``` + * + * @since 2.0.0 + * @category math + */ +export const sum: { + /** + * Provides an addition operation on `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { sum, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(sum(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("5")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (that: BigDecimal): (self: BigDecimal) => BigDecimal + /** + * Provides an addition operation on `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { sum, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(sum(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("5")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (self: BigDecimal, that: BigDecimal): BigDecimal +} = dual(2, (self: BigDecimal, that: BigDecimal): BigDecimal => { + if (that.value === bigint0) { + return self + } + + if (self.value === bigint0) { + return that + } + + if (self.scale > that.scale) { + return make(scale(that, self.scale).value + self.value, self.scale) + } + + if (self.scale < that.scale) { + return make(scale(self, that.scale).value + that.value, that.scale) + } + + return make(self.value + that.value, self.scale) +}) + +/** + * Provides a multiplication operation on `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { multiply, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(multiply(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("6")) + * ``` + * + * @since 2.0.0 + * @category math + */ +export const multiply: { + /** + * Provides a multiplication operation on `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { multiply, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(multiply(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("6")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (that: BigDecimal): (self: BigDecimal) => BigDecimal + /** + * Provides a multiplication operation on `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { multiply, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(multiply(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("6")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (self: BigDecimal, that: BigDecimal): BigDecimal +} = dual(2, (self: BigDecimal, that: BigDecimal): BigDecimal => { + if (that.value === bigint0 || self.value === bigint0) { + return zero + } + + return make(self.value * that.value, self.scale + that.scale) +}) + +/** + * Provides a subtraction operation on `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { subtract, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(subtract(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("-1")) + * ``` + * + * @since 2.0.0 + * @category math + */ +export const subtract: { + /** + * Provides a subtraction operation on `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { subtract, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(subtract(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("-1")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (that: BigDecimal): (self: BigDecimal) => BigDecimal + /** + * Provides a subtraction operation on `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { subtract, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(subtract(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("-1")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (self: BigDecimal, that: BigDecimal): BigDecimal +} = dual(2, (self: BigDecimal, that: BigDecimal): BigDecimal => { + if (that.value === bigint0) { + return self + } + + if (self.value === bigint0) { + return make(-that.value, that.scale) + } + + if (self.scale > that.scale) { + return make(self.value - scale(that, self.scale).value, self.scale) + } + + if (self.scale < that.scale) { + return make(scale(self, that.scale).value - that.value, that.scale) + } + + return make(self.value - that.value, self.scale) +}) + +/** + * Internal function used for arbitrary precision division. + */ +const divideWithPrecision = ( + num: bigint, + den: bigint, + scale: number, + precision: number +): BigDecimal => { + const numNegative = num < bigint0 + const denNegative = den < bigint0 + const negateResult = numNegative !== denNegative + + num = numNegative ? -num : num + den = denNegative ? -den : den + + // Shift digits until numerator is larger than denominator (set scale appropriately). + while (num < den) { + num *= bigint10 + scale++ + } + + // First division. + let quotient = num / den + let remainder = num % den + + if (remainder === bigint0) { + // No remainder, return immediately. + return make(negateResult ? -quotient : quotient, scale) + } + + // The quotient is guaranteed to be non-negative at this point. No need to consider sign. + let count = `${quotient}`.length + + // Shift the remainder by 1 decimal; The quotient will be 1 digit upon next division. + remainder *= bigint10 + while (remainder !== bigint0 && count < precision) { + const q = remainder / den + const r = remainder % den + quotient = quotient * bigint10 + q + remainder = r * bigint10 + + count++ + scale++ + } + + if (remainder !== bigint0) { + // Round final number with remainder. + quotient += roundTerminal(remainder / den) + } + + return make(negateResult ? -quotient : quotient, scale) +} + +/** + * Internal function used for rounding. + * + * Returns 1 if the most significant digit is >= 5, otherwise 0. + * + * This is used after dividing a number by a power of ten and rounding the last digit. + * + * @internal + */ +export const roundTerminal = (n: bigint): bigint => { + const pos = n >= bigint0 ? 0 : 1 + return Number(`${n}`[pos]) < 5 ? bigint0 : bigint1 +} + +/** + * Provides a division operation on `BigDecimal`s. + * + * If the dividend is not a multiple of the divisor the result will be a `BigDecimal` value + * which represents the integer division rounded down to the nearest integer. + * + * If the divisor is `0`, the result will be `None`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal, Option } from "effect" + * + * assert.deepStrictEqual(BigDecimal.divide(BigDecimal.unsafeFromString("6"), BigDecimal.unsafeFromString("3")), Option.some(BigDecimal.unsafeFromString("2"))) + * assert.deepStrictEqual(BigDecimal.divide(BigDecimal.unsafeFromString("6"), BigDecimal.unsafeFromString("4")), Option.some(BigDecimal.unsafeFromString("1.5"))) + * assert.deepStrictEqual(BigDecimal.divide(BigDecimal.unsafeFromString("6"), BigDecimal.unsafeFromString("0")), Option.none()) + * ``` + * + * @since 2.0.0 + * @category math + */ +export const divide: { + /** + * Provides a division operation on `BigDecimal`s. + * + * If the dividend is not a multiple of the divisor the result will be a `BigDecimal` value + * which represents the integer division rounded down to the nearest integer. + * + * If the divisor is `0`, the result will be `None`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal, Option } from "effect" + * + * assert.deepStrictEqual(BigDecimal.divide(BigDecimal.unsafeFromString("6"), BigDecimal.unsafeFromString("3")), Option.some(BigDecimal.unsafeFromString("2"))) + * assert.deepStrictEqual(BigDecimal.divide(BigDecimal.unsafeFromString("6"), BigDecimal.unsafeFromString("4")), Option.some(BigDecimal.unsafeFromString("1.5"))) + * assert.deepStrictEqual(BigDecimal.divide(BigDecimal.unsafeFromString("6"), BigDecimal.unsafeFromString("0")), Option.none()) + * ``` + * + * @since 2.0.0 + * @category math + */ + (that: BigDecimal): (self: BigDecimal) => Option.Option + /** + * Provides a division operation on `BigDecimal`s. + * + * If the dividend is not a multiple of the divisor the result will be a `BigDecimal` value + * which represents the integer division rounded down to the nearest integer. + * + * If the divisor is `0`, the result will be `None`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal, Option } from "effect" + * + * assert.deepStrictEqual(BigDecimal.divide(BigDecimal.unsafeFromString("6"), BigDecimal.unsafeFromString("3")), Option.some(BigDecimal.unsafeFromString("2"))) + * assert.deepStrictEqual(BigDecimal.divide(BigDecimal.unsafeFromString("6"), BigDecimal.unsafeFromString("4")), Option.some(BigDecimal.unsafeFromString("1.5"))) + * assert.deepStrictEqual(BigDecimal.divide(BigDecimal.unsafeFromString("6"), BigDecimal.unsafeFromString("0")), Option.none()) + * ``` + * + * @since 2.0.0 + * @category math + */ + (self: BigDecimal, that: BigDecimal): Option.Option +} = dual(2, (self: BigDecimal, that: BigDecimal): Option.Option => { + if (that.value === bigint0) { + return Option.none() + } + + if (self.value === bigint0) { + return Option.some(zero) + } + + const scale = self.scale - that.scale + if (self.value === that.value) { + return Option.some(make(bigint1, scale)) + } + + return Option.some(divideWithPrecision(self.value, that.value, scale, DEFAULT_PRECISION)) +}) + +/** + * Provides an unsafe division operation on `BigDecimal`s. + * + * If the dividend is not a multiple of the divisor the result will be a `BigDecimal` value + * which represents the integer division rounded down to the nearest integer. + * + * Throws a `RangeError` if the divisor is `0`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { unsafeDivide, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(unsafeDivide(unsafeFromString("6"), unsafeFromString("3")), unsafeFromString("2")) + * assert.deepStrictEqual(unsafeDivide(unsafeFromString("6"), unsafeFromString("4")), unsafeFromString("1.5")) + * ``` + * + * @since 2.0.0 + * @category math + */ +export const unsafeDivide: { + /** + * Provides an unsafe division operation on `BigDecimal`s. + * + * If the dividend is not a multiple of the divisor the result will be a `BigDecimal` value + * which represents the integer division rounded down to the nearest integer. + * + * Throws a `RangeError` if the divisor is `0`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { unsafeDivide, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(unsafeDivide(unsafeFromString("6"), unsafeFromString("3")), unsafeFromString("2")) + * assert.deepStrictEqual(unsafeDivide(unsafeFromString("6"), unsafeFromString("4")), unsafeFromString("1.5")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (that: BigDecimal): (self: BigDecimal) => BigDecimal + /** + * Provides an unsafe division operation on `BigDecimal`s. + * + * If the dividend is not a multiple of the divisor the result will be a `BigDecimal` value + * which represents the integer division rounded down to the nearest integer. + * + * Throws a `RangeError` if the divisor is `0`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { unsafeDivide, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(unsafeDivide(unsafeFromString("6"), unsafeFromString("3")), unsafeFromString("2")) + * assert.deepStrictEqual(unsafeDivide(unsafeFromString("6"), unsafeFromString("4")), unsafeFromString("1.5")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (self: BigDecimal, that: BigDecimal): BigDecimal +} = dual(2, (self: BigDecimal, that: BigDecimal): BigDecimal => { + if (that.value === bigint0) { + throw new RangeError("Division by zero") + } + + if (self.value === bigint0) { + return zero + } + + const scale = self.scale - that.scale + if (self.value === that.value) { + return make(bigint1, scale) + } + return divideWithPrecision(self.value, that.value, scale, DEFAULT_PRECISION) +}) + +/** + * @since 2.0.0 + * @category instances + */ +export const Order: order.Order = order.make((self, that) => { + const scmp = order.number(sign(self), sign(that)) + if (scmp !== 0) { + return scmp + } + + if (self.scale > that.scale) { + return order.bigint(self.value, scale(that, self.scale).value) + } + + if (self.scale < that.scale) { + return order.bigint(scale(self, that.scale).value, that.value) + } + + return order.bigint(self.value, that.value) +}) + +/** + * Returns `true` if the first argument is less than the second, otherwise `false`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { lessThan, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(lessThan(unsafeFromString("2"), unsafeFromString("3")), true) + * assert.deepStrictEqual(lessThan(unsafeFromString("3"), unsafeFromString("3")), false) + * assert.deepStrictEqual(lessThan(unsafeFromString("4"), unsafeFromString("3")), false) + * ``` + * + * @since 2.0.0 + * @category predicates + */ +export const lessThan: { + /** + * Returns `true` if the first argument is less than the second, otherwise `false`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { lessThan, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(lessThan(unsafeFromString("2"), unsafeFromString("3")), true) + * assert.deepStrictEqual(lessThan(unsafeFromString("3"), unsafeFromString("3")), false) + * assert.deepStrictEqual(lessThan(unsafeFromString("4"), unsafeFromString("3")), false) + * ``` + * + * @since 2.0.0 + * @category predicates + */ + (that: BigDecimal): (self: BigDecimal) => boolean + /** + * Returns `true` if the first argument is less than the second, otherwise `false`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { lessThan, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(lessThan(unsafeFromString("2"), unsafeFromString("3")), true) + * assert.deepStrictEqual(lessThan(unsafeFromString("3"), unsafeFromString("3")), false) + * assert.deepStrictEqual(lessThan(unsafeFromString("4"), unsafeFromString("3")), false) + * ``` + * + * @since 2.0.0 + * @category predicates + */ + (self: BigDecimal, that: BigDecimal): boolean +} = order.lessThan(Order) + +/** + * Checks if a given `BigDecimal` is less than or equal to the provided one. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { lessThanOrEqualTo, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(lessThanOrEqualTo(unsafeFromString("2"), unsafeFromString("3")), true) + * assert.deepStrictEqual(lessThanOrEqualTo(unsafeFromString("3"), unsafeFromString("3")), true) + * assert.deepStrictEqual(lessThanOrEqualTo(unsafeFromString("4"), unsafeFromString("3")), false) + * ``` + * + * @since 2.0.0 + * @category predicates + */ +export const lessThanOrEqualTo: { + /** + * Checks if a given `BigDecimal` is less than or equal to the provided one. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { lessThanOrEqualTo, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(lessThanOrEqualTo(unsafeFromString("2"), unsafeFromString("3")), true) + * assert.deepStrictEqual(lessThanOrEqualTo(unsafeFromString("3"), unsafeFromString("3")), true) + * assert.deepStrictEqual(lessThanOrEqualTo(unsafeFromString("4"), unsafeFromString("3")), false) + * ``` + * + * @since 2.0.0 + * @category predicates + */ + (that: BigDecimal): (self: BigDecimal) => boolean + /** + * Checks if a given `BigDecimal` is less than or equal to the provided one. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { lessThanOrEqualTo, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(lessThanOrEqualTo(unsafeFromString("2"), unsafeFromString("3")), true) + * assert.deepStrictEqual(lessThanOrEqualTo(unsafeFromString("3"), unsafeFromString("3")), true) + * assert.deepStrictEqual(lessThanOrEqualTo(unsafeFromString("4"), unsafeFromString("3")), false) + * ``` + * + * @since 2.0.0 + * @category predicates + */ + (self: BigDecimal, that: BigDecimal): boolean +} = order.lessThanOrEqualTo(Order) + +/** + * Returns `true` if the first argument is greater than the second, otherwise `false`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { greaterThan, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(greaterThan(unsafeFromString("2"), unsafeFromString("3")), false) + * assert.deepStrictEqual(greaterThan(unsafeFromString("3"), unsafeFromString("3")), false) + * assert.deepStrictEqual(greaterThan(unsafeFromString("4"), unsafeFromString("3")), true) + * ``` + * + * @since 2.0.0 + * @category predicates + */ +export const greaterThan: { + /** + * Returns `true` if the first argument is greater than the second, otherwise `false`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { greaterThan, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(greaterThan(unsafeFromString("2"), unsafeFromString("3")), false) + * assert.deepStrictEqual(greaterThan(unsafeFromString("3"), unsafeFromString("3")), false) + * assert.deepStrictEqual(greaterThan(unsafeFromString("4"), unsafeFromString("3")), true) + * ``` + * + * @since 2.0.0 + * @category predicates + */ + (that: BigDecimal): (self: BigDecimal) => boolean + /** + * Returns `true` if the first argument is greater than the second, otherwise `false`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { greaterThan, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(greaterThan(unsafeFromString("2"), unsafeFromString("3")), false) + * assert.deepStrictEqual(greaterThan(unsafeFromString("3"), unsafeFromString("3")), false) + * assert.deepStrictEqual(greaterThan(unsafeFromString("4"), unsafeFromString("3")), true) + * ``` + * + * @since 2.0.0 + * @category predicates + */ + (self: BigDecimal, that: BigDecimal): boolean +} = order.greaterThan(Order) + +/** + * Checks if a given `BigDecimal` is greater than or equal to the provided one. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { greaterThanOrEqualTo, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(greaterThanOrEqualTo(unsafeFromString("2"), unsafeFromString("3")), false) + * assert.deepStrictEqual(greaterThanOrEqualTo(unsafeFromString("3"), unsafeFromString("3")), true) + * assert.deepStrictEqual(greaterThanOrEqualTo(unsafeFromString("4"), unsafeFromString("3")), true) + * ``` + * + * @since 2.0.0 + * @category predicates + */ +export const greaterThanOrEqualTo: { + /** + * Checks if a given `BigDecimal` is greater than or equal to the provided one. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { greaterThanOrEqualTo, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(greaterThanOrEqualTo(unsafeFromString("2"), unsafeFromString("3")), false) + * assert.deepStrictEqual(greaterThanOrEqualTo(unsafeFromString("3"), unsafeFromString("3")), true) + * assert.deepStrictEqual(greaterThanOrEqualTo(unsafeFromString("4"), unsafeFromString("3")), true) + * ``` + * + * @since 2.0.0 + * @category predicates + */ + (that: BigDecimal): (self: BigDecimal) => boolean + /** + * Checks if a given `BigDecimal` is greater than or equal to the provided one. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { greaterThanOrEqualTo, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(greaterThanOrEqualTo(unsafeFromString("2"), unsafeFromString("3")), false) + * assert.deepStrictEqual(greaterThanOrEqualTo(unsafeFromString("3"), unsafeFromString("3")), true) + * assert.deepStrictEqual(greaterThanOrEqualTo(unsafeFromString("4"), unsafeFromString("3")), true) + * ``` + * + * @since 2.0.0 + * @category predicates + */ + (self: BigDecimal, that: BigDecimal): boolean +} = order.greaterThanOrEqualTo(Order) + +/** + * Checks if a `BigDecimal` is between a `minimum` and `maximum` value (inclusive). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal } from "effect" + * + * const between = BigDecimal.between({ + * minimum: BigDecimal.unsafeFromString("1"), + * maximum: BigDecimal.unsafeFromString("5") } + * ) + * + * assert.deepStrictEqual(between(BigDecimal.unsafeFromString("3")), true) + * assert.deepStrictEqual(between(BigDecimal.unsafeFromString("0")), false) + * assert.deepStrictEqual(between(BigDecimal.unsafeFromString("6")), false) + * ``` + * + * @since 2.0.0 + * @category predicates + */ +export const between: { + /** + * Checks if a `BigDecimal` is between a `minimum` and `maximum` value (inclusive). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal } from "effect" + * + * const between = BigDecimal.between({ + * minimum: BigDecimal.unsafeFromString("1"), + * maximum: BigDecimal.unsafeFromString("5") } + * ) + * + * assert.deepStrictEqual(between(BigDecimal.unsafeFromString("3")), true) + * assert.deepStrictEqual(between(BigDecimal.unsafeFromString("0")), false) + * assert.deepStrictEqual(between(BigDecimal.unsafeFromString("6")), false) + * ``` + * + * @since 2.0.0 + * @category predicates + */ + ( + options: { + minimum: BigDecimal + maximum: BigDecimal + } + ): (self: BigDecimal) => boolean + /** + * Checks if a `BigDecimal` is between a `minimum` and `maximum` value (inclusive). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal } from "effect" + * + * const between = BigDecimal.between({ + * minimum: BigDecimal.unsafeFromString("1"), + * maximum: BigDecimal.unsafeFromString("5") } + * ) + * + * assert.deepStrictEqual(between(BigDecimal.unsafeFromString("3")), true) + * assert.deepStrictEqual(between(BigDecimal.unsafeFromString("0")), false) + * assert.deepStrictEqual(between(BigDecimal.unsafeFromString("6")), false) + * ``` + * + * @since 2.0.0 + * @category predicates + */ + ( + self: BigDecimal, + options: { + minimum: BigDecimal + maximum: BigDecimal + } + ): boolean +} = order.between(Order) + +/** + * Restricts the given `BigDecimal` to be within the range specified by the `minimum` and `maximum` values. + * + * - If the `BigDecimal` is less than the `minimum` value, the function returns the `minimum` value. + * - If the `BigDecimal` is greater than the `maximum` value, the function returns the `maximum` value. + * - Otherwise, it returns the original `BigDecimal`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal } from "effect" + * + * const clamp = BigDecimal.clamp({ + * minimum: BigDecimal.unsafeFromString("1"), + * maximum: BigDecimal.unsafeFromString("5") } + * ) + * + * assert.deepStrictEqual(clamp(BigDecimal.unsafeFromString("3")), BigDecimal.unsafeFromString("3")) + * assert.deepStrictEqual(clamp(BigDecimal.unsafeFromString("0")), BigDecimal.unsafeFromString("1")) + * assert.deepStrictEqual(clamp(BigDecimal.unsafeFromString("6")), BigDecimal.unsafeFromString("5")) + * ``` + * + * @since 2.0.0 + * @category math + */ +export const clamp: { + /** + * Restricts the given `BigDecimal` to be within the range specified by the `minimum` and `maximum` values. + * + * - If the `BigDecimal` is less than the `minimum` value, the function returns the `minimum` value. + * - If the `BigDecimal` is greater than the `maximum` value, the function returns the `maximum` value. + * - Otherwise, it returns the original `BigDecimal`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal } from "effect" + * + * const clamp = BigDecimal.clamp({ + * minimum: BigDecimal.unsafeFromString("1"), + * maximum: BigDecimal.unsafeFromString("5") } + * ) + * + * assert.deepStrictEqual(clamp(BigDecimal.unsafeFromString("3")), BigDecimal.unsafeFromString("3")) + * assert.deepStrictEqual(clamp(BigDecimal.unsafeFromString("0")), BigDecimal.unsafeFromString("1")) + * assert.deepStrictEqual(clamp(BigDecimal.unsafeFromString("6")), BigDecimal.unsafeFromString("5")) + * ``` + * + * @since 2.0.0 + * @category math + */ + ( + options: { + minimum: BigDecimal + maximum: BigDecimal + } + ): (self: BigDecimal) => BigDecimal + /** + * Restricts the given `BigDecimal` to be within the range specified by the `minimum` and `maximum` values. + * + * - If the `BigDecimal` is less than the `minimum` value, the function returns the `minimum` value. + * - If the `BigDecimal` is greater than the `maximum` value, the function returns the `maximum` value. + * - Otherwise, it returns the original `BigDecimal`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal } from "effect" + * + * const clamp = BigDecimal.clamp({ + * minimum: BigDecimal.unsafeFromString("1"), + * maximum: BigDecimal.unsafeFromString("5") } + * ) + * + * assert.deepStrictEqual(clamp(BigDecimal.unsafeFromString("3")), BigDecimal.unsafeFromString("3")) + * assert.deepStrictEqual(clamp(BigDecimal.unsafeFromString("0")), BigDecimal.unsafeFromString("1")) + * assert.deepStrictEqual(clamp(BigDecimal.unsafeFromString("6")), BigDecimal.unsafeFromString("5")) + * ``` + * + * @since 2.0.0 + * @category math + */ + ( + self: BigDecimal, + options: { + minimum: BigDecimal + maximum: BigDecimal + } + ): BigDecimal +} = order.clamp(Order) + +/** + * Returns the minimum between two `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { min, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(min(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("2")) + * ``` + * + * @since 2.0.0 + * @category math + */ +export const min: { + /** + * Returns the minimum between two `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { min, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(min(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("2")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (that: BigDecimal): (self: BigDecimal) => BigDecimal + /** + * Returns the minimum between two `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { min, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(min(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("2")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (self: BigDecimal, that: BigDecimal): BigDecimal +} = order.min(Order) + +/** + * Returns the maximum between two `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { max, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(max(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("3")) + * ``` + * + * @since 2.0.0 + * @category math + */ +export const max: { + /** + * Returns the maximum between two `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { max, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(max(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("3")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (that: BigDecimal): (self: BigDecimal) => BigDecimal + /** + * Returns the maximum between two `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { max, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(max(unsafeFromString("2"), unsafeFromString("3")), unsafeFromString("3")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (self: BigDecimal, that: BigDecimal): BigDecimal +} = order.max(Order) + +/** + * Determines the sign of a given `BigDecimal`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { sign, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(sign(unsafeFromString("-5")), -1) + * assert.deepStrictEqual(sign(unsafeFromString("0")), 0) + * assert.deepStrictEqual(sign(unsafeFromString("5")), 1) + * ``` + * + * @since 2.0.0 + * @category math + */ +export const sign = (n: BigDecimal): Ordering => n.value === bigint0 ? 0 : n.value < bigint0 ? -1 : 1 + +/** + * Determines the absolute value of a given `BigDecimal`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { abs, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(abs(unsafeFromString("-5")), unsafeFromString("5")) + * assert.deepStrictEqual(abs(unsafeFromString("0")), unsafeFromString("0")) + * assert.deepStrictEqual(abs(unsafeFromString("5")), unsafeFromString("5")) + * ``` + * + * @since 2.0.0 + * @category math + */ +export const abs = (n: BigDecimal): BigDecimal => n.value < bigint0 ? make(-n.value, n.scale) : n + +/** + * Provides a negate operation on `BigDecimal`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { negate, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(negate(unsafeFromString("3")), unsafeFromString("-3")) + * assert.deepStrictEqual(negate(unsafeFromString("-6")), unsafeFromString("6")) + * ``` + * + * @since 2.0.0 + * @category math + */ +export const negate = (n: BigDecimal): BigDecimal => make(-n.value, n.scale) + +/** + * Returns the remainder left over when one operand is divided by a second operand. + * + * If the divisor is `0`, the result will be `None`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal, Option } from "effect" + * + * assert.deepStrictEqual(BigDecimal.remainder(BigDecimal.unsafeFromString("2"), BigDecimal.unsafeFromString("2")), Option.some(BigDecimal.unsafeFromString("0"))) + * assert.deepStrictEqual(BigDecimal.remainder(BigDecimal.unsafeFromString("3"), BigDecimal.unsafeFromString("2")), Option.some(BigDecimal.unsafeFromString("1"))) + * assert.deepStrictEqual(BigDecimal.remainder(BigDecimal.unsafeFromString("-4"), BigDecimal.unsafeFromString("2")), Option.some(BigDecimal.unsafeFromString("0"))) + * ``` + * + * @since 2.0.0 + * @category math + */ +export const remainder: { + /** + * Returns the remainder left over when one operand is divided by a second operand. + * + * If the divisor is `0`, the result will be `None`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal, Option } from "effect" + * + * assert.deepStrictEqual(BigDecimal.remainder(BigDecimal.unsafeFromString("2"), BigDecimal.unsafeFromString("2")), Option.some(BigDecimal.unsafeFromString("0"))) + * assert.deepStrictEqual(BigDecimal.remainder(BigDecimal.unsafeFromString("3"), BigDecimal.unsafeFromString("2")), Option.some(BigDecimal.unsafeFromString("1"))) + * assert.deepStrictEqual(BigDecimal.remainder(BigDecimal.unsafeFromString("-4"), BigDecimal.unsafeFromString("2")), Option.some(BigDecimal.unsafeFromString("0"))) + * ``` + * + * @since 2.0.0 + * @category math + */ + (divisor: BigDecimal): (self: BigDecimal) => Option.Option + /** + * Returns the remainder left over when one operand is divided by a second operand. + * + * If the divisor is `0`, the result will be `None`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal, Option } from "effect" + * + * assert.deepStrictEqual(BigDecimal.remainder(BigDecimal.unsafeFromString("2"), BigDecimal.unsafeFromString("2")), Option.some(BigDecimal.unsafeFromString("0"))) + * assert.deepStrictEqual(BigDecimal.remainder(BigDecimal.unsafeFromString("3"), BigDecimal.unsafeFromString("2")), Option.some(BigDecimal.unsafeFromString("1"))) + * assert.deepStrictEqual(BigDecimal.remainder(BigDecimal.unsafeFromString("-4"), BigDecimal.unsafeFromString("2")), Option.some(BigDecimal.unsafeFromString("0"))) + * ``` + * + * @since 2.0.0 + * @category math + */ + (self: BigDecimal, divisor: BigDecimal): Option.Option +} = dual(2, (self: BigDecimal, divisor: BigDecimal): Option.Option => { + if (divisor.value === bigint0) { + return Option.none() + } + + const max = Math.max(self.scale, divisor.scale) + return Option.some(make(scale(self, max).value % scale(divisor, max).value, max)) +}) + +/** + * Returns the remainder left over when one operand is divided by a second operand. + * + * Throws a `RangeError` if the divisor is `0`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { unsafeRemainder, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(unsafeRemainder(unsafeFromString("2"), unsafeFromString("2")), unsafeFromString("0")) + * assert.deepStrictEqual(unsafeRemainder(unsafeFromString("3"), unsafeFromString("2")), unsafeFromString("1")) + * assert.deepStrictEqual(unsafeRemainder(unsafeFromString("-4"), unsafeFromString("2")), unsafeFromString("0")) + * ``` + * + * @since 2.0.0 + * @category math + */ +export const unsafeRemainder: { + /** + * Returns the remainder left over when one operand is divided by a second operand. + * + * Throws a `RangeError` if the divisor is `0`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { unsafeRemainder, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(unsafeRemainder(unsafeFromString("2"), unsafeFromString("2")), unsafeFromString("0")) + * assert.deepStrictEqual(unsafeRemainder(unsafeFromString("3"), unsafeFromString("2")), unsafeFromString("1")) + * assert.deepStrictEqual(unsafeRemainder(unsafeFromString("-4"), unsafeFromString("2")), unsafeFromString("0")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (divisor: BigDecimal): (self: BigDecimal) => BigDecimal + /** + * Returns the remainder left over when one operand is divided by a second operand. + * + * Throws a `RangeError` if the divisor is `0`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { unsafeRemainder, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(unsafeRemainder(unsafeFromString("2"), unsafeFromString("2")), unsafeFromString("0")) + * assert.deepStrictEqual(unsafeRemainder(unsafeFromString("3"), unsafeFromString("2")), unsafeFromString("1")) + * assert.deepStrictEqual(unsafeRemainder(unsafeFromString("-4"), unsafeFromString("2")), unsafeFromString("0")) + * ``` + * + * @since 2.0.0 + * @category math + */ + (self: BigDecimal, divisor: BigDecimal): BigDecimal +} = dual(2, (self: BigDecimal, divisor: BigDecimal): BigDecimal => { + if (divisor.value === bigint0) { + throw new RangeError("Division by zero") + } + + const max = Math.max(self.scale, divisor.scale) + return make(scale(self, max).value % scale(divisor, max).value, max) +}) + +/** + * @category instances + * @since 2.0.0 + */ +export const Equivalence: equivalence.Equivalence = equivalence.make((self, that) => { + if (self.scale > that.scale) { + return scale(that, self.scale).value === self.value + } + + if (self.scale < that.scale) { + return scale(self, that.scale).value === that.value + } + + return self.value === that.value +}) + +/** + * Checks if two `BigDecimal`s are equal. + * + * @since 2.0.0 + * @category predicates + */ +export const equals: { + /** + * Checks if two `BigDecimal`s are equal. + * + * @since 2.0.0 + * @category predicates + */ + (that: BigDecimal): (self: BigDecimal) => boolean + /** + * Checks if two `BigDecimal`s are equal. + * + * @since 2.0.0 + * @category predicates + */ + (self: BigDecimal, that: BigDecimal): boolean +} = dual(2, (self: BigDecimal, that: BigDecimal): boolean => Equivalence(self, that)) + +/** + * Creates a `BigDecimal` from a `bigint` value. + * + * @since 2.0.0 + * @category constructors + */ +export const fromBigInt = (n: bigint): BigDecimal => make(n, 0) + +/** + * Creates a `BigDecimal` from a `number` value. + * + * It is not recommended to convert a floating point number to a decimal directly, + * as the floating point representation may be unexpected. + * + * Throws a `RangeError` if the number is not finite (`NaN`, `+Infinity` or `-Infinity`). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { unsafeFromNumber, make } from "effect/BigDecimal" + * + * assert.deepStrictEqual(unsafeFromNumber(123), make(123n, 0)) + * assert.deepStrictEqual(unsafeFromNumber(123.456), make(123456n, 3)) + * ``` + * + * @since 3.11.0 + * @category constructors + */ +export const unsafeFromNumber = (n: number): BigDecimal => + Option.getOrThrowWith(safeFromNumber(n), () => new RangeError(`Number must be finite, got ${n}`)) + +/** + * Creates a `BigDecimal` from a `number` value. + * + * It is not recommended to convert a floating point number to a decimal directly, + * as the floating point representation may be unexpected. + * + * Throws a `RangeError` if the number is not finite (`NaN`, `+Infinity` or `-Infinity`). + * + * @since 2.0.0 + * @category constructors + * @deprecated Use {@link unsafeFromNumber} instead. + */ +export const fromNumber: (n: number) => BigDecimal = unsafeFromNumber + +// TODO(4.0): Rename this to `fromNumber` after removing the current, unsafe implementation of `fromNumber`. +/** + * Creates a `BigDecimal` from a `number` value. + * + * It is not recommended to convert a floating point number to a decimal directly, + * as the floating point representation may be unexpected. + * + * Returns `None` if the number is not finite (`NaN`, `+Infinity` or `-Infinity`). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal, Option } from "effect" + * + * assert.deepStrictEqual(BigDecimal.safeFromNumber(123), Option.some(BigDecimal.make(123n, 0))) + * assert.deepStrictEqual(BigDecimal.safeFromNumber(123.456), Option.some(BigDecimal.make(123456n, 3))) + * assert.deepStrictEqual(BigDecimal.safeFromNumber(Infinity), Option.none()) + * ``` + * + * @since 3.11.0 + * @category constructors + */ +export const safeFromNumber = (n: number): Option.Option => { + if (!Number.isFinite(n)) { + return Option.none() + } + + const string = `${n}` + if (string.includes("e")) { + return fromString(string) + } + + const [lead, trail = ""] = string.split(".") + return Option.some(make(BigInt(`${lead}${trail}`), trail.length)) +} + +/** + * Parses a numerical `string` into a `BigDecimal`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { BigDecimal, Option } from "effect" + * + * assert.deepStrictEqual(BigDecimal.fromString("123"), Option.some(BigDecimal.make(123n, 0))) + * assert.deepStrictEqual(BigDecimal.fromString("123.456"), Option.some(BigDecimal.make(123456n, 3))) + * assert.deepStrictEqual(BigDecimal.fromString("123.abc"), Option.none()) + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export const fromString = (s: string): Option.Option => { + if (s === "") { + return Option.some(zero) + } + + let base: string + let exp: number + const seperator = s.search(/[eE]/) + if (seperator !== -1) { + const trail = s.slice(seperator + 1) + base = s.slice(0, seperator) + exp = Number(trail) + if (base === "" || !Number.isSafeInteger(exp) || !FINITE_INT_REGEX.test(trail)) { + return Option.none() + } + } else { + base = s + exp = 0 + } + + let digits: string + let offset: number + const dot = base.search(/\./) + if (dot !== -1) { + const lead = base.slice(0, dot) + const trail = base.slice(dot + 1) + digits = `${lead}${trail}` + offset = trail.length + } else { + digits = base + offset = 0 + } + + if (!FINITE_INT_REGEX.test(digits)) { + return Option.none() + } + + const scale = offset - exp + if (!Number.isSafeInteger(scale)) { + return Option.none() + } + + return Option.some(make(BigInt(digits), scale)) +} + +/** + * Parses a numerical `string` into a `BigDecimal`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { unsafeFromString, make } from "effect/BigDecimal" + * + * assert.deepStrictEqual(unsafeFromString("123"), make(123n, 0)) + * assert.deepStrictEqual(unsafeFromString("123.456"), make(123456n, 3)) + * assert.throws(() => unsafeFromString("123.abc")) + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export const unsafeFromString = (s: string): BigDecimal => + Option.getOrThrowWith(fromString(s), () => new Error("Invalid numerical string")) + +/** + * Formats a given `BigDecimal` as a `string`. + * + * If the scale of the `BigDecimal` is greater than or equal to 16, the `BigDecimal` will + * be formatted in scientific notation. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { format, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(format(unsafeFromString("-5")), "-5") + * assert.deepStrictEqual(format(unsafeFromString("123.456")), "123.456") + * assert.deepStrictEqual(format(unsafeFromString("-0.00000123")), "-0.00000123") + * ``` + * + * @since 2.0.0 + * @category conversions + */ +export const format = (n: BigDecimal): string => { + const normalized = normalize(n) + if (Math.abs(normalized.scale) >= 16) { + return toExponential(normalized) + } + + const negative = normalized.value < bigint0 + const absolute = negative ? `${normalized.value}`.substring(1) : `${normalized.value}` + + let before: string + let after: string + + if (normalized.scale >= absolute.length) { + before = "0" + after = "0".repeat(normalized.scale - absolute.length) + absolute + } else { + const location = absolute.length - normalized.scale + if (location > absolute.length) { + const zeros = location - absolute.length + before = `${absolute}${"0".repeat(zeros)}` + after = "" + } else { + after = absolute.slice(location) + before = absolute.slice(0, location) + } + } + + const complete = after === "" ? before : `${before}.${after}` + return negative ? `-${complete}` : complete +} + +/** + * Formats a given `BigDecimal` as a `string` in scientific notation. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { toExponential, make } from "effect/BigDecimal" + * + * assert.deepStrictEqual(toExponential(make(123456n, -5)), "1.23456e+10") + * ``` + * + * @since 3.11.0 + * @category conversions + */ +export const toExponential = (n: BigDecimal): string => { + if (isZero(n)) { + return "0e+0" + } + + const normalized = normalize(n) + const digits = `${abs(normalized).value}` + const head = digits.slice(0, 1) + const tail = digits.slice(1) + + let output = `${isNegative(normalized) ? "-" : ""}${head}` + if (tail !== "") { + output += `.${tail}` + } + + const exp = tail.length - normalized.scale + return `${output}e${exp >= 0 ? "+" : ""}${exp}` +} + +/** + * Converts a `BigDecimal` to a `number`. + * + * This function will produce incorrect results if the `BigDecimal` exceeds the 64-bit range of a `number`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { unsafeToNumber, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(unsafeToNumber(unsafeFromString("123.456")), 123.456) + * ``` + * + * @since 2.0.0 + * @category conversions + */ +export const unsafeToNumber = (n: BigDecimal): number => Number(format(n)) + +/** + * Checks if a given `BigDecimal` is an integer. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { isInteger, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(isInteger(unsafeFromString("0")), true) + * assert.deepStrictEqual(isInteger(unsafeFromString("1")), true) + * assert.deepStrictEqual(isInteger(unsafeFromString("1.1")), false) + * ``` + * + * @since 2.0.0 + * @category predicates + */ +export const isInteger = (n: BigDecimal): boolean => normalize(n).scale <= 0 + +/** + * Checks if a given `BigDecimal` is `0`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { isZero, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(isZero(unsafeFromString("0")), true) + * assert.deepStrictEqual(isZero(unsafeFromString("1")), false) + * ``` + * + * @since 2.0.0 + * @category predicates + */ +export const isZero = (n: BigDecimal): boolean => n.value === bigint0 + +/** + * Checks if a given `BigDecimal` is negative. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { isNegative, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(isNegative(unsafeFromString("-1")), true) + * assert.deepStrictEqual(isNegative(unsafeFromString("0")), false) + * assert.deepStrictEqual(isNegative(unsafeFromString("1")), false) + * ``` + * + * @since 2.0.0 + * @category predicates + */ +export const isNegative = (n: BigDecimal): boolean => n.value < bigint0 + +/** + * Checks if a given `BigDecimal` is positive. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { isPositive, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(isPositive(unsafeFromString("-1")), false) + * assert.deepStrictEqual(isPositive(unsafeFromString("0")), false) + * assert.deepStrictEqual(isPositive(unsafeFromString("1")), true) + * ``` + * + * @since 2.0.0 + * @category predicates + */ +export const isPositive = (n: BigDecimal): boolean => n.value > bigint0 + +const isBigDecimalArgs = (args: IArguments) => isBigDecimal(args[0]) + +/** + * Calculate the ceiling of a `BigDecimal` at the given scale. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { ceil, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(ceil(unsafeFromString("145"), -1), unsafeFromString("150")) + * assert.deepStrictEqual(ceil(unsafeFromString("-14.5")), unsafeFromString("-14")) + * ``` + * + * @since 3.16.0 + * @category math + */ +export const ceil: { + /** + * Calculate the ceiling of a `BigDecimal` at the given scale. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { ceil, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(ceil(unsafeFromString("145"), -1), unsafeFromString("150")) + * assert.deepStrictEqual(ceil(unsafeFromString("-14.5")), unsafeFromString("-14")) + * ``` + * + * @since 3.16.0 + * @category math + */ + (scale: number): (self: BigDecimal) => BigDecimal + /** + * Calculate the ceiling of a `BigDecimal` at the given scale. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { ceil, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(ceil(unsafeFromString("145"), -1), unsafeFromString("150")) + * assert.deepStrictEqual(ceil(unsafeFromString("-14.5")), unsafeFromString("-14")) + * ``` + * + * @since 3.16.0 + * @category math + */ + (self: BigDecimal, scale?: number): BigDecimal +} = dual(isBigDecimalArgs, (self: BigDecimal, scale: number = 0): BigDecimal => { + const truncated = truncate(self, scale) + + if (isPositive(self) && lessThan(truncated, self)) { + return sum(truncated, make(1n, scale)) + } + + return truncated +}) + +/** + * Calculate the floor of a `BigDecimal` at the given scale. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { floor, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(floor(unsafeFromString("145"), -1), unsafeFromString("140")) + * assert.deepStrictEqual(floor(unsafeFromString("-14.5")), unsafeFromString("-15")) + * ``` + * + * @since 3.16.0 + * @category math + */ +export const floor: { + /** + * Calculate the floor of a `BigDecimal` at the given scale. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { floor, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(floor(unsafeFromString("145"), -1), unsafeFromString("140")) + * assert.deepStrictEqual(floor(unsafeFromString("-14.5")), unsafeFromString("-15")) + * ``` + * + * @since 3.16.0 + * @category math + */ + (scale: number): (self: BigDecimal) => BigDecimal + /** + * Calculate the floor of a `BigDecimal` at the given scale. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { floor, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(floor(unsafeFromString("145"), -1), unsafeFromString("140")) + * assert.deepStrictEqual(floor(unsafeFromString("-14.5")), unsafeFromString("-15")) + * ``` + * + * @since 3.16.0 + * @category math + */ + (self: BigDecimal, scale?: number): BigDecimal +} = dual(isBigDecimalArgs, (self: BigDecimal, scale: number = 0): BigDecimal => { + const truncated = truncate(self, scale) + + if (isNegative(self) && greaterThan(truncated, self)) { + return sum(truncated, make(-1n, scale)) + } + + return truncated +}) + +/** + * Truncate a `BigDecimal` at the given scale. This is the same operation as rounding away from zero. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { truncate, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(truncate(unsafeFromString("145"), -1), unsafeFromString("140")) + * assert.deepStrictEqual(truncate(unsafeFromString("-14.5")), unsafeFromString("-14")) + * ``` + * + * @since 3.16.0 + * @category math + */ +export const truncate: { + /** + * Truncate a `BigDecimal` at the given scale. This is the same operation as rounding away from zero. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { truncate, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(truncate(unsafeFromString("145"), -1), unsafeFromString("140")) + * assert.deepStrictEqual(truncate(unsafeFromString("-14.5")), unsafeFromString("-14")) + * ``` + * + * @since 3.16.0 + * @category math + */ + (scale: number): (self: BigDecimal) => BigDecimal + /** + * Truncate a `BigDecimal` at the given scale. This is the same operation as rounding away from zero. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { truncate, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(truncate(unsafeFromString("145"), -1), unsafeFromString("140")) + * assert.deepStrictEqual(truncate(unsafeFromString("-14.5")), unsafeFromString("-14")) + * ``` + * + * @since 3.16.0 + * @category math + */ + (self: BigDecimal, scale?: number): BigDecimal +} = dual(isBigDecimalArgs, (self: BigDecimal, scale: number = 0): BigDecimal => { + if (self.scale <= scale) { + return self + } + + // BigInt division truncates towards zero + return make(self.value / (10n ** BigInt(self.scale - scale)), scale) +}) + +/** + * Internal function used by `round` for `half-even` and `half-odd` rounding modes. + * + * Returns the digit at the position of the given `scale` within the `BigDecimal`. + * + * @internal + */ +export const digitAt: { + /** + * Internal function used by `round` for `half-even` and `half-odd` rounding modes. + * + * Returns the digit at the position of the given `scale` within the `BigDecimal`. + * + * @internal + */ + (scale: number): (self: BigDecimal) => bigint + /** + * Internal function used by `round` for `half-even` and `half-odd` rounding modes. + * + * Returns the digit at the position of the given `scale` within the `BigDecimal`. + * + * @internal + */ + (self: BigDecimal, scale: number): bigint +} = dual(2, (self: BigDecimal, scale: number): bigint => { + if (self.scale < scale) { + return 0n + } + + const scaled = self.value / (10n ** BigInt(self.scale - scale)) + return scaled % 10n +}) + +/** + * Rounding modes for `BigDecimal`. + * + * `ceil`: round towards positive infinity + * `floor`: round towards negative infinity + * `to-zero`: round towards zero + * `from-zero`: round away from zero + * `half-ceil`: round to the nearest neighbor; if equidistant round towards positive infinity + * `half-floor`: round to the nearest neighbor; if equidistant round towards negative infinity + * `half-to-zero`: round to the nearest neighbor; if equidistant round towards zero + * `half-from-zero`: round to the nearest neighbor; if equidistant round away from zero + * `half-even`: round to the nearest neighbor; if equidistant round to the neighbor with an even digit + * `half-odd`: round to the nearest neighbor; if equidistant round to the neighbor with an odd digit + * + * @since 3.16.0 + * @category math + */ +export type RoundingMode = + | "ceil" + | "floor" + | "to-zero" + | "from-zero" + | "half-ceil" + | "half-floor" + | "half-to-zero" + | "half-from-zero" + | "half-even" + | "half-odd" + +/** + * Rounds a `BigDecimal` at the given scale with the specified rounding mode. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { round, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(round(unsafeFromString("145"), { mode: "from-zero", scale: -1 }), unsafeFromString("150")) + * assert.deepStrictEqual(round(unsafeFromString("-14.5")), unsafeFromString("-15")) + * ``` + * + * @since 3.16.0 + * @category math + */ +export const round: { + /** + * Rounds a `BigDecimal` at the given scale with the specified rounding mode. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { round, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(round(unsafeFromString("145"), { mode: "from-zero", scale: -1 }), unsafeFromString("150")) + * assert.deepStrictEqual(round(unsafeFromString("-14.5")), unsafeFromString("-15")) + * ``` + * + * @since 3.16.0 + * @category math + */ + (options: { scale?: number; mode?: RoundingMode }): (self: BigDecimal) => BigDecimal + /** + * Rounds a `BigDecimal` at the given scale with the specified rounding mode. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { round, unsafeFromString } from "effect/BigDecimal" + * + * assert.deepStrictEqual(round(unsafeFromString("145"), { mode: "from-zero", scale: -1 }), unsafeFromString("150")) + * assert.deepStrictEqual(round(unsafeFromString("-14.5")), unsafeFromString("-15")) + * ``` + * + * @since 3.16.0 + * @category math + */ + (n: BigDecimal, options?: { scale?: number; mode?: RoundingMode }): BigDecimal +} = dual(isBigDecimalArgs, (self: BigDecimal, options?: { scale?: number; mode?: RoundingMode }): BigDecimal => { + const mode = options?.mode ?? "half-from-zero" + const scale = options?.scale ?? 0 + + switch (mode) { + case "ceil": + return ceil(self, scale) + + case "floor": + return floor(self, scale) + + case "to-zero": + return truncate(self, scale) + + case "from-zero": + return (isPositive(self) ? ceil(self, scale) : floor(self, scale)) + + case "half-ceil": + return floor(sum(self, make(5n, scale + 1)), scale) + + case "half-floor": + return ceil(sum(self, make(-5n, scale + 1)), scale) + + case "half-to-zero": + return isNegative(self) + ? floor(sum(self, make(5n, scale + 1)), scale) + : ceil(sum(self, make(-5n, scale + 1)), scale) + + case "half-from-zero": + return isNegative(self) + ? ceil(sum(self, make(-5n, scale + 1)), scale) + : floor(sum(self, make(5n, scale + 1)), scale) + } + + const halfCeil = floor(sum(self, make(5n, scale + 1)), scale) + const halfFloor = ceil(sum(self, make(-5n, scale + 1)), scale) + const digit = digitAt(halfCeil, scale) + + switch (mode) { + case "half-even": + return equals(halfCeil, halfFloor) ? halfCeil : (digit % 2n === 0n) ? halfCeil : halfFloor + + case "half-odd": + return equals(halfCeil, halfFloor) ? halfCeil : (digit % 2n === 0n) ? halfFloor : halfCeil + } +}) + +/** + * Takes an `Iterable` of `BigDecimal`s and returns their sum as a single `BigDecimal` + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { unsafeFromString, sumAll } from "effect/BigDecimal" + * + * assert.deepStrictEqual(sumAll([unsafeFromString("2"), unsafeFromString("3"), unsafeFromString("4")]), unsafeFromString("9")) + * ``` + * + * @category math + * @since 3.16.0 + */ +export const sumAll = (collection: Iterable): BigDecimal => { + let out = zero + for (const n of collection) { + out = sum(out, n) + } + + return out +} diff --git a/backend/node_modules/effect/src/Brand.ts b/backend/node_modules/effect/src/Brand.ts new file mode 100644 index 0000000000000000000000000000000000000000..e6576dea09432f46b5739522690056433844b4f8 --- /dev/null +++ b/backend/node_modules/effect/src/Brand.ts @@ -0,0 +1,360 @@ +/** + * This module provides types and utility functions to create and work with branded types, + * which are TypeScript types with an added type tag to prevent accidental usage of a value in the wrong context. + * + * The `refined` and `nominal` functions are both used to create branded types in TypeScript. + * The main difference between them is that `refined` allows for validation of the data, while `nominal` does not. + * + * The `nominal` function is used to create a new branded type that has the same underlying type as the input, but with a different name. + * This is useful when you want to distinguish between two values of the same type that have different meanings. + * The `nominal` function does not perform any validation of the input data. + * + * On the other hand, the `refined` function is used to create a new branded type that has the same underlying type as the input, + * but with a different name, and it also allows for validation of the input data. + * The `refined` function takes a predicate that is used to validate the input data. + * If the input data fails the validation, a `BrandErrors` is returned, which provides information about the specific validation failure. + * + * @since 2.0.0 + */ +import * as Arr from "./Array.js" +import * as Either from "./Either.js" +import { identity, unsafeCoerce } from "./Function.js" +import * as Option from "./Option.js" +import type { Predicate } from "./Predicate.js" +import type * as Types from "./Types.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const BrandTypeId: unique symbol = Symbol.for("effect/Brand") + +/** + * @since 2.0.0 + * @category symbols + */ +export type BrandTypeId = typeof BrandTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export const RefinedConstructorsTypeId: unique symbol = Symbol.for("effect/Brand/Refined") + +/** + * @since 2.0.0 + * @category symbols + */ +export type RefinedConstructorsTypeId = typeof RefinedConstructorsTypeId + +/** + * A generic interface that defines a branded type. + * + * @since 2.0.0 + * @category models + */ +export interface Brand { + readonly [BrandTypeId]: { + readonly [k in K]: K + } +} + +/** + * @since 2.0.0 + */ +export declare namespace Brand { + /** + * Represents a list of refinement errors. + * + * @since 2.0.0 + * @category models + */ + export interface BrandErrors extends Array {} + + /** + * Represents an error that occurs when the provided value of the branded type does not pass the refinement predicate. + * + * @since 2.0.0 + * @category models + */ + export interface RefinementError { + readonly meta: unknown + readonly message: string + } + + /** + * @since 2.0.0 + * @category models + */ + export interface Constructor> { + readonly [RefinedConstructorsTypeId]: RefinedConstructorsTypeId + /** + * Constructs a branded type from a value of type `A`, throwing an error if + * the provided `A` is not valid. + */ + (args: Brand.Unbranded): A + /** + * Constructs a branded type from a value of type `A`, returning `Some` + * if the provided `A` is valid, `None` otherwise. + */ + option(args: Brand.Unbranded): Option.Option + /** + * Constructs a branded type from a value of type `A`, returning `Right` + * if the provided `A` is valid, `Left` otherwise. + */ + either(args: Brand.Unbranded): Either.Either + /** + * Attempts to refine the provided value of type `A`, returning `true` if + * the provided `A` is valid, `false` otherwise. + */ + is(a: Brand.Unbranded): a is Brand.Unbranded & A + } + + /** + * A utility type to extract a branded type from a `Brand.Constructor`. + * + * @since 2.0.0 + * @category models + */ + export type FromConstructor = A extends Brand.Constructor ? B : never + + /** + * A utility type to extract the value type from a brand. + * + * @since 2.0.0 + * @category models + */ + export type Unbranded

= P extends infer Q & Brands

? Q : P + + /** + * A utility type to extract the brands from a branded type. + * + * @since 2.0.0 + * @category models + */ + export type Brands

= P extends Brand ? Types.UnionToIntersection< + { + [k in keyof P[BrandTypeId]]: k extends string | symbol ? Brand + : never + }[keyof P[BrandTypeId]] + > + : never + + /** + * A utility type that checks that all brands have the same base type. + * + * @since 2.0.0 + * @category models + */ + export type EnsureCommonBase< + Brands extends readonly [Brand.Constructor, ...Array>] + > = { + [B in keyof Brands]: Brand.Unbranded> extends + Brand.Unbranded> + ? Brand.Unbranded> extends Brand.Unbranded> + ? Brands[B] + : Brands[B] + : "ERROR: All brands should have the same base type" + } +} + +/** + * @category alias + * @since 2.0.0 + */ +export type Branded = A & Brand + +/** + * Returns a `BrandErrors` that contains a single `RefinementError`. + * + * @since 2.0.0 + * @category constructors + */ +export const error = (message: string, meta?: unknown): Brand.BrandErrors => [{ + message, + meta +}] + +/** + * Takes a variable number of `BrandErrors` and returns a single `BrandErrors` that contains all refinement errors. + * + * @since 2.0.0 + * @category constructors + */ +export const errors: (...errors: Array) => Brand.BrandErrors = ( + ...errors: Array +): Brand.BrandErrors => Arr.flatten(errors) + +/** + * Returns a `Brand.Constructor` that can construct a branded type from an unbranded value using the provided `refinement` + * predicate as validation of the input data. + * + * If you don't want to perform any validation but only distinguish between two values of the same type but with different meanings, + * see {@link nominal}. + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Brand } from "effect" + * + * type Int = number & Brand.Brand<"Int"> + * + * const Int = Brand.refined( + * (n) => Number.isInteger(n), + * (n) => Brand.error(`Expected ${n} to be an integer`) + * ) + * + * console.log(Int(1)) + * // 1 + * + * assert.throws(() => Int(1.1)) + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export function refined>( + f: (unbranded: Brand.Unbranded) => Option.Option +): Brand.Constructor +export function refined>( + refinement: Predicate>, + onFailure: (unbranded: Brand.Unbranded) => Brand.BrandErrors +): Brand.Constructor +export function refined>( + ...args: [(unbranded: Brand.Unbranded) => Option.Option] | [ + Predicate>, + (unbranded: Brand.Unbranded) => Brand.BrandErrors + ] +): Brand.Constructor { + const either: (unbranded: Brand.Unbranded) => Either.Either = args.length === 2 ? + (unbranded) => args[0](unbranded) ? Either.right(unbranded as A) : Either.left(args[1](unbranded)) : + (unbranded) => { + return Option.match(args[0](unbranded), { + onNone: () => Either.right(unbranded as A), + onSome: Either.left + }) + } + return Object.assign((unbranded: Brand.Unbranded) => Either.getOrThrowWith(either(unbranded), identity), { + [RefinedConstructorsTypeId]: RefinedConstructorsTypeId, + option: (args: any) => Option.getRight(either(args)), + either, + is: (args: any): args is Brand.Unbranded & A => Either.isRight(either(args)) + }) as any +} + +/** + * This function returns a `Brand.Constructor` that **does not apply any runtime checks**, it just returns the provided value. + * It can be used to create nominal types that allow distinguishing between two values of the same type but with different meanings. + * + * If you also want to perform some validation, see {@link refined}. + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Brand } from "effect" + * + * type UserId = number & Brand.Brand<"UserId"> + * + * const UserId = Brand.nominal() + * + * console.log(UserId(1)) + * // 1 + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export const nominal = >(): Brand.Constructor< + A +> => { + // @ts-expect-error + return Object.assign((args) => args, { + [RefinedConstructorsTypeId]: RefinedConstructorsTypeId, + option: (args: any) => Option.some(args), + either: (args: any) => Either.right(args), + is: (_args: any): _args is Brand.Unbranded & A => true + }) +} + +/** + * Combines two or more brands together to form a single branded type. + * This API is useful when you want to validate that the input data passes multiple brand validators. + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Brand } from "effect" + * + * type Int = number & Brand.Brand<"Int"> + * const Int = Brand.refined( + * (n) => Number.isInteger(n), + * (n) => Brand.error(`Expected ${n} to be an integer`) + * ) + * type Positive = number & Brand.Brand<"Positive"> + * const Positive = Brand.refined( + * (n) => n > 0, + * (n) => Brand.error(`Expected ${n} to be positive`) + * ) + * + * const PositiveInt = Brand.all(Int, Positive) + * + * console.log(PositiveInt(1)) + * // 1 + * + * assert.throws(() => PositiveInt(1.1)) + * ``` + * + * @since 2.0.0 + * @category combining + */ +export const all: , ...Array>]>( + ...brands: Brand.EnsureCommonBase +) => Brand.Constructor< + Types.UnionToIntersection<{ [B in keyof Brands]: Brand.FromConstructor }[number]> extends + infer X extends Brand ? X : Brand +> = < + Brands extends readonly [Brand.Constructor, ...Array>] +>(...brands: Brand.EnsureCommonBase): Brand.Constructor< + Types.UnionToIntersection< + { + [B in keyof Brands]: Brand.FromConstructor + }[number] + > extends infer X extends Brand ? X : Brand +> => { + const either = (args: any): Either.Either => { + let result: Either.Either = Either.right(args) + for (const brand of brands) { + const nextResult = brand.either(args) + if (Either.isLeft(result) && Either.isLeft(nextResult)) { + result = Either.left([...result.left, ...nextResult.left]) + } else { + result = Either.isLeft(result) ? result : nextResult + } + } + return result + } + // @ts-expect-error + return Object.assign((args) => + Either.match(either(args), { + onLeft: (e) => { + throw e + }, + onRight: identity + }), { + [RefinedConstructorsTypeId]: RefinedConstructorsTypeId, + option: (args: any) => Option.getRight(either(args)), + either, + is: (args: any): args is any => Either.isRight(either(args)) + }) +} + +/** + * Retrieves the unbranded value from a `Brand` instance. + * + * @since 3.15.0 + * @category getters + */ +export const unbranded: >(branded: A) => Brand.Unbranded = unsafeCoerce diff --git a/backend/node_modules/effect/src/ConfigProvider.ts b/backend/node_modules/effect/src/ConfigProvider.ts new file mode 100644 index 0000000000000000000000000000000000000000..da4f175bf7f83ff3b8c02da74f4ac89b2e1b245c --- /dev/null +++ b/backend/node_modules/effect/src/ConfigProvider.ts @@ -0,0 +1,421 @@ +/** + * @since 2.0.0 + */ +import type * as Config from "./Config.js" +import type * as ConfigError from "./ConfigError.js" +import type * as PathPatch from "./ConfigProviderPathPatch.js" +import type * as Context from "./Context.js" +import type * as Effect from "./Effect.js" +import type { LazyArg } from "./Function.js" +import type * as HashSet from "./HashSet.js" +import * as internal from "./internal/configProvider.js" +import type { Pipeable } from "./Pipeable.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const ConfigProviderTypeId: unique symbol = internal.ConfigProviderTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type ConfigProviderTypeId = typeof ConfigProviderTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export const FlatConfigProviderTypeId: unique symbol = internal.FlatConfigProviderTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type FlatConfigProviderTypeId = typeof FlatConfigProviderTypeId + +/** + * A ConfigProvider is a service that provides configuration given a description + * of the structure of that configuration. + * + * @since 2.0.0 + * @category models + */ +export interface ConfigProvider extends ConfigProvider.Proto, Pipeable { + /** + * Loads the specified configuration, or fails with a config error. + */ + load(config: Config.Config): Effect.Effect + /** + * Flattens this config provider into a simplified config provider that knows + * only how to deal with flat (key/value) properties. + */ + readonly flattened: ConfigProvider.Flat +} + +/** + * @since 2.0.0 + */ +export declare namespace ConfigProvider { + /** + * @since 2.0.0 + * @category models + */ + export interface Proto { + readonly [ConfigProviderTypeId]: ConfigProviderTypeId + } + + /** + * A simplified config provider that knows only how to deal with flat + * (key/value) properties. Because these providers are common, there is + * special support for implementing them. + * + * @since 2.0.0 + * @category models + */ + export interface Flat { + readonly [FlatConfigProviderTypeId]: FlatConfigProviderTypeId + readonly patch: PathPatch.PathPatch + load( + path: ReadonlyArray, + config: Config.Config.Primitive, + split?: boolean + ): Effect.Effect, ConfigError.ConfigError> + enumerateChildren( + path: ReadonlyArray + ): Effect.Effect, ConfigError.ConfigError> + } + + /** + * @since 2.0.0 + * @category models + */ + export interface FromMapConfig { + readonly pathDelim: string + readonly seqDelim: string + } + + /** + * @since 2.0.0 + * @category models + */ + export interface FromEnvConfig { + readonly pathDelim: string + readonly seqDelim: string + } + + /** + * @since 1.0.0 + * @category models + */ + export type KeyComponent = KeyName | KeyIndex + + /** + * @since 1.0.0 + * @category models + */ + export interface KeyName { + readonly _tag: "KeyName" + readonly name: string + } + + /** + * @since 1.0.0 + * @category models + */ + export interface KeyIndex { + readonly _tag: "KeyIndex" + readonly index: number + } +} + +/** + * The service tag for `ConfigProvider`. + * + * @since 2.0.0 + * @category context + */ +export const ConfigProvider: Context.Tag = internal.configProviderTag + +/** + * Creates a new config provider. + * + * @since 2.0.0 + * @category constructors + */ +export const make: ( + options: { + readonly load: (config: Config.Config) => Effect.Effect + readonly flattened: ConfigProvider.Flat + } +) => ConfigProvider = internal.make + +/** + * Creates a new flat config provider. + * + * @since 2.0.0 + * @category constructors + */ +export const makeFlat: (options: { + readonly load: ( + path: ReadonlyArray, + config: Config.Config.Primitive, + split: boolean + ) => Effect.Effect, ConfigError.ConfigError> + readonly enumerateChildren: ( + path: ReadonlyArray + ) => Effect.Effect, ConfigError.ConfigError> + readonly patch: PathPatch.PathPatch +}) => ConfigProvider.Flat = internal.makeFlat + +/** + * A config provider that loads configuration from context variables + * + * **Options**: + * + * - `pathDelim`: The delimiter for the path segments (default: `"_"`). + * - `seqDelim`: The delimiter for the sequence of values (default: `","`). + * + * @since 2.0.0 + * @category constructors + */ +export const fromEnv: (options?: Partial) => ConfigProvider = internal.fromEnv + +/** + * Constructs a new `ConfigProvider` from a key/value (flat) provider, where + * nesting is embedded into the string keys. + * + * @since 2.0.0 + * @category constructors + */ +export const fromFlat: (flat: ConfigProvider.Flat) => ConfigProvider = internal.fromFlat + +/** + * Constructs a new `ConfigProvider` from a JSON object. + * + * @since 2.0.0 + * @category constructors + */ +export const fromJson: (json: unknown) => ConfigProvider = internal.fromJson + +// TODO(4.0): use `_` for nested configs instead of `.` in next major +/** + * Constructs a ConfigProvider using a map and the specified delimiter string, + * which determines how to split the keys in the map into path segments. + * + * @since 2.0.0 + * @category constructors + */ +export const fromMap: (map: Map, config?: Partial) => ConfigProvider = + internal.fromMap + +/** + * Returns a new config provider that will automatically convert all property + * names to constant case. This can be utilized to adapt the names of + * configuration properties from the default naming convention of camel case + * to the naming convention of a config provider. + * + * @since 2.0.0 + * @category combinators + */ +export const constantCase: (self: ConfigProvider) => ConfigProvider = internal.constantCase + +/** + * Returns a new config provider that will automatically tranform all path + * configuration names with the specified function. This can be utilized to + * adapt the names of configuration properties from one naming convention to + * another. + * + * @since 2.0.0 + * @category utils + */ +export const mapInputPath: { + /** + * Returns a new config provider that will automatically tranform all path + * configuration names with the specified function. This can be utilized to + * adapt the names of configuration properties from one naming convention to + * another. + * + * @since 2.0.0 + * @category utils + */ + (f: (path: string) => string): (self: ConfigProvider) => ConfigProvider + /** + * Returns a new config provider that will automatically tranform all path + * configuration names with the specified function. This can be utilized to + * adapt the names of configuration properties from one naming convention to + * another. + * + * @since 2.0.0 + * @category utils + */ + (self: ConfigProvider, f: (path: string) => string): ConfigProvider +} = internal.mapInputPath + +/** + * Returns a new config provider that will automatically convert all property + * names to kebab case. This can be utilized to adapt the names of + * configuration properties from the default naming convention of camel case + * to the naming convention of a config provider. + * + * @since 2.0.0 + * @category combinators + */ +export const kebabCase: (self: ConfigProvider) => ConfigProvider = internal.kebabCase + +/** + * Returns a new config provider that will automatically convert all property + * names to lower case. This can be utilized to adapt the names of + * configuration properties from the default naming convention of camel case + * to the naming convention of a config provider. + * + * @since 2.0.0 + * @category combinators + */ +export const lowerCase: (self: ConfigProvider) => ConfigProvider = internal.lowerCase + +/** + * Returns a new config provider that will automatically nest all + * configuration under the specified property name. This can be utilized to + * aggregate separate configuration sources that are all required to load a + * single configuration value. + * + * @since 2.0.0 + * @category utils + */ +export const nested: { + /** + * Returns a new config provider that will automatically nest all + * configuration under the specified property name. This can be utilized to + * aggregate separate configuration sources that are all required to load a + * single configuration value. + * + * @since 2.0.0 + * @category utils + */ + (name: string): (self: ConfigProvider) => ConfigProvider + /** + * Returns a new config provider that will automatically nest all + * configuration under the specified property name. This can be utilized to + * aggregate separate configuration sources that are all required to load a + * single configuration value. + * + * @since 2.0.0 + * @category utils + */ + (self: ConfigProvider, name: string): ConfigProvider +} = internal.nested + +/** + * Returns a new config provider that preferentially loads configuration data + * from this one, but which will fall back to the specified alternate provider + * if there are any issues loading the configuration from this provider. + * + * @since 2.0.0 + * @category utils + */ +export const orElse: { + /** + * Returns a new config provider that preferentially loads configuration data + * from this one, but which will fall back to the specified alternate provider + * if there are any issues loading the configuration from this provider. + * + * @since 2.0.0 + * @category utils + */ + (that: LazyArg): (self: ConfigProvider) => ConfigProvider + /** + * Returns a new config provider that preferentially loads configuration data + * from this one, but which will fall back to the specified alternate provider + * if there are any issues loading the configuration from this provider. + * + * @since 2.0.0 + * @category utils + */ + (self: ConfigProvider, that: LazyArg): ConfigProvider +} = internal.orElse + +/** + * Returns a new config provider that will automatically un-nest all + * configuration under the specified property name. This can be utilized to + * de-aggregate separate configuration sources that are all required to load a + * single configuration value. + * + * @since 2.0.0 + * @category utils + */ +export const unnested: { + /** + * Returns a new config provider that will automatically un-nest all + * configuration under the specified property name. This can be utilized to + * de-aggregate separate configuration sources that are all required to load a + * single configuration value. + * + * @since 2.0.0 + * @category utils + */ + (name: string): (self: ConfigProvider) => ConfigProvider + /** + * Returns a new config provider that will automatically un-nest all + * configuration under the specified property name. This can be utilized to + * de-aggregate separate configuration sources that are all required to load a + * single configuration value. + * + * @since 2.0.0 + * @category utils + */ + (self: ConfigProvider, name: string): ConfigProvider +} = internal.unnested + +/** + * Returns a new config provider that will automatically convert all property + * names to upper case. This can be utilized to adapt the names of + * configuration properties from the default naming convention of camel case + * to the naming convention of a config provider. + * + * @since 2.0.0 + * @category combinators + */ +export const snakeCase: (self: ConfigProvider) => ConfigProvider = internal.snakeCase + +/** + * Returns a new config provider that will automatically convert all property + * names to upper case. This can be utilized to adapt the names of + * configuration properties from the default naming convention of camel case + * to the naming convention of a config provider. + * + * @since 2.0.0 + * @category combinators + */ +export const upperCase: (self: ConfigProvider) => ConfigProvider = internal.upperCase + +/** + * Returns a new config provider that transforms the config provider with the + * specified function within the specified path. + * + * @since 2.0.0 + * @category combinators + */ +export const within: { + /** + * Returns a new config provider that transforms the config provider with the + * specified function within the specified path. + * + * @since 2.0.0 + * @category combinators + */ + (path: ReadonlyArray, f: (self: ConfigProvider) => ConfigProvider): (self: ConfigProvider) => ConfigProvider + /** + * Returns a new config provider that transforms the config provider with the + * specified function within the specified path. + * + * @since 2.0.0 + * @category combinators + */ + ( + self: ConfigProvider, + path: ReadonlyArray, + f: (self: ConfigProvider) => ConfigProvider + ): ConfigProvider +} = internal.within diff --git a/backend/node_modules/effect/src/Console.ts b/backend/node_modules/effect/src/Console.ts new file mode 100644 index 0000000000000000000000000000000000000000..b6f37d739d507bbcfb6466da994648e1fabf8907 --- /dev/null +++ b/backend/node_modules/effect/src/Console.ts @@ -0,0 +1,255 @@ +/** + * @since 2.0.0 + */ +import type * as Context from "./Context.js" +import type { Effect } from "./Effect.js" +import * as internal from "./internal/console.js" +import * as defaultConsole from "./internal/defaultServices/console.js" +import type * as Layer from "./Layer.js" +import type { Scope } from "./Scope.js" + +/** + * @since 2.0.0 + * @category type ids + */ +export const TypeId: unique symbol = defaultConsole.TypeId + +/** + * @since 2.0.0 + * @category type ids + */ +export type TypeId = typeof TypeId + +/** + * @since 2.0.0 + * @category model + */ +export interface Console { + readonly [TypeId]: TypeId + assert(condition: boolean, ...args: ReadonlyArray): Effect + readonly clear: Effect + count(label?: string): Effect + countReset(label?: string): Effect + debug(...args: ReadonlyArray): Effect + dir(item: any, options?: any): Effect + dirxml(...args: ReadonlyArray): Effect + error(...args: ReadonlyArray): Effect + group(options?: { + readonly label?: string | undefined + readonly collapsed?: boolean | undefined + }): Effect + readonly groupEnd: Effect + info(...args: ReadonlyArray): Effect + log(...args: ReadonlyArray): Effect + table(tabularData: any, properties?: ReadonlyArray): Effect + time(label?: string): Effect + timeEnd(label?: string): Effect + timeLog(label?: string, ...args: ReadonlyArray): Effect + trace(...args: ReadonlyArray): Effect + warn(...args: ReadonlyArray): Effect + readonly unsafe: UnsafeConsole +} + +/** + * @since 2.0.0 + * @category model + */ +export interface UnsafeConsole { + assert(condition: boolean, ...args: ReadonlyArray): void + clear(): void + count(label?: string): void + countReset(label?: string): void + debug(...args: ReadonlyArray): void + dir(item: any, options?: any): void + dirxml(...args: ReadonlyArray): void + error(...args: ReadonlyArray): void + group(...args: ReadonlyArray): void + groupCollapsed(...args: ReadonlyArray): void + groupEnd(): void + info(...args: ReadonlyArray): void + log(...args: ReadonlyArray): void + table(tabularData: any, properties?: ReadonlyArray): void + time(label?: string): void + timeEnd(label?: string): void + timeLog(label?: string, ...args: ReadonlyArray): void + trace(...args: ReadonlyArray): void + warn(...args: ReadonlyArray): void +} + +/** + * @since 2.0.0 + * @category context + */ +export const Console: Context.Tag = defaultConsole.consoleTag + +/** + * @since 2.0.0 + * @category default services + */ +export const withConsole: { + /** + * @since 2.0.0 + * @category default services + */ + (console: C): (effect: Effect) => Effect + /** + * @since 2.0.0 + * @category default services + */ + (effect: Effect, console: C): Effect +} = internal.withConsole + +/** + * @since 2.0.0 + * @category default services + */ +export const setConsole: (console: A) => Layer.Layer = internal.setConsole + +/** + * @since 2.0.0 + * @category accessor + */ +export const consoleWith: (f: (console: Console) => Effect) => Effect = internal.consoleWith + +/** + * @since 2.0.0 + * @category accessor + */ +export const assert: (condition: boolean, ...args: ReadonlyArray) => Effect = internal.assert + +/** + * @since 2.0.0 + * @category accessor + */ +export const clear: Effect = internal.clear + +/** + * @since 2.0.0 + * @category accessor + */ +export const count: (label?: string) => Effect = internal.count + +/** + * @since 2.0.0 + * @category accessor + */ +export const countReset: (label?: string) => Effect = internal.countReset + +/** + * @since 2.0.0 + * @category accessor + */ +export const debug: (...args: ReadonlyArray) => Effect = internal.debug + +/** + * @since 2.0.0 + * @category accessor + */ +export const dir: (item: any, options?: any) => Effect = internal.dir + +/** + * @since 2.0.0 + * @category accessor + */ +export const dirxml: (...args: ReadonlyArray) => Effect = internal.dirxml + +/** + * @since 2.0.0 + * @category accessor + */ +export const error: (...args: ReadonlyArray) => Effect = internal.error + +/** + * @since 2.0.0 + * @category accessor + */ +export const group: ( + options?: { label?: string | undefined; collapsed?: boolean | undefined } | undefined +) => Effect = internal.group + +/** + * @since 2.0.0 + * @category accessor + */ +export const info: (...args: ReadonlyArray) => Effect = internal.info + +/** + * @since 2.0.0 + * @category accessor + */ +export const log: (...args: ReadonlyArray) => Effect = internal.log + +/** + * @since 2.0.0 + * @category accessor + */ +export const table: (tabularData: any, properties?: ReadonlyArray) => Effect = internal.table + +/** + * @since 2.0.0 + * @category accessor + */ +export const time: (label?: string | undefined) => Effect = internal.time + +/** + * @since 2.0.0 + * @category accessor + */ +export const timeLog: (label?: string, ...args: ReadonlyArray) => Effect = internal.timeLog + +/** + * @since 2.0.0 + * @category accessor + */ +export const trace: (...args: ReadonlyArray) => Effect = internal.trace + +/** + * @since 2.0.0 + * @category accessor + */ +export const warn: (...args: ReadonlyArray) => Effect = internal.warn + +/** + * @since 2.0.0 + * @category accessor + */ +export const withGroup: { + /** + * @since 2.0.0 + * @category accessor + */ + ( + options?: { + readonly label?: string | undefined + readonly collapsed?: boolean | undefined + } + ): (self: Effect) => Effect + /** + * @since 2.0.0 + * @category accessor + */ + ( + self: Effect, + options?: { + readonly label?: string | undefined + readonly collapsed?: boolean | undefined + } + ): Effect +} = internal.withGroup + +/** + * @since 2.0.0 + * @category accessor + */ +export const withTime: { + /** + * @since 2.0.0 + * @category accessor + */ + (label?: string): (self: Effect) => Effect + /** + * @since 2.0.0 + * @category accessor + */ + (self: Effect, label?: string): Effect +} = internal.withTime diff --git a/backend/node_modules/effect/src/Data.ts b/backend/node_modules/effect/src/Data.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3747c791f90618df7020eafc96a154785236d69 --- /dev/null +++ b/backend/node_modules/effect/src/Data.ts @@ -0,0 +1,765 @@ +/** + * @since 2.0.0 + */ +import type * as Cause from "./Cause.js" +import * as core from "./internal/core.js" +import * as internal from "./internal/data.js" +import { StructuralPrototype } from "./internal/effectable.js" +import * as Predicate from "./Predicate.js" +import type * as Types from "./Types.js" +import type { Unify } from "./Unify.js" + +/** + * @since 2.0.0 + */ +export declare namespace Case { + /** + * @since 2.0.0 + * @category models + */ + export interface Constructor { + ( + args: Types.VoidIfEmpty<{ readonly [P in keyof A as P extends Tag ? never : P]: A[P] }> + ): A + } +} + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { Data, Equal } from "effect" + * + * const alice = Data.struct({ name: "Alice", age: 30 }) + * + * const bob = Data.struct({ name: "Bob", age: 40 }) + * + * assert.deepStrictEqual(Equal.equals(alice, alice), true) + * assert.deepStrictEqual(Equal.equals(alice, Data.struct({ name: "Alice", age: 30 })), true) + * + * assert.deepStrictEqual(Equal.equals(alice, { name: "Alice", age: 30 }), false) + * assert.deepStrictEqual(Equal.equals(alice, bob), false) + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const struct: >(a: A) => { readonly [P in keyof A]: A[P] } = internal.struct + +/** + * @category constructors + * @since 2.0.0 + */ +export const unsafeStruct = >(as: A): { readonly [P in keyof A]: A[P] } => + Object.setPrototypeOf(as, StructuralPrototype) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { Data, Equal } from "effect" + * + * const alice = Data.tuple("Alice", 30) + * + * const bob = Data.tuple("Bob", 40) + * + * assert.deepStrictEqual(Equal.equals(alice, alice), true) + * assert.deepStrictEqual(Equal.equals(alice, Data.tuple("Alice", 30)), true) + * + * assert.deepStrictEqual(Equal.equals(alice, ["Alice", 30]), false) + * assert.deepStrictEqual(Equal.equals(alice, bob), false) + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const tuple = >(...as: As): Readonly => unsafeArray(as) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { Data, Equal } from "effect" + * + * const alice = Data.struct({ name: "Alice", age: 30 }) + * const bob = Data.struct({ name: "Bob", age: 40 }) + * + * const persons = Data.array([alice, bob]) + * + * assert.deepStrictEqual( + * Equal.equals( + * persons, + * Data.array([ + * Data.struct({ name: "Alice", age: 30 }), + * Data.struct({ name: "Bob", age: 40 }) + * ]) + * ), + * true + * ) + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const array = >(as: As): Readonly => unsafeArray(as.slice(0) as unknown as As) + +/** + * @category constructors + * @since 2.0.0 + */ +export const unsafeArray = >(as: As): Readonly => + Object.setPrototypeOf(as, internal.ArrayProto) + +const _case = (): Case.Constructor => (args) => + (args === undefined ? Object.create(StructuralPrototype) : struct(args)) as any + +export { + /** + * Provides a constructor for the specified `Case`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Data, Equal } from "effect" + * + * interface Person { + * readonly name: string + * } + * + * // Creating a constructor for the specified Case + * const Person = Data.case() + * + * // Creating instances of Person + * const mike1 = Person({ name: "Mike" }) + * const mike2 = Person({ name: "Mike" }) + * const john = Person({ name: "John" }) + * + * // Checking equality + * assert.deepStrictEqual(Equal.equals(mike1, mike2), true) + * assert.deepStrictEqual(Equal.equals(mike1, john), false) + * + * ``` + * @since 2.0.0 + * @category constructors + */ + _case as case +} + +/** + * Provides a tagged constructor for the specified `Case`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Data } from "effect" + * + * interface Person { + * readonly _tag: "Person" // the tag + * readonly name: string + * } + * + * const Person = Data.tagged("Person") + * + * const mike = Person({ name: "Mike" }) + * + * assert.deepEqual(mike, { _tag: "Person", name: "Mike" }) + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export const tagged = ( + tag: A["_tag"] +): Case.Constructor => +(args) => { + const value = args === undefined ? Object.create(StructuralPrototype) : struct(args) + value._tag = tag + return value +} + +/** + * Provides a constructor for a Case Class. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Data, Equal } from "effect" + * + * class Person extends Data.Class<{ readonly name: string }> {} + * + * // Creating instances of Person + * const mike1 = new Person({ name: "Mike" }) + * const mike2 = new Person({ name: "Mike" }) + * const john = new Person({ name: "John" }) + * + * // Checking equality + * assert.deepStrictEqual(Equal.equals(mike1, mike2), true) + * assert.deepStrictEqual(Equal.equals(mike1, john), false) + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export const Class: new = {}>( + args: Types.VoidIfEmpty<{ readonly [P in keyof A]: A[P] }> +) => Readonly = internal.Structural as any + +/** + * Provides a Tagged constructor for a Case Class. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Data, Equal } from "effect" + * + * class Person extends Data.TaggedClass("Person")<{ readonly name: string }> {} + * + * // Creating instances of Person + * const mike1 = new Person({ name: "Mike" }) + * const mike2 = new Person({ name: "Mike" }) + * const john = new Person({ name: "John" }) + * + * // Checking equality + * assert.deepStrictEqual(Equal.equals(mike1, mike2), true) + * assert.deepStrictEqual(Equal.equals(mike1, john), false) + * + * assert.deepStrictEqual(mike1._tag, "Person") + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export const TaggedClass = ( + tag: Tag +): new = {}>( + args: Types.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }> +) => Readonly & { readonly _tag: Tag } => { + class Base extends Class { + readonly _tag = tag + } + return Base as any +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const Structural: new( + args: Types.VoidIfEmpty<{ readonly [P in keyof A]: A[P] }> +) => {} = internal.Structural as any + +/** + * Create a tagged enum data type, which is a union of `Data` structs. + * + * ```ts + * import * as assert from "node:assert" + * import { Data } from "effect" + * + * type HttpError = Data.TaggedEnum<{ + * BadRequest: { readonly status: 400, readonly message: string } + * NotFound: { readonly status: 404, readonly message: string } + * }> + * + * // Equivalent to: + * type HttpErrorPlain = + * | { + * readonly _tag: "BadRequest" + * readonly status: 400 + * readonly message: string + * } + * | { + * readonly _tag: "NotFound" + * readonly status: 404 + * readonly message: string + * } + * ``` + * + * @since 2.0.0 + * @category models + */ +export type TaggedEnum< + A extends Record> & UntaggedChildren +> = keyof A extends infer Tag ? + Tag extends keyof A ? Types.Simplify<{ readonly _tag: Tag } & { readonly [K in keyof A[Tag]]: A[Tag][K] }> + : never + : never + +type ChildrenAreTagged = keyof A extends infer K ? K extends keyof A ? "_tag" extends keyof A[K] ? true + : false + : never + : never + +type UntaggedChildren = true extends ChildrenAreTagged + ? "It looks like you're trying to create a tagged enum, but one or more of its members already has a `_tag` property." + : unknown + +/** + * @since 2.0.0 + */ +export declare namespace TaggedEnum { + /** + * @since 2.0.0 + * @category models + */ + export interface WithGenerics { + readonly taggedEnum: { readonly _tag: string } + readonly numberOfGenerics: Count + + readonly A: unknown + readonly B: unknown + readonly C: unknown + readonly D: unknown + } + + /** + * @since 2.0.0 + * @category models + */ + export type Kind< + Z extends WithGenerics, + A = unknown, + B = unknown, + C = unknown, + D = unknown + > = (Z & { + readonly A: A + readonly B: B + readonly C: C + readonly D: D + })["taggedEnum"] + + /** + * @since 2.0.0 + */ + export type Args< + A extends { readonly _tag: string }, + K extends A["_tag"], + E = Extract + > = { readonly [K in keyof E as K extends "_tag" ? never : K]: E[K] } extends infer T ? Types.VoidIfEmpty + : never + + /** + * @since 2.0.0 + */ + export type Value< + A extends { readonly _tag: string }, + K extends A["_tag"] + > = Extract + + /** + * @since 3.1.0 + */ + export type Constructor = Types.Simplify< + & { + readonly [Tag in A["_tag"]]: Case.Constructor, "_tag"> + } + & { + readonly $is: (tag: Tag) => (u: unknown) => u is Extract + readonly $match: { + < + const Cases extends { + readonly [Tag in A["_tag"]]: (args: Extract) => any + } + >( + cases: Cases & { [K in Exclude]: never } + ): (value: A) => Unify> + < + const Cases extends { + readonly [Tag in A["_tag"]]: (args: Extract) => any + } + >( + value: A, + cases: Cases & { [K in Exclude]: never } + ): Unify> + } + } + > + + /** + * @since 3.2.0 + */ + export interface GenericMatchers> { + readonly $is: ( + tag: Tag + ) => { + >( + u: T + ): u is T & { readonly _tag: Tag } + (u: unknown): u is Extract, { readonly _tag: Tag }> + } + readonly $match: { + < + A, + B, + C, + D, + Cases extends { + readonly [Tag in Z["taggedEnum"]["_tag"]]: ( + args: Extract, { readonly _tag: Tag }> + ) => any + } + >( + cases: Cases & { [K in Exclude]: never } + ): (self: TaggedEnum.Kind) => Unify> + < + A, + B, + C, + D, + Cases extends { + readonly [Tag in Z["taggedEnum"]["_tag"]]: ( + args: Extract, { readonly _tag: Tag }> + ) => any + } + >( + self: TaggedEnum.Kind, + cases: Cases & { [K in Exclude]: never } + ): Unify> + } + } +} + +/** + * Create a constructor for a tagged union of `Data` structs. + * + * You can also pass a `TaggedEnum.WithGenerics` if you want to add generics to + * the constructor. + * + * @example + * ```ts + * import { Data } from "effect" + * + * const { BadRequest, NotFound } = Data.taggedEnum< + * | { readonly _tag: "BadRequest"; readonly status: 400; readonly message: string } + * | { readonly _tag: "NotFound"; readonly status: 404; readonly message: string } + * >() + * + * const notFound = NotFound({ status: 404, message: "Not Found" }) + * ``` + * + * @example + * import { Data } from "effect" + * + * type MyResult = Data.TaggedEnum<{ + * Failure: { readonly error: E } + * Success: { readonly value: A } + * }> + * interface MyResultDefinition extends Data.TaggedEnum.WithGenerics<2> { + * readonly taggedEnum: MyResult + * } + * const { Failure, Success } = Data.taggedEnum() + * + * const success = Success({ value: 1 }) + * + * @category constructors + * @since 2.0.0 + */ +export const taggedEnum: { + /** + * Create a constructor for a tagged union of `Data` structs. + * + * You can also pass a `TaggedEnum.WithGenerics` if you want to add generics to + * the constructor. + * + * @example + * ```ts + * import { Data } from "effect" + * + * const { BadRequest, NotFound } = Data.taggedEnum< + * | { readonly _tag: "BadRequest"; readonly status: 400; readonly message: string } + * | { readonly _tag: "NotFound"; readonly status: 404; readonly message: string } + * >() + * + * const notFound = NotFound({ status: 404, message: "Not Found" }) + * ``` + * + * @example + * import { Data } from "effect" + * + * type MyResult = Data.TaggedEnum<{ + * Failure: { readonly error: E } + * Success: { readonly value: A } + * }> + * interface MyResultDefinition extends Data.TaggedEnum.WithGenerics<2> { + * readonly taggedEnum: MyResult + * } + * const { Failure, Success } = Data.taggedEnum() + * + * const success = Success({ value: 1 }) + * + * @category constructors + * @since 2.0.0 + */ + >(): Types.Simplify< + { + readonly [Tag in Z["taggedEnum"]["_tag"]]: ( + args: TaggedEnum.Args< + TaggedEnum.Kind, + Tag, + Extract, { readonly _tag: Tag }> + > + ) => TaggedEnum.Value, Tag> + } & TaggedEnum.GenericMatchers + > + + /** + * Create a constructor for a tagged union of `Data` structs. + * + * You can also pass a `TaggedEnum.WithGenerics` if you want to add generics to + * the constructor. + * + * @example + * ```ts + * import { Data } from "effect" + * + * const { BadRequest, NotFound } = Data.taggedEnum< + * | { readonly _tag: "BadRequest"; readonly status: 400; readonly message: string } + * | { readonly _tag: "NotFound"; readonly status: 404; readonly message: string } + * >() + * + * const notFound = NotFound({ status: 404, message: "Not Found" }) + * ``` + * + * @example + * import { Data } from "effect" + * + * type MyResult = Data.TaggedEnum<{ + * Failure: { readonly error: E } + * Success: { readonly value: A } + * }> + * interface MyResultDefinition extends Data.TaggedEnum.WithGenerics<2> { + * readonly taggedEnum: MyResult + * } + * const { Failure, Success } = Data.taggedEnum() + * + * const success = Success({ value: 1 }) + * + * @category constructors + * @since 2.0.0 + */ + >(): Types.Simplify< + { + readonly [Tag in Z["taggedEnum"]["_tag"]]: ( + args: TaggedEnum.Args< + TaggedEnum.Kind, + Tag, + Extract, { readonly _tag: Tag }> + > + ) => TaggedEnum.Value, Tag> + } & TaggedEnum.GenericMatchers + > + + /** + * Create a constructor for a tagged union of `Data` structs. + * + * You can also pass a `TaggedEnum.WithGenerics` if you want to add generics to + * the constructor. + * + * @example + * ```ts + * import { Data } from "effect" + * + * const { BadRequest, NotFound } = Data.taggedEnum< + * | { readonly _tag: "BadRequest"; readonly status: 400; readonly message: string } + * | { readonly _tag: "NotFound"; readonly status: 404; readonly message: string } + * >() + * + * const notFound = NotFound({ status: 404, message: "Not Found" }) + * ``` + * + * @example + * import { Data } from "effect" + * + * type MyResult = Data.TaggedEnum<{ + * Failure: { readonly error: E } + * Success: { readonly value: A } + * }> + * interface MyResultDefinition extends Data.TaggedEnum.WithGenerics<2> { + * readonly taggedEnum: MyResult + * } + * const { Failure, Success } = Data.taggedEnum() + * + * const success = Success({ value: 1 }) + * + * @category constructors + * @since 2.0.0 + */ + >(): Types.Simplify< + { + readonly [Tag in Z["taggedEnum"]["_tag"]]: ( + args: TaggedEnum.Args< + TaggedEnum.Kind, + Tag, + Extract, { readonly _tag: Tag }> + > + ) => TaggedEnum.Value, Tag> + } & TaggedEnum.GenericMatchers + > + + /** + * Create a constructor for a tagged union of `Data` structs. + * + * You can also pass a `TaggedEnum.WithGenerics` if you want to add generics to + * the constructor. + * + * @example + * ```ts + * import { Data } from "effect" + * + * const { BadRequest, NotFound } = Data.taggedEnum< + * | { readonly _tag: "BadRequest"; readonly status: 400; readonly message: string } + * | { readonly _tag: "NotFound"; readonly status: 404; readonly message: string } + * >() + * + * const notFound = NotFound({ status: 404, message: "Not Found" }) + * ``` + * + * @example + * import { Data } from "effect" + * + * type MyResult = Data.TaggedEnum<{ + * Failure: { readonly error: E } + * Success: { readonly value: A } + * }> + * interface MyResultDefinition extends Data.TaggedEnum.WithGenerics<2> { + * readonly taggedEnum: MyResult + * } + * const { Failure, Success } = Data.taggedEnum() + * + * const success = Success({ value: 1 }) + * + * @category constructors + * @since 2.0.0 + */ + >(): Types.Simplify< + { + readonly [Tag in Z["taggedEnum"]["_tag"]]: ( + args: TaggedEnum.Args< + TaggedEnum.Kind, + Tag, + Extract, { readonly _tag: Tag }> + > + ) => TaggedEnum.Value, Tag> + } & TaggedEnum.GenericMatchers + > + + /** + * Create a constructor for a tagged union of `Data` structs. + * + * You can also pass a `TaggedEnum.WithGenerics` if you want to add generics to + * the constructor. + * + * @example + * ```ts + * import { Data } from "effect" + * + * const { BadRequest, NotFound } = Data.taggedEnum< + * | { readonly _tag: "BadRequest"; readonly status: 400; readonly message: string } + * | { readonly _tag: "NotFound"; readonly status: 404; readonly message: string } + * >() + * + * const notFound = NotFound({ status: 404, message: "Not Found" }) + * ``` + * + * @example + * import { Data } from "effect" + * + * type MyResult = Data.TaggedEnum<{ + * Failure: { readonly error: E } + * Success: { readonly value: A } + * }> + * interface MyResultDefinition extends Data.TaggedEnum.WithGenerics<2> { + * readonly taggedEnum: MyResult + * } + * const { Failure, Success } = Data.taggedEnum() + * + * const success = Success({ value: 1 }) + * + * @category constructors + * @since 2.0.0 + */ + (): TaggedEnum.Constructor +} = () => + new Proxy({}, { + get(_target, tag, _receiver) { + if (tag === "$is") { + return Predicate.isTagged + } else if (tag === "$match") { + return taggedMatch + } + return tagged(tag as string) + } + }) as any + +function taggedMatch< + A extends { readonly _tag: string }, + Cases extends { + readonly [K in A["_tag"]]: (args: Extract) => any + } +>(self: A, cases: Cases): ReturnType +function taggedMatch< + A extends { readonly _tag: string }, + Cases extends { + readonly [K in A["_tag"]]: (args: Extract) => any + } +>(cases: Cases): (value: A) => ReturnType +function taggedMatch< + A extends { readonly _tag: string }, + Cases extends { + readonly [K in A["_tag"]]: (args: Extract) => any + } +>(): any { + if (arguments.length === 1) { + const cases = arguments[0] as Cases + return function(value: A): ReturnType { + return cases[value._tag as A["_tag"]](value as any) + } + } + const value = arguments[0] as A + const cases = arguments[1] as Cases + return cases[value._tag as A["_tag"]](value as any) +} + +/** + * Provides a constructor for a Case Class. + * + * @since 2.0.0 + * @category constructors + */ +export const Error: new = {}>( + args: Types.VoidIfEmpty<{ readonly [P in keyof A]: A[P] }> +) => Cause.YieldableError & Readonly = (function() { + const plainArgsSymbol = Symbol.for("effect/Data/Error/plainArgs") + const O = { + BaseEffectError: class extends core.YieldableError { + constructor(args: any) { + super(args?.message, args?.cause ? { cause: args.cause } : undefined) + if (args) { + Object.assign(this, args) + // @effect-diagnostics-next-line floatingEffect:off + Object.defineProperty(this, plainArgsSymbol, { value: args, enumerable: false }) + } + } + toJSON() { + return { ...(this as any)[plainArgsSymbol], ...this } + } + } as any + } + return O.BaseEffectError +})() + +/** + * @since 2.0.0 + * @category constructors + */ +export const TaggedError = (tag: Tag): new = {}>( + args: Types.VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }> +) => Cause.YieldableError & { readonly _tag: Tag } & Readonly => { + const O = { + BaseEffectError: class extends Error<{}> { + readonly _tag = tag + } + } + ;(O.BaseEffectError.prototype as any).name = tag + return O.BaseEffectError as any +} diff --git a/backend/node_modules/effect/src/DateTime.ts b/backend/node_modules/effect/src/DateTime.ts new file mode 100644 index 0000000000000000000000000000000000000000..a782e920f9e40c0282a71994e4ecc41d52807141 --- /dev/null +++ b/backend/node_modules/effect/src/DateTime.ts @@ -0,0 +1,2715 @@ +/** + * @since 3.6.0 + */ +import type { IllegalArgumentException } from "./Cause.js" +import * as Context from "./Context.js" +import type * as Duration from "./Duration.js" +import * as Effect from "./Effect.js" +import type * as Either from "./Either.js" +import type * as equivalence from "./Equivalence.js" +import { dual, type LazyArg } from "./Function.js" +import type { Inspectable } from "./Inspectable.js" +import * as Internal from "./internal/dateTime.js" +import * as Layer from "./Layer.js" +import type * as Option from "./Option.js" +import type * as order from "./Order.js" +import type { Pipeable } from "./Pipeable.js" + +/** + * @since 3.6.0 + * @category type ids + */ +export const TypeId: unique symbol = Internal.TypeId + +/** + * @since 3.6.0 + * @category type ids + */ +export type TypeId = typeof TypeId + +/** + * A `DateTime` represents a point in time. It can optionally have a time zone + * associated with it. + * + * @since 3.6.0 + * @category models + */ +export type DateTime = Utc | Zoned + +/** + * @since 3.6.0 + * @category models + */ +export interface Utc extends DateTime.Proto { + readonly _tag: "Utc" + readonly epochMillis: number + partsUtc: DateTime.PartsWithWeekday | undefined +} + +/** + * @since 3.6.0 + * @category models + */ +export interface Zoned extends DateTime.Proto { + readonly _tag: "Zoned" + readonly epochMillis: number + readonly zone: TimeZone + adjustedEpochMillis: number | undefined + partsAdjusted: DateTime.PartsWithWeekday | undefined + partsUtc: DateTime.PartsWithWeekday | undefined +} + +/** + * @since 3.6.0 + * @category models + */ +export declare namespace DateTime { + /** + * @since 3.6.0 + * @category models + */ + export type Input = DateTime | Partial | Date | number | string + + /** + * @since 3.6.0 + * @category models + */ + export type PreserveZone = A extends Zoned ? Zoned : Utc + + /** + * @since 3.6.0 + * @category models + */ + export type Unit = UnitSingular | UnitPlural + + /** + * @since 3.6.0 + * @category models + */ + export type UnitSingular = + | "milli" + | "second" + | "minute" + | "hour" + | "day" + | "week" + | "month" + | "year" + + /** + * @since 3.6.0 + * @category models + */ + export type UnitPlural = + | "millis" + | "seconds" + | "minutes" + | "hours" + | "days" + | "weeks" + | "months" + | "years" + + /** + * @since 3.6.0 + * @category models + */ + export interface PartsWithWeekday { + readonly millis: number + readonly seconds: number + readonly minutes: number + readonly hours: number + readonly day: number + readonly weekDay: number + readonly month: number + readonly year: number + } + + /** + * @since 3.6.0 + * @category models + */ + export interface Parts { + readonly millis: number + readonly seconds: number + readonly minutes: number + readonly hours: number + readonly day: number + readonly month: number + readonly year: number + } + + /** + * @since 3.6.0 + * @category models + */ + export interface PartsForMath { + readonly millis: number + readonly seconds: number + readonly minutes: number + readonly hours: number + readonly days: number + readonly weeks: number + readonly months: number + readonly years: number + } + + /** + * @since 3.6.0 + * @category models + */ + export interface Proto extends Pipeable, Inspectable { + readonly [TypeId]: TypeId + } +} + +/** + * @since 3.6.0 + * @category type ids + */ +export const TimeZoneTypeId: unique symbol = Internal.TimeZoneTypeId + +/** + * @since 3.6.0 + * @category type ids + */ +export type TimeZoneTypeId = typeof TimeZoneTypeId + +/** + * @since 3.6.0 + * @category models + */ +export type TimeZone = TimeZone.Offset | TimeZone.Named + +/** + * @since 3.6.0 + * @category models + */ +export declare namespace TimeZone { + /** + * @since 3.6.0 + * @category models + */ + export interface Proto extends Inspectable { + readonly [TimeZoneTypeId]: TimeZoneTypeId + } + + /** + * @since 3.6.0 + * @category models + */ + export interface Offset extends Proto { + readonly _tag: "Offset" + readonly offset: number + } + + /** + * @since 3.6.0 + * @category models + */ + export interface Named extends Proto { + readonly _tag: "Named" + readonly id: string + /** @internal */ + readonly format: Intl.DateTimeFormat + } +} + +/** + * A `Disambiguation` is used to resolve ambiguities when a `DateTime` is + * ambiguous, such as during a daylight saving time transition. + * + * For more information, see the [Temporal documentation](https://tc39.es/proposal-temporal/docs/timezone.html#ambiguity-due-to-dst-or-other-time-zone-offset-changes) + * + * - `"compatible"`: (default) Behavior matching Temporal API and legacy JavaScript Date and moment.js. + * For repeated times, chooses the earlier occurrence. For gap times, chooses the later interpretation. + * + * - `"earlier"`: For repeated times, always choose the earlier occurrence. + * For gap times, choose the time before the gap. + * + * - `"later"`: For repeated times, always choose the later occurrence. + * For gap times, choose the time after the gap. + * + * - `"reject"`: Throw an `RangeError` when encountering ambiguous or non-existent times. + * + * @example + * ```ts + * import { DateTime } from "effect" + * + * // Fall-back example: 01:30 on Nov 2, 2025 in New York happens twice + * const ambiguousTime = { year: 2025, month: 11, day: 2, hours: 1, minutes: 30 } + * const timeZone = DateTime.zoneUnsafeMakeNamed("America/New_York") + * + * DateTime.makeZoned(ambiguousTime, { timeZone, adjustForTimeZone: true, disambiguation: "earlier" }) + * // Earlier occurrence (DST time): 2025-11-02T05:30:00.000Z + * + * DateTime.makeZoned(ambiguousTime, { timeZone, adjustForTimeZone: true, disambiguation: "later" }) + * // Later occurrence (standard time): 2025-11-02T06:30:00.000Z + * + * // Gap example: 02:30 on Mar 9, 2025 in New York doesn't exist + * const gapTime = { year: 2025, month: 3, day: 9, hours: 2, minutes: 30 } + * + * DateTime.makeZoned(gapTime, { timeZone, adjustForTimeZone: true, disambiguation: "earlier" }) + * // Time before gap: 2025-03-09T06:30:00.000Z (01:30 EST) + * + * DateTime.makeZoned(gapTime, { timeZone, adjustForTimeZone: true, disambiguation: "later" }) + * // Time after gap: 2025-03-09T07:30:00.000Z (03:30 EDT) + * ``` + * + * @since 3.18.0 + * @category models + */ +export type Disambiguation = "compatible" | "earlier" | "later" | "reject" + +// ============================================================================= +// guards +// ============================================================================= + +/** + * @since 3.6.0 + * @category guards + */ +export const isDateTime: (u: unknown) => u is DateTime = Internal.isDateTime + +/** + * @since 3.6.0 + * @category guards + */ +export const isTimeZone: (u: unknown) => u is TimeZone = Internal.isTimeZone + +/** + * @since 3.6.0 + * @category guards + */ +export const isTimeZoneOffset: (u: unknown) => u is TimeZone.Offset = Internal.isTimeZoneOffset + +/** + * @since 3.6.0 + * @category guards + */ +export const isTimeZoneNamed: (u: unknown) => u is TimeZone.Named = Internal.isTimeZoneNamed + +/** + * @since 3.6.0 + * @category guards + */ +export const isUtc: (self: DateTime) => self is Utc = Internal.isUtc + +/** + * @since 3.6.0 + * @category guards + */ +export const isZoned: (self: DateTime) => self is Zoned = Internal.isZoned + +// ============================================================================= +// instances +// ============================================================================= + +/** + * @since 3.6.0 + * @category instances + */ +export const Equivalence: equivalence.Equivalence = Internal.Equivalence + +/** + * @since 3.6.0 + * @category instances + */ +export const Order: order.Order = Internal.Order + +/** + * @since 3.6.0 + */ +export const clamp: { + /** + * @since 3.6.0 + */ + (options: { readonly minimum: Min; readonly maximum: Max }): (self: A) => A | Min | Max + /** + * @since 3.6.0 + */ + (self: A, options: { readonly minimum: Min; readonly maximum: Max }): A | Min | Max +} = Internal.clamp + +// ============================================================================= +// constructors +// ============================================================================= + +/** + * Create a `DateTime` from a `Date`. + * + * If the `Date` is invalid, an `IllegalArgumentException` will be thrown. + * + * @since 3.6.0 + * @category constructors + */ +export const unsafeFromDate: (date: Date) => Utc = Internal.unsafeFromDate + +/** + * Create a `DateTime` from one of the following: + * + * - A `DateTime` + * - A `Date` instance (invalid dates will throw an `IllegalArgumentException`) + * - The `number` of milliseconds since the Unix epoch + * - An object with the parts of a date + * - A `string` that can be parsed by `Date.parse` + * + * @since 3.6.0 + * @category constructors + * @example + * ```ts + * import { DateTime } from "effect" + * + * // from Date + * DateTime.unsafeMake(new Date()) + * + * // from parts + * DateTime.unsafeMake({ year: 2024 }) + * + * // from string + * DateTime.unsafeMake("2024-01-01") + * ``` + */ +export const unsafeMake: (input: A) => DateTime.PreserveZone = Internal.unsafeMake + +/** + * Create a `DateTime.Zoned` using `DateTime.unsafeMake` and a time zone. + * + * The input is treated as UTC and then the time zone is attached, unless + * `adjustForTimeZone` is set to `true`. In that case, the input is treated as + * already in the time zone. + * + * When `adjustForTimeZone` is true and ambiguous times occur during DST transitions, + * the `disambiguation` option controls how to resolve the ambiguity: + * - `compatible` (default): Choose earlier time for repeated times, later for gaps + * - `earlier`: Always choose the earlier of two possible times + * - `later`: Always choose the later of two possible times + * - `reject`: Throw an error when ambiguous times are encountered + * + * @since 3.6.0 + * @category constructors + * @example + * ```ts + * import { DateTime } from "effect" + * + * DateTime.unsafeMakeZoned(new Date(), { timeZone: "Europe/London" }) + * ``` + */ +export const unsafeMakeZoned: (input: DateTime.Input, options?: { + readonly timeZone?: number | string | TimeZone | undefined + readonly adjustForTimeZone?: boolean | undefined + readonly disambiguation?: Disambiguation | undefined +}) => Zoned = Internal.unsafeMakeZoned + +/** + * Create a `DateTime.Zoned` using `DateTime.make` and a time zone. + * + * The input is treated as UTC and then the time zone is attached, unless + * `adjustForTimeZone` is set to `true`. In that case, the input is treated as + * already in the time zone. + * + * When `adjustForTimeZone` is true and ambiguous times occur during DST transitions, + * the `disambiguation` option controls how to resolve the ambiguity: + * - `compatible` (default): Choose earlier time for repeated times, later for gaps + * - `earlier`: Always choose the earlier of two possible times + * - `later`: Always choose the later of two possible times + * - `reject`: Throw an error when ambiguous times are encountered + * + * If the date time input or time zone is invalid, `None` will be returned. + * + * @since 3.6.0 + * @category constructors + * @example + * ```ts + * import { DateTime } from "effect" + * + * DateTime.makeZoned(new Date(), { timeZone: "Europe/London" }) + * ``` + */ +export const makeZoned: ( + input: DateTime.Input, + options?: { + readonly timeZone?: number | string | TimeZone | undefined + readonly adjustForTimeZone?: boolean | undefined + readonly disambiguation?: Disambiguation | undefined + } +) => Option.Option = Internal.makeZoned + +/** + * Create a `DateTime` from one of the following: + * + * - A `DateTime` + * - A `Date` instance (invalid dates will throw an `IllegalArgumentException`) + * - The `number` of milliseconds since the Unix epoch + * - An object with the parts of a date + * - A `string` that can be parsed by `Date.parse` + * + * If the input is invalid, `None` will be returned. + * + * @since 3.6.0 + * @category constructors + * @example + * ```ts + * import { DateTime } from "effect" + * + * // from Date + * DateTime.make(new Date()) + * + * // from parts + * DateTime.make({ year: 2024 }) + * + * // from string + * DateTime.make("2024-01-01") + * ``` + */ +export const make: (input: A) => Option.Option> = Internal.make + +/** + * Create a `DateTime.Zoned` from a string. + * + * It uses the format: `YYYY-MM-DDTHH:mm:ss.sss+HH:MM[Time/Zone]`. + * + * @since 3.6.0 + * @category constructors + */ +export const makeZonedFromString: (input: string) => Option.Option = Internal.makeZonedFromString + +/** + * Get the current time using the `Clock` service and convert it to a `DateTime`. + * + * @since 3.6.0 + * @category constructors + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * }) + * ``` + */ +export const now: Effect.Effect = Internal.now + +/** + * Get the current time using the `Clock` service. + * + * @since 3.14.0 + * @category constructors + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.nowAsDate + * }) + * ``` + */ +export const nowAsDate: Effect.Effect = Internal.nowAsDate + +/** + * Get the current time using `Date.now`. + * + * @since 3.6.0 + * @category constructors + */ +export const unsafeNow: LazyArg = Internal.unsafeNow + +// ============================================================================= +// time zones +// ============================================================================= + +/** + * For a `DateTime` returns a new `DateTime.Utc`. + * + * @since 3.13.0 + * @category time zones + * @example + * ```ts + * import { DateTime } from "effect" + * + * const now = DateTime.unsafeMakeZoned({ year: 2024 }, { timeZone: "Europe/London" }) + * + * // set as UTC + * const utc: DateTime.Utc = DateTime.toUtc(now) + * ``` + */ +export const toUtc: (self: DateTime) => Utc = Internal.toUtc + +/** + * Set the time zone of a `DateTime`, returning a new `DateTime.Zoned`. + * + * @since 3.6.0 + * @category time zones + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * const zone = DateTime.zoneUnsafeMakeNamed("Europe/London") + * + * // set the time zone + * const zoned: DateTime.Zoned = DateTime.setZone(now, zone) + * }) + * ``` + */ +export const setZone: { + /** + * Set the time zone of a `DateTime`, returning a new `DateTime.Zoned`. + * + * @since 3.6.0 + * @category time zones + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * const zone = DateTime.zoneUnsafeMakeNamed("Europe/London") + * + * // set the time zone + * const zoned: DateTime.Zoned = DateTime.setZone(now, zone) + * }) + * ``` + */ + ( + zone: TimeZone, + options?: { + readonly adjustForTimeZone?: boolean | undefined + readonly disambiguation?: Disambiguation | undefined + } + ): (self: DateTime) => Zoned + /** + * Set the time zone of a `DateTime`, returning a new `DateTime.Zoned`. + * + * @since 3.6.0 + * @category time zones + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * const zone = DateTime.zoneUnsafeMakeNamed("Europe/London") + * + * // set the time zone + * const zoned: DateTime.Zoned = DateTime.setZone(now, zone) + * }) + * ``` + */ + ( + self: DateTime, + zone: TimeZone, + options?: { + readonly adjustForTimeZone?: boolean | undefined + readonly disambiguation?: Disambiguation | undefined + } + ): Zoned +} = Internal.setZone + +/** + * Add a fixed offset time zone to a `DateTime`. + * + * The offset is in milliseconds. + * + * @since 3.6.0 + * @category time zones + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * + * // set the offset time zone in milliseconds + * const zoned: DateTime.Zoned = DateTime.setZoneOffset(now, 3 * 60 * 60 * 1000) + * }) + * ``` + */ +export const setZoneOffset: { + /** + * Add a fixed offset time zone to a `DateTime`. + * + * The offset is in milliseconds. + * + * @since 3.6.0 + * @category time zones + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * + * // set the offset time zone in milliseconds + * const zoned: DateTime.Zoned = DateTime.setZoneOffset(now, 3 * 60 * 60 * 1000) + * }) + * ``` + */ + ( + offset: number, + options?: { + readonly adjustForTimeZone?: boolean | undefined + readonly disambiguation?: Disambiguation | undefined + } + ): (self: DateTime) => Zoned + /** + * Add a fixed offset time zone to a `DateTime`. + * + * The offset is in milliseconds. + * + * @since 3.6.0 + * @category time zones + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * + * // set the offset time zone in milliseconds + * const zoned: DateTime.Zoned = DateTime.setZoneOffset(now, 3 * 60 * 60 * 1000) + * }) + * ``` + */ + ( + self: DateTime, + offset: number, + options?: { + readonly adjustForTimeZone?: boolean | undefined + readonly disambiguation?: Disambiguation | undefined + } + ): Zoned +} = Internal.setZoneOffset + +/** + * Attempt to create a named time zone from a IANA time zone identifier. + * + * If the time zone is invalid, an `IllegalArgumentException` will be thrown. + * + * @since 3.6.0 + * @category time zones + */ +export const zoneUnsafeMakeNamed: (zoneId: string) => TimeZone.Named = Internal.zoneUnsafeMakeNamed + +/** + * Create a fixed offset time zone. + * + * @since 3.6.0 + * @category time zones + */ +export const zoneMakeOffset: (offset: number) => TimeZone.Offset = Internal.zoneMakeOffset + +/** + * Create a named time zone from a IANA time zone identifier. If the time zone + * is invalid, `None` will be returned. + * + * @since 3.6.0 + * @category time zones + */ +export const zoneMakeNamed: (zoneId: string) => Option.Option = Internal.zoneMakeNamed + +/** + * Create a named time zone from a IANA time zone identifier. If the time zone + * is invalid, it will fail with an `IllegalArgumentException`. + * + * @since 3.6.0 + * @category time zones + */ +export const zoneMakeNamedEffect: (zoneId: string) => Effect.Effect = + Internal.zoneMakeNamedEffect + +/** + * Create a named time zone from the system's local time zone. + * + * @since 3.6.0 + * @category time zones + */ +export const zoneMakeLocal: () => TimeZone.Named = Internal.zoneMakeLocal + +/** + * Try parse a TimeZone from a string + * + * @since 3.6.0 + * @category time zones + */ +export const zoneFromString: (zone: string) => Option.Option = Internal.zoneFromString + +/** + * Format a `TimeZone` as a string. + * + * @since 3.6.0 + * @category time zones + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * // Outputs "+03:00" + * DateTime.zoneToString(DateTime.zoneMakeOffset(3 * 60 * 60 * 1000)) + * + * // Outputs "Europe/London" + * DateTime.zoneToString(DateTime.zoneUnsafeMakeNamed("Europe/London")) + * ``` + */ +export const zoneToString: (self: TimeZone) => string = Internal.zoneToString + +/** + * Set the time zone of a `DateTime` from an IANA time zone identifier. If the + * time zone is invalid, `None` will be returned. + * + * @since 3.6.0 + * @category time zones + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * // set the time zone, returns an Option + * DateTime.setZoneNamed(now, "Europe/London") + * }) + * ``` + */ +export const setZoneNamed: { + /** + * Set the time zone of a `DateTime` from an IANA time zone identifier. If the + * time zone is invalid, `None` will be returned. + * + * @since 3.6.0 + * @category time zones + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * // set the time zone, returns an Option + * DateTime.setZoneNamed(now, "Europe/London") + * }) + * ``` + */ + ( + zoneId: string, + options?: { + readonly adjustForTimeZone?: boolean | undefined + readonly disambiguation?: Disambiguation | undefined + } + ): (self: DateTime) => Option.Option + /** + * Set the time zone of a `DateTime` from an IANA time zone identifier. If the + * time zone is invalid, `None` will be returned. + * + * @since 3.6.0 + * @category time zones + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * // set the time zone, returns an Option + * DateTime.setZoneNamed(now, "Europe/London") + * }) + * ``` + */ + ( + self: DateTime, + zoneId: string, + options?: { + readonly adjustForTimeZone?: boolean | undefined + readonly disambiguation?: Disambiguation | undefined + } + ): Option.Option +} = Internal.setZoneNamed + +/** + * Set the time zone of a `DateTime` from an IANA time zone identifier. If the + * time zone is invalid, an `IllegalArgumentException` will be thrown. + * + * @since 3.6.0 + * @category time zones + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * // set the time zone + * DateTime.unsafeSetZoneNamed(now, "Europe/London") + * }) + * ``` + */ +export const unsafeSetZoneNamed: { + /** + * Set the time zone of a `DateTime` from an IANA time zone identifier. If the + * time zone is invalid, an `IllegalArgumentException` will be thrown. + * + * @since 3.6.0 + * @category time zones + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * // set the time zone + * DateTime.unsafeSetZoneNamed(now, "Europe/London") + * }) + * ``` + */ + ( + zoneId: string, + options?: { + readonly adjustForTimeZone?: boolean | undefined + readonly disambiguation?: Disambiguation | undefined + } + ): (self: DateTime) => Zoned + /** + * Set the time zone of a `DateTime` from an IANA time zone identifier. If the + * time zone is invalid, an `IllegalArgumentException` will be thrown. + * + * @since 3.6.0 + * @category time zones + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * // set the time zone + * DateTime.unsafeSetZoneNamed(now, "Europe/London") + * }) + * ``` + */ + ( + self: DateTime, + zoneId: string, + options?: { + readonly adjustForTimeZone?: boolean | undefined + readonly disambiguation?: Disambiguation | undefined + } + ): Zoned +} = Internal.unsafeSetZoneNamed + +// ============================================================================= +// comparisons +// ============================================================================= + +/** + * Calulate the difference between two `DateTime` values, returning the number + * of milliseconds the `other` DateTime is from `self`. + * + * If `other` is *after* `self`, the result will be a positive number. + * + * @since 3.6.0 + * @category comparisons + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * const other = DateTime.add(now, { minutes: 1 }) + * + * // returns 60000 + * DateTime.distance(now, other) + * }) + * ``` + */ +export const distance: { + // ============================================================================= + // comparisons + // ============================================================================= + + /** + * Calulate the difference between two `DateTime` values, returning the number + * of milliseconds the `other` DateTime is from `self`. + * + * If `other` is *after* `self`, the result will be a positive number. + * + * @since 3.6.0 + * @category comparisons + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * const other = DateTime.add(now, { minutes: 1 }) + * + * // returns 60000 + * DateTime.distance(now, other) + * }) + * ``` + */ + (other: DateTime): (self: DateTime) => number + // ============================================================================= + // comparisons + // ============================================================================= + + /** + * Calulate the difference between two `DateTime` values, returning the number + * of milliseconds the `other` DateTime is from `self`. + * + * If `other` is *after* `self`, the result will be a positive number. + * + * @since 3.6.0 + * @category comparisons + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * const other = DateTime.add(now, { minutes: 1 }) + * + * // returns 60000 + * DateTime.distance(now, other) + * }) + * ``` + */ + (self: DateTime, other: DateTime): number +} = Internal.distance + +/** + * Calulate the difference between two `DateTime` values. + * + * If the `other` DateTime is before `self`, the result will be a negative + * `Duration`, returned as a `Left`. + * + * If the `other` DateTime is after `self`, the result will be a positive + * `Duration`, returned as a `Right`. + * + * @since 3.6.0 + * @category comparisons + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * const other = DateTime.add(now, { minutes: 1 }) + * + * // returns Either.right(Duration.minutes(1)) + * DateTime.distanceDurationEither(now, other) + * + * // returns Either.left(Duration.minutes(1)) + * DateTime.distanceDurationEither(other, now) + * }) + * ``` + */ +export const distanceDurationEither: { + /** + * Calulate the difference between two `DateTime` values. + * + * If the `other` DateTime is before `self`, the result will be a negative + * `Duration`, returned as a `Left`. + * + * If the `other` DateTime is after `self`, the result will be a positive + * `Duration`, returned as a `Right`. + * + * @since 3.6.0 + * @category comparisons + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * const other = DateTime.add(now, { minutes: 1 }) + * + * // returns Either.right(Duration.minutes(1)) + * DateTime.distanceDurationEither(now, other) + * + * // returns Either.left(Duration.minutes(1)) + * DateTime.distanceDurationEither(other, now) + * }) + * ``` + */ + (other: DateTime): (self: DateTime) => Either.Either + /** + * Calulate the difference between two `DateTime` values. + * + * If the `other` DateTime is before `self`, the result will be a negative + * `Duration`, returned as a `Left`. + * + * If the `other` DateTime is after `self`, the result will be a positive + * `Duration`, returned as a `Right`. + * + * @since 3.6.0 + * @category comparisons + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * const other = DateTime.add(now, { minutes: 1 }) + * + * // returns Either.right(Duration.minutes(1)) + * DateTime.distanceDurationEither(now, other) + * + * // returns Either.left(Duration.minutes(1)) + * DateTime.distanceDurationEither(other, now) + * }) + * ``` + */ + (self: DateTime, other: DateTime): Either.Either +} = Internal.distanceDurationEither + +/** + * Calulate the distance between two `DateTime` values. + * + * @since 3.6.0 + * @category comparisons + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * const other = DateTime.add(now, { minutes: 1 }) + * + * // returns Duration.minutes(1) + * DateTime.distanceDuration(now, other) + * }) + * ``` + */ +export const distanceDuration: { + /** + * Calulate the distance between two `DateTime` values. + * + * @since 3.6.0 + * @category comparisons + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * const other = DateTime.add(now, { minutes: 1 }) + * + * // returns Duration.minutes(1) + * DateTime.distanceDuration(now, other) + * }) + * ``` + */ + (other: DateTime): (self: DateTime) => Duration.Duration + /** + * Calulate the distance between two `DateTime` values. + * + * @since 3.6.0 + * @category comparisons + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * const other = DateTime.add(now, { minutes: 1 }) + * + * // returns Duration.minutes(1) + * DateTime.distanceDuration(now, other) + * }) + * ``` + */ + (self: DateTime, other: DateTime): Duration.Duration +} = Internal.distanceDuration + +/** + * @since 3.6.0 + * @category comparisons + */ +export const min: { + /** + * @since 3.6.0 + * @category comparisons + */ + (that: That): (self: Self) => Self | That + /** + * @since 3.6.0 + * @category comparisons + */ + (self: Self, that: That): Self | That +} = Internal.min + +/** + * @since 3.6.0 + * @category comparisons + */ +export const max: { + /** + * @since 3.6.0 + * @category comparisons + */ + (that: That): (self: Self) => Self | That + /** + * @since 3.6.0 + * @category comparisons + */ + (self: Self, that: That): Self | That +} = Internal.max + +/** + * @since 3.6.0 + * @category comparisons + */ +export const greaterThan: { + /** + * @since 3.6.0 + * @category comparisons + */ + (that: DateTime): (self: DateTime) => boolean + /** + * @since 3.6.0 + * @category comparisons + */ + (self: DateTime, that: DateTime): boolean +} = Internal.greaterThan + +/** + * @since 3.6.0 + * @category comparisons + */ +export const greaterThanOrEqualTo: { + /** + * @since 3.6.0 + * @category comparisons + */ + (that: DateTime): (self: DateTime) => boolean + /** + * @since 3.6.0 + * @category comparisons + */ + (self: DateTime, that: DateTime): boolean +} = Internal.greaterThanOrEqualTo + +/** + * @since 3.6.0 + * @category comparisons + */ +export const lessThan: { + /** + * @since 3.6.0 + * @category comparisons + */ + (that: DateTime): (self: DateTime) => boolean + /** + * @since 3.6.0 + * @category comparisons + */ + (self: DateTime, that: DateTime): boolean +} = Internal.lessThan + +/** + * @since 3.6.0 + * @category comparisons + */ +export const lessThanOrEqualTo: { + /** + * @since 3.6.0 + * @category comparisons + */ + (that: DateTime): (self: DateTime) => boolean + /** + * @since 3.6.0 + * @category comparisons + */ + (self: DateTime, that: DateTime): boolean +} = Internal.lessThanOrEqualTo + +/** + * @since 3.6.0 + * @category comparisons + */ +export const between: { + /** + * @since 3.6.0 + * @category comparisons + */ + (options: { minimum: DateTime; maximum: DateTime }): (self: DateTime) => boolean + /** + * @since 3.6.0 + * @category comparisons + */ + (self: DateTime, options: { minimum: DateTime; maximum: DateTime }): boolean +} = Internal.between + +/** + * @since 3.6.0 + * @category comparisons + */ +export const isFuture: (self: DateTime) => Effect.Effect = Internal.isFuture + +/** + * @since 3.6.0 + * @category comparisons + */ +export const unsafeIsFuture: (self: DateTime) => boolean = Internal.unsafeIsFuture + +/** + * @since 3.6.0 + * @category comparisons + */ +export const isPast: (self: DateTime) => Effect.Effect = Internal.isPast + +/** + * @since 3.6.0 + * @category comparisons + */ +export const unsafeIsPast: (self: DateTime) => boolean = Internal.unsafeIsPast + +// ============================================================================= +// conversions +// ============================================================================= + +/** + * Get the UTC `Date` of a `DateTime`. + * + * @since 3.6.0 + * @category conversions + */ +export const toDateUtc: (self: DateTime) => Date = Internal.toDateUtc + +/** + * Convert a `DateTime` to a `Date`, applying the time zone first. + * + * @since 3.6.0 + * @category conversions + */ +export const toDate: (self: DateTime) => Date = Internal.toDate + +/** + * Calculate the time zone offset of a `DateTime.Zoned` in milliseconds. + * + * @since 3.6.0 + * @category conversions + */ +export const zonedOffset: (self: Zoned) => number = Internal.zonedOffset + +/** + * Calculate the time zone offset of a `DateTime` in milliseconds. + * + * The offset is formatted as "±HH:MM". + * + * @since 3.6.0 + * @category conversions + */ +export const zonedOffsetIso: (self: Zoned) => string = Internal.zonedOffsetIso + +/** + * Get the milliseconds since the Unix epoch of a `DateTime`. + * + * @since 3.6.0 + * @category conversions + */ +export const toEpochMillis: (self: DateTime) => number = Internal.toEpochMillis + +/** + * Remove the time aspect of a `DateTime`, first adjusting for the time + * zone. It will return a `DateTime.Utc` only containing the date. + * + * @since 3.6.0 + * @category conversions + * @example + * ```ts + * import { DateTime } from "effect" + * + * // returns "2024-01-01T00:00:00Z" + * DateTime.unsafeMakeZoned("2024-01-01T05:00:00Z", { + * timeZone: "Pacific/Auckland", + * adjustForTimeZone: true + * }).pipe( + * DateTime.removeTime, + * DateTime.formatIso + * ) + * ``` + */ +export const removeTime: (self: DateTime) => Utc = Internal.removeTime + +// ============================================================================= +// parts +// ============================================================================= + +/** + * Get the different parts of a `DateTime` as an object. + * + * The parts will be time zone adjusted. + * + * @since 3.6.0 + * @category parts + */ +export const toParts: (self: DateTime) => DateTime.PartsWithWeekday = Internal.toParts + +/** + * Get the different parts of a `DateTime` as an object. + * + * The parts will be in UTC. + * + * @since 3.6.0 + * @category parts + */ +export const toPartsUtc: (self: DateTime) => DateTime.PartsWithWeekday = Internal.toPartsUtc + +/** + * Get a part of a `DateTime` as a number. + * + * The part will be in the UTC time zone. + * + * @since 3.6.0 + * @category parts + * @example + * ```ts + * import * as assert from "node:assert" + * import { DateTime } from "effect" + * + * const now = DateTime.unsafeMake({ year: 2024 }) + * const year = DateTime.getPartUtc(now, "year") + * assert.strictEqual(year, 2024) + * ``` + */ +export const getPartUtc: { + /** + * Get a part of a `DateTime` as a number. + * + * The part will be in the UTC time zone. + * + * @since 3.6.0 + * @category parts + * @example + * ```ts + * import * as assert from "node:assert" + * import { DateTime } from "effect" + * + * const now = DateTime.unsafeMake({ year: 2024 }) + * const year = DateTime.getPartUtc(now, "year") + * assert.strictEqual(year, 2024) + * ``` + */ + (part: keyof DateTime.PartsWithWeekday): (self: DateTime) => number + /** + * Get a part of a `DateTime` as a number. + * + * The part will be in the UTC time zone. + * + * @since 3.6.0 + * @category parts + * @example + * ```ts + * import * as assert from "node:assert" + * import { DateTime } from "effect" + * + * const now = DateTime.unsafeMake({ year: 2024 }) + * const year = DateTime.getPartUtc(now, "year") + * assert.strictEqual(year, 2024) + * ``` + */ + (self: DateTime, part: keyof DateTime.PartsWithWeekday): number +} = Internal.getPartUtc + +/** + * Get a part of a `DateTime` as a number. + * + * The part will be time zone adjusted. + * + * @since 3.6.0 + * @category parts + * @example + * ```ts + * import * as assert from "node:assert" + * import { DateTime } from "effect" + * + * const now = DateTime.unsafeMakeZoned({ year: 2024 }, { timeZone: "Europe/London" }) + * const year = DateTime.getPart(now, "year") + * assert.strictEqual(year, 2024) + * ``` + */ +export const getPart: { + /** + * Get a part of a `DateTime` as a number. + * + * The part will be time zone adjusted. + * + * @since 3.6.0 + * @category parts + * @example + * ```ts + * import * as assert from "node:assert" + * import { DateTime } from "effect" + * + * const now = DateTime.unsafeMakeZoned({ year: 2024 }, { timeZone: "Europe/London" }) + * const year = DateTime.getPart(now, "year") + * assert.strictEqual(year, 2024) + * ``` + */ + (part: keyof DateTime.PartsWithWeekday): (self: DateTime) => number + /** + * Get a part of a `DateTime` as a number. + * + * The part will be time zone adjusted. + * + * @since 3.6.0 + * @category parts + * @example + * ```ts + * import * as assert from "node:assert" + * import { DateTime } from "effect" + * + * const now = DateTime.unsafeMakeZoned({ year: 2024 }, { timeZone: "Europe/London" }) + * const year = DateTime.getPart(now, "year") + * assert.strictEqual(year, 2024) + * ``` + */ + (self: DateTime, part: keyof DateTime.PartsWithWeekday): number +} = Internal.getPart + +/** + * Set the different parts of a `DateTime` as an object. + * + * The Date will be time zone adjusted. + * + * @since 3.6.0 + * @category parts + */ +export const setParts: { + /** + * Set the different parts of a `DateTime` as an object. + * + * The Date will be time zone adjusted. + * + * @since 3.6.0 + * @category parts + */ + (parts: Partial): (self: A) => A + /** + * Set the different parts of a `DateTime` as an object. + * + * The Date will be time zone adjusted. + * + * @since 3.6.0 + * @category parts + */ + (self: A, parts: Partial): A +} = Internal.setParts + +/** + * Set the different parts of a `DateTime` as an object. + * + * @since 3.6.0 + * @category parts + */ +export const setPartsUtc: { + /** + * Set the different parts of a `DateTime` as an object. + * + * @since 3.6.0 + * @category parts + */ + (parts: Partial): (self: A) => A + /** + * Set the different parts of a `DateTime` as an object. + * + * @since 3.6.0 + * @category parts + */ + (self: A, parts: Partial): A +} = Internal.setPartsUtc + +// ============================================================================= +// current time zone +// ============================================================================= + +/** + * @since 3.11.0 + * @category current time zone + */ +export class CurrentTimeZone extends Context.Tag("effect/DateTime/CurrentTimeZone")() {} + +/** + * Set the time zone of a `DateTime` to the current time zone, which is + * determined by the `CurrentTimeZone` service. + * + * @since 3.6.0 + * @category current time zone + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * const now = yield* DateTime.now + * + * // set the time zone to "Europe/London" + * const zoned = yield* DateTime.setZoneCurrent(now) + * }).pipe(DateTime.withCurrentZoneNamed("Europe/London")) + * ``` + */ +export const setZoneCurrent = (self: DateTime): Effect.Effect => + Effect.map(CurrentTimeZone, (zone) => setZone(self, zone)) + +/** + * Provide the `CurrentTimeZone` to an effect. + * + * @since 3.6.0 + * @category current time zone + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * const zone = DateTime.zoneUnsafeMakeNamed("Europe/London") + * + * Effect.gen(function* () { + * const now = yield* DateTime.nowInCurrentZone + * }).pipe(DateTime.withCurrentZone(zone)) + * ``` + */ +export const withCurrentZone: { + /** + * Provide the `CurrentTimeZone` to an effect. + * + * @since 3.6.0 + * @category current time zone + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * const zone = DateTime.zoneUnsafeMakeNamed("Europe/London") + * + * Effect.gen(function* () { + * const now = yield* DateTime.nowInCurrentZone + * }).pipe(DateTime.withCurrentZone(zone)) + * ``` + */ + (zone: TimeZone): (effect: Effect.Effect) => Effect.Effect> + /** + * Provide the `CurrentTimeZone` to an effect. + * + * @since 3.6.0 + * @category current time zone + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * const zone = DateTime.zoneUnsafeMakeNamed("Europe/London") + * + * Effect.gen(function* () { + * const now = yield* DateTime.nowInCurrentZone + * }).pipe(DateTime.withCurrentZone(zone)) + * ``` + */ + (effect: Effect.Effect, zone: TimeZone): Effect.Effect> +} = dual( + 2, + ( + effect: Effect.Effect, + zone: TimeZone + ): Effect.Effect> => Effect.provideService(effect, CurrentTimeZone, zone) +) + +/** + * Provide the `CurrentTimeZone` to an effect, using the system's local time + * zone. + * + * @since 3.6.0 + * @category current time zone + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * // will use the system's local time zone + * const now = yield* DateTime.nowInCurrentZone + * }).pipe(DateTime.withCurrentZoneLocal) + * ``` + */ +export const withCurrentZoneLocal = ( + effect: Effect.Effect +): Effect.Effect> => + Effect.provideServiceEffect(effect, CurrentTimeZone, Effect.sync(zoneMakeLocal)) + +/** + * Provide the `CurrentTimeZone` to an effect, using a offset. + * + * @since 3.6.0 + * @category current time zone + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * // will use the system's local time zone + * const now = yield* DateTime.nowInCurrentZone + * }).pipe(DateTime.withCurrentZoneOffset(3 * 60 * 60 * 1000)) + * ``` + */ +export const withCurrentZoneOffset: { + /** + * Provide the `CurrentTimeZone` to an effect, using a offset. + * + * @since 3.6.0 + * @category current time zone + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * // will use the system's local time zone + * const now = yield* DateTime.nowInCurrentZone + * }).pipe(DateTime.withCurrentZoneOffset(3 * 60 * 60 * 1000)) + * ``` + */ + (offset: number): ( + effect: Effect.Effect + ) => Effect.Effect> + /** + * Provide the `CurrentTimeZone` to an effect, using a offset. + * + * @since 3.6.0 + * @category current time zone + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * // will use the system's local time zone + * const now = yield* DateTime.nowInCurrentZone + * }).pipe(DateTime.withCurrentZoneOffset(3 * 60 * 60 * 1000)) + * ``` + */ + (effect: Effect.Effect, offset: number): Effect.Effect> +} = dual( + 2, + (effect: Effect.Effect, offset: number): Effect.Effect> => + Effect.provideService(effect, CurrentTimeZone, zoneMakeOffset(offset)) +) + +/** + * Provide the `CurrentTimeZone` to an effect using an IANA time zone + * identifier. + * + * If the time zone is invalid, it will fail with an `IllegalArgumentException`. + * + * @since 3.6.0 + * @category current time zone + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * // will use the "Europe/London" time zone + * const now = yield* DateTime.nowInCurrentZone + * }).pipe(DateTime.withCurrentZoneNamed("Europe/London")) + * ``` + */ +export const withCurrentZoneNamed: { + /** + * Provide the `CurrentTimeZone` to an effect using an IANA time zone + * identifier. + * + * If the time zone is invalid, it will fail with an `IllegalArgumentException`. + * + * @since 3.6.0 + * @category current time zone + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * // will use the "Europe/London" time zone + * const now = yield* DateTime.nowInCurrentZone + * }).pipe(DateTime.withCurrentZoneNamed("Europe/London")) + * ``` + */ + (zone: string): ( + effect: Effect.Effect + ) => Effect.Effect> + /** + * Provide the `CurrentTimeZone` to an effect using an IANA time zone + * identifier. + * + * If the time zone is invalid, it will fail with an `IllegalArgumentException`. + * + * @since 3.6.0 + * @category current time zone + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * // will use the "Europe/London" time zone + * const now = yield* DateTime.nowInCurrentZone + * }).pipe(DateTime.withCurrentZoneNamed("Europe/London")) + * ``` + */ + (effect: Effect.Effect, zone: string): Effect.Effect> +} = dual( + 2, + ( + effect: Effect.Effect, + zone: string + ): Effect.Effect> => + Effect.provideServiceEffect(effect, CurrentTimeZone, zoneMakeNamedEffect(zone)) +) + +/** + * Get the current time as a `DateTime.Zoned`, using the `CurrentTimeZone`. + * + * @since 3.6.0 + * @category current time zone + * @example + * ```ts + * import { DateTime, Effect } from "effect" + * + * Effect.gen(function* () { + * // will use the "Europe/London" time zone + * const now = yield* DateTime.nowInCurrentZone + * }).pipe(DateTime.withCurrentZoneNamed("Europe/London")) + * ``` + */ +export const nowInCurrentZone: Effect.Effect = Effect.flatMap(now, setZoneCurrent) + +// ============================================================================= +// mapping +// ============================================================================= + +/** + * Modify a `DateTime` by applying a function to a cloned `Date` instance. + * + * The `Date` will first have the time zone applied if possible, and then be + * converted back to a `DateTime` within the same time zone. + * + * Supports `disambiguation` when the new wall clock time is ambiguous. + * + * @since 3.6.0 + * @category mapping + */ +export const mutate: { + // ============================================================================= + // mapping + // ============================================================================= + + /** + * Modify a `DateTime` by applying a function to a cloned `Date` instance. + * + * The `Date` will first have the time zone applied if possible, and then be + * converted back to a `DateTime` within the same time zone. + * + * Supports `disambiguation` when the new wall clock time is ambiguous. + * + * @since 3.6.0 + * @category mapping + */ + ( + f: (date: Date) => void, + options?: { + readonly disambiguation?: Disambiguation | undefined + } + ): (self: A) => A + // ============================================================================= + // mapping + // ============================================================================= + + /** + * Modify a `DateTime` by applying a function to a cloned `Date` instance. + * + * The `Date` will first have the time zone applied if possible, and then be + * converted back to a `DateTime` within the same time zone. + * + * Supports `disambiguation` when the new wall clock time is ambiguous. + * + * @since 3.6.0 + * @category mapping + */ + ( + self: A, + f: (date: Date) => void, + options?: { + readonly disambiguation?: Disambiguation | undefined + } + ): A +} = Internal.mutate + +/** + * Modify a `DateTime` by applying a function to a cloned UTC `Date` instance. + * + * @since 3.6.0 + * @category mapping + */ +export const mutateUtc: { + /** + * Modify a `DateTime` by applying a function to a cloned UTC `Date` instance. + * + * @since 3.6.0 + * @category mapping + */ + (f: (date: Date) => void): (self: A) => A + /** + * Modify a `DateTime` by applying a function to a cloned UTC `Date` instance. + * + * @since 3.6.0 + * @category mapping + */ + (self: A, f: (date: Date) => void): A +} = Internal.mutateUtc + +/** + * Transform a `DateTime` by applying a function to the number of milliseconds + * since the Unix epoch. + * + * @since 3.6.0 + * @category mapping + * @example + * ```ts + * import { DateTime } from "effect" + * + * // add 10 milliseconds + * DateTime.unsafeMake(0).pipe( + * DateTime.mapEpochMillis((millis) => millis + 10) + * ) + * ``` + */ +export const mapEpochMillis: { + /** + * Transform a `DateTime` by applying a function to the number of milliseconds + * since the Unix epoch. + * + * @since 3.6.0 + * @category mapping + * @example + * ```ts + * import { DateTime } from "effect" + * + * // add 10 milliseconds + * DateTime.unsafeMake(0).pipe( + * DateTime.mapEpochMillis((millis) => millis + 10) + * ) + * ``` + */ + (f: (millis: number) => number): (self: A) => A + /** + * Transform a `DateTime` by applying a function to the number of milliseconds + * since the Unix epoch. + * + * @since 3.6.0 + * @category mapping + * @example + * ```ts + * import { DateTime } from "effect" + * + * // add 10 milliseconds + * DateTime.unsafeMake(0).pipe( + * DateTime.mapEpochMillis((millis) => millis + 10) + * ) + * ``` + */ + (self: A, f: (millis: number) => number): A +} = Internal.mapEpochMillis + +/** + * Using the time zone adjusted `Date`, apply a function to the `Date` and + * return the result. + * + * @since 3.6.0 + * @category mapping + * @example + * ```ts + * import { DateTime } from "effect" + * + * // get the time zone adjusted date in milliseconds + * DateTime.unsafeMakeZoned(0, { timeZone: "Europe/London" }).pipe( + * DateTime.withDate((date) => date.getTime()) + * ) + * ``` + */ +export const withDate: { + /** + * Using the time zone adjusted `Date`, apply a function to the `Date` and + * return the result. + * + * @since 3.6.0 + * @category mapping + * @example + * ```ts + * import { DateTime } from "effect" + * + * // get the time zone adjusted date in milliseconds + * DateTime.unsafeMakeZoned(0, { timeZone: "Europe/London" }).pipe( + * DateTime.withDate((date) => date.getTime()) + * ) + * ``` + */ + (f: (date: Date) => A): (self: DateTime) => A + /** + * Using the time zone adjusted `Date`, apply a function to the `Date` and + * return the result. + * + * @since 3.6.0 + * @category mapping + * @example + * ```ts + * import { DateTime } from "effect" + * + * // get the time zone adjusted date in milliseconds + * DateTime.unsafeMakeZoned(0, { timeZone: "Europe/London" }).pipe( + * DateTime.withDate((date) => date.getTime()) + * ) + * ``` + */ + (self: DateTime, f: (date: Date) => A): A +} = Internal.withDate + +/** + * Using the time zone adjusted `Date`, apply a function to the `Date` and + * return the result. + * + * @since 3.6.0 + * @category mapping + * @example + * ```ts + * import { DateTime } from "effect" + * + * // get the date in milliseconds + * DateTime.unsafeMake(0).pipe( + * DateTime.withDateUtc((date) => date.getTime()) + * ) + * ``` + */ +export const withDateUtc: { + /** + * Using the time zone adjusted `Date`, apply a function to the `Date` and + * return the result. + * + * @since 3.6.0 + * @category mapping + * @example + * ```ts + * import { DateTime } from "effect" + * + * // get the date in milliseconds + * DateTime.unsafeMake(0).pipe( + * DateTime.withDateUtc((date) => date.getTime()) + * ) + * ``` + */ + (f: (date: Date) => A): (self: DateTime) => A + /** + * Using the time zone adjusted `Date`, apply a function to the `Date` and + * return the result. + * + * @since 3.6.0 + * @category mapping + * @example + * ```ts + * import { DateTime } from "effect" + * + * // get the date in milliseconds + * DateTime.unsafeMake(0).pipe( + * DateTime.withDateUtc((date) => date.getTime()) + * ) + * ``` + */ + (self: DateTime, f: (date: Date) => A): A +} = Internal.withDateUtc + +/** + * @since 3.6.0 + * @category mapping + */ +export const match: { + /** + * @since 3.6.0 + * @category mapping + */ + ( + options: { + readonly onUtc: (_: Utc) => A + readonly onZoned: (_: Zoned) => B + } + ): (self: DateTime) => A | B + /** + * @since 3.6.0 + * @category mapping + */ + ( + self: DateTime, + options: { + readonly onUtc: (_: Utc) => A + readonly onZoned: (_: Zoned) => B + } + ): A | B +} = Internal.match + +// ============================================================================= +// math +// ============================================================================= + +/** + * Add the given `Duration` to a `DateTime`. + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // add 5 minutes + * DateTime.unsafeMake(0).pipe( + * DateTime.addDuration("5 minutes") + * ) + * ``` + */ +export const addDuration: { + // ============================================================================= + // math + // ============================================================================= + + /** + * Add the given `Duration` to a `DateTime`. + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // add 5 minutes + * DateTime.unsafeMake(0).pipe( + * DateTime.addDuration("5 minutes") + * ) + * ``` + */ + (duration: Duration.DurationInput): (self: A) => A + // ============================================================================= + // math + // ============================================================================= + + /** + * Add the given `Duration` to a `DateTime`. + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // add 5 minutes + * DateTime.unsafeMake(0).pipe( + * DateTime.addDuration("5 minutes") + * ) + * ``` + */ + (self: A, duration: Duration.DurationInput): A +} = Internal.addDuration + +/** + * Subtract the given `Duration` from a `DateTime`. + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // subtract 5 minutes + * DateTime.unsafeMake(0).pipe( + * DateTime.subtractDuration("5 minutes") + * ) + * ``` + */ +export const subtractDuration: { + /** + * Subtract the given `Duration` from a `DateTime`. + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // subtract 5 minutes + * DateTime.unsafeMake(0).pipe( + * DateTime.subtractDuration("5 minutes") + * ) + * ``` + */ + (duration: Duration.DurationInput): (self: A) => A + /** + * Subtract the given `Duration` from a `DateTime`. + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // subtract 5 minutes + * DateTime.unsafeMake(0).pipe( + * DateTime.subtractDuration("5 minutes") + * ) + * ``` + */ + (self: A, duration: Duration.DurationInput): A +} = Internal.subtractDuration + +/** + * Add the given `amount` of `unit`'s to a `DateTime`. + * + * The time zone is taken into account when adding days, weeks, months, and + * years. + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // add 5 minutes + * DateTime.unsafeMake(0).pipe( + * DateTime.add({ minutes: 5 }) + * ) + * ``` + */ +export const add: { + /** + * Add the given `amount` of `unit`'s to a `DateTime`. + * + * The time zone is taken into account when adding days, weeks, months, and + * years. + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // add 5 minutes + * DateTime.unsafeMake(0).pipe( + * DateTime.add({ minutes: 5 }) + * ) + * ``` + */ + (parts: Partial): (self: A) => A + /** + * Add the given `amount` of `unit`'s to a `DateTime`. + * + * The time zone is taken into account when adding days, weeks, months, and + * years. + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // add 5 minutes + * DateTime.unsafeMake(0).pipe( + * DateTime.add({ minutes: 5 }) + * ) + * ``` + */ + (self: A, parts: Partial): A +} = Internal.add + +/** + * Subtract the given `amount` of `unit`'s from a `DateTime`. + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // subtract 5 minutes + * DateTime.unsafeMake(0).pipe( + * DateTime.subtract({ minutes: 5 }) + * ) + * ``` + */ +export const subtract: { + /** + * Subtract the given `amount` of `unit`'s from a `DateTime`. + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // subtract 5 minutes + * DateTime.unsafeMake(0).pipe( + * DateTime.subtract({ minutes: 5 }) + * ) + * ``` + */ + (parts: Partial): (self: A) => A + /** + * Subtract the given `amount` of `unit`'s from a `DateTime`. + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // subtract 5 minutes + * DateTime.unsafeMake(0).pipe( + * DateTime.subtract({ minutes: 5 }) + * ) + * ``` + */ + (self: A, parts: Partial): A +} = Internal.subtract + +/** + * Converts a `DateTime` to the start of the given `part`. + * + * If the part is `week`, the `weekStartsOn` option can be used to specify the + * day of the week that the week starts on. The default is 0 (Sunday). + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // returns "2024-01-01T00:00:00Z" + * DateTime.unsafeMake("2024-01-01T12:00:00Z").pipe( + * DateTime.startOf("day"), + * DateTime.formatIso + * ) + * ``` + */ +export const startOf: { + /** + * Converts a `DateTime` to the start of the given `part`. + * + * If the part is `week`, the `weekStartsOn` option can be used to specify the + * day of the week that the week starts on. The default is 0 (Sunday). + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // returns "2024-01-01T00:00:00Z" + * DateTime.unsafeMake("2024-01-01T12:00:00Z").pipe( + * DateTime.startOf("day"), + * DateTime.formatIso + * ) + * ``` + */ + ( + part: DateTime.UnitSingular, + options?: { readonly weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | undefined } + ): (self: A) => A + /** + * Converts a `DateTime` to the start of the given `part`. + * + * If the part is `week`, the `weekStartsOn` option can be used to specify the + * day of the week that the week starts on. The default is 0 (Sunday). + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // returns "2024-01-01T00:00:00Z" + * DateTime.unsafeMake("2024-01-01T12:00:00Z").pipe( + * DateTime.startOf("day"), + * DateTime.formatIso + * ) + * ``` + */ + ( + self: A, + part: DateTime.UnitSingular, + options?: { readonly weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | undefined } + ): A +} = Internal.startOf + +/** + * Converts a `DateTime` to the end of the given `part`. + * + * If the part is `week`, the `weekStartsOn` option can be used to specify the + * day of the week that the week starts on. The default is 0 (Sunday). + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // returns "2024-01-01T23:59:59.999Z" + * DateTime.unsafeMake("2024-01-01T12:00:00Z").pipe( + * DateTime.endOf("day"), + * DateTime.formatIso + * ) + * ``` + */ +export const endOf: { + /** + * Converts a `DateTime` to the end of the given `part`. + * + * If the part is `week`, the `weekStartsOn` option can be used to specify the + * day of the week that the week starts on. The default is 0 (Sunday). + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // returns "2024-01-01T23:59:59.999Z" + * DateTime.unsafeMake("2024-01-01T12:00:00Z").pipe( + * DateTime.endOf("day"), + * DateTime.formatIso + * ) + * ``` + */ + ( + part: DateTime.UnitSingular, + options?: { readonly weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | undefined } + ): (self: A) => A + /** + * Converts a `DateTime` to the end of the given `part`. + * + * If the part is `week`, the `weekStartsOn` option can be used to specify the + * day of the week that the week starts on. The default is 0 (Sunday). + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // returns "2024-01-01T23:59:59.999Z" + * DateTime.unsafeMake("2024-01-01T12:00:00Z").pipe( + * DateTime.endOf("day"), + * DateTime.formatIso + * ) + * ``` + */ + ( + self: A, + part: DateTime.UnitSingular, + options?: { readonly weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | undefined } + ): A +} = Internal.endOf + +/** + * Converts a `DateTime` to the nearest given `part`. + * + * If the part is `week`, the `weekStartsOn` option can be used to specify the + * day of the week that the week starts on. The default is 0 (Sunday). + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // returns "2024-01-02T00:00:00Z" + * DateTime.unsafeMake("2024-01-01T12:01:00Z").pipe( + * DateTime.nearest("day"), + * DateTime.formatIso + * ) + * ``` + */ +export const nearest: { + /** + * Converts a `DateTime` to the nearest given `part`. + * + * If the part is `week`, the `weekStartsOn` option can be used to specify the + * day of the week that the week starts on. The default is 0 (Sunday). + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // returns "2024-01-02T00:00:00Z" + * DateTime.unsafeMake("2024-01-01T12:01:00Z").pipe( + * DateTime.nearest("day"), + * DateTime.formatIso + * ) + * ``` + */ + ( + part: DateTime.UnitSingular, + options?: { readonly weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | undefined } + ): (self: A) => A + /** + * Converts a `DateTime` to the nearest given `part`. + * + * If the part is `week`, the `weekStartsOn` option can be used to specify the + * day of the week that the week starts on. The default is 0 (Sunday). + * + * @since 3.6.0 + * @category math + * @example + * ```ts + * import { DateTime } from "effect" + * + * // returns "2024-01-02T00:00:00Z" + * DateTime.unsafeMake("2024-01-01T12:01:00Z").pipe( + * DateTime.nearest("day"), + * DateTime.formatIso + * ) + * ``` + */ + ( + self: A, + part: DateTime.UnitSingular, + options?: { readonly weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | undefined } + ): A +} = Internal.nearest + +// ============================================================================= +// formatting +// ============================================================================= + +/** + * Format a `DateTime` as a string using the `DateTimeFormat` API. + * + * The `timeZone` option is set to the offset of the time zone. + * + * Note: On Node versions < 22, fixed "Offset" zones will set the time zone to + * "UTC" and use the adjusted `Date`. + * + * @since 3.6.0 + * @category formatting + */ +export const format: { + // ============================================================================= + // formatting + // ============================================================================= + + /** + * Format a `DateTime` as a string using the `DateTimeFormat` API. + * + * The `timeZone` option is set to the offset of the time zone. + * + * Note: On Node versions < 22, fixed "Offset" zones will set the time zone to + * "UTC" and use the adjusted `Date`. + * + * @since 3.6.0 + * @category formatting + */ + ( + options?: + | Intl.DateTimeFormatOptions & { + readonly locale?: Intl.LocalesArgument + } + | undefined + ): (self: DateTime) => string + // ============================================================================= + // formatting + // ============================================================================= + + /** + * Format a `DateTime` as a string using the `DateTimeFormat` API. + * + * The `timeZone` option is set to the offset of the time zone. + * + * Note: On Node versions < 22, fixed "Offset" zones will set the time zone to + * "UTC" and use the adjusted `Date`. + * + * @since 3.6.0 + * @category formatting + */ + ( + self: DateTime, + options?: + | Intl.DateTimeFormatOptions & { + readonly locale?: Intl.LocalesArgument + } + | undefined + ): string +} = Internal.format + +/** + * Format a `DateTime` as a string using the `DateTimeFormat` API. + * + * It will use the system's local time zone & locale. + * + * @since 3.6.0 + * @category formatting + */ +export const formatLocal: { + /** + * Format a `DateTime` as a string using the `DateTimeFormat` API. + * + * It will use the system's local time zone & locale. + * + * @since 3.6.0 + * @category formatting + */ + ( + options?: + | Intl.DateTimeFormatOptions & { + readonly locale?: Intl.LocalesArgument + } + | undefined + ): (self: DateTime) => string + /** + * Format a `DateTime` as a string using the `DateTimeFormat` API. + * + * It will use the system's local time zone & locale. + * + * @since 3.6.0 + * @category formatting + */ + ( + self: DateTime, + options?: + | Intl.DateTimeFormatOptions & { + readonly locale?: Intl.LocalesArgument + } + | undefined + ): string +} = Internal.formatLocal + +/** + * Format a `DateTime` as a string using the `DateTimeFormat` API. + * + * This forces the time zone to be UTC. + * + * @since 3.6.0 + * @category formatting + */ +export const formatUtc: { + /** + * Format a `DateTime` as a string using the `DateTimeFormat` API. + * + * This forces the time zone to be UTC. + * + * @since 3.6.0 + * @category formatting + */ + ( + options?: + | Intl.DateTimeFormatOptions & { + readonly locale?: Intl.LocalesArgument + } + | undefined + ): (self: DateTime) => string + /** + * Format a `DateTime` as a string using the `DateTimeFormat` API. + * + * This forces the time zone to be UTC. + * + * @since 3.6.0 + * @category formatting + */ + ( + self: DateTime, + options?: + | Intl.DateTimeFormatOptions & { + readonly locale?: Intl.LocalesArgument + } + | undefined + ): string +} = Internal.formatUtc + +/** + * Format a `DateTime` as a string using the `DateTimeFormat` API. + * + * @since 3.6.0 + * @category formatting + */ +export const formatIntl: { + /** + * Format a `DateTime` as a string using the `DateTimeFormat` API. + * + * @since 3.6.0 + * @category formatting + */ + (format: Intl.DateTimeFormat): (self: DateTime) => string + /** + * Format a `DateTime` as a string using the `DateTimeFormat` API. + * + * @since 3.6.0 + * @category formatting + */ + (self: DateTime, format: Intl.DateTimeFormat): string +} = Internal.formatIntl + +/** + * Format a `DateTime` as a UTC ISO string. + * + * @since 3.6.0 + * @category formatting + */ +export const formatIso: (self: DateTime) => string = Internal.formatIso + +/** + * Format a `DateTime` as a time zone adjusted ISO date string. + * + * @since 3.6.0 + * @category formatting + */ +export const formatIsoDate: (self: DateTime) => string = Internal.formatIsoDate + +/** + * Format a `DateTime` as a UTC ISO date string. + * + * @since 3.6.0 + * @category formatting + */ +export const formatIsoDateUtc: (self: DateTime) => string = Internal.formatIsoDateUtc + +/** + * Format a `DateTime.Zoned` as a ISO string with an offset. + * + * @since 3.6.0 + * @category formatting + */ +export const formatIsoOffset: (self: DateTime) => string = Internal.formatIsoOffset + +/** + * Format a `DateTime.Zoned` as a string. + * + * It uses the format: `YYYY-MM-DDTHH:mm:ss.sss+HH:MM[Time/Zone]`. + * + * @since 3.6.0 + * @category formatting + */ +export const formatIsoZoned: (self: Zoned) => string = Internal.formatIsoZoned + +/** + * Create a Layer from the given time zone. + * + * @since 3.6.0 + * @category current time zone + */ +export const layerCurrentZone = (zone: TimeZone): Layer.Layer => Layer.succeed(CurrentTimeZone, zone) + +/** + * Create a Layer from the given time zone offset. + * + * @since 3.6.0 + * @category current time zone + */ +export const layerCurrentZoneOffset = (offset: number): Layer.Layer => + Layer.succeed(CurrentTimeZone, Internal.zoneMakeOffset(offset)) + +/** + * Create a Layer from the given IANA time zone identifier. + * + * @since 3.6.0 + * @category current time zone + */ +export const layerCurrentZoneNamed = ( + zoneId: string +): Layer.Layer => + Layer.effect(CurrentTimeZone, Internal.zoneMakeNamedEffect(zoneId)) + +/** + * Create a Layer from the systems local time zone. + * + * @since 3.6.0 + * @category current time zone + */ +export const layerCurrentZoneLocal: Layer.Layer = Layer.sync(CurrentTimeZone, zoneMakeLocal) diff --git a/backend/node_modules/effect/src/Effect.ts b/backend/node_modules/effect/src/Effect.ts new file mode 100644 index 0000000000000000000000000000000000000000..d62d11363a41975b47f2b8656119005f20657011 --- /dev/null +++ b/backend/node_modules/effect/src/Effect.ts @@ -0,0 +1,29102 @@ +/** + * @since 2.0.0 + */ +import type * as RA from "./Array.js" +import type * as Cause from "./Cause.js" +import type * as Chunk from "./Chunk.js" +import type * as Clock from "./Clock.js" +import type { ConfigProvider } from "./ConfigProvider.js" +import type { Console } from "./Console.js" +import type * as Context from "./Context.js" +import type * as Deferred from "./Deferred.js" +import type * as Duration from "./Duration.js" +import type * as Either from "./Either.js" +import type { Equivalence } from "./Equivalence.js" +import type { ExecutionPlan } from "./ExecutionPlan.js" +import type { ExecutionStrategy } from "./ExecutionStrategy.js" +import type * as Exit from "./Exit.js" +import type * as Fiber from "./Fiber.js" +import type * as FiberId from "./FiberId.js" +import type * as FiberRef from "./FiberRef.js" +import type * as FiberRefs from "./FiberRefs.js" +import type * as FiberRefsPatch from "./FiberRefsPatch.js" +import type * as FiberStatus from "./FiberStatus.js" +import type { LazyArg } from "./Function.js" +import { dual } from "./Function.js" +import type * as HashMap from "./HashMap.js" +import type * as HashSet from "./HashSet.js" +import type { TypeLambda } from "./HKT.js" +import * as internalCause from "./internal/cause.js" +import * as console_ from "./internal/console.js" +import { TagProto } from "./internal/context.js" +import * as effect from "./internal/core-effect.js" +import * as core from "./internal/core.js" +import * as defaultServices from "./internal/defaultServices.js" +import * as circular from "./internal/effect/circular.js" +import * as internalExecutionPlan from "./internal/executionPlan.js" +import * as fiberRuntime from "./internal/fiberRuntime.js" +import * as layer from "./internal/layer.js" +import * as option_ from "./internal/option.js" +import * as query from "./internal/query.js" +import * as runtime_ from "./internal/runtime.js" +import * as schedule_ from "./internal/schedule.js" +import * as internalTracer from "./internal/tracer.js" +import type * as Layer from "./Layer.js" +import type * as LogLevel from "./LogLevel.js" +import type * as ManagedRuntime from "./ManagedRuntime.js" +import type * as Metric from "./Metric.js" +import type * as MetricLabel from "./MetricLabel.js" +import type * as Option from "./Option.js" +import type { Pipeable } from "./Pipeable.js" +import type { Predicate, Refinement } from "./Predicate.js" +import * as Random from "./Random.js" +import type * as Ref from "./Ref.js" +import * as Request from "./Request.js" +import type { RequestBlock } from "./RequestBlock.js" +import type { RequestResolver } from "./RequestResolver.js" +import type * as Runtime from "./Runtime.js" +import type * as RuntimeFlags from "./RuntimeFlags.js" +import type * as RuntimeFlagsPatch from "./RuntimeFlagsPatch.js" +import type * as Schedule from "./Schedule.js" +import * as Scheduler from "./Scheduler.js" +import type * as Scope from "./Scope.js" +import type * as Supervisor from "./Supervisor.js" +import type * as Tracer from "./Tracer.js" +import type { + Concurrency, + Contravariant, + Covariant, + EqualsWith, + NoExcessProperties, + NoInfer, + NotFunction +} from "./Types.js" +import type * as Unify from "./Unify.js" +import { isGeneratorFunction, type YieldWrap } from "./Utils.js" + +/** + * @since 2.0.0 + * @category Symbols + */ +export const EffectTypeId: unique symbol = core.EffectTypeId + +/** + * @since 2.0.0 + * @category Symbols + */ +export type EffectTypeId = typeof EffectTypeId + +/** + * The `Effect` interface defines a value that describes a workflow or job, + * which can succeed or fail. + * + * **Details** + * + * The `Effect` interface represents a computation that can model a workflow + * involving various types of operations, such as synchronous, asynchronous, + * concurrent, and parallel interactions. It operates within a context of type + * `R`, and the result can either be a success with a value of type `A` or a + * failure with an error of type `E`. The `Effect` is designed to handle complex + * interactions with external resources, offering advanced features such as + * fiber-based concurrency, scheduling, interruption handling, and scalability. + * This makes it suitable for tasks that require fine-grained control over + * concurrency and error management. + * + * To execute an `Effect` value, you need a `Runtime`, which provides the + * environment necessary to run and manage the computation. + * + * @since 2.0.0 + * @category Models + */ +export interface Effect extends Effect.Variance, Pipeable { + readonly [Unify.typeSymbol]?: unknown + readonly [Unify.unifySymbol]?: EffectUnify + readonly [Unify.ignoreSymbol]?: EffectUnifyIgnore + [Symbol.iterator](): EffectGenerator> +} + +/** + * @since 3.0.0 + * @category Models + */ +export interface EffectGenerator> { + next(...args: ReadonlyArray): IteratorResult, Effect.Success> +} + +/** + * @since 2.0.0 + * @category Models + */ +export interface EffectUnify + extends Either.EitherUnify, Option.OptionUnify, Context.TagUnify +{ + Effect?: () => A[Unify.typeSymbol] extends Effect | infer _ ? Effect : never +} + +/** + * @category Models + * @since 2.0.0 + */ +export interface EffectUnifyIgnore { + Tag?: true + Option?: true + Either?: true +} + +/** + * @category Type lambdas + * @since 2.0.0 + */ +export interface EffectTypeLambda extends TypeLambda { + readonly type: Effect +} + +/** + * @since 2.0.0 + * @category Models + */ +export interface Blocked extends Effect { + readonly _op: "Blocked" + readonly effect_instruction_i0: RequestBlock + readonly effect_instruction_i1: Effect +} + +/** + * @since 2.0.0 + * @category Models + */ +declare module "./Context.js" { + interface Tag extends Effect { + [Symbol.iterator](): EffectGenerator> + } + interface Reference extends Effect { + [Symbol.iterator](): EffectGenerator> + } + interface TagUnifyIgnore { + Effect?: true + Either?: true + Option?: true + } +} + +/** + * @since 2.0.0 + * @category Models + */ +declare module "./Either.js" { + interface Left extends Effect { + readonly _tag: "Left" + [Symbol.iterator](): EffectGenerator> + } + interface Right extends Effect { + readonly _tag: "Right" + [Symbol.iterator](): EffectGenerator> + } + interface EitherUnifyIgnore { + Effect?: true + Tag?: true + Option?: true + } +} + +/** + * @since 2.0.0 + * @category Models + */ +declare module "./Option.js" { + interface None extends Effect { + readonly _tag: "None" + [Symbol.iterator](): EffectGenerator> + } + interface Some extends Effect { + readonly _tag: "Some" + [Symbol.iterator](): EffectGenerator> + } + interface OptionUnifyIgnore { + Effect?: true + Tag?: true + Either?: true + } +} + +/** + * @since 2.0.0 + */ +export declare namespace Effect { + /** + * @since 2.0.0 + * @category Models + */ + export interface Variance { + readonly [EffectTypeId]: VarianceStruct + } + /** + * @since 2.0.0 + * @category Models + */ + export interface VarianceStruct { + readonly _V: string + readonly _A: Covariant + readonly _E: Covariant + readonly _R: Covariant + } + /** + * @since 2.0.0 + * @category Effect Type Extractors + */ + export type Context> = [T] extends [Effect] ? _R : never + /** + * @since 2.0.0 + * @category Effect Type Extractors + */ + export type Error> = [T] extends [Effect] ? _E : never + /** + * @since 2.0.0 + * @category Effect Type Extractors + */ + export type Success> = [T] extends [Effect] ? _A : never + /** + * @since 3.15.5 + * @category Effect Type Extractors + */ + export type AsEffect> = Effect< + T extends Effect ? _A : never, + T extends Effect ? _E : never, + T extends Effect ? _R : never + > extends infer Q ? Q : never +} + +/** + * Checks if a given value is an `Effect` value. + * + * **When to Use** + * + * This function can be useful for checking the type of a value before + * attempting to operate on it as an `Effect` value. For example, you could use + * `Effect.isEffect` to check the type of a value before using it as an argument + * to a function that expects an `Effect` value. + * + * @since 2.0.0 + * @category Guards + */ +export const isEffect: (u: unknown) => u is Effect = core.isEffect + +/** + * Returns an effect that caches its result for a specified `Duration`, + * known as "timeToLive" (TTL). + * + * **Details** + * + * This function is used to cache the result of an effect for a specified amount + * of time. This means that the first time the effect is evaluated, its result + * is computed and stored. + * + * If the effect is evaluated again within the specified `timeToLive`, the + * cached result will be used, avoiding recomputation. + * + * After the specified duration has passed, the cache expires, and the effect + * will be recomputed upon the next evaluation. + * + * **When to Use** + * + * Use this function when you have an effect that involves costly operations or + * computations, and you want to avoid repeating them within a short time frame. + * + * It's ideal for scenarios where the result of an effect doesn't change + * frequently and can be reused for a specified duration. + * + * By caching the result, you can improve efficiency and reduce unnecessary + * computations, especially in performance-critical applications. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * let i = 1 + * const expensiveTask = Effect.promise(() => { + * console.log("expensive task...") + * return new Promise((resolve) => { + * setTimeout(() => { + * resolve(`result ${i++}`) + * }, 100) + * }) + * }) + * + * const program = Effect.gen(function* () { + * const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis") + * yield* cached.pipe(Effect.andThen(Console.log)) + * yield* cached.pipe(Effect.andThen(Console.log)) + * yield* Effect.sleep("100 millis") + * yield* cached.pipe(Effect.andThen(Console.log)) + * }) + * + * Effect.runFork(program) + * // Output: + * // expensive task... + * // result 1 + * // result 1 + * // expensive task... + * // result 2 + * ``` + * + * @see {@link cached} for a similar function that caches the result + * indefinitely. + * @see {@link cachedInvalidateWithTTL} for a similar function that includes an + * additional effect for manually invalidating the cached value. + * + * @since 2.0.0 + * @category Caching + */ +export const cachedWithTTL: { + /** + * Returns an effect that caches its result for a specified `Duration`, + * known as "timeToLive" (TTL). + * + * **Details** + * + * This function is used to cache the result of an effect for a specified amount + * of time. This means that the first time the effect is evaluated, its result + * is computed and stored. + * + * If the effect is evaluated again within the specified `timeToLive`, the + * cached result will be used, avoiding recomputation. + * + * After the specified duration has passed, the cache expires, and the effect + * will be recomputed upon the next evaluation. + * + * **When to Use** + * + * Use this function when you have an effect that involves costly operations or + * computations, and you want to avoid repeating them within a short time frame. + * + * It's ideal for scenarios where the result of an effect doesn't change + * frequently and can be reused for a specified duration. + * + * By caching the result, you can improve efficiency and reduce unnecessary + * computations, especially in performance-critical applications. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * let i = 1 + * const expensiveTask = Effect.promise(() => { + * console.log("expensive task...") + * return new Promise((resolve) => { + * setTimeout(() => { + * resolve(`result ${i++}`) + * }, 100) + * }) + * }) + * + * const program = Effect.gen(function* () { + * const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis") + * yield* cached.pipe(Effect.andThen(Console.log)) + * yield* cached.pipe(Effect.andThen(Console.log)) + * yield* Effect.sleep("100 millis") + * yield* cached.pipe(Effect.andThen(Console.log)) + * }) + * + * Effect.runFork(program) + * // Output: + * // expensive task... + * // result 1 + * // result 1 + * // expensive task... + * // result 2 + * ``` + * + * @see {@link cached} for a similar function that caches the result + * indefinitely. + * @see {@link cachedInvalidateWithTTL} for a similar function that includes an + * additional effect for manually invalidating the cached value. + * + * @since 2.0.0 + * @category Caching + */ + (timeToLive: Duration.DurationInput): (self: Effect) => Effect, never, R> + /** + * Returns an effect that caches its result for a specified `Duration`, + * known as "timeToLive" (TTL). + * + * **Details** + * + * This function is used to cache the result of an effect for a specified amount + * of time. This means that the first time the effect is evaluated, its result + * is computed and stored. + * + * If the effect is evaluated again within the specified `timeToLive`, the + * cached result will be used, avoiding recomputation. + * + * After the specified duration has passed, the cache expires, and the effect + * will be recomputed upon the next evaluation. + * + * **When to Use** + * + * Use this function when you have an effect that involves costly operations or + * computations, and you want to avoid repeating them within a short time frame. + * + * It's ideal for scenarios where the result of an effect doesn't change + * frequently and can be reused for a specified duration. + * + * By caching the result, you can improve efficiency and reduce unnecessary + * computations, especially in performance-critical applications. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * let i = 1 + * const expensiveTask = Effect.promise(() => { + * console.log("expensive task...") + * return new Promise((resolve) => { + * setTimeout(() => { + * resolve(`result ${i++}`) + * }, 100) + * }) + * }) + * + * const program = Effect.gen(function* () { + * const cached = yield* Effect.cachedWithTTL(expensiveTask, "150 millis") + * yield* cached.pipe(Effect.andThen(Console.log)) + * yield* cached.pipe(Effect.andThen(Console.log)) + * yield* Effect.sleep("100 millis") + * yield* cached.pipe(Effect.andThen(Console.log)) + * }) + * + * Effect.runFork(program) + * // Output: + * // expensive task... + * // result 1 + * // result 1 + * // expensive task... + * // result 2 + * ``` + * + * @see {@link cached} for a similar function that caches the result + * indefinitely. + * @see {@link cachedInvalidateWithTTL} for a similar function that includes an + * additional effect for manually invalidating the cached value. + * + * @since 2.0.0 + * @category Caching + */ + (self: Effect, timeToLive: Duration.DurationInput): Effect, never, R> +} = circular.cached + +/** + * Caches an effect's result for a specified duration and allows manual + * invalidation before expiration. + * + * **Details** + * + * This function behaves similarly to {@link cachedWithTTL} by caching the + * result of an effect for a specified period of time. However, it introduces an + * additional feature: it provides an effect that allows you to manually + * invalidate the cached result before it naturally expires. + * + * This gives you more control over the cache, allowing you to refresh the + * result when needed, even if the original cache has not yet expired. + * + * Once the cache is invalidated, the next time the effect is evaluated, the + * result will be recomputed, and the cache will be refreshed. + * + * **When to Use** + * + * Use this function when you have an effect whose result needs to be cached for + * a certain period, but you also want the option to refresh the cache manually + * before the expiration time. + * + * This is useful when you need to ensure that the cached data remains valid for + * a certain period but still want to invalidate it if the underlying data + * changes or if you want to force a recomputation. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * let i = 1 + * const expensiveTask = Effect.promise(() => { + * console.log("expensive task...") + * return new Promise((resolve) => { + * setTimeout(() => { + * resolve(`result ${i++}`) + * }, 100) + * }) + * }) + * + * const program = Effect.gen(function* () { + * const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL( + * expensiveTask, + * "1 hour" + * ) + * yield* cached.pipe(Effect.andThen(Console.log)) + * yield* cached.pipe(Effect.andThen(Console.log)) + * yield* invalidate + * yield* cached.pipe(Effect.andThen(Console.log)) + * }) + * + * Effect.runFork(program) + * // Output: + * // expensive task... + * // result 1 + * // result 1 + * // expensive task... + * // result 2 + * ``` + * + * @see {@link cached} for a similar function that caches the result + * indefinitely. + * @see {@link cachedWithTTL} for a similar function that caches the result for + * a specified duration but does not include an effect for manual invalidation. + * + * @since 2.0.0 + * @category Caching + */ +export const cachedInvalidateWithTTL: { + /** + * Caches an effect's result for a specified duration and allows manual + * invalidation before expiration. + * + * **Details** + * + * This function behaves similarly to {@link cachedWithTTL} by caching the + * result of an effect for a specified period of time. However, it introduces an + * additional feature: it provides an effect that allows you to manually + * invalidate the cached result before it naturally expires. + * + * This gives you more control over the cache, allowing you to refresh the + * result when needed, even if the original cache has not yet expired. + * + * Once the cache is invalidated, the next time the effect is evaluated, the + * result will be recomputed, and the cache will be refreshed. + * + * **When to Use** + * + * Use this function when you have an effect whose result needs to be cached for + * a certain period, but you also want the option to refresh the cache manually + * before the expiration time. + * + * This is useful when you need to ensure that the cached data remains valid for + * a certain period but still want to invalidate it if the underlying data + * changes or if you want to force a recomputation. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * let i = 1 + * const expensiveTask = Effect.promise(() => { + * console.log("expensive task...") + * return new Promise((resolve) => { + * setTimeout(() => { + * resolve(`result ${i++}`) + * }, 100) + * }) + * }) + * + * const program = Effect.gen(function* () { + * const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL( + * expensiveTask, + * "1 hour" + * ) + * yield* cached.pipe(Effect.andThen(Console.log)) + * yield* cached.pipe(Effect.andThen(Console.log)) + * yield* invalidate + * yield* cached.pipe(Effect.andThen(Console.log)) + * }) + * + * Effect.runFork(program) + * // Output: + * // expensive task... + * // result 1 + * // result 1 + * // expensive task... + * // result 2 + * ``` + * + * @see {@link cached} for a similar function that caches the result + * indefinitely. + * @see {@link cachedWithTTL} for a similar function that caches the result for + * a specified duration but does not include an effect for manual invalidation. + * + * @since 2.0.0 + * @category Caching + */ + (timeToLive: Duration.DurationInput): ( + self: Effect + ) => Effect<[Effect, Effect], never, R> + /** + * Caches an effect's result for a specified duration and allows manual + * invalidation before expiration. + * + * **Details** + * + * This function behaves similarly to {@link cachedWithTTL} by caching the + * result of an effect for a specified period of time. However, it introduces an + * additional feature: it provides an effect that allows you to manually + * invalidate the cached result before it naturally expires. + * + * This gives you more control over the cache, allowing you to refresh the + * result when needed, even if the original cache has not yet expired. + * + * Once the cache is invalidated, the next time the effect is evaluated, the + * result will be recomputed, and the cache will be refreshed. + * + * **When to Use** + * + * Use this function when you have an effect whose result needs to be cached for + * a certain period, but you also want the option to refresh the cache manually + * before the expiration time. + * + * This is useful when you need to ensure that the cached data remains valid for + * a certain period but still want to invalidate it if the underlying data + * changes or if you want to force a recomputation. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * let i = 1 + * const expensiveTask = Effect.promise(() => { + * console.log("expensive task...") + * return new Promise((resolve) => { + * setTimeout(() => { + * resolve(`result ${i++}`) + * }, 100) + * }) + * }) + * + * const program = Effect.gen(function* () { + * const [cached, invalidate] = yield* Effect.cachedInvalidateWithTTL( + * expensiveTask, + * "1 hour" + * ) + * yield* cached.pipe(Effect.andThen(Console.log)) + * yield* cached.pipe(Effect.andThen(Console.log)) + * yield* invalidate + * yield* cached.pipe(Effect.andThen(Console.log)) + * }) + * + * Effect.runFork(program) + * // Output: + * // expensive task... + * // result 1 + * // result 1 + * // expensive task... + * // result 2 + * ``` + * + * @see {@link cached} for a similar function that caches the result + * indefinitely. + * @see {@link cachedWithTTL} for a similar function that caches the result for + * a specified duration but does not include an effect for manual invalidation. + * + * @since 2.0.0 + * @category Caching + */ + (self: Effect, timeToLive: Duration.DurationInput): Effect<[Effect, Effect], never, R> +} = circular.cachedInvalidateWithTTL + +/** + * Returns an effect that lazily computes a result and caches it for subsequent + * evaluations. + * + * **Details** + * + * This function wraps an effect and ensures that its result is computed only + * once. Once the result is computed, it is cached, meaning that subsequent + * evaluations of the same effect will return the cached result without + * re-executing the logic. + * + * **When to Use** + * + * Use this function when you have an expensive or time-consuming operation that + * you want to avoid repeating. The first evaluation will compute the result, + * and all following evaluations will immediately return the cached value, + * improving performance and reducing unnecessary work. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * let i = 1 + * const expensiveTask = Effect.promise(() => { + * console.log("expensive task...") + * return new Promise((resolve) => { + * setTimeout(() => { + * resolve(`result ${i++}`) + * }, 100) + * }) + * }) + * + * const program = Effect.gen(function* () { + * console.log("non-cached version:") + * yield* expensiveTask.pipe(Effect.andThen(Console.log)) + * yield* expensiveTask.pipe(Effect.andThen(Console.log)) + * console.log("cached version:") + * const cached = yield* Effect.cached(expensiveTask) + * yield* cached.pipe(Effect.andThen(Console.log)) + * yield* cached.pipe(Effect.andThen(Console.log)) + * }) + * + * Effect.runFork(program) + * // Output: + * // non-cached version: + * // expensive task... + * // result 1 + * // expensive task... + * // result 2 + * // cached version: + * // expensive task... + * // result 3 + * // result 3 + * ``` + * + * @see {@link cachedWithTTL} for a similar function that includes a + * time-to-live duration for the cached value. + * @see {@link cachedInvalidateWithTTL} for a similar function that includes an + * additional effect for manually invalidating the cached value. + * + * @since 2.0.0 + * @category Caching + */ +export const cached: (self: Effect) => Effect> = effect.memoize + +/** + * Returns a memoized version of a function with effects, reusing results for + * the same inputs. + * + * **Details** + * + * This function creates a memoized version of a given function that performs an + * effect. Memoization ensures that once a result is computed for a specific + * input, it is stored and reused for subsequent calls with the same input, + * reducing the need to recompute the result. + * + * The function can optionally take an `Equivalence` parameter to + * determine how inputs are compared for caching purposes. + * + * **When to Use** + * + * Use this function when you have a function that performs an effect and you + * want to avoid recomputing the result for the same input multiple times. + * + * It's ideal for functions that produce deterministic results based on their + * inputs, and you want to improve performance by caching the output. + * + * This is particularly useful in scenarios where the function involves + * expensive calculations or operations that should be avoided after the first + * execution with the same parameters. + * + * **Example** + * + * ```ts + * import { Effect, Random } from "effect" + * + * const program = Effect.gen(function* () { + * const randomNumber = (n: number) => Random.nextIntBetween(1, n) + * console.log("non-memoized version:") + * console.log(yield* randomNumber(10)) + * console.log(yield* randomNumber(10)) + * + * console.log("memoized version:") + * const memoized = yield* Effect.cachedFunction(randomNumber) + * console.log(yield* memoized(10)) + * console.log(yield* memoized(10)) + * }) + * + * Effect.runFork(program) + * // Example Output: + * // non-memoized version: + * // 2 + * // 8 + * // memoized version: + * // 5 + * // 5 + * ``` + * + * @since 2.0.0 + * @category Caching + */ +export const cachedFunction: ( + f: (a: A) => Effect, + eq?: Equivalence +) => Effect<(a: A) => Effect> = circular.cachedFunction + +/** + * Returns an effect that executes only once, regardless of how many times it's + * called. + * + * **Details** + * + * This function ensures that a specific effect is executed only a single time, + * no matter how many times it is invoked. The result of the effect will be + * cached, and subsequent calls to the effect will immediately return the cached + * result without re-executing the original logic. + * + * **When to Use** + * + * Use this function when you need to perform a task only once, regardless of + * how many times the effect is triggered. It's particularly useful when you + * have initialization tasks, logging, or other one-time actions that should not + * be repeated. This can help optimize performance and avoid redundant actions. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * const program = Effect.gen(function* () { + * const task1 = Console.log("task1") + * yield* Effect.repeatN(task1, 2) + * const task2 = yield* Effect.once(Console.log("task2")) + * yield* Effect.repeatN(task2, 2) + * }) + * + * Effect.runFork(program) + * // Output: + * // task1 + * // task1 + * // task1 + * // task2 + * ``` + * + * @since 2.0.0 + * @category Caching + */ +export const once: (self: Effect) => Effect> = effect.once + +/** + * Combines multiple effects into one, returning results based on the input + * structure. + * + * **Details** + * + * Use this function when you need to run multiple effects and combine their + * results into a single output. It supports tuples, iterables, structs, and + * records, making it flexible for different input types. + * + * For instance, if the input is a tuple: + * + * ```ts skip-type-checking + * // ┌─── a tuple of effects + * // ▼ + * Effect.all([effect1, effect2, ...]) + * ``` + * + * the effects are executed sequentially, and the result is a new effect + * containing the results as a tuple. The results in the tuple match the order + * of the effects passed to `Effect.all`. + * + * **Concurrency** + * + * You can control the execution order (e.g., sequential vs. concurrent) using + * the `concurrency` option. + * + * **Short-Circuiting Behavior** + * + * This function stops execution on the first error it encounters, this is + * called "short-circuiting". If any effect in the collection fails, the + * remaining effects will not run, and the error will be propagated. To change + * this behavior, you can use the `mode` option, which allows all effects to run + * and collect results as `Either` or `Option`. + * + * **The `mode` option** + * + * The `{ mode: "either" }` option changes the behavior of `Effect.all` to + * ensure all effects run, even if some fail. Instead of stopping on the first + * failure, this mode collects both successes and failures, returning an array + * of `Either` instances where each result is either a `Right` (success) or a + * `Left` (failure). + * + * Similarly, the `{ mode: "validate" }` option uses `Option` to indicate + * success or failure. Each effect returns `None` for success and `Some` with + * the error for failure. + * + * **Example** (Combining Effects in Tuples) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const tupleOfEffects = [ + * Effect.succeed(42).pipe(Effect.tap(Console.log)), + * Effect.succeed("Hello").pipe(Effect.tap(Console.log)) + * ] as const + * + * // ┌─── Effect<[number, string], never, never> + * // ▼ + * const resultsAsTuple = Effect.all(tupleOfEffects) + * + * Effect.runPromise(resultsAsTuple).then(console.log) + * // Output: + * // 42 + * // Hello + * // [ 42, 'Hello' ] + * ``` + * + * **Example** (Combining Effects in Iterables) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const iterableOfEffects: Iterable> = [1, 2, 3].map( + * (n) => Effect.succeed(n).pipe(Effect.tap(Console.log)) + * ) + * + * // ┌─── Effect + * // ▼ + * const resultsAsArray = Effect.all(iterableOfEffects) + * + * Effect.runPromise(resultsAsArray).then(console.log) + * // Output: + * // 1 + * // 2 + * // 3 + * // [ 1, 2, 3 ] + * ``` + * + * **Example** (Combining Effects in Structs) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const structOfEffects = { + * a: Effect.succeed(42).pipe(Effect.tap(Console.log)), + * b: Effect.succeed("Hello").pipe(Effect.tap(Console.log)) + * } + * + * // ┌─── Effect<{ a: number; b: string; }, never, never> + * // ▼ + * const resultsAsStruct = Effect.all(structOfEffects) + * + * Effect.runPromise(resultsAsStruct).then(console.log) + * // Output: + * // 42 + * // Hello + * // { a: 42, b: 'Hello' } + * ``` + * + * **Example** (Combining Effects in Records) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const recordOfEffects: Record> = { + * key1: Effect.succeed(1).pipe(Effect.tap(Console.log)), + * key2: Effect.succeed(2).pipe(Effect.tap(Console.log)) + * } + * + * // ┌─── Effect<{ [x: string]: number; }, never, never> + * // ▼ + * const resultsAsRecord = Effect.all(recordOfEffects) + * + * Effect.runPromise(resultsAsRecord).then(console.log) + * // Output: + * // 1 + * // 2 + * // { key1: 1, key2: 2 } + * ``` + * + * **Example** (Short-Circuiting Behavior) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const program = Effect.all([ + * Effect.succeed("Task1").pipe(Effect.tap(Console.log)), + * Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), + * // Won't execute due to earlier failure + * Effect.succeed("Task3").pipe(Effect.tap(Console.log)) + * ]) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // Task1 + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Task2: Oh no!' } + * // } + * ``` + * + * **Example** (Collecting Results with `mode: "either"`) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const effects = [ + * Effect.succeed("Task1").pipe(Effect.tap(Console.log)), + * Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), + * Effect.succeed("Task3").pipe(Effect.tap(Console.log)) + * ] + * + * const program = Effect.all(effects, { mode: "either" }) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // Task1 + * // Task3 + * // { + * // _id: 'Exit', + * // _tag: 'Success', + * // value: [ + * // { _id: 'Either', _tag: 'Right', right: 'Task1' }, + * // { _id: 'Either', _tag: 'Left', left: 'Task2: Oh no!' }, + * // { _id: 'Either', _tag: 'Right', right: 'Task3' } + * // ] + * // } + * ``` + * + * **Example** (Collecting Results with `mode: "validate"`) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const effects = [ + * Effect.succeed("Task1").pipe(Effect.tap(Console.log)), + * Effect.fail("Task2: Oh no!").pipe(Effect.tap(Console.log)), + * Effect.succeed("Task3").pipe(Effect.tap(Console.log)) + * ] + * + * const program = Effect.all(effects, { mode: "validate" }) + * + * Effect.runPromiseExit(program).then((result) => console.log("%o", result)) + * // Output: + * // Task1 + * // Task3 + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: [ + * // { _id: 'Option', _tag: 'None' }, + * // { _id: 'Option', _tag: 'Some', value: 'Task2: Oh no!' }, + * // { _id: 'Option', _tag: 'None' } + * // ] + * // } + * // } + * ``` + * + * @see {@link forEach} for iterating over elements and applying an effect. + * @see {@link allWith} for a data-last version of this function. + * + * @since 2.0.0 + * @category Collecting + */ +export const all: < + const Arg extends Iterable> | Record>, + O extends NoExcessProperties<{ + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard?: boolean | undefined + readonly mode?: "default" | "validate" | "either" | undefined + readonly concurrentFinalizers?: boolean | undefined + }, O> +>(arg: Arg, options?: O) => All.Return = fiberRuntime.all + +/** + * A data-last version of {@link all}, designed for use in pipelines. + * + * **When to Use** + * + * This function enables you to combine multiple effects and customize execution + * options such as concurrency levels. This version is useful in functional + * pipelines where you first define your data and then apply operations to it. + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * const program = pipe( + * [task1, task2], + * // Run both effects concurrently using the concurrent option + * Effect.allWith({ concurrency: 2 }) + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#3 message="task2 done" + * // timestamp=... level=INFO fiber=#2 message="task1 done" + * // [ 1, 'hello' ] + * ``` + * + * @since 2.0.0 + * @category Collecting + */ +export const allWith: < + O extends NoExcessProperties<{ + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard?: boolean | undefined + readonly mode?: "default" | "validate" | "either" | undefined + readonly concurrentFinalizers?: boolean | undefined + }, O> +>( + options?: O +) => > | Record>>( + arg: Arg +) => All.Return = fiberRuntime.allWith + +/** + * @since 2.0.0 + */ +export declare namespace All { + /** + * @since 2.0.0 + */ + export type EffectAny = Effect + + /** + * @since 2.0.0 + */ + export type ReturnIterable, Discard extends boolean, Mode> = [T] extends + [Iterable>] ? Effect< + Discard extends true ? void : Mode extends "either" ? Array> : Array, + Mode extends "either" ? never + : Mode extends "validate" ? Array> + : L0, + R + > + : never + + /** + * @since 2.0.0 + */ + export type ReturnTuple, Discard extends boolean, Mode> = Effect< + Discard extends true ? void + : T[number] extends never ? [] + : Mode extends "either" ? { + -readonly [K in keyof T]: [T[K]] extends [Effect.Variance] ? + Either.Either<_A, _E> + : never + } + : { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance] ? _A : never }, + Mode extends "either" ? never + : T[number] extends never ? never + : Mode extends "validate" ? { + -readonly [K in keyof T]: [T[K]] extends [Effect.Variance] ? Option.Option<_E> + : never + } + : [T[number]] extends [{ [EffectTypeId]: { _E: (_: never) => infer E } }] ? E + : never, + T[number] extends never ? never + : [T[number]] extends [{ [EffectTypeId]: { _R: (_: never) => infer R } }] ? R + : never + > extends infer X ? X : never + + /** + * @since 2.0.0 + */ + export type ReturnObject = [T] extends [{ [K: string]: EffectAny }] ? Effect< + Discard extends true ? void + : Mode extends "either" ? { + -readonly [K in keyof T]: [T[K]] extends [Effect.Variance] ? + Either.Either<_A, _E> + : never + } + : { -readonly [K in keyof T]: [T[K]] extends [Effect.Variance] ? _A : never }, + Mode extends "either" ? never + : keyof T extends never ? never + : Mode extends "validate" ? { + -readonly [K in keyof T]: [T[K]] extends [Effect.Variance] ? Option.Option<_E> + : never + } + : [T[keyof T]] extends [{ [EffectTypeId]: { _E: (_: never) => infer E } }] ? E + : never, + keyof T extends never ? never + : [T[keyof T]] extends [{ [EffectTypeId]: { _R: (_: never) => infer R } }] ? R + : never + > + : never + + /** + * @since 2.0.0 + */ + export type IsDiscard = [Extract] extends [never] ? false : true + + /** + * @since 2.0.0 + */ + export type ExtractMode = [A] extends [{ mode: infer M }] ? M : "default" + + /** + * @since 2.0.0 + */ + export type Return< + Arg extends Iterable | Record, + O extends NoExcessProperties<{ + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard?: boolean | undefined + readonly mode?: "default" | "validate" | "either" | undefined + readonly concurrentFinalizers?: boolean | undefined + }, O> + > = [Arg] extends [ReadonlyArray] ? ReturnTuple, ExtractMode> + : [Arg] extends [Iterable] ? ReturnIterable, ExtractMode> + : [Arg] extends [Record] ? ReturnObject, ExtractMode> + : never +} + +/** + * Evaluates and runs each effect in the iterable, collecting only the + * successful results while discarding failures. + * + * **Details** + * + * This function function processes an iterable of effects and runs each one. If + * an effect is successful, its result is collected; if it fails, the result is + * discarded. This ensures that only successful outcomes are kept. + * + * **Options** + * + * The function also allows you to customize how the effects are handled by + * specifying options such as concurrency, batching, and how finalizers behave. + * These options provide flexibility in running the effects concurrently or + * adjusting other execution details. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const tasks = [ + * Effect.succeed(1), + * Effect.fail("Error 1"), + * Effect.succeed(2), + * Effect.fail("Error 2") + * ] + * + * const program = Effect.gen(function*() { + * const successfulResults = yield* Effect.allSuccesses(tasks) + * console.log(successfulResults) + * }) + * + * Effect.runFork(program) + * // Output: [1, 2] + * + * ``` + * + * @since 2.0.0 + * @category Collecting + */ +export const allSuccesses: >( + elements: Iterable, + options?: + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined +) => Effect>, never, Effect.Context> = fiberRuntime.allSuccesses + +/** + * Drops elements until the effectful predicate returns `true`. + * + * **Details** + * + * This function processes a collection of elements and uses an effectful + * predicate to determine when to stop dropping elements. It drops elements from + * the beginning of the collection until the predicate returns `true`. + * + * The predicate is a function that takes an element and its index in the + * collection and returns an effect that evaluates to a boolean. + * + * Once the predicate returns `true`, the remaining elements of the collection + * are returned. + * + * **Note**: The first element for which the predicate returns `true` is also + * dropped. + * + * **When to Use** + * + * This function allows you to conditionally skip over a part of the collection + * based on some criteria defined in the predicate. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5, 6] + * const predicate = (n: number, i: number) => Effect.succeed(n > 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.dropUntil(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [5, 6] + * ``` + * + * @see {@link dropWhile} for a similar function that drops elements while the + * predicate returns `true`. + * + * @since 2.0.0 + * @category Collecting + */ +export const dropUntil: { + /** + * Drops elements until the effectful predicate returns `true`. + * + * **Details** + * + * This function processes a collection of elements and uses an effectful + * predicate to determine when to stop dropping elements. It drops elements from + * the beginning of the collection until the predicate returns `true`. + * + * The predicate is a function that takes an element and its index in the + * collection and returns an effect that evaluates to a boolean. + * + * Once the predicate returns `true`, the remaining elements of the collection + * are returned. + * + * **Note**: The first element for which the predicate returns `true` is also + * dropped. + * + * **When to Use** + * + * This function allows you to conditionally skip over a part of the collection + * based on some criteria defined in the predicate. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5, 6] + * const predicate = (n: number, i: number) => Effect.succeed(n > 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.dropUntil(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [5, 6] + * ``` + * + * @see {@link dropWhile} for a similar function that drops elements while the + * predicate returns `true`. + * + * @since 2.0.0 + * @category Collecting + */ + (predicate: (a: NoInfer, i: number) => Effect): (elements: Iterable) => Effect, E, R> + /** + * Drops elements until the effectful predicate returns `true`. + * + * **Details** + * + * This function processes a collection of elements and uses an effectful + * predicate to determine when to stop dropping elements. It drops elements from + * the beginning of the collection until the predicate returns `true`. + * + * The predicate is a function that takes an element and its index in the + * collection and returns an effect that evaluates to a boolean. + * + * Once the predicate returns `true`, the remaining elements of the collection + * are returned. + * + * **Note**: The first element for which the predicate returns `true` is also + * dropped. + * + * **When to Use** + * + * This function allows you to conditionally skip over a part of the collection + * based on some criteria defined in the predicate. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5, 6] + * const predicate = (n: number, i: number) => Effect.succeed(n > 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.dropUntil(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [5, 6] + * ``` + * + * @see {@link dropWhile} for a similar function that drops elements while the + * predicate returns `true`. + * + * @since 2.0.0 + * @category Collecting + */ + ( + elements: Iterable, + predicate: (a: A, i: number) => Effect + ): Effect, E, R> +} = effect.dropUntil + +/** + * Drops elements as long as the predicate returns `true`. + * + * **Details** + * + * This function processes a collection of elements and uses a predicate to + * decide whether to drop an element. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * As long as the predicate returns `true`, elements will continue to be dropped + * from the collection. + * + * Once the predicate returns `false`, the remaining elements are kept. + * + * **When to Use** + * + * This function allows you to discard elements from the start of a collection + * based on a condition, and only keep the rest when the condition no longer + * holds. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5, 6] + * const predicate = (n: number, i: number) => Effect.succeed(n <= 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.dropWhile(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [4, 5, 6] + * ``` + * + * @see {@link dropUntil} for a similar function that drops elements until the + * predicate returns `true`. + * + * @since 2.0.0 + * @category Collecting + */ +export const dropWhile: { + /** + * Drops elements as long as the predicate returns `true`. + * + * **Details** + * + * This function processes a collection of elements and uses a predicate to + * decide whether to drop an element. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * As long as the predicate returns `true`, elements will continue to be dropped + * from the collection. + * + * Once the predicate returns `false`, the remaining elements are kept. + * + * **When to Use** + * + * This function allows you to discard elements from the start of a collection + * based on a condition, and only keep the rest when the condition no longer + * holds. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5, 6] + * const predicate = (n: number, i: number) => Effect.succeed(n <= 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.dropWhile(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [4, 5, 6] + * ``` + * + * @see {@link dropUntil} for a similar function that drops elements until the + * predicate returns `true`. + * + * @since 2.0.0 + * @category Collecting + */ + (predicate: (a: NoInfer, i: number) => Effect): (elements: Iterable) => Effect, E, R> + /** + * Drops elements as long as the predicate returns `true`. + * + * **Details** + * + * This function processes a collection of elements and uses a predicate to + * decide whether to drop an element. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * As long as the predicate returns `true`, elements will continue to be dropped + * from the collection. + * + * Once the predicate returns `false`, the remaining elements are kept. + * + * **When to Use** + * + * This function allows you to discard elements from the start of a collection + * based on a condition, and only keep the rest when the condition no longer + * holds. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5, 6] + * const predicate = (n: number, i: number) => Effect.succeed(n <= 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.dropWhile(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [4, 5, 6] + * ``` + * + * @see {@link dropUntil} for a similar function that drops elements until the + * predicate returns `true`. + * + * @since 2.0.0 + * @category Collecting + */ + ( + elements: Iterable, + predicate: (a: A, i: number) => Effect + ): Effect, E, R> +} = effect.dropWhile + +/** + * Takes elements from a collection until the effectful predicate returns + * `true`. + * + * **Details** + * + * This function processes a collection of elements and uses an effectful + * predicate to decide when to stop taking elements. The elements are taken from + * the beginning of the collection until the predicate returns `true`. + * + * The predicate is a function that takes an element and its index in the + * collection, and returns an effect that resolves to a boolean. + * + * Once the predicate returns `true`, the remaining elements of the collection + * are discarded, and the function stops taking more elements. + * + * **Note**: The first element for which the predicate returns `true` is also + * included in the result. + * + * **When to Use** + * + * Use this function when you want to conditionally take elements from a + * collection based on a dynamic condition. For example, you may want to collect + * numbers from a list until a certain threshold is reached, or gather items + * until a specific condition is met. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5, 6] + * const predicate = (n: number, i: number) => Effect.succeed(n > 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.takeUntil(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [ 1, 2, 3, 4 ] + * ``` + * + * @see {@link takeWhile} for a similar function that takes elements while the + * predicate returns `true`. + * + * @since 2.0.0 + * @category Collecting + */ +export const takeUntil: { + /** + * Takes elements from a collection until the effectful predicate returns + * `true`. + * + * **Details** + * + * This function processes a collection of elements and uses an effectful + * predicate to decide when to stop taking elements. The elements are taken from + * the beginning of the collection until the predicate returns `true`. + * + * The predicate is a function that takes an element and its index in the + * collection, and returns an effect that resolves to a boolean. + * + * Once the predicate returns `true`, the remaining elements of the collection + * are discarded, and the function stops taking more elements. + * + * **Note**: The first element for which the predicate returns `true` is also + * included in the result. + * + * **When to Use** + * + * Use this function when you want to conditionally take elements from a + * collection based on a dynamic condition. For example, you may want to collect + * numbers from a list until a certain threshold is reached, or gather items + * until a specific condition is met. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5, 6] + * const predicate = (n: number, i: number) => Effect.succeed(n > 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.takeUntil(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [ 1, 2, 3, 4 ] + * ``` + * + * @see {@link takeWhile} for a similar function that takes elements while the + * predicate returns `true`. + * + * @since 2.0.0 + * @category Collecting + */ + (predicate: (a: NoInfer, i: number) => Effect): (elements: Iterable) => Effect, E, R> + /** + * Takes elements from a collection until the effectful predicate returns + * `true`. + * + * **Details** + * + * This function processes a collection of elements and uses an effectful + * predicate to decide when to stop taking elements. The elements are taken from + * the beginning of the collection until the predicate returns `true`. + * + * The predicate is a function that takes an element and its index in the + * collection, and returns an effect that resolves to a boolean. + * + * Once the predicate returns `true`, the remaining elements of the collection + * are discarded, and the function stops taking more elements. + * + * **Note**: The first element for which the predicate returns `true` is also + * included in the result. + * + * **When to Use** + * + * Use this function when you want to conditionally take elements from a + * collection based on a dynamic condition. For example, you may want to collect + * numbers from a list until a certain threshold is reached, or gather items + * until a specific condition is met. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5, 6] + * const predicate = (n: number, i: number) => Effect.succeed(n > 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.takeUntil(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [ 1, 2, 3, 4 ] + * ``` + * + * @see {@link takeWhile} for a similar function that takes elements while the + * predicate returns `true`. + * + * @since 2.0.0 + * @category Collecting + */ + ( + elements: Iterable, + predicate: (a: NoInfer, i: number) => Effect + ): Effect, E, R> +} = effect.takeUntil + +/** + * Takes elements as long as the predicate returns `true`. + * + * **Details** + * + * This function processes a collection of elements and uses a predicate to + * decide whether to take an element. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * As long as the predicate returns `true`, elements will continue to be taken + * from the collection. + * + * Once the predicate returns `false`, the remaining elements are discarded. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5, 6] + * const predicate = (n: number, i: number) => Effect.succeed(n <= 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.takeWhile(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [1, 2, 3] + * ``` + * + * @see {@link takeUntil} for a similar function that takes elements until the predicate returns `true`. + * + * @since 2.0.0 + * @category Collecting + */ +export const takeWhile: { + /** + * Takes elements as long as the predicate returns `true`. + * + * **Details** + * + * This function processes a collection of elements and uses a predicate to + * decide whether to take an element. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * As long as the predicate returns `true`, elements will continue to be taken + * from the collection. + * + * Once the predicate returns `false`, the remaining elements are discarded. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5, 6] + * const predicate = (n: number, i: number) => Effect.succeed(n <= 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.takeWhile(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [1, 2, 3] + * ``` + * + * @see {@link takeUntil} for a similar function that takes elements until the predicate returns `true`. + * + * @since 2.0.0 + * @category Collecting + */ + (predicate: (a: NoInfer, i: number) => Effect): (elements: Iterable) => Effect, E, R> + /** + * Takes elements as long as the predicate returns `true`. + * + * **Details** + * + * This function processes a collection of elements and uses a predicate to + * decide whether to take an element. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * As long as the predicate returns `true`, elements will continue to be taken + * from the collection. + * + * Once the predicate returns `false`, the remaining elements are discarded. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5, 6] + * const predicate = (n: number, i: number) => Effect.succeed(n <= 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.takeWhile(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [1, 2, 3] + * ``` + * + * @see {@link takeUntil} for a similar function that takes elements until the predicate returns `true`. + * + * @since 2.0.0 + * @category Collecting + */ + ( + elements: Iterable, + predicate: (a: NoInfer, i: number) => Effect + ): Effect, E, R> +} = effect.takeWhile + +/** + * Determines whether all elements of the iterable satisfy the effectful + * predicate. + * + * **Details** + * + * This function checks whether every element in a given collection (an + * iterable) satisfies a condition defined by an effectful predicate. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * The function will process each element and return `true` if all elements + * satisfy the predicate; otherwise, it returns `false`. + * + * **When to Use** + * + * This function is useful when you need to verify that all items in a + * collection meet certain criteria, even when the evaluation of each item + * involves effects, such as asynchronous checks or complex computations. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [2, 4, 6, 8] + * const predicate = (n: number, i: number) => Effect.succeed(n % 2 === 0) + * + * const program = Effect.gen(function*() { + * const allEven = yield* Effect.every(numbers, predicate) + * console.log(allEven) + * }) + * + * Effect.runFork(program) + * // Output: true + * ``` + * + * @see {@link exists} for a similar function that returns a boolean indicating + * whether **any** element satisfies the predicate. + * + * @since 2.0.0 + * @category Condition Checking + */ +export const every: { + /** + * Determines whether all elements of the iterable satisfy the effectful + * predicate. + * + * **Details** + * + * This function checks whether every element in a given collection (an + * iterable) satisfies a condition defined by an effectful predicate. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * The function will process each element and return `true` if all elements + * satisfy the predicate; otherwise, it returns `false`. + * + * **When to Use** + * + * This function is useful when you need to verify that all items in a + * collection meet certain criteria, even when the evaluation of each item + * involves effects, such as asynchronous checks or complex computations. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [2, 4, 6, 8] + * const predicate = (n: number, i: number) => Effect.succeed(n % 2 === 0) + * + * const program = Effect.gen(function*() { + * const allEven = yield* Effect.every(numbers, predicate) + * console.log(allEven) + * }) + * + * Effect.runFork(program) + * // Output: true + * ``` + * + * @see {@link exists} for a similar function that returns a boolean indicating + * whether **any** element satisfies the predicate. + * + * @since 2.0.0 + * @category Condition Checking + */ + (predicate: (a: A, i: number) => Effect): (elements: Iterable) => Effect + /** + * Determines whether all elements of the iterable satisfy the effectful + * predicate. + * + * **Details** + * + * This function checks whether every element in a given collection (an + * iterable) satisfies a condition defined by an effectful predicate. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * The function will process each element and return `true` if all elements + * satisfy the predicate; otherwise, it returns `false`. + * + * **When to Use** + * + * This function is useful when you need to verify that all items in a + * collection meet certain criteria, even when the evaluation of each item + * involves effects, such as asynchronous checks or complex computations. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [2, 4, 6, 8] + * const predicate = (n: number, i: number) => Effect.succeed(n % 2 === 0) + * + * const program = Effect.gen(function*() { + * const allEven = yield* Effect.every(numbers, predicate) + * console.log(allEven) + * }) + * + * Effect.runFork(program) + * // Output: true + * ``` + * + * @see {@link exists} for a similar function that returns a boolean indicating + * whether **any** element satisfies the predicate. + * + * @since 2.0.0 + * @category Condition Checking + */ + ( + elements: Iterable, + predicate: (a: A, i: number) => Effect + ): Effect +} = effect.every + +/** + * Determines whether any element of the iterable satisfies the effectual + * predicate. + * + * **Details** + * + * This function checks whether any element in a given collection (an iterable) + * satisfies a condition defined by an effectful predicate. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * The function will process each element, and if any element satisfies the + * predicate (returns `true`), the function will immediately return `true`. + * + * If none of the elements satisfy the condition, it will return `false`. + * + * **When to Use** + * + * This function allows you to quickly check for a condition in a collection + * without having to manually iterate over it. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4] + * const predicate = (n: number, i: number) => Effect.succeed(n > 2) + * + * const program = Effect.gen(function*() { + * const hasLargeNumber = yield* Effect.exists(numbers, predicate) + * console.log(hasLargeNumber) + * }) + * + * Effect.runFork(program) + * // Output: true + * ``` + * + * @see {@link every} for a similar function that checks if **all** elements + * satisfy the predicate. + * + * @since 2.0.0 + * @category Condition Checking + */ +export const exists: { + /** + * Determines whether any element of the iterable satisfies the effectual + * predicate. + * + * **Details** + * + * This function checks whether any element in a given collection (an iterable) + * satisfies a condition defined by an effectful predicate. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * The function will process each element, and if any element satisfies the + * predicate (returns `true`), the function will immediately return `true`. + * + * If none of the elements satisfy the condition, it will return `false`. + * + * **When to Use** + * + * This function allows you to quickly check for a condition in a collection + * without having to manually iterate over it. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4] + * const predicate = (n: number, i: number) => Effect.succeed(n > 2) + * + * const program = Effect.gen(function*() { + * const hasLargeNumber = yield* Effect.exists(numbers, predicate) + * console.log(hasLargeNumber) + * }) + * + * Effect.runFork(program) + * // Output: true + * ``` + * + * @see {@link every} for a similar function that checks if **all** elements + * satisfy the predicate. + * + * @since 2.0.0 + * @category Condition Checking + */ + ( + predicate: (a: A, i: number) => Effect, + options?: + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): (elements: Iterable) => Effect + /** + * Determines whether any element of the iterable satisfies the effectual + * predicate. + * + * **Details** + * + * This function checks whether any element in a given collection (an iterable) + * satisfies a condition defined by an effectful predicate. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * The function will process each element, and if any element satisfies the + * predicate (returns `true`), the function will immediately return `true`. + * + * If none of the elements satisfy the condition, it will return `false`. + * + * **When to Use** + * + * This function allows you to quickly check for a condition in a collection + * without having to manually iterate over it. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4] + * const predicate = (n: number, i: number) => Effect.succeed(n > 2) + * + * const program = Effect.gen(function*() { + * const hasLargeNumber = yield* Effect.exists(numbers, predicate) + * console.log(hasLargeNumber) + * }) + * + * Effect.runFork(program) + * // Output: true + * ``` + * + * @see {@link every} for a similar function that checks if **all** elements + * satisfy the predicate. + * + * @since 2.0.0 + * @category Condition Checking + */ + ( + elements: Iterable, + predicate: (a: A, i: number) => Effect, + options?: + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): Effect +} = fiberRuntime.exists + +/** + * Filters an iterable using the specified effectful predicate. + * + * **Details** + * + * This function filters a collection (an iterable) by applying an effectful + * predicate. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * The function processes each element in the collection and keeps only those + * that satisfy the condition defined by the predicate. + * + * **Options** + * + * You can also adjust the behavior with options such as concurrency, batching, + * or whether to negate the condition. + * + * **When to Use** + * + * This function allows you to selectively keep or remove elements based on a + * condition that may involve asynchronous or side-effect-causing operations. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5] + * const predicate = (n: number, i: number) => Effect.succeed(n % 2 === 0) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.filter(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [2, 4] + * ``` + * + * @since 2.0.0 + * @category Filtering + */ +export const filter: { + /** + * Filters an iterable using the specified effectful predicate. + * + * **Details** + * + * This function filters a collection (an iterable) by applying an effectful + * predicate. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * The function processes each element in the collection and keeps only those + * that satisfy the condition defined by the predicate. + * + * **Options** + * + * You can also adjust the behavior with options such as concurrency, batching, + * or whether to negate the condition. + * + * **When to Use** + * + * This function allows you to selectively keep or remove elements based on a + * condition that may involve asynchronous or side-effect-causing operations. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5] + * const predicate = (n: number, i: number) => Effect.succeed(n % 2 === 0) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.filter(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [2, 4] + * ``` + * + * @since 2.0.0 + * @category Filtering + */ + ( + predicate: (a: NoInfer, i: number) => Effect, + options?: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly negate?: boolean | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined + ): (elements: Iterable) => Effect, E, R> + /** + * Filters an iterable using the specified effectful predicate. + * + * **Details** + * + * This function filters a collection (an iterable) by applying an effectful + * predicate. + * + * The predicate is a function that takes an element and its index, and it + * returns an effect that evaluates to a boolean. + * + * The function processes each element in the collection and keeps only those + * that satisfy the condition defined by the predicate. + * + * **Options** + * + * You can also adjust the behavior with options such as concurrency, batching, + * or whether to negate the condition. + * + * **When to Use** + * + * This function allows you to selectively keep or remove elements based on a + * condition that may involve asynchronous or side-effect-causing operations. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5] + * const predicate = (n: number, i: number) => Effect.succeed(n % 2 === 0) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.filter(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: [2, 4] + * ``` + * + * @since 2.0.0 + * @category Filtering + */ + ( + elements: Iterable, + predicate: (a: NoInfer, i: number) => Effect, + options?: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly negate?: boolean | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined + ): Effect, E, R> +} = fiberRuntime.filter + +/** + * Filters and maps elements sequentially in one operation. + * + * This function processes each element one by one. It applies a function that + * returns an `Option` to each element. If the function returns `Some`, the + * element is kept; if it returns `None`, the element is removed. The operation + * is done sequentially for each element. + * + * **Example** + * + * ```ts + * import { Console, Effect, Option } from "effect" + * + * const task = (n: number) => + * Effect.succeed(n).pipe( + * Effect.delay(1000 - (n * 100)), + * Effect.tap(Console.log(`task${n} done`)) + * ) + * + * const program = Effect.filterMap( + * [task(1), task(2), task(3), task(4)], + * (n) => n % 2 === 0 ? Option.some(n) : Option.none() + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // task1 done + * // task2 done + * // task3 done + * // task4 done + * // [ 2, 4 ] + * ``` + * + * @since 2.0.0 + * @category Filtering + */ +export const filterMap: { + /** + * Filters and maps elements sequentially in one operation. + * + * This function processes each element one by one. It applies a function that + * returns an `Option` to each element. If the function returns `Some`, the + * element is kept; if it returns `None`, the element is removed. The operation + * is done sequentially for each element. + * + * **Example** + * + * ```ts + * import { Console, Effect, Option } from "effect" + * + * const task = (n: number) => + * Effect.succeed(n).pipe( + * Effect.delay(1000 - (n * 100)), + * Effect.tap(Console.log(`task${n} done`)) + * ) + * + * const program = Effect.filterMap( + * [task(1), task(2), task(3), task(4)], + * (n) => n % 2 === 0 ? Option.some(n) : Option.none() + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // task1 done + * // task2 done + * // task3 done + * // task4 done + * // [ 2, 4 ] + * ``` + * + * @since 2.0.0 + * @category Filtering + */ + , B>(pf: (a: Effect.Success) => Option.Option): (elements: Iterable) => Effect, Effect.Error, Effect.Context> + /** + * Filters and maps elements sequentially in one operation. + * + * This function processes each element one by one. It applies a function that + * returns an `Option` to each element. If the function returns `Some`, the + * element is kept; if it returns `None`, the element is removed. The operation + * is done sequentially for each element. + * + * **Example** + * + * ```ts + * import { Console, Effect, Option } from "effect" + * + * const task = (n: number) => + * Effect.succeed(n).pipe( + * Effect.delay(1000 - (n * 100)), + * Effect.tap(Console.log(`task${n} done`)) + * ) + * + * const program = Effect.filterMap( + * [task(1), task(2), task(3), task(4)], + * (n) => n % 2 === 0 ? Option.some(n) : Option.none() + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // task1 done + * // task2 done + * // task3 done + * // task4 done + * // [ 2, 4 ] + * ``` + * + * @since 2.0.0 + * @category Filtering + */ + , B>(elements: Iterable, pf: (a: Effect.Success) => Option.Option): Effect, Effect.Error, Effect.Context> +} = effect.filterMap + +/** + * Returns the first element that satisfies the effectful predicate. + * + * **Details** + * + * This function processes a collection of elements and applies an effectful + * predicate to each element. + * + * The predicate is a function that takes an element and its index in the + * collection, and it returns an effect that evaluates to a boolean. + * + * The function stops as soon as it finds the first element for which the + * predicate returns `true` and returns that element wrapped in an `Option`. + * + * If no element satisfies the predicate, the result will be `None`. + * + * **When to Use** + * + * This function allows you to efficiently find an element that meets a specific + * condition, even when the evaluation involves effects like asynchronous + * operations or side effects. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5] + * const predicate = (n: number, i: number) => Effect.succeed(n > 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.findFirst(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: { _id: 'Option', _tag: 'Some', value: 4 } + * ``` + * + * @since 2.0.0 + * @category Collecting + */ +export const findFirst: { + /** + * Returns the first element that satisfies the effectful predicate. + * + * **Details** + * + * This function processes a collection of elements and applies an effectful + * predicate to each element. + * + * The predicate is a function that takes an element and its index in the + * collection, and it returns an effect that evaluates to a boolean. + * + * The function stops as soon as it finds the first element for which the + * predicate returns `true` and returns that element wrapped in an `Option`. + * + * If no element satisfies the predicate, the result will be `None`. + * + * **When to Use** + * + * This function allows you to efficiently find an element that meets a specific + * condition, even when the evaluation involves effects like asynchronous + * operations or side effects. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5] + * const predicate = (n: number, i: number) => Effect.succeed(n > 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.findFirst(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: { _id: 'Option', _tag: 'Some', value: 4 } + * ``` + * + * @since 2.0.0 + * @category Collecting + */ + (predicate: (a: NoInfer, i: number) => Effect): (elements: Iterable) => Effect, E, R> + /** + * Returns the first element that satisfies the effectful predicate. + * + * **Details** + * + * This function processes a collection of elements and applies an effectful + * predicate to each element. + * + * The predicate is a function that takes an element and its index in the + * collection, and it returns an effect that evaluates to a boolean. + * + * The function stops as soon as it finds the first element for which the + * predicate returns `true` and returns that element wrapped in an `Option`. + * + * If no element satisfies the predicate, the result will be `None`. + * + * **When to Use** + * + * This function allows you to efficiently find an element that meets a specific + * condition, even when the evaluation involves effects like asynchronous + * operations or side effects. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [1, 2, 3, 4, 5] + * const predicate = (n: number, i: number) => Effect.succeed(n > 3) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.findFirst(numbers, predicate) + * console.log(result) + * }) + * + * Effect.runFork(program) + * // Output: { _id: 'Option', _tag: 'Some', value: 4 } + * ``` + * + * @since 2.0.0 + * @category Collecting + */ + ( + elements: Iterable, + predicate: (a: NoInfer, i: number) => Effect + ): Effect, E, R> +} = effect.findFirst + +/** + * Executes an effectful operation for each element in an `Iterable`. + * + * **Details** + * + * This function applies a provided operation to each element in the iterable, + * producing a new effect that returns an array of results. + * + * If any effect fails, the iteration stops immediately (short-circuiting), and + * the error is propagated. + * + * **Concurrency** + * + * The `concurrency` option controls how many operations are performed + * concurrently. By default, the operations are performed sequentially. + * + * **Discarding Results** + * + * If the `discard` option is set to `true`, the intermediate results are not + * collected, and the final result of the operation is `void`. + * + * **Example** (Applying Effects to Iterable Elements) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const result = Effect.forEach([1, 2, 3, 4, 5], (n, index) => + * Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)) + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at index 0 + * // Currently at index 1 + * // Currently at index 2 + * // Currently at index 3 + * // Currently at index 4 + * // [ 2, 4, 6, 8, 10 ] + * ``` + * + * **Example** (Discarding Results) + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Apply effects but discard the results + * const result = Effect.forEach( + * [1, 2, 3, 4, 5], + * (n, index) => + * Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)), + * { discard: true } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at index 0 + * // Currently at index 1 + * // Currently at index 2 + * // Currently at index 3 + * // Currently at index 4 + * // undefined + * ``` + * + * @see {@link all} for combining multiple effects into one. + * + * @since 2.0.0 + * @category Looping + */ +export const forEach: { + /** + * Executes an effectful operation for each element in an `Iterable`. + * + * **Details** + * + * This function applies a provided operation to each element in the iterable, + * producing a new effect that returns an array of results. + * + * If any effect fails, the iteration stops immediately (short-circuiting), and + * the error is propagated. + * + * **Concurrency** + * + * The `concurrency` option controls how many operations are performed + * concurrently. By default, the operations are performed sequentially. + * + * **Discarding Results** + * + * If the `discard` option is set to `true`, the intermediate results are not + * collected, and the final result of the operation is `void`. + * + * **Example** (Applying Effects to Iterable Elements) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const result = Effect.forEach([1, 2, 3, 4, 5], (n, index) => + * Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)) + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at index 0 + * // Currently at index 1 + * // Currently at index 2 + * // Currently at index 3 + * // Currently at index 4 + * // [ 2, 4, 6, 8, 10 ] + * ``` + * + * **Example** (Discarding Results) + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Apply effects but discard the results + * const result = Effect.forEach( + * [1, 2, 3, 4, 5], + * (n, index) => + * Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)), + * { discard: true } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at index 0 + * // Currently at index 1 + * // Currently at index 2 + * // Currently at index 3 + * // Currently at index 4 + * // undefined + * ``` + * + * @see {@link all} for combining multiple effects into one. + * + * @since 2.0.0 + * @category Looping + */ + >( + f: (a: RA.ReadonlyArray.Infer, i: number) => Effect, + options?: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined + ): ( + self: S + ) => Effect, E, R> + /** + * Executes an effectful operation for each element in an `Iterable`. + * + * **Details** + * + * This function applies a provided operation to each element in the iterable, + * producing a new effect that returns an array of results. + * + * If any effect fails, the iteration stops immediately (short-circuiting), and + * the error is propagated. + * + * **Concurrency** + * + * The `concurrency` option controls how many operations are performed + * concurrently. By default, the operations are performed sequentially. + * + * **Discarding Results** + * + * If the `discard` option is set to `true`, the intermediate results are not + * collected, and the final result of the operation is `void`. + * + * **Example** (Applying Effects to Iterable Elements) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const result = Effect.forEach([1, 2, 3, 4, 5], (n, index) => + * Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)) + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at index 0 + * // Currently at index 1 + * // Currently at index 2 + * // Currently at index 3 + * // Currently at index 4 + * // [ 2, 4, 6, 8, 10 ] + * ``` + * + * **Example** (Discarding Results) + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Apply effects but discard the results + * const result = Effect.forEach( + * [1, 2, 3, 4, 5], + * (n, index) => + * Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)), + * { discard: true } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at index 0 + * // Currently at index 1 + * // Currently at index 2 + * // Currently at index 3 + * // Currently at index 4 + * // undefined + * ``` + * + * @see {@link all} for combining multiple effects into one. + * + * @since 2.0.0 + * @category Looping + */ + ( + f: (a: A, i: number) => Effect, + options: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard: true + readonly concurrentFinalizers?: boolean | undefined + } + ): (self: Iterable) => Effect + /** + * Executes an effectful operation for each element in an `Iterable`. + * + * **Details** + * + * This function applies a provided operation to each element in the iterable, + * producing a new effect that returns an array of results. + * + * If any effect fails, the iteration stops immediately (short-circuiting), and + * the error is propagated. + * + * **Concurrency** + * + * The `concurrency` option controls how many operations are performed + * concurrently. By default, the operations are performed sequentially. + * + * **Discarding Results** + * + * If the `discard` option is set to `true`, the intermediate results are not + * collected, and the final result of the operation is `void`. + * + * **Example** (Applying Effects to Iterable Elements) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const result = Effect.forEach([1, 2, 3, 4, 5], (n, index) => + * Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)) + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at index 0 + * // Currently at index 1 + * // Currently at index 2 + * // Currently at index 3 + * // Currently at index 4 + * // [ 2, 4, 6, 8, 10 ] + * ``` + * + * **Example** (Discarding Results) + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Apply effects but discard the results + * const result = Effect.forEach( + * [1, 2, 3, 4, 5], + * (n, index) => + * Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)), + * { discard: true } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at index 0 + * // Currently at index 1 + * // Currently at index 2 + * // Currently at index 3 + * // Currently at index 4 + * // undefined + * ``` + * + * @see {@link all} for combining multiple effects into one. + * + * @since 2.0.0 + * @category Looping + */ + >( + self: S, + f: (a: RA.ReadonlyArray.Infer, i: number) => Effect, + options?: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined + ): Effect, E, R> + /** + * Executes an effectful operation for each element in an `Iterable`. + * + * **Details** + * + * This function applies a provided operation to each element in the iterable, + * producing a new effect that returns an array of results. + * + * If any effect fails, the iteration stops immediately (short-circuiting), and + * the error is propagated. + * + * **Concurrency** + * + * The `concurrency` option controls how many operations are performed + * concurrently. By default, the operations are performed sequentially. + * + * **Discarding Results** + * + * If the `discard` option is set to `true`, the intermediate results are not + * collected, and the final result of the operation is `void`. + * + * **Example** (Applying Effects to Iterable Elements) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const result = Effect.forEach([1, 2, 3, 4, 5], (n, index) => + * Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)) + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at index 0 + * // Currently at index 1 + * // Currently at index 2 + * // Currently at index 3 + * // Currently at index 4 + * // [ 2, 4, 6, 8, 10 ] + * ``` + * + * **Example** (Discarding Results) + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Apply effects but discard the results + * const result = Effect.forEach( + * [1, 2, 3, 4, 5], + * (n, index) => + * Console.log(`Currently at index ${index}`).pipe(Effect.as(n * 2)), + * { discard: true } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at index 0 + * // Currently at index 1 + * // Currently at index 2 + * // Currently at index 3 + * // Currently at index 4 + * // undefined + * ``` + * + * @see {@link all} for combining multiple effects into one. + * + * @since 2.0.0 + * @category Looping + */ + ( + self: Iterable, + f: (a: A, i: number) => Effect, + options: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard: true + readonly concurrentFinalizers?: boolean | undefined + } + ): Effect +} = fiberRuntime.forEach + +/** + * Returns the first element of the iterable if the collection is non-empty, or + * fails with the error `NoSuchElementException` if the collection is empty. + * + * **When to Use** + * + * This function is useful when you need to retrieve the first item from a + * collection and want to handle the case where the collection might be empty + * without causing an unhandled exception. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // Simulate an async operation + * const fetchNumbers = Effect.succeed([1, 2, 3]).pipe(Effect.delay("100 millis")) + * + * const program = Effect.gen(function*() { + * const firstElement = yield* Effect.head(fetchNumbers) + * console.log(firstElement) + * }) + * + * Effect.runFork(program) + * // Output: 1 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ +export const head: (self: Effect, E, R>) => Effect = + effect.head + +/** + * Merges an `Iterable>` to a single effect. + * + * **Details** + * + * This function takes an iterable of effects and combines them into a single + * effect. It does this by iterating over each effect in the collection and + * applying a function that accumulates results into a "zero" value, which + * starts with an initial value and is updated with each effect's success. + * + * The provided function `f` is called for each element in the iterable, + * allowing you to specify how to combine the results. + * + * **Options** + * + * The function also allows you to customize how the effects are handled by + * specifying options such as concurrency, batching, and how finalizers behave. + * These options provide flexibility in running the effects concurrently or + * adjusting other execution details. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [Effect.succeed(1), Effect.succeed(2), Effect.succeed(3)] + * const add = (sum: number, value: number, i: number) => sum + value + * const zero = 0 + * + * const program = Effect.gen(function*() { + * const total = yield* Effect.mergeAll(numbers, zero, add) + * console.log(total) + * }) + * + * Effect.runFork(program) + * // Output: 6 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ +export const mergeAll: { + /** + * Merges an `Iterable>` to a single effect. + * + * **Details** + * + * This function takes an iterable of effects and combines them into a single + * effect. It does this by iterating over each effect in the collection and + * applying a function that accumulates results into a "zero" value, which + * starts with an initial value and is updated with each effect's success. + * + * The provided function `f` is called for each element in the iterable, + * allowing you to specify how to combine the results. + * + * **Options** + * + * The function also allows you to customize how the effects are handled by + * specifying options such as concurrency, batching, and how finalizers behave. + * These options provide flexibility in running the effects concurrently or + * adjusting other execution details. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [Effect.succeed(1), Effect.succeed(2), Effect.succeed(3)] + * const add = (sum: number, value: number, i: number) => sum + value + * const zero = 0 + * + * const program = Effect.gen(function*() { + * const total = yield* Effect.mergeAll(numbers, zero, add) + * console.log(total) + * }) + * + * Effect.runFork(program) + * // Output: 6 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ + >( + zero: Z, + f: (z: Z, a: Effect.Success, i: number) => Z, + options?: + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): (elements: Iterable) => Effect, Effect.Context> + /** + * Merges an `Iterable>` to a single effect. + * + * **Details** + * + * This function takes an iterable of effects and combines them into a single + * effect. It does this by iterating over each effect in the collection and + * applying a function that accumulates results into a "zero" value, which + * starts with an initial value and is updated with each effect's success. + * + * The provided function `f` is called for each element in the iterable, + * allowing you to specify how to combine the results. + * + * **Options** + * + * The function also allows you to customize how the effects are handled by + * specifying options such as concurrency, batching, and how finalizers behave. + * These options provide flexibility in running the effects concurrently or + * adjusting other execution details. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const numbers = [Effect.succeed(1), Effect.succeed(2), Effect.succeed(3)] + * const add = (sum: number, value: number, i: number) => sum + value + * const zero = 0 + * + * const program = Effect.gen(function*() { + * const total = yield* Effect.mergeAll(numbers, zero, add) + * console.log(total) + * }) + * + * Effect.runFork(program) + * // Output: 6 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ + , Z>( + elements: Iterable, + zero: Z, + f: (z: Z, a: Effect.Success, i: number) => Z, + options?: + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): Effect, Effect.Context> +} = fiberRuntime.mergeAll + +/** + * Processes an iterable and applies an effectful function to each element, + * categorizing the results into successes and failures. + * + * **Details** + * + * This function processes each element in the provided iterable by applying an + * effectful function to it. The results are then categorized into two separate + * lists: one for failures and another for successes. This separation allows you + * to handle the two categories differently. Failures are collected in a list + * without interrupting the processing of the remaining elements, so the + * operation continues even if some elements fail. This is particularly useful + * when you need to handle both successful and failed results separately, + * without stopping the entire process on encountering a failure. + * + * **When to Use** + * + * Use this function when you want to process a collection of items and handle + * errors or failures without interrupting the processing of other items. It's + * useful when you need to distinguish between successful and failed results and + * process them separately, for example, when logging errors while continuing to + * work with valid data. The function ensures that failures are captured, while + * successes are processed normally. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect<[string[], number[]], never, never> + * // ▼ + * const program = Effect.partition([0, 1, 2, 3, 4], (n) => { + * if (n % 2 === 0) { + * return Effect.succeed(n) + * } else { + * return Effect.fail(`${n} is not even`) + * } + * }) + * + * Effect.runPromise(program).then(console.log, console.error) + * // Output: + * // [ [ '1 is not even', '3 is not even' ], [ 0, 2, 4 ] ] + * ``` + * + * @see {@link validateAll} for a function that either collects all failures or all successes. + * @see {@link validateFirst} for a function that stops at the first success. + * + * @since 2.0.0 + * @category Error Accumulation + */ +export const partition: { + /** + * Processes an iterable and applies an effectful function to each element, + * categorizing the results into successes and failures. + * + * **Details** + * + * This function processes each element in the provided iterable by applying an + * effectful function to it. The results are then categorized into two separate + * lists: one for failures and another for successes. This separation allows you + * to handle the two categories differently. Failures are collected in a list + * without interrupting the processing of the remaining elements, so the + * operation continues even if some elements fail. This is particularly useful + * when you need to handle both successful and failed results separately, + * without stopping the entire process on encountering a failure. + * + * **When to Use** + * + * Use this function when you want to process a collection of items and handle + * errors or failures without interrupting the processing of other items. It's + * useful when you need to distinguish between successful and failed results and + * process them separately, for example, when logging errors while continuing to + * work with valid data. The function ensures that failures are captured, while + * successes are processed normally. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect<[string[], number[]], never, never> + * // ▼ + * const program = Effect.partition([0, 1, 2, 3, 4], (n) => { + * if (n % 2 === 0) { + * return Effect.succeed(n) + * } else { + * return Effect.fail(`${n} is not even`) + * } + * }) + * + * Effect.runPromise(program).then(console.log, console.error) + * // Output: + * // [ [ '1 is not even', '3 is not even' ], [ 0, 2, 4 ] ] + * ``` + * + * @see {@link validateAll} for a function that either collects all failures or all successes. + * @see {@link validateFirst} for a function that stops at the first success. + * + * @since 2.0.0 + * @category Error Accumulation + */ + ( + f: (a: A, i: number) => Effect, + options?: + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): (elements: Iterable) => Effect<[excluded: Array, satisfying: Array], never, R> + /** + * Processes an iterable and applies an effectful function to each element, + * categorizing the results into successes and failures. + * + * **Details** + * + * This function processes each element in the provided iterable by applying an + * effectful function to it. The results are then categorized into two separate + * lists: one for failures and another for successes. This separation allows you + * to handle the two categories differently. Failures are collected in a list + * without interrupting the processing of the remaining elements, so the + * operation continues even if some elements fail. This is particularly useful + * when you need to handle both successful and failed results separately, + * without stopping the entire process on encountering a failure. + * + * **When to Use** + * + * Use this function when you want to process a collection of items and handle + * errors or failures without interrupting the processing of other items. It's + * useful when you need to distinguish between successful and failed results and + * process them separately, for example, when logging errors while continuing to + * work with valid data. The function ensures that failures are captured, while + * successes are processed normally. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect<[string[], number[]], never, never> + * // ▼ + * const program = Effect.partition([0, 1, 2, 3, 4], (n) => { + * if (n % 2 === 0) { + * return Effect.succeed(n) + * } else { + * return Effect.fail(`${n} is not even`) + * } + * }) + * + * Effect.runPromise(program).then(console.log, console.error) + * // Output: + * // [ [ '1 is not even', '3 is not even' ], [ 0, 2, 4 ] ] + * ``` + * + * @see {@link validateAll} for a function that either collects all failures or all successes. + * @see {@link validateFirst} for a function that stops at the first success. + * + * @since 2.0.0 + * @category Error Accumulation + */ + ( + elements: Iterable, + f: (a: A, i: number) => Effect, + options?: + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): Effect<[excluded: Array, satisfying: Array], never, R> +} = fiberRuntime.partition + +/** + * Reduces an `Iterable` using an effectual function `f`, working + * sequentially from left to right. + * + * **Details** + * + * This function takes an iterable and applies a function `f` to each element in + * the iterable. The function works sequentially, starting with an initial value + * `zero` and then combining it with each element in the collection. The + * provided function `f` is called for each element in the iterable, allowing + * you to accumulate a result based on the current value and the element being + * processed. + * + * **When to Use** + * + * The function is often used for operations like summing a collection of + * numbers or combining results from multiple tasks. It ensures that operations + * are performed one after the other, maintaining the order of the elements. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const processOrder = (id: number) => + * Effect.succeed({ id, price: 100 * id }) + * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) + * + * const program = Effect.reduce( + * [1, 2, 3, 4], + * 0, + * (acc, id, i) => + * processOrder(id) + * .pipe(Effect.map((order) => acc + order.price)) + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Order 1 processed + * // Order 2 processed + * // Order 3 processed + * // Order 4 processed + * // 1000 + * ``` + * + * @see {@link reduceWhile} for a similar function that stops the process based on a predicate. + * @see {@link reduceRight} for a similar function that works from right to left. + * + * @since 2.0.0 + * @category Collecting + */ +export const reduce: { + /** + * Reduces an `Iterable` using an effectual function `f`, working + * sequentially from left to right. + * + * **Details** + * + * This function takes an iterable and applies a function `f` to each element in + * the iterable. The function works sequentially, starting with an initial value + * `zero` and then combining it with each element in the collection. The + * provided function `f` is called for each element in the iterable, allowing + * you to accumulate a result based on the current value and the element being + * processed. + * + * **When to Use** + * + * The function is often used for operations like summing a collection of + * numbers or combining results from multiple tasks. It ensures that operations + * are performed one after the other, maintaining the order of the elements. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const processOrder = (id: number) => + * Effect.succeed({ id, price: 100 * id }) + * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) + * + * const program = Effect.reduce( + * [1, 2, 3, 4], + * 0, + * (acc, id, i) => + * processOrder(id) + * .pipe(Effect.map((order) => acc + order.price)) + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Order 1 processed + * // Order 2 processed + * // Order 3 processed + * // Order 4 processed + * // 1000 + * ``` + * + * @see {@link reduceWhile} for a similar function that stops the process based on a predicate. + * @see {@link reduceRight} for a similar function that works from right to left. + * + * @since 2.0.0 + * @category Collecting + */ + (zero: Z, f: (z: Z, a: A, i: number) => Effect): (elements: Iterable) => Effect + /** + * Reduces an `Iterable` using an effectual function `f`, working + * sequentially from left to right. + * + * **Details** + * + * This function takes an iterable and applies a function `f` to each element in + * the iterable. The function works sequentially, starting with an initial value + * `zero` and then combining it with each element in the collection. The + * provided function `f` is called for each element in the iterable, allowing + * you to accumulate a result based on the current value and the element being + * processed. + * + * **When to Use** + * + * The function is often used for operations like summing a collection of + * numbers or combining results from multiple tasks. It ensures that operations + * are performed one after the other, maintaining the order of the elements. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const processOrder = (id: number) => + * Effect.succeed({ id, price: 100 * id }) + * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) + * + * const program = Effect.reduce( + * [1, 2, 3, 4], + * 0, + * (acc, id, i) => + * processOrder(id) + * .pipe(Effect.map((order) => acc + order.price)) + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Order 1 processed + * // Order 2 processed + * // Order 3 processed + * // Order 4 processed + * // 1000 + * ``` + * + * @see {@link reduceWhile} for a similar function that stops the process based on a predicate. + * @see {@link reduceRight} for a similar function that works from right to left. + * + * @since 2.0.0 + * @category Collecting + */ + ( + elements: Iterable, + zero: Z, + f: (z: Z, a: A, i: number) => Effect + ): Effect +} = effect.reduce + +/** + * Reduces an `Iterable` using an effectual function `body`, working + * sequentially from left to right, stopping the process early when the + * predicate `while` is not satisfied. + * + * **Details** + * + * This function processes a collection of elements, applying a function `body` + * to reduce them to a single value, starting from the first element. It checks + * the value of the accumulator against a predicate (`while`). If at any point + * the predicate returns `false`, the reduction stops, and the accumulated + * result is returned. + * + * **When to Use** + * + * Use this function when you need to reduce a collection of elements, but only + * continue the process as long as a certain condition holds true. For example, + * if you want to sum values in a list but stop as soon as the sum exceeds a + * certain threshold, you can use this function. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const processOrder = (id: number) => + * Effect.succeed({ id, price: 100 * id }) + * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) + * + * const program = Effect.reduceWhile( + * [1, 2, 3, 4], + * 0, + * { + * body: (acc, id, i) => + * processOrder(id) + * .pipe(Effect.map((order) => acc + order.price)), + * while: (acc) => acc < 500 + * } + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Order 1 processed + * // Order 2 processed + * // Order 3 processed + * // 600 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ +export const reduceWhile: { + /** + * Reduces an `Iterable` using an effectual function `body`, working + * sequentially from left to right, stopping the process early when the + * predicate `while` is not satisfied. + * + * **Details** + * + * This function processes a collection of elements, applying a function `body` + * to reduce them to a single value, starting from the first element. It checks + * the value of the accumulator against a predicate (`while`). If at any point + * the predicate returns `false`, the reduction stops, and the accumulated + * result is returned. + * + * **When to Use** + * + * Use this function when you need to reduce a collection of elements, but only + * continue the process as long as a certain condition holds true. For example, + * if you want to sum values in a list but stop as soon as the sum exceeds a + * certain threshold, you can use this function. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const processOrder = (id: number) => + * Effect.succeed({ id, price: 100 * id }) + * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) + * + * const program = Effect.reduceWhile( + * [1, 2, 3, 4], + * 0, + * { + * body: (acc, id, i) => + * processOrder(id) + * .pipe(Effect.map((order) => acc + order.price)), + * while: (acc) => acc < 500 + * } + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Order 1 processed + * // Order 2 processed + * // Order 3 processed + * // 600 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ + ( + zero: Z, + options: { readonly while: Predicate; readonly body: (s: Z, a: A, i: number) => Effect } + ): (elements: Iterable) => Effect + /** + * Reduces an `Iterable` using an effectual function `body`, working + * sequentially from left to right, stopping the process early when the + * predicate `while` is not satisfied. + * + * **Details** + * + * This function processes a collection of elements, applying a function `body` + * to reduce them to a single value, starting from the first element. It checks + * the value of the accumulator against a predicate (`while`). If at any point + * the predicate returns `false`, the reduction stops, and the accumulated + * result is returned. + * + * **When to Use** + * + * Use this function when you need to reduce a collection of elements, but only + * continue the process as long as a certain condition holds true. For example, + * if you want to sum values in a list but stop as soon as the sum exceeds a + * certain threshold, you can use this function. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const processOrder = (id: number) => + * Effect.succeed({ id, price: 100 * id }) + * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) + * + * const program = Effect.reduceWhile( + * [1, 2, 3, 4], + * 0, + * { + * body: (acc, id, i) => + * processOrder(id) + * .pipe(Effect.map((order) => acc + order.price)), + * while: (acc) => acc < 500 + * } + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Order 1 processed + * // Order 2 processed + * // Order 3 processed + * // 600 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ + ( + elements: Iterable, + zero: Z, + options: { readonly while: Predicate; readonly body: (s: Z, a: A, i: number) => Effect } + ): Effect +} = effect.reduceWhile + +/** + * Reduces an `Iterable` using an effectual function `f`, working + * sequentially from right to left. + * + * **Details** + * + * This function takes an iterable and applies a function `f` to each element in + * the iterable. The function works sequentially, starting with an initial value + * `zero` and then combining it with each element in the collection. The + * provided function `f` is called for each element in the iterable, allowing + * you to accumulate a result based on the current value and the element being + * processed. + * + * **When to Use** + * + * The function is often used for operations like summing a collection of + * numbers or combining results from multiple tasks. It ensures that operations + * are performed one after the other, maintaining the order of the elements. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const processOrder = (id: number) => + * Effect.succeed({ id, price: 100 * id }) + * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) + * + * const program = Effect.reduceRight( + * [1, 2, 3, 4], + * 0, + * (id, acc, i) => + * processOrder(id) + * .pipe(Effect.map((order) => acc + order.price)) + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Order 4 processed + * // Order 3 processed + * // Order 2 processed + * // Order 1 processed + * // 1000 + * ``` + * + * @see {@link reduce} for a similar function that works from left to right. + * + * @since 2.0.0 + * @category Collecting + */ +export const reduceRight: { + /** + * Reduces an `Iterable` using an effectual function `f`, working + * sequentially from right to left. + * + * **Details** + * + * This function takes an iterable and applies a function `f` to each element in + * the iterable. The function works sequentially, starting with an initial value + * `zero` and then combining it with each element in the collection. The + * provided function `f` is called for each element in the iterable, allowing + * you to accumulate a result based on the current value and the element being + * processed. + * + * **When to Use** + * + * The function is often used for operations like summing a collection of + * numbers or combining results from multiple tasks. It ensures that operations + * are performed one after the other, maintaining the order of the elements. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const processOrder = (id: number) => + * Effect.succeed({ id, price: 100 * id }) + * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) + * + * const program = Effect.reduceRight( + * [1, 2, 3, 4], + * 0, + * (id, acc, i) => + * processOrder(id) + * .pipe(Effect.map((order) => acc + order.price)) + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Order 4 processed + * // Order 3 processed + * // Order 2 processed + * // Order 1 processed + * // 1000 + * ``` + * + * @see {@link reduce} for a similar function that works from left to right. + * + * @since 2.0.0 + * @category Collecting + */ + (zero: Z, f: (a: A, z: Z, i: number) => Effect): (elements: Iterable) => Effect + /** + * Reduces an `Iterable` using an effectual function `f`, working + * sequentially from right to left. + * + * **Details** + * + * This function takes an iterable and applies a function `f` to each element in + * the iterable. The function works sequentially, starting with an initial value + * `zero` and then combining it with each element in the collection. The + * provided function `f` is called for each element in the iterable, allowing + * you to accumulate a result based on the current value and the element being + * processed. + * + * **When to Use** + * + * The function is often used for operations like summing a collection of + * numbers or combining results from multiple tasks. It ensures that operations + * are performed one after the other, maintaining the order of the elements. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const processOrder = (id: number) => + * Effect.succeed({ id, price: 100 * id }) + * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) + * + * const program = Effect.reduceRight( + * [1, 2, 3, 4], + * 0, + * (id, acc, i) => + * processOrder(id) + * .pipe(Effect.map((order) => acc + order.price)) + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Order 4 processed + * // Order 3 processed + * // Order 2 processed + * // Order 1 processed + * // 1000 + * ``` + * + * @see {@link reduce} for a similar function that works from left to right. + * + * @since 2.0.0 + * @category Collecting + */ + ( + elements: Iterable, + zero: Z, + f: (a: A, z: Z, i: number) => Effect + ): Effect +} = effect.reduceRight + +/** + * Reduces an `Iterable>` to a single effect. + * + * **Details** + * + * This function processes a collection of effects and combines them into one + * single effect. It starts with an initial effect (`zero`) and applies a + * function `f` to each element in the collection. + * + * **Options** + * + * The function also allows you to customize how the effects are handled by + * specifying options such as concurrency, batching, and how finalizers behave. + * These options provide flexibility in running the effects concurrently or + * adjusting other execution details. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const processOrder = (id: number) => + * Effect.succeed({ id, price: 100 * id }) + * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) + * + * const program = Effect.reduceEffect( + * [processOrder(1), processOrder(2), processOrder(3), processOrder(4)], + * Effect.succeed(0), + * (acc, order, i) => acc + order.price + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Order 1 processed + * // Order 2 processed + * // Order 3 processed + * // Order 4 processed + * // 1000 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ +export const reduceEffect: { + /** + * Reduces an `Iterable>` to a single effect. + * + * **Details** + * + * This function processes a collection of effects and combines them into one + * single effect. It starts with an initial effect (`zero`) and applies a + * function `f` to each element in the collection. + * + * **Options** + * + * The function also allows you to customize how the effects are handled by + * specifying options such as concurrency, batching, and how finalizers behave. + * These options provide flexibility in running the effects concurrently or + * adjusting other execution details. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const processOrder = (id: number) => + * Effect.succeed({ id, price: 100 * id }) + * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) + * + * const program = Effect.reduceEffect( + * [processOrder(1), processOrder(2), processOrder(3), processOrder(4)], + * Effect.succeed(0), + * (acc, order, i) => acc + order.price + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Order 1 processed + * // Order 2 processed + * // Order 3 processed + * // Order 4 processed + * // 1000 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ + >( + zero: Effect, + f: (z: NoInfer, a: Effect.Success, i: number) => Z, + options?: + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): (elements: Iterable) => Effect, R | Effect.Context> + /** + * Reduces an `Iterable>` to a single effect. + * + * **Details** + * + * This function processes a collection of effects and combines them into one + * single effect. It starts with an initial effect (`zero`) and applies a + * function `f` to each element in the collection. + * + * **Options** + * + * The function also allows you to customize how the effects are handled by + * specifying options such as concurrency, batching, and how finalizers behave. + * These options provide flexibility in running the effects concurrently or + * adjusting other execution details. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const processOrder = (id: number) => + * Effect.succeed({ id, price: 100 * id }) + * .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100))) + * + * const program = Effect.reduceEffect( + * [processOrder(1), processOrder(2), processOrder(3), processOrder(4)], + * Effect.succeed(0), + * (acc, order, i) => acc + order.price + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Order 1 processed + * // Order 2 processed + * // Order 3 processed + * // Order 4 processed + * // 1000 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ + , Z, E, R>( + elements: Iterable, + zero: Effect, + f: (z: NoInfer, a: Effect.Success, i: number) => Z, + options?: + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): Effect, R | Effect.Context> +} = fiberRuntime.reduceEffect + +/** + * Replicates the given effect `n` times. + * + * **Details** + * + * This function takes an effect and replicates it a specified number of times + * (`n`). The result is an array of `n` effects, each of which is identical to + * the original effect. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const task = Effect.succeed("Hello, World!").pipe( + * Effect.tap(Console.log) + * ) + * + * const program = Effect.gen(function*() { + * // Replicate the task 3 times + * const tasks = Effect.replicate(task, 3) + * for (const t of tasks) { + * // Run each task + * yield* t + * } + * }) + * + * Effect.runFork(program) + * // Output: + * // Hello, World! + * // Hello, World! + * // Hello, World! + * ``` + * + * @since 2.0.0 + */ +export const replicate: { + /** + * Replicates the given effect `n` times. + * + * **Details** + * + * This function takes an effect and replicates it a specified number of times + * (`n`). The result is an array of `n` effects, each of which is identical to + * the original effect. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const task = Effect.succeed("Hello, World!").pipe( + * Effect.tap(Console.log) + * ) + * + * const program = Effect.gen(function*() { + * // Replicate the task 3 times + * const tasks = Effect.replicate(task, 3) + * for (const t of tasks) { + * // Run each task + * yield* t + * } + * }) + * + * Effect.runFork(program) + * // Output: + * // Hello, World! + * // Hello, World! + * // Hello, World! + * ``` + * + * @since 2.0.0 + */ + (n: number): (self: Effect) => Array> + /** + * Replicates the given effect `n` times. + * + * **Details** + * + * This function takes an effect and replicates it a specified number of times + * (`n`). The result is an array of `n` effects, each of which is identical to + * the original effect. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const task = Effect.succeed("Hello, World!").pipe( + * Effect.tap(Console.log) + * ) + * + * const program = Effect.gen(function*() { + * // Replicate the task 3 times + * const tasks = Effect.replicate(task, 3) + * for (const t of tasks) { + * // Run each task + * yield* t + * } + * }) + * + * Effect.runFork(program) + * // Output: + * // Hello, World! + * // Hello, World! + * // Hello, World! + * ``` + * + * @since 2.0.0 + */ + (self: Effect, n: number): Array> +} = fiberRuntime.replicate + +/** + * Performs this effect the specified number of times and collects the results. + * + * **Details** + * + * This function repeats an effect multiple times and collects the results into + * an array. You specify how many times to execute the effect, and it runs that + * many times, either in sequence or concurrently depending on the provided + * options. + * + * **Options** + * + * If the `discard` option is set to `true`, the intermediate results are not + * collected, and the final result of the operation is `void`. + * + * The function also allows you to customize how the effects are handled by + * specifying options such as concurrency, batching, and how finalizers behave. + * These options provide flexibility in running the effects concurrently or + * adjusting other execution details. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * let counter = 0 + * + * const task = Effect.sync(() => ++counter).pipe( + * Effect.tap(() => Console.log(`Task completed`)) + * ) + * + * const program = Effect.gen(function*() { + * // Replicate the task 3 times and collect the results + * const results = yield* Effect.replicateEffect(task, 3) + * yield* Console.log(`Results: ${results.join(", ")}`) + * }) + * + * Effect.runFork(program) + * // Output: + * // Task completed + * // Task completed + * // Task completed + * // Results: 1, 2, 3 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ +export const replicateEffect: { + /** + * Performs this effect the specified number of times and collects the results. + * + * **Details** + * + * This function repeats an effect multiple times and collects the results into + * an array. You specify how many times to execute the effect, and it runs that + * many times, either in sequence or concurrently depending on the provided + * options. + * + * **Options** + * + * If the `discard` option is set to `true`, the intermediate results are not + * collected, and the final result of the operation is `void`. + * + * The function also allows you to customize how the effects are handled by + * specifying options such as concurrency, batching, and how finalizers behave. + * These options provide flexibility in running the effects concurrently or + * adjusting other execution details. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * let counter = 0 + * + * const task = Effect.sync(() => ++counter).pipe( + * Effect.tap(() => Console.log(`Task completed`)) + * ) + * + * const program = Effect.gen(function*() { + * // Replicate the task 3 times and collect the results + * const results = yield* Effect.replicateEffect(task, 3) + * yield* Console.log(`Results: ${results.join(", ")}`) + * }) + * + * Effect.runFork(program) + * // Output: + * // Task completed + * // Task completed + * // Task completed + * // Results: 1, 2, 3 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ + ( + n: number, + options?: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined + } + ): (self: Effect) => Effect, E, R> + /** + * Performs this effect the specified number of times and collects the results. + * + * **Details** + * + * This function repeats an effect multiple times and collects the results into + * an array. You specify how many times to execute the effect, and it runs that + * many times, either in sequence or concurrently depending on the provided + * options. + * + * **Options** + * + * If the `discard` option is set to `true`, the intermediate results are not + * collected, and the final result of the operation is `void`. + * + * The function also allows you to customize how the effects are handled by + * specifying options such as concurrency, batching, and how finalizers behave. + * These options provide flexibility in running the effects concurrently or + * adjusting other execution details. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * let counter = 0 + * + * const task = Effect.sync(() => ++counter).pipe( + * Effect.tap(() => Console.log(`Task completed`)) + * ) + * + * const program = Effect.gen(function*() { + * // Replicate the task 3 times and collect the results + * const results = yield* Effect.replicateEffect(task, 3) + * yield* Console.log(`Results: ${results.join(", ")}`) + * }) + * + * Effect.runFork(program) + * // Output: + * // Task completed + * // Task completed + * // Task completed + * // Results: 1, 2, 3 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ + ( + n: number, + options: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard: true + readonly concurrentFinalizers?: boolean | undefined + } + ): (self: Effect) => Effect + /** + * Performs this effect the specified number of times and collects the results. + * + * **Details** + * + * This function repeats an effect multiple times and collects the results into + * an array. You specify how many times to execute the effect, and it runs that + * many times, either in sequence or concurrently depending on the provided + * options. + * + * **Options** + * + * If the `discard` option is set to `true`, the intermediate results are not + * collected, and the final result of the operation is `void`. + * + * The function also allows you to customize how the effects are handled by + * specifying options such as concurrency, batching, and how finalizers behave. + * These options provide flexibility in running the effects concurrently or + * adjusting other execution details. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * let counter = 0 + * + * const task = Effect.sync(() => ++counter).pipe( + * Effect.tap(() => Console.log(`Task completed`)) + * ) + * + * const program = Effect.gen(function*() { + * // Replicate the task 3 times and collect the results + * const results = yield* Effect.replicateEffect(task, 3) + * yield* Console.log(`Results: ${results.join(", ")}`) + * }) + * + * Effect.runFork(program) + * // Output: + * // Task completed + * // Task completed + * // Task completed + * // Results: 1, 2, 3 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ + ( + self: Effect, + n: number, + options?: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined + } + ): Effect, E, R> + /** + * Performs this effect the specified number of times and collects the results. + * + * **Details** + * + * This function repeats an effect multiple times and collects the results into + * an array. You specify how many times to execute the effect, and it runs that + * many times, either in sequence or concurrently depending on the provided + * options. + * + * **Options** + * + * If the `discard` option is set to `true`, the intermediate results are not + * collected, and the final result of the operation is `void`. + * + * The function also allows you to customize how the effects are handled by + * specifying options such as concurrency, batching, and how finalizers behave. + * These options provide flexibility in running the effects concurrently or + * adjusting other execution details. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * let counter = 0 + * + * const task = Effect.sync(() => ++counter).pipe( + * Effect.tap(() => Console.log(`Task completed`)) + * ) + * + * const program = Effect.gen(function*() { + * // Replicate the task 3 times and collect the results + * const results = yield* Effect.replicateEffect(task, 3) + * yield* Console.log(`Results: ${results.join(", ")}`) + * }) + * + * Effect.runFork(program) + * // Output: + * // Task completed + * // Task completed + * // Task completed + * // Results: 1, 2, 3 + * ``` + * + * @since 2.0.0 + * @category Collecting + */ + ( + self: Effect, + n: number, + options: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard: true + readonly concurrentFinalizers?: boolean | undefined + } + ): Effect +} = fiberRuntime.replicateEffect + +/** + * Applies an effectful operation to each element in a collection while + * collecting both successes and failures. + * + * **Details** + * + * This function allows you to apply an effectful operation to every item in a + * collection. + * + * Unlike {@link forEach}, which would stop at the first error, this function + * continues processing all elements, accumulating both successes and failures. + * + * **When to Use** + * + * Use this function when you want to process every item in a collection, even + * if some items fail. This is particularly useful when you need to perform + * operations on all elements without halting due to an error. + * + * Keep in mind that if there are any failures, **all successes will be lost**, + * so this function is not suitable when you need to keep the successful results + * in case of errors. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.validateAll([1, 2, 3, 4, 5], (n) => { + * if (n < 4) { + * return Console.log(`item ${n}`).pipe(Effect.as(n)) + * } else { + * return Effect.fail(`${n} is not less that 4`) + * } + * }) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // item 1 + * // item 2 + * // item 3 + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: [ '4 is not less that 4', '5 is not less that 4' ] + * // } + * // } + * ``` + * + * @see {@link forEach} for a similar function that stops at the first error. + * @see {@link partition} when you need to separate successes and failures + * instead of losing successes with errors. + * + * @since 2.0.0 + * @category Error Accumulation + */ +export const validateAll: { + /** + * Applies an effectful operation to each element in a collection while + * collecting both successes and failures. + * + * **Details** + * + * This function allows you to apply an effectful operation to every item in a + * collection. + * + * Unlike {@link forEach}, which would stop at the first error, this function + * continues processing all elements, accumulating both successes and failures. + * + * **When to Use** + * + * Use this function when you want to process every item in a collection, even + * if some items fail. This is particularly useful when you need to perform + * operations on all elements without halting due to an error. + * + * Keep in mind that if there are any failures, **all successes will be lost**, + * so this function is not suitable when you need to keep the successful results + * in case of errors. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.validateAll([1, 2, 3, 4, 5], (n) => { + * if (n < 4) { + * return Console.log(`item ${n}`).pipe(Effect.as(n)) + * } else { + * return Effect.fail(`${n} is not less that 4`) + * } + * }) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // item 1 + * // item 2 + * // item 3 + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: [ '4 is not less that 4', '5 is not less that 4' ] + * // } + * // } + * ``` + * + * @see {@link forEach} for a similar function that stops at the first error. + * @see {@link partition} when you need to separate successes and failures + * instead of losing successes with errors. + * + * @since 2.0.0 + * @category Error Accumulation + */ + ( + f: (a: A, i: number) => Effect, + options?: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined + ): (elements: Iterable) => Effect, RA.NonEmptyArray, R> + /** + * Applies an effectful operation to each element in a collection while + * collecting both successes and failures. + * + * **Details** + * + * This function allows you to apply an effectful operation to every item in a + * collection. + * + * Unlike {@link forEach}, which would stop at the first error, this function + * continues processing all elements, accumulating both successes and failures. + * + * **When to Use** + * + * Use this function when you want to process every item in a collection, even + * if some items fail. This is particularly useful when you need to perform + * operations on all elements without halting due to an error. + * + * Keep in mind that if there are any failures, **all successes will be lost**, + * so this function is not suitable when you need to keep the successful results + * in case of errors. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.validateAll([1, 2, 3, 4, 5], (n) => { + * if (n < 4) { + * return Console.log(`item ${n}`).pipe(Effect.as(n)) + * } else { + * return Effect.fail(`${n} is not less that 4`) + * } + * }) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // item 1 + * // item 2 + * // item 3 + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: [ '4 is not less that 4', '5 is not less that 4' ] + * // } + * // } + * ``` + * + * @see {@link forEach} for a similar function that stops at the first error. + * @see {@link partition} when you need to separate successes and failures + * instead of losing successes with errors. + * + * @since 2.0.0 + * @category Error Accumulation + */ + ( + f: (a: A, i: number) => Effect, + options: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard: true + readonly concurrentFinalizers?: boolean | undefined + } + ): (elements: Iterable) => Effect, R> + /** + * Applies an effectful operation to each element in a collection while + * collecting both successes and failures. + * + * **Details** + * + * This function allows you to apply an effectful operation to every item in a + * collection. + * + * Unlike {@link forEach}, which would stop at the first error, this function + * continues processing all elements, accumulating both successes and failures. + * + * **When to Use** + * + * Use this function when you want to process every item in a collection, even + * if some items fail. This is particularly useful when you need to perform + * operations on all elements without halting due to an error. + * + * Keep in mind that if there are any failures, **all successes will be lost**, + * so this function is not suitable when you need to keep the successful results + * in case of errors. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.validateAll([1, 2, 3, 4, 5], (n) => { + * if (n < 4) { + * return Console.log(`item ${n}`).pipe(Effect.as(n)) + * } else { + * return Effect.fail(`${n} is not less that 4`) + * } + * }) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // item 1 + * // item 2 + * // item 3 + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: [ '4 is not less that 4', '5 is not less that 4' ] + * // } + * // } + * ``` + * + * @see {@link forEach} for a similar function that stops at the first error. + * @see {@link partition} when you need to separate successes and failures + * instead of losing successes with errors. + * + * @since 2.0.0 + * @category Error Accumulation + */ + ( + elements: Iterable, + f: (a: A, i: number) => Effect, + options?: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard?: false | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined + ): Effect, RA.NonEmptyArray, R> + /** + * Applies an effectful operation to each element in a collection while + * collecting both successes and failures. + * + * **Details** + * + * This function allows you to apply an effectful operation to every item in a + * collection. + * + * Unlike {@link forEach}, which would stop at the first error, this function + * continues processing all elements, accumulating both successes and failures. + * + * **When to Use** + * + * Use this function when you want to process every item in a collection, even + * if some items fail. This is particularly useful when you need to perform + * operations on all elements without halting due to an error. + * + * Keep in mind that if there are any failures, **all successes will be lost**, + * so this function is not suitable when you need to keep the successful results + * in case of errors. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.validateAll([1, 2, 3, 4, 5], (n) => { + * if (n < 4) { + * return Console.log(`item ${n}`).pipe(Effect.as(n)) + * } else { + * return Effect.fail(`${n} is not less that 4`) + * } + * }) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // item 1 + * // item 2 + * // item 3 + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: [ '4 is not less that 4', '5 is not less that 4' ] + * // } + * // } + * ``` + * + * @see {@link forEach} for a similar function that stops at the first error. + * @see {@link partition} when you need to separate successes and failures + * instead of losing successes with errors. + * + * @since 2.0.0 + * @category Error Accumulation + */ + ( + elements: Iterable, + f: (a: A, i: number) => Effect, + options: { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly discard: true + readonly concurrentFinalizers?: boolean | undefined + } + ): Effect, R> +} = fiberRuntime.validateAll + +/** + * This function is similar to {@link validateAll} but with a key difference: it + * returns the first successful result or all errors if none of the operations + * succeed. + * + * **Details** + * + * This function processes a collection of elements and applies an effectful + * operation to each. Unlike {@link validateAll}, which accumulates both + * successes and failures, `Effect.validateFirst` stops and returns the first + * success it encounters. If no success occurs, it returns all accumulated + * errors. This can be useful when you are interested in the first successful + * result and want to avoid processing further once a valid result is found. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.validateFirst([1, 2, 3, 4, 5], (n) => { + * if (n < 4) { + * return Effect.fail(`${n} is not less that 4`) + * } else { + * return Console.log(`item ${n}`).pipe(Effect.as(n)) + * } + * }) + * + * Effect.runPromise(program).then(console.log, console.error) + * // Output: + * // item 4 + * // 4 + * ``` + * + * @see {@link validateAll} for a similar function that accumulates all results. + * @see {@link firstSuccessOf} for a similar function that processes multiple + * effects and returns the first successful one or the last error. + * + * @since 2.0.0 + * @category Error Accumulation + */ +export const validateFirst: { + /** + * This function is similar to {@link validateAll} but with a key difference: it + * returns the first successful result or all errors if none of the operations + * succeed. + * + * **Details** + * + * This function processes a collection of elements and applies an effectful + * operation to each. Unlike {@link validateAll}, which accumulates both + * successes and failures, `Effect.validateFirst` stops and returns the first + * success it encounters. If no success occurs, it returns all accumulated + * errors. This can be useful when you are interested in the first successful + * result and want to avoid processing further once a valid result is found. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.validateFirst([1, 2, 3, 4, 5], (n) => { + * if (n < 4) { + * return Effect.fail(`${n} is not less that 4`) + * } else { + * return Console.log(`item ${n}`).pipe(Effect.as(n)) + * } + * }) + * + * Effect.runPromise(program).then(console.log, console.error) + * // Output: + * // item 4 + * // 4 + * ``` + * + * @see {@link validateAll} for a similar function that accumulates all results. + * @see {@link firstSuccessOf} for a similar function that processes multiple + * effects and returns the first successful one or the last error. + * + * @since 2.0.0 + * @category Error Accumulation + */ + ( + f: (a: A, i: number) => Effect, + options?: + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): (elements: Iterable) => Effect, R> + /** + * This function is similar to {@link validateAll} but with a key difference: it + * returns the first successful result or all errors if none of the operations + * succeed. + * + * **Details** + * + * This function processes a collection of elements and applies an effectful + * operation to each. Unlike {@link validateAll}, which accumulates both + * successes and failures, `Effect.validateFirst` stops and returns the first + * success it encounters. If no success occurs, it returns all accumulated + * errors. This can be useful when you are interested in the first successful + * result and want to avoid processing further once a valid result is found. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.validateFirst([1, 2, 3, 4, 5], (n) => { + * if (n < 4) { + * return Effect.fail(`${n} is not less that 4`) + * } else { + * return Console.log(`item ${n}`).pipe(Effect.as(n)) + * } + * }) + * + * Effect.runPromise(program).then(console.log, console.error) + * // Output: + * // item 4 + * // 4 + * ``` + * + * @see {@link validateAll} for a similar function that accumulates all results. + * @see {@link firstSuccessOf} for a similar function that processes multiple + * effects and returns the first successful one or the last error. + * + * @since 2.0.0 + * @category Error Accumulation + */ + ( + elements: Iterable, + f: (a: A, i: number) => Effect, + options?: + | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): Effect, R> +} = fiberRuntime.validateFirst + +/** + * Creates an `Effect` from a callback-based asynchronous function. + * + * **Details** + * + * The `resume` function: + * - Must be called exactly once. Any additional calls will be ignored. + * - Can return an optional `Effect` that will be run if the `Fiber` executing + * this `Effect` is interrupted. This can be useful in scenarios where you + * need to handle resource cleanup if the operation is interrupted. + * - Can receive an `AbortSignal` to handle interruption if needed. + * + * The `FiberId` of the fiber that may complete the async callback may also be + * specified using the `blockingOn` argument. This is called the "blocking + * fiber" because it suspends the fiber executing the `async` effect (i.e. + * semantically blocks the fiber from making progress). Specifying this fiber id + * in cases where it is known will improve diagnostics, but not affect the + * behavior of the returned effect. + * + * **When to Use** + * + * Use `Effect.async` when dealing with APIs that use callback-style instead of + * `async/await` or `Promise`. + * + * **Example** (Wrapping a Callback API) + * + * ```ts + * import { Effect } from "effect" + * import * as NodeFS from "node:fs" + * + * const readFile = (filename: string) => + * Effect.async((resume) => { + * NodeFS.readFile(filename, (error, data) => { + * if (error) { + * // Resume with a failed Effect if an error occurs + * resume(Effect.fail(error)) + * } else { + * // Resume with a succeeded Effect if successful + * resume(Effect.succeed(data)) + * } + * }) + * }) + * + * // ┌─── Effect + * // ▼ + * const program = readFile("example.txt") + * ``` + * + * **Example** (Handling Interruption with Cleanup) + * + * ```ts + * import { Effect, Fiber } from "effect" + * import * as NodeFS from "node:fs" + * + * // Simulates a long-running operation to write to a file + * const writeFileWithCleanup = (filename: string, data: string) => + * Effect.async((resume) => { + * const writeStream = NodeFS.createWriteStream(filename) + * + * // Start writing data to the file + * writeStream.write(data) + * + * // When the stream is finished, resume with success + * writeStream.on("finish", () => resume(Effect.void)) + * + * // In case of an error during writing, resume with failure + * writeStream.on("error", (err) => resume(Effect.fail(err))) + * + * // Handle interruption by returning a cleanup effect + * return Effect.sync(() => { + * console.log(`Cleaning up ${filename}`) + * NodeFS.unlinkSync(filename) + * }) + * }) + * + * const program = Effect.gen(function* () { + * const fiber = yield* Effect.fork( + * writeFileWithCleanup("example.txt", "Some long data...") + * ) + * // Simulate interrupting the fiber after 1 second + * yield* Effect.sleep("1 second") + * yield* Fiber.interrupt(fiber) // This will trigger the cleanup + * }) + * + * // Run the program + * Effect.runPromise(program) + * // Output: + * // Cleaning up example.txt + * ``` + * + * **Example** (Handling Interruption with AbortSignal) + * + * ```ts + * import { Effect, Fiber } from "effect" + * + * // A task that supports interruption using AbortSignal + * const interruptibleTask = Effect.async((resume, signal) => { + * // Handle interruption + * signal.addEventListener("abort", () => { + * console.log("Abort signal received") + * clearTimeout(timeoutId) + * }) + * + * // Simulate a long-running task + * const timeoutId = setTimeout(() => { + * console.log("Operation completed") + * resume(Effect.void) + * }, 2000) + * }) + * + * const program = Effect.gen(function* () { + * const fiber = yield* Effect.fork(interruptibleTask) + * // Simulate interrupting the fiber after 1 second + * yield* Effect.sleep("1 second") + * yield* Fiber.interrupt(fiber) + * }) + * + * // Run the program + * Effect.runPromise(program) + * // Output: + * // Abort signal received + * ``` + * + * @since 2.0.0 + * @category Creating Effects + */ +export const async: ( + resume: (callback: (_: Effect) => void, signal: AbortSignal) => void | Effect, + blockingOn?: FiberId.FiberId +) => Effect = core.async + +/** + * A variant of {@link async} where the registration function may return an `Effect`. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const asyncEffect: ( + register: (callback: (_: Effect) => void) => Effect | void, E2, R2> +) => Effect = runtime_.asyncEffect + +/** + * Low level constructor that enables for custom stack tracing cutpoints. + * + * It is meant to be called with a bag of instructions that become available in + * the "this" of the effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const throwingFunction = () => { throw new Error() } + * const blowUp = Effect.custom(throwingFunction, function() { + * return Effect.succeed(this.effect_instruction_i0()) + * }) + * ``` + * + * @since 2.0.0 + * @category Creating Effects + */ +export const custom: { + /** + * Low level constructor that enables for custom stack tracing cutpoints. + * + * It is meant to be called with a bag of instructions that become available in + * the "this" of the effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const throwingFunction = () => { throw new Error() } + * const blowUp = Effect.custom(throwingFunction, function() { + * return Effect.succeed(this.effect_instruction_i0()) + * }) + * ``` + * + * @since 2.0.0 + * @category Creating Effects + */ + (i0: X, body: (this: { effect_instruction_i0: X }) => Effect): Effect + /** + * Low level constructor that enables for custom stack tracing cutpoints. + * + * It is meant to be called with a bag of instructions that become available in + * the "this" of the effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const throwingFunction = () => { throw new Error() } + * const blowUp = Effect.custom(throwingFunction, function() { + * return Effect.succeed(this.effect_instruction_i0()) + * }) + * ``` + * + * @since 2.0.0 + * @category Creating Effects + */ + ( + i0: X, + i1: Y, + body: (this: { effect_instruction_i0: X; effect_instruction_i1: Y }) => Effect + ): Effect + /** + * Low level constructor that enables for custom stack tracing cutpoints. + * + * It is meant to be called with a bag of instructions that become available in + * the "this" of the effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const throwingFunction = () => { throw new Error() } + * const blowUp = Effect.custom(throwingFunction, function() { + * return Effect.succeed(this.effect_instruction_i0()) + * }) + * ``` + * + * @since 2.0.0 + * @category Creating Effects + */ + ( + i0: X, + i1: Y, + i2: Z, + body: (this: { effect_instruction_i0: X; effect_instruction_i1: Y; effect_instruction_i2: Z }) => Effect + ): Effect +} = core.custom + +/** + * @since 2.0.0 + * @category Creating Effects + */ +export const withFiberRuntime: ( + withRuntime: ( + fiber: Fiber.RuntimeFiber, + status: FiberStatus.Running + ) => Effect +) => Effect = core.withFiberRuntime + +/** + * Creates an `Effect` that represents a recoverable error. + * + * **When to Use** + * + * Use this function to explicitly signal an error in an `Effect`. The error + * will keep propagating unless it is handled. You can handle the error with + * functions like {@link catchAll} or {@link catchTag}. + * + * **Example** (Creating a Failed Effect) + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const failure = Effect.fail( + * new Error("Operation failed due to network error") + * ) + * ``` + * + * @see {@link succeed} to create an effect that represents a successful value. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const fail: (error: E) => Effect = core.fail + +/** + * Creates an `Effect` that fails with the specified error, evaluated lazily. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const failSync: (evaluate: LazyArg) => Effect = core.failSync + +/** + * Creates an `Effect` that fails with the specified `Cause`. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const failCause: (cause: Cause.Cause) => Effect = core.failCause + +/** + * Creates an `Effect` that fails with the specified `Cause`, evaluated lazily. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const failCauseSync: (evaluate: LazyArg>) => Effect = core.failCauseSync + +/** + * Creates an effect that terminates a fiber with a specified error. + * + * **Details** + * + * This function is used to signal a defect, which represents a critical and + * unexpected error in the code. When invoked, it produces an effect that does + * not handle the error and instead terminates the fiber. + * + * The error channel of the resulting effect is of type `never`, indicating that + * it cannot recover from this failure. + * + * **When to Use** + * + * Use this function when encountering unexpected conditions in your code that + * should not be handled as regular errors but instead represent unrecoverable + * defects. + * + * **Example** (Terminating on Division by Zero with a Specified Error) + * + * ```ts + * import { Effect } from "effect" + * + * const divide = (a: number, b: number) => + * b === 0 + * ? Effect.die(new Error("Cannot divide by zero")) + * : Effect.succeed(a / b) + * + * // ┌─── Effect + * // ▼ + * const program = divide(1, 0) + * + * Effect.runPromise(program).catch(console.error) + * // Output: + * // (FiberFailure) Error: Cannot divide by zero + * // ...stack trace... + * ``` + * + * @see {@link dieSync} for a variant that throws a specified error, evaluated + * lazily. + * @see {@link dieMessage} for a variant that throws a `RuntimeException` with a + * message. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const die: (defect: unknown) => Effect = core.die + +/** + * Creates an effect that terminates a fiber with a `RuntimeException` + * containing the specified message. + * + * **Details** + * + * This function is used to signal a defect, representing a critical and + * unexpected error in the code. When invoked, it produces an effect that + * terminates the fiber with a `RuntimeException` carrying the given message. + * + * The resulting effect has an error channel of type `never`, indicating it does + * not handle or recover from the error. + * + * **When to Use** + * + * Use this function when you want to terminate a fiber due to an unrecoverable + * defect and include a clear explanation in the message. + * + * **Example** (Terminating on Division by Zero with a Specified Message) + * + * ```ts + * import { Effect } from "effect" + * + * const divide = (a: number, b: number) => + * b === 0 + * ? Effect.dieMessage("Cannot divide by zero") + * : Effect.succeed(a / b) + * + * // ┌─── Effect + * // ▼ + * const program = divide(1, 0) + * + * Effect.runPromise(program).catch(console.error) + * // Output: + * // (FiberFailure) RuntimeException: Cannot divide by zero + * // ...stack trace... + * ``` + * + * @see {@link die} for a variant that throws a specified error. + * @see {@link dieSync} for a variant that throws a specified error, evaluated + * lazily. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const dieMessage: (message: string) => Effect = core.dieMessage + +/** + * Creates an effect that dies with the specified error, evaluated lazily. + * + * **Details** + * + * This function allows you to create an effect that will terminate with a fatal error. + * The error is provided as a lazy argument, meaning it will only be evaluated when the effect runs. + * + * @see {@link die} if you don't need to evaluate the error lazily. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const dieSync: (evaluate: LazyArg) => Effect = core.dieSync + +/** + * Provides a way to write effectful code using generator functions, simplifying + * control flow and error handling. + * + * **When to Use** + * + * `Effect.gen` allows you to write code that looks and behaves like synchronous + * code, but it can handle asynchronous tasks, errors, and complex control flow + * (like loops and conditions). It helps make asynchronous code more readable + * and easier to manage. + * + * The generator functions work similarly to `async/await` but with more + * explicit control over the execution of effects. You can `yield*` values from + * effects and return the final result at the end. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const addServiceCharge = (amount: number) => amount + 1 + * + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const fetchDiscountRate = Effect.promise(() => Promise.resolve(5)) + * + * export const program = Effect.gen(function* () { + * const transactionAmount = yield* fetchTransactionAmount + * const discountRate = yield* fetchDiscountRate + * const discountedAmount = yield* applyDiscount( + * transactionAmount, + * discountRate + * ) + * const finalAmount = addServiceCharge(discountedAmount) + * return `Final amount to charge: ${finalAmount}` + * }) + * ``` + * + * @since 2.0.0 + * @category Creating Effects + */ +export const gen: { + /** + * Provides a way to write effectful code using generator functions, simplifying + * control flow and error handling. + * + * **When to Use** + * + * `Effect.gen` allows you to write code that looks and behaves like synchronous + * code, but it can handle asynchronous tasks, errors, and complex control flow + * (like loops and conditions). It helps make asynchronous code more readable + * and easier to manage. + * + * The generator functions work similarly to `async/await` but with more + * explicit control over the execution of effects. You can `yield*` values from + * effects and return the final result at the end. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const addServiceCharge = (amount: number) => amount + 1 + * + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const fetchDiscountRate = Effect.promise(() => Promise.resolve(5)) + * + * export const program = Effect.gen(function* () { + * const transactionAmount = yield* fetchTransactionAmount + * const discountRate = yield* fetchDiscountRate + * const discountedAmount = yield* applyDiscount( + * transactionAmount, + * discountRate + * ) + * const finalAmount = addServiceCharge(discountedAmount) + * return `Final amount to charge: ${finalAmount}` + * }) + * ``` + * + * @since 2.0.0 + * @category Creating Effects + */ + >, AEff>(f: (resume: Adapter) => Generator): Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + > + /** + * Provides a way to write effectful code using generator functions, simplifying + * control flow and error handling. + * + * **When to Use** + * + * `Effect.gen` allows you to write code that looks and behaves like synchronous + * code, but it can handle asynchronous tasks, errors, and complex control flow + * (like loops and conditions). It helps make asynchronous code more readable + * and easier to manage. + * + * The generator functions work similarly to `async/await` but with more + * explicit control over the execution of effects. You can `yield*` values from + * effects and return the final result at the end. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const addServiceCharge = (amount: number) => amount + 1 + * + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const fetchDiscountRate = Effect.promise(() => Promise.resolve(5)) + * + * export const program = Effect.gen(function* () { + * const transactionAmount = yield* fetchTransactionAmount + * const discountRate = yield* fetchDiscountRate + * const discountedAmount = yield* applyDiscount( + * transactionAmount, + * discountRate + * ) + * const finalAmount = addServiceCharge(discountedAmount) + * return `Final amount to charge: ${finalAmount}` + * }) + * ``` + * + * @since 2.0.0 + * @category Creating Effects + */ + >, AEff>( + self: Self, + f: (this: Self, resume: Adapter) => Generator + ): Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + > +} = core.gen + +/** + * @since 2.0.0 + * @category Models + */ +export interface Adapter { + (self: Effect): Effect + (a: A, ab: (a: A) => Effect<_A, _E, _R>): Effect<_A, _E, _R> + (a: A, ab: (a: A) => B, bc: (b: B) => Effect<_A, _E, _R>): Effect<_A, _E, _R> + (a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => Effect<_A, _E, _R>): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (g: H) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => S, + st: (s: S) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => S, + st: (s: S) => T, + tu: (s: T) => Effect<_A, _E, _R> + ): Effect<_A, _E, _R> +} + +/** + * An effect that that runs indefinitely and never produces any result. The + * moral equivalent of `while(true) {}`, only without the wasted CPU cycles. + * + * **When to Use** + * + * It could be useful for long-running background tasks or to simulate waiting + * behavior without actually consuming resources. This effect is ideal for cases + * where you want to keep the program alive or in a certain state without + * performing any active work. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const never: Effect = core.never + +/** + * Ensures the `Option` is `None`, returning `void`. Otherwise, raises a + * `NoSuchElementException`. + * + * **Details** + * + * This function checks if the provided `Option` is `None`. If it is, it returns + * an effect that produces no result (i.e., `void`). If the `Option` is not + * `None` (i.e., it contains a value), the function will raise a + * `NoSuchElementException` error. + * + * **When to Use** + * + * This is useful when you want to ensure that a certain value is absent (i.e., + * `None`) before continuing execution, and to handle cases where the value is + * unexpectedly present. + * + * @since 2.0.0 + */ +export const none: ( + self: Effect, E, R> +) => Effect = effect.none + +/** + * Creates an `Effect` that represents an asynchronous computation guaranteed to + * succeed. + * + * **Details** + * + * The provided function (`thunk`) returns a `Promise` that should never reject; if it does, the error + * will be treated as a "defect". + * + * This defect is not a standard error but indicates a flaw in the logic that + * was expected to be error-free. You can think of it similar to an unexpected + * crash in the program, which can be further managed or logged using tools like + * {@link catchAllDefect}. + * + * **Interruptions** + * + * An optional `AbortSignal` can be provided to allow for interruption of the + * wrapped `Promise` API. + * + * **When to Use** + * + * Use this function when you are sure the operation will not reject. + * + * **Example** (Delayed Message) + * + * ```ts + * import { Effect } from "effect" + * + * const delay = (message: string) => + * Effect.promise( + * () => + * new Promise((resolve) => { + * setTimeout(() => { + * resolve(message) + * }, 2000) + * }) + * ) + * + * // ┌─── Effect + * // ▼ + * const program = delay("Async operation completed successfully!") + * ``` + * + * @see {@link tryPromise} for a version that can handle failures. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const promise: ( + evaluate: (signal: AbortSignal) => PromiseLike +) => Effect = effect.promise + +/** + * Creates an `Effect` that always succeeds with a given value. + * + * **When to Use** + * + * Use this function when you need an effect that completes successfully with a + * specific value without any errors or external dependencies. + * + * **Example** (Creating a Successful Effect) + * + * ```ts + * import { Effect } from "effect" + * + * // Creating an effect that represents a successful scenario + * // + * // ┌─── Effect + * // ▼ + * const success = Effect.succeed(42) + * ``` + * + * @see {@link fail} to create an effect that represents a failure. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const succeed: (value: A) => Effect = core.succeed + +/** + * Returns an effect which succeeds with `None`. + * + * **When to Use** + * + * Use this function when you need to represent the absence of a value in your + * code, especially when working with optional data. This can be helpful when + * you want to indicate that no result is available without throwing an error or + * performing additional logic. + * + * @see {@link succeedSome} to create an effect that succeeds with a `Some` value. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const succeedNone: Effect> = effect.succeedNone + +/** + * Returns an effect which succeeds with the value wrapped in a `Some`. + * + * @see {@link succeedNone} for a similar function that returns `None` when the value is absent. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const succeedSome: (value: A) => Effect> = effect.succeedSome + +/** + * Delays the creation of an `Effect` until it is actually needed. + * + * **Details** + * + * The `Effect.suspend` function takes a thunk that represents the effect and + * wraps it in a suspended effect. This means the effect will not be created + * until it is explicitly needed, which is helpful in various scenarios: + * - **Lazy Evaluation**: Helps optimize performance by deferring computations, + * especially when the effect might not be needed, or when its computation is + * expensive. This also ensures that any side effects or scoped captures are + * re-executed on each invocation. + * - **Handling Circular Dependencies**: Useful in managing circular + * dependencies, such as recursive functions that need to avoid eager + * evaluation to prevent stack overflow. + * - **Unifying Return Types**: Can help TypeScript unify return types in + * situations where multiple branches of logic return different effects, + * simplifying type inference. + * + * **When to Use** + * + * Use this function when you need to defer the evaluation of an effect until it + * is required. This is particularly useful for optimizing expensive + * computations, managing circular dependencies, or resolving type inference + * issues. + * + * **Example** (Lazy Evaluation with Side Effects) + * + * ```ts + * import { Effect } from "effect" + * + * let i = 0 + * + * const bad = Effect.succeed(i++) + * + * const good = Effect.suspend(() => Effect.succeed(i++)) + * + * console.log(Effect.runSync(bad)) // Output: 0 + * console.log(Effect.runSync(bad)) // Output: 0 + * + * console.log(Effect.runSync(good)) // Output: 1 + * console.log(Effect.runSync(good)) // Output: 2 + * ``` + * + * **Example** (Recursive Fibonacci) + * + * ```ts + * import { Effect } from "effect" + * + * const blowsUp = (n: number): Effect.Effect => + * n < 2 + * ? Effect.succeed(1) + * : Effect.zipWith(blowsUp(n - 1), blowsUp(n - 2), (a, b) => a + b) + * + * console.log(Effect.runSync(blowsUp(32))) + * // crash: JavaScript heap out of memory + * + * const allGood = (n: number): Effect.Effect => + * n < 2 + * ? Effect.succeed(1) + * : Effect.zipWith( + * Effect.suspend(() => allGood(n - 1)), + * Effect.suspend(() => allGood(n - 2)), + * (a, b) => a + b + * ) + * + * console.log(Effect.runSync(allGood(32))) + * // Output: 3524578 + * ``` + * + * **Example** (Using Effect.suspend to Help TypeScript Infer Types) + * + * ```ts + * import { Effect } from "effect" + * + * // Without suspend, TypeScript may struggle with type inference. + * // Inferred type: + * // (a: number, b: number) => + * // Effect | Effect + * const withoutSuspend = (a: number, b: number) => + * b === 0 + * ? Effect.fail(new Error("Cannot divide by zero")) + * : Effect.succeed(a / b) + * + * // Using suspend to unify return types. + * // Inferred type: + * // (a: number, b: number) => Effect + * const withSuspend = (a: number, b: number) => + * Effect.suspend(() => + * b === 0 + * ? Effect.fail(new Error("Cannot divide by zero")) + * : Effect.succeed(a / b) + * ) + * ``` + * + * @since 2.0.0 + * @category Creating Effects + */ +export const suspend: (effect: LazyArg>) => Effect = core.suspend + +/** + * Creates an `Effect` that represents a synchronous side-effectful computation. + * + * **Details** + * + * The provided function (`thunk`) must not throw errors; if it does, the error + * will be treated as a "defect". + * + * This defect is not a standard error but indicates a flaw in the logic that + * was expected to be error-free. You can think of it similar to an unexpected + * crash in the program, which can be further managed or logged using tools like + * {@link catchAllDefect}. + * + * **When to Use** + * + * Use this function when you are sure the operation will not fail. + * + * **Example** (Logging a Message) + * + * ```ts + * import { Effect } from "effect" + * + * const log = (message: string) => + * Effect.sync(() => { + * console.log(message) // side effect + * }) + * + * // ┌─── Effect + * // ▼ + * const program = log("Hello, World!") + * ``` + * + * @see {@link try_ | try} for a version that can handle failures. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const sync: (thunk: LazyArg) => Effect = core.sync + +const _void: Effect = core.void + +export { + /** + * Represents an effect that does nothing and produces no value. + * + * **When to Use** + * + * Use this effect when you need to represent an effect that does nothing. + * This is useful in scenarios where you need to satisfy an effect-based + * interface or control program flow without performing any operations. For + * example, it can be used in situations where you want to return an effect + * from a function but do not need to compute or return any result. + * + * @since 2.0.0 + * @category Creating Effects + */ + _void as void +} + +/** + * @since 2.0.0 + * @category Creating Effects + */ +export const yieldNow: (options?: { + readonly priority?: number | undefined +}) => Effect = core.yieldNow + +const _catch: { + ( + discriminator: N, + options: { readonly failure: K; readonly onFailure: (error: Extract) => Effect } + ): (self: Effect) => Effect, R1 | R> + ( + self: Effect, + discriminator: N, + options: { readonly failure: K; readonly onFailure: (error: Extract) => Effect } + ): Effect, R | R1> +} = effect._catch + +export { + /** + * Recovers from a specified error by catching it and handling it with a provided function. + * + * **Details** + * + * This function allows you to recover from specific errors that occur during + * the execution of an effect. It works by catching a specific type of error + * (identified by a discriminator) and then handling it using a provided + * handler function. The handler can return a new effect that helps recover + * from the error, allowing the program to continue. If the error doesn't + * match the specified type, the function allows the original effect to + * continue as it was. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * class NetworkError { + * readonly _tag = "NetworkError" + * } + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // Simulate an effect that may fail + * const task: Effect.Effect = Effect.fail(new NetworkError()) + * + * const program = Effect.gen(function*() { + * const result = yield* Effect.catch(task, "_tag", { + * failure: "NetworkError", + * onFailure: (error) => Effect.succeed(`recovered from error: ${error._tag}`) + * }) + * console.log(`Result: ${result}`) + * }) + * + * Effect.runFork(program) + * // Output: Result: recovered from error: NetworkError + * ``` + * + * @see {@link catchTag} for a version that can recover from errors based on a `_tag` discriminator. + * + * @since 2.0.0 + * @category Error handling + */ + _catch as catch +} + +/** + * Handles all errors in an effect by providing a fallback effect. + * + * **Details** + * + * This function catches any errors that may occur during the execution of an + * effect and allows you to handle them by specifying a fallback effect. This + * ensures that the program continues without failing by recovering from errors + * using the provided fallback logic. + * + * **Note**: This function only handles recoverable errors. It will not recover + * from unrecoverable defects. + * + * **Example** (Providing Recovery Logic for Recoverable Errors) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchAll((error) => + * Effect.succeed(`Recovering from ${error._tag}`) + * ) + * ) + * ``` + * + * @see {@link catchAllCause} for a version that can recover from both + * recoverable and unrecoverable errors. + * + * @since 2.0.0 + * @category Error handling + */ +export const catchAll: { + /** + * Handles all errors in an effect by providing a fallback effect. + * + * **Details** + * + * This function catches any errors that may occur during the execution of an + * effect and allows you to handle them by specifying a fallback effect. This + * ensures that the program continues without failing by recovering from errors + * using the provided fallback logic. + * + * **Note**: This function only handles recoverable errors. It will not recover + * from unrecoverable defects. + * + * **Example** (Providing Recovery Logic for Recoverable Errors) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchAll((error) => + * Effect.succeed(`Recovering from ${error._tag}`) + * ) + * ) + * ``` + * + * @see {@link catchAllCause} for a version that can recover from both + * recoverable and unrecoverable errors. + * + * @since 2.0.0 + * @category Error handling + */ + (f: (e: E) => Effect): (self: Effect) => Effect + /** + * Handles all errors in an effect by providing a fallback effect. + * + * **Details** + * + * This function catches any errors that may occur during the execution of an + * effect and allows you to handle them by specifying a fallback effect. This + * ensures that the program continues without failing by recovering from errors + * using the provided fallback logic. + * + * **Note**: This function only handles recoverable errors. It will not recover + * from unrecoverable defects. + * + * **Example** (Providing Recovery Logic for Recoverable Errors) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchAll((error) => + * Effect.succeed(`Recovering from ${error._tag}`) + * ) + * ) + * ``` + * + * @see {@link catchAllCause} for a version that can recover from both + * recoverable and unrecoverable errors. + * + * @since 2.0.0 + * @category Error handling + */ + (self: Effect, f: (e: E) => Effect): Effect +} = core.catchAll + +/** + * Handles both recoverable and unrecoverable errors by providing a recovery + * effect. + * + * **When to Use** + * + * The `catchAllCause` function allows you to handle all errors, including + * unrecoverable defects, by providing a recovery effect. The recovery logic is + * based on the `Cause` of the error, which provides detailed information about + * the failure. + * + * **When to Recover from Defects** + * + * Defects are unexpected errors that typically shouldn't be recovered from, as + * they often indicate serious issues. However, in some cases, such as + * dynamically loaded plugins, controlled recovery might be needed. + * + * **Example** (Recovering from All Errors) + * + * ```ts + * import { Cause, Effect } from "effect" + * + * // Define an effect that may fail with a recoverable or unrecoverable error + * const program = Effect.fail("Something went wrong!") + * + * // Recover from all errors by examining the cause + * const recovered = program.pipe( + * Effect.catchAllCause((cause) => + * Cause.isFailure(cause) + * ? Effect.succeed("Recovered from a regular error") + * : Effect.succeed("Recovered from a defect") + * ) + * ) + * + * Effect.runPromise(recovered).then(console.log) + * // Output: "Recovered from a regular error" + * ``` + * + * @since 2.0.0 + * @category Error handling + */ +export const catchAllCause: { + /** + * Handles both recoverable and unrecoverable errors by providing a recovery + * effect. + * + * **When to Use** + * + * The `catchAllCause` function allows you to handle all errors, including + * unrecoverable defects, by providing a recovery effect. The recovery logic is + * based on the `Cause` of the error, which provides detailed information about + * the failure. + * + * **When to Recover from Defects** + * + * Defects are unexpected errors that typically shouldn't be recovered from, as + * they often indicate serious issues. However, in some cases, such as + * dynamically loaded plugins, controlled recovery might be needed. + * + * **Example** (Recovering from All Errors) + * + * ```ts + * import { Cause, Effect } from "effect" + * + * // Define an effect that may fail with a recoverable or unrecoverable error + * const program = Effect.fail("Something went wrong!") + * + * // Recover from all errors by examining the cause + * const recovered = program.pipe( + * Effect.catchAllCause((cause) => + * Cause.isFailure(cause) + * ? Effect.succeed("Recovered from a regular error") + * : Effect.succeed("Recovered from a defect") + * ) + * ) + * + * Effect.runPromise(recovered).then(console.log) + * // Output: "Recovered from a regular error" + * ``` + * + * @since 2.0.0 + * @category Error handling + */ + (f: (cause: Cause.Cause) => Effect): (self: Effect) => Effect + /** + * Handles both recoverable and unrecoverable errors by providing a recovery + * effect. + * + * **When to Use** + * + * The `catchAllCause` function allows you to handle all errors, including + * unrecoverable defects, by providing a recovery effect. The recovery logic is + * based on the `Cause` of the error, which provides detailed information about + * the failure. + * + * **When to Recover from Defects** + * + * Defects are unexpected errors that typically shouldn't be recovered from, as + * they often indicate serious issues. However, in some cases, such as + * dynamically loaded plugins, controlled recovery might be needed. + * + * **Example** (Recovering from All Errors) + * + * ```ts + * import { Cause, Effect } from "effect" + * + * // Define an effect that may fail with a recoverable or unrecoverable error + * const program = Effect.fail("Something went wrong!") + * + * // Recover from all errors by examining the cause + * const recovered = program.pipe( + * Effect.catchAllCause((cause) => + * Cause.isFailure(cause) + * ? Effect.succeed("Recovered from a regular error") + * : Effect.succeed("Recovered from a defect") + * ) + * ) + * + * Effect.runPromise(recovered).then(console.log) + * // Output: "Recovered from a regular error" + * ``` + * + * @since 2.0.0 + * @category Error handling + */ + (self: Effect, f: (cause: Cause.Cause) => Effect): Effect +} = core.catchAllCause + +/** + * Recovers from all defects using a provided recovery function. + * + * **When to Use** + * + * There is no sensible way to recover from defects. This method should be used + * only at the boundary between Effect and an external system, to transmit + * information on a defect for diagnostic or explanatory purposes. + * + * **Details** + * + * `catchAllDefect` allows you to handle defects, which are unexpected errors + * that usually cause the program to terminate. This function lets you recover + * from these defects by providing a function that handles the error. However, + * it does not handle expected errors (like those from {@link fail}) or + * execution interruptions (like those from {@link interrupt}). + * + * **When to Recover from Defects** + * + * Defects are unexpected errors that typically shouldn't be recovered from, as + * they often indicate serious issues. However, in some cases, such as + * dynamically loaded plugins, controlled recovery might be needed. + * + * **Example** (Handling All Defects) + * + * ```ts + * import { Effect, Cause, Console } from "effect" + * + * // Simulating a runtime error + * const task = Effect.dieMessage("Boom!") + * + * const program = Effect.catchAllDefect(task, (defect) => { + * if (Cause.isRuntimeException(defect)) { + * return Console.log( + * `RuntimeException defect caught: ${defect.message}` + * ) + * } + * return Console.log("Unknown defect caught.") + * }) + * + * // We get an Exit.Success because we caught all defects + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // RuntimeException defect caught: Boom! + * // { + * // _id: "Exit", + * // _tag: "Success", + * // value: undefined + * // } + * ``` + * + * @since 2.0.0 + * @category Error handling + */ +export const catchAllDefect: { + /** + * Recovers from all defects using a provided recovery function. + * + * **When to Use** + * + * There is no sensible way to recover from defects. This method should be used + * only at the boundary between Effect and an external system, to transmit + * information on a defect for diagnostic or explanatory purposes. + * + * **Details** + * + * `catchAllDefect` allows you to handle defects, which are unexpected errors + * that usually cause the program to terminate. This function lets you recover + * from these defects by providing a function that handles the error. However, + * it does not handle expected errors (like those from {@link fail}) or + * execution interruptions (like those from {@link interrupt}). + * + * **When to Recover from Defects** + * + * Defects are unexpected errors that typically shouldn't be recovered from, as + * they often indicate serious issues. However, in some cases, such as + * dynamically loaded plugins, controlled recovery might be needed. + * + * **Example** (Handling All Defects) + * + * ```ts + * import { Effect, Cause, Console } from "effect" + * + * // Simulating a runtime error + * const task = Effect.dieMessage("Boom!") + * + * const program = Effect.catchAllDefect(task, (defect) => { + * if (Cause.isRuntimeException(defect)) { + * return Console.log( + * `RuntimeException defect caught: ${defect.message}` + * ) + * } + * return Console.log("Unknown defect caught.") + * }) + * + * // We get an Exit.Success because we caught all defects + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // RuntimeException defect caught: Boom! + * // { + * // _id: "Exit", + * // _tag: "Success", + * // value: undefined + * // } + * ``` + * + * @since 2.0.0 + * @category Error handling + */ + (f: (defect: unknown) => Effect): (self: Effect) => Effect + /** + * Recovers from all defects using a provided recovery function. + * + * **When to Use** + * + * There is no sensible way to recover from defects. This method should be used + * only at the boundary between Effect and an external system, to transmit + * information on a defect for diagnostic or explanatory purposes. + * + * **Details** + * + * `catchAllDefect` allows you to handle defects, which are unexpected errors + * that usually cause the program to terminate. This function lets you recover + * from these defects by providing a function that handles the error. However, + * it does not handle expected errors (like those from {@link fail}) or + * execution interruptions (like those from {@link interrupt}). + * + * **When to Recover from Defects** + * + * Defects are unexpected errors that typically shouldn't be recovered from, as + * they often indicate serious issues. However, in some cases, such as + * dynamically loaded plugins, controlled recovery might be needed. + * + * **Example** (Handling All Defects) + * + * ```ts + * import { Effect, Cause, Console } from "effect" + * + * // Simulating a runtime error + * const task = Effect.dieMessage("Boom!") + * + * const program = Effect.catchAllDefect(task, (defect) => { + * if (Cause.isRuntimeException(defect)) { + * return Console.log( + * `RuntimeException defect caught: ${defect.message}` + * ) + * } + * return Console.log("Unknown defect caught.") + * }) + * + * // We get an Exit.Success because we caught all defects + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // RuntimeException defect caught: Boom! + * // { + * // _id: "Exit", + * // _tag: "Success", + * // value: undefined + * // } + * ``` + * + * @since 2.0.0 + * @category Error handling + */ + (self: Effect, f: (defect: unknown) => Effect): Effect +} = effect.catchAllDefect + +/** + * Recovers from specific errors based on a predicate. + * + * **When to Use** + * + * `catchIf` works similarly to {@link catchSome}, but it allows you to + * recover from errors by providing a predicate function. If the predicate + * matches the error, the recovery effect is applied. This function doesn't + * alter the error type, so the resulting effect still carries the original + * error type unless a user-defined type guard is used to narrow the type. + * + * **Example** (Catching Specific Errors with a Predicate) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchIf( + * // Only handle HttpError errors + * (error) => error._tag === "HttpError", + * () => Effect.succeed("Recovering from HttpError") + * ) + * ) + * ``` + * + * @since 2.0.0 + * @category Error handling + */ +export const catchIf: { + /** + * Recovers from specific errors based on a predicate. + * + * **When to Use** + * + * `catchIf` works similarly to {@link catchSome}, but it allows you to + * recover from errors by providing a predicate function. If the predicate + * matches the error, the recovery effect is applied. This function doesn't + * alter the error type, so the resulting effect still carries the original + * error type unless a user-defined type guard is used to narrow the type. + * + * **Example** (Catching Specific Errors with a Predicate) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchIf( + * // Only handle HttpError errors + * (error) => error._tag === "HttpError", + * () => Effect.succeed("Recovering from HttpError") + * ) + * ) + * ``` + * + * @since 2.0.0 + * @category Error handling + */ + (refinement: Refinement, EB>, f: (e: EB) => Effect): (self: Effect) => Effect, R2 | R> + /** + * Recovers from specific errors based on a predicate. + * + * **When to Use** + * + * `catchIf` works similarly to {@link catchSome}, but it allows you to + * recover from errors by providing a predicate function. If the predicate + * matches the error, the recovery effect is applied. This function doesn't + * alter the error type, so the resulting effect still carries the original + * error type unless a user-defined type guard is used to narrow the type. + * + * **Example** (Catching Specific Errors with a Predicate) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchIf( + * // Only handle HttpError errors + * (error) => error._tag === "HttpError", + * () => Effect.succeed("Recovering from HttpError") + * ) + * ) + * ``` + * + * @since 2.0.0 + * @category Error handling + */ + (predicate: Predicate>, f: (e: NoInfer) => Effect): (self: Effect) => Effect + /** + * Recovers from specific errors based on a predicate. + * + * **When to Use** + * + * `catchIf` works similarly to {@link catchSome}, but it allows you to + * recover from errors by providing a predicate function. If the predicate + * matches the error, the recovery effect is applied. This function doesn't + * alter the error type, so the resulting effect still carries the original + * error type unless a user-defined type guard is used to narrow the type. + * + * **Example** (Catching Specific Errors with a Predicate) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchIf( + * // Only handle HttpError errors + * (error) => error._tag === "HttpError", + * () => Effect.succeed("Recovering from HttpError") + * ) + * ) + * ``` + * + * @since 2.0.0 + * @category Error handling + */ + ( + self: Effect, + refinement: Refinement, + f: (e: EB) => Effect + ): Effect, R | R2> + /** + * Recovers from specific errors based on a predicate. + * + * **When to Use** + * + * `catchIf` works similarly to {@link catchSome}, but it allows you to + * recover from errors by providing a predicate function. If the predicate + * matches the error, the recovery effect is applied. This function doesn't + * alter the error type, so the resulting effect still carries the original + * error type unless a user-defined type guard is used to narrow the type. + * + * **Example** (Catching Specific Errors with a Predicate) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchIf( + * // Only handle HttpError errors + * (error) => error._tag === "HttpError", + * () => Effect.succeed("Recovering from HttpError") + * ) + * ) + * ``` + * + * @since 2.0.0 + * @category Error handling + */ + ( + self: Effect, + predicate: Predicate, + f: (e: E) => Effect + ): Effect +} = core.catchIf + +/** + * Catches and recovers from specific types of errors, allowing you to attempt + * recovery only for certain errors. + * + * **Details** + * + * `catchSome` lets you selectively catch and handle errors of certain + * types by providing a recovery effect for specific errors. If the error + * matches a condition, recovery is attempted; if not, it doesn't affect the + * program. This function doesn't alter the error type, meaning the error type + * remains the same as in the original effect. + * + * **Example** (Handling Specific Errors with Effect.catchSome) + * + * ```ts + * import { Effect, Random, Option } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchSome((error) => { + * // Only handle HttpError errors + * if (error._tag === "HttpError") { + * return Option.some(Effect.succeed("Recovering from HttpError")) + * } else { + * return Option.none() + * } + * }) + * ) + * ``` + * + * @see {@link catchIf} for a version that allows you to recover from errors based on a predicate. + * + * @since 2.0.0 + * @category Error handling + */ +export const catchSome: { + /** + * Catches and recovers from specific types of errors, allowing you to attempt + * recovery only for certain errors. + * + * **Details** + * + * `catchSome` lets you selectively catch and handle errors of certain + * types by providing a recovery effect for specific errors. If the error + * matches a condition, recovery is attempted; if not, it doesn't affect the + * program. This function doesn't alter the error type, meaning the error type + * remains the same as in the original effect. + * + * **Example** (Handling Specific Errors with Effect.catchSome) + * + * ```ts + * import { Effect, Random, Option } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchSome((error) => { + * // Only handle HttpError errors + * if (error._tag === "HttpError") { + * return Option.some(Effect.succeed("Recovering from HttpError")) + * } else { + * return Option.none() + * } + * }) + * ) + * ``` + * + * @see {@link catchIf} for a version that allows you to recover from errors based on a predicate. + * + * @since 2.0.0 + * @category Error handling + */ + (pf: (e: NoInfer) => Option.Option>): (self: Effect) => Effect + /** + * Catches and recovers from specific types of errors, allowing you to attempt + * recovery only for certain errors. + * + * **Details** + * + * `catchSome` lets you selectively catch and handle errors of certain + * types by providing a recovery effect for specific errors. If the error + * matches a condition, recovery is attempted; if not, it doesn't affect the + * program. This function doesn't alter the error type, meaning the error type + * remains the same as in the original effect. + * + * **Example** (Handling Specific Errors with Effect.catchSome) + * + * ```ts + * import { Effect, Random, Option } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchSome((error) => { + * // Only handle HttpError errors + * if (error._tag === "HttpError") { + * return Option.some(Effect.succeed("Recovering from HttpError")) + * } else { + * return Option.none() + * } + * }) + * ) + * ``` + * + * @see {@link catchIf} for a version that allows you to recover from errors based on a predicate. + * + * @since 2.0.0 + * @category Error handling + */ + ( + self: Effect, + pf: (e: NoInfer) => Option.Option> + ): Effect +} = core.catchSome + +/** + * Recovers from specific causes using a provided partial function. + * + * @see {@link catchSome} for a version that allows you to recover from errors. + * @see {@link catchSomeDefect} for a version that allows you to recover from defects. + * + * @since 2.0.0 + * @category Error handling + */ +export const catchSomeCause: { + /** + * Recovers from specific causes using a provided partial function. + * + * @see {@link catchSome} for a version that allows you to recover from errors. + * @see {@link catchSomeDefect} for a version that allows you to recover from defects. + * + * @since 2.0.0 + * @category Error handling + */ + (f: (cause: Cause.Cause>) => Option.Option>): (self: Effect) => Effect + /** + * Recovers from specific causes using a provided partial function. + * + * @see {@link catchSome} for a version that allows you to recover from errors. + * @see {@link catchSomeDefect} for a version that allows you to recover from defects. + * + * @since 2.0.0 + * @category Error handling + */ + ( + self: Effect, + f: (cause: Cause.Cause>) => Option.Option> + ): Effect +} = effect.catchSomeCause + +/** + * Recovers from specific defects using a provided partial function. + * + * **Details** + * + * `catchSomeDefect` allows you to handle specific defects, which are + * unexpected errors that can cause the program to stop. It uses a partial + * function to catch only certain defects and ignores others. The function does + * not handle expected errors (such as those caused by {@link fail}) or + * interruptions in execution (like those caused by {@link interrupt}). + * + * This function provides a way to handle certain types of defects while + * allowing others to propagate and cause failure in the program. + * + * **Note**: There is no sensible way to recover from defects. This method + * should be used only at the boundary between Effect and an external system, to + * transmit information on a defect for diagnostic or explanatory purposes. + * + * **How the Partial Function Works** + * + * The function provided to `catchSomeDefect` acts as a filter and a handler for defects: + * - It receives the defect as an input. + * - If the defect matches a specific condition (e.g., a certain error type), the function returns + * an `Option.some` containing the recovery logic. + * - If the defect does not match, the function returns `Option.none`, allowing the defect to propagate. + * + * **Example** (Handling Specific Defects) + * + * ```ts + * import { Effect, Cause, Option, Console } from "effect" + * + * // Simulating a runtime error + * const task = Effect.dieMessage("Boom!") + * + * const program = Effect.catchSomeDefect(task, (defect) => { + * if (Cause.isIllegalArgumentException(defect)) { + * return Option.some( + * Console.log( + * `Caught an IllegalArgumentException defect: ${defect.message}` + * ) + * ) + * } + * return Option.none() + * }) + * + * // Since we are only catching IllegalArgumentException + * // we will get an Exit.Failure because we simulated a runtime error. + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Die', + * // defect: { _tag: 'RuntimeException' } + * // } + * // } + * ``` + * + * @since 2.0.0 + * @category Error handling + */ +export const catchSomeDefect: { + /** + * Recovers from specific defects using a provided partial function. + * + * **Details** + * + * `catchSomeDefect` allows you to handle specific defects, which are + * unexpected errors that can cause the program to stop. It uses a partial + * function to catch only certain defects and ignores others. The function does + * not handle expected errors (such as those caused by {@link fail}) or + * interruptions in execution (like those caused by {@link interrupt}). + * + * This function provides a way to handle certain types of defects while + * allowing others to propagate and cause failure in the program. + * + * **Note**: There is no sensible way to recover from defects. This method + * should be used only at the boundary between Effect and an external system, to + * transmit information on a defect for diagnostic or explanatory purposes. + * + * **How the Partial Function Works** + * + * The function provided to `catchSomeDefect` acts as a filter and a handler for defects: + * - It receives the defect as an input. + * - If the defect matches a specific condition (e.g., a certain error type), the function returns + * an `Option.some` containing the recovery logic. + * - If the defect does not match, the function returns `Option.none`, allowing the defect to propagate. + * + * **Example** (Handling Specific Defects) + * + * ```ts + * import { Effect, Cause, Option, Console } from "effect" + * + * // Simulating a runtime error + * const task = Effect.dieMessage("Boom!") + * + * const program = Effect.catchSomeDefect(task, (defect) => { + * if (Cause.isIllegalArgumentException(defect)) { + * return Option.some( + * Console.log( + * `Caught an IllegalArgumentException defect: ${defect.message}` + * ) + * ) + * } + * return Option.none() + * }) + * + * // Since we are only catching IllegalArgumentException + * // we will get an Exit.Failure because we simulated a runtime error. + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Die', + * // defect: { _tag: 'RuntimeException' } + * // } + * // } + * ``` + * + * @since 2.0.0 + * @category Error handling + */ + (pf: (defect: unknown) => Option.Option>): (self: Effect) => Effect + /** + * Recovers from specific defects using a provided partial function. + * + * **Details** + * + * `catchSomeDefect` allows you to handle specific defects, which are + * unexpected errors that can cause the program to stop. It uses a partial + * function to catch only certain defects and ignores others. The function does + * not handle expected errors (such as those caused by {@link fail}) or + * interruptions in execution (like those caused by {@link interrupt}). + * + * This function provides a way to handle certain types of defects while + * allowing others to propagate and cause failure in the program. + * + * **Note**: There is no sensible way to recover from defects. This method + * should be used only at the boundary between Effect and an external system, to + * transmit information on a defect for diagnostic or explanatory purposes. + * + * **How the Partial Function Works** + * + * The function provided to `catchSomeDefect` acts as a filter and a handler for defects: + * - It receives the defect as an input. + * - If the defect matches a specific condition (e.g., a certain error type), the function returns + * an `Option.some` containing the recovery logic. + * - If the defect does not match, the function returns `Option.none`, allowing the defect to propagate. + * + * **Example** (Handling Specific Defects) + * + * ```ts + * import { Effect, Cause, Option, Console } from "effect" + * + * // Simulating a runtime error + * const task = Effect.dieMessage("Boom!") + * + * const program = Effect.catchSomeDefect(task, (defect) => { + * if (Cause.isIllegalArgumentException(defect)) { + * return Option.some( + * Console.log( + * `Caught an IllegalArgumentException defect: ${defect.message}` + * ) + * ) + * } + * return Option.none() + * }) + * + * // Since we are only catching IllegalArgumentException + * // we will get an Exit.Failure because we simulated a runtime error. + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Die', + * // defect: { _tag: 'RuntimeException' } + * // } + * // } + * ``` + * + * @since 2.0.0 + * @category Error handling + */ + ( + self: Effect, + pf: (defect: unknown) => Option.Option> + ): Effect +} = effect.catchSomeDefect + +/** + * Catches and handles specific errors by their `_tag` field, which is used as a + * discriminator. + * + * **When to Use** + * + * `catchTag` is useful when your errors are tagged with a readonly `_tag` field + * that identifies the error type. You can use this function to handle specific + * error types by matching the `_tag` value. This allows for precise error + * handling, ensuring that only specific errors are caught and handled. + * + * The error type must have a readonly `_tag` field to use `catchTag`. This + * field is used to identify and match errors. + * + * **Example** (Handling Errors by Tag) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * // Only handle HttpError errors + * Effect.catchTag("HttpError", (_HttpError) => + * Effect.succeed("Recovering from HttpError") + * ) + * ) + * ``` + * + * @see {@link catchTags} for a version that allows you to handle multiple error + * types at once. + * + * @since 2.0.0 + * @category Error handling + */ +export const catchTag: { + /** + * Catches and handles specific errors by their `_tag` field, which is used as a + * discriminator. + * + * **When to Use** + * + * `catchTag` is useful when your errors are tagged with a readonly `_tag` field + * that identifies the error type. You can use this function to handle specific + * error types by matching the `_tag` value. This allows for precise error + * handling, ensuring that only specific errors are caught and handled. + * + * The error type must have a readonly `_tag` field to use `catchTag`. This + * field is used to identify and match errors. + * + * **Example** (Handling Errors by Tag) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * // Only handle HttpError errors + * Effect.catchTag("HttpError", (_HttpError) => + * Effect.succeed("Recovering from HttpError") + * ) + * ) + * ``` + * + * @see {@link catchTags} for a version that allows you to handle multiple error + * types at once. + * + * @since 2.0.0 + * @category Error handling + */ + , A1, E1, R1>( + ...args: [...tags: K, f: (e: Extract, { _tag: K[number] }>) => Effect] + ): (self: Effect) => Effect | E1, R | R1> + /** + * Catches and handles specific errors by their `_tag` field, which is used as a + * discriminator. + * + * **When to Use** + * + * `catchTag` is useful when your errors are tagged with a readonly `_tag` field + * that identifies the error type. You can use this function to handle specific + * error types by matching the `_tag` value. This allows for precise error + * handling, ensuring that only specific errors are caught and handled. + * + * The error type must have a readonly `_tag` field to use `catchTag`. This + * field is used to identify and match errors. + * + * **Example** (Handling Errors by Tag) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * // Only handle HttpError errors + * Effect.catchTag("HttpError", (_HttpError) => + * Effect.succeed("Recovering from HttpError") + * ) + * ) + * ``` + * + * @see {@link catchTags} for a version that allows you to handle multiple error + * types at once. + * + * @since 2.0.0 + * @category Error handling + */ + , A1, E1, R1>( + self: Effect, + ...args: [...tags: K, f: (e: Extract, { _tag: K[number] }>) => Effect] + ): Effect | E1, R | R1> +} = effect.catchTag + +/** + * Handles multiple errors in a single block of code using their `_tag` field. + * + * **When to Use** + * + * `catchTags` is a convenient way to handle multiple error types at + * once. Instead of using {@link catchTag} multiple times, you can pass an + * object where each key is an error type's `_tag`, and the value is the handler + * for that specific error. This allows you to catch and recover from multiple + * error types in a single call. + * + * The error type must have a readonly `_tag` field to use `catchTag`. This + * field is used to identify and match errors. + * + * **Example** (Handling Multiple Tagged Error Types at Once) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchTags({ + * HttpError: (_HttpError) => + * Effect.succeed(`Recovering from HttpError`), + * ValidationError: (_ValidationError) => + * Effect.succeed(`Recovering from ValidationError`) + * }) + * ) + * ``` + * + * @since 2.0.0 + * @category Error handling + */ +export const catchTags: { + /** + * Handles multiple errors in a single block of code using their `_tag` field. + * + * **When to Use** + * + * `catchTags` is a convenient way to handle multiple error types at + * once. Instead of using {@link catchTag} multiple times, you can pass an + * object where each key is an error type's `_tag`, and the value is the handler + * for that specific error. This allows you to catch and recover from multiple + * error types in a single call. + * + * The error type must have a readonly `_tag` field to use `catchTag`. This + * field is used to identify and match errors. + * + * **Example** (Handling Multiple Tagged Error Types at Once) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchTags({ + * HttpError: (_HttpError) => + * Effect.succeed(`Recovering from HttpError`), + * ValidationError: (_ValidationError) => + * Effect.succeed(`Recovering from ValidationError`) + * }) + * ) + * ``` + * + * @since 2.0.0 + * @category Error handling + */ + < + E, + Cases extends + & { [K in Extract["_tag"]]+?: ((error: Extract) => Effect) } + & (unknown extends E ? {} : { [K in Exclude["_tag"]>]: never }) + >(cases: Cases): ( + self: Effect + ) => Effect< + | A + | { + [K in keyof Cases]: Cases[K] extends (...args: Array) => Effect ? A : never + }[keyof Cases], + | Exclude + | { + [K in keyof Cases]: Cases[K] extends (...args: Array) => Effect ? E : never + }[keyof Cases], + | R + | { + [K in keyof Cases]: Cases[K] extends (...args: Array) => Effect ? R : never + }[keyof Cases] + > + /** + * Handles multiple errors in a single block of code using their `_tag` field. + * + * **When to Use** + * + * `catchTags` is a convenient way to handle multiple error types at + * once. Instead of using {@link catchTag} multiple times, you can pass an + * object where each key is an error type's `_tag`, and the value is the handler + * for that specific error. This allows you to catch and recover from multiple + * error types in a single call. + * + * The error type must have a readonly `_tag` field to use `catchTag`. This + * field is used to identify and match errors. + * + * **Example** (Handling Multiple Tagged Error Types at Once) + * + * ```ts + * import { Effect, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = program.pipe( + * Effect.catchTags({ + * HttpError: (_HttpError) => + * Effect.succeed(`Recovering from HttpError`), + * ValidationError: (_ValidationError) => + * Effect.succeed(`Recovering from ValidationError`) + * }) + * ) + * ``` + * + * @since 2.0.0 + * @category Error handling + */ + < + R, + E, + A, + Cases extends + & { [K in Extract["_tag"]]+?: ((error: Extract) => Effect) } + & (unknown extends E ? {} : { [K in Exclude["_tag"]>]: never }) + >(self: Effect, cases: Cases): Effect< + | A + | { + [K in keyof Cases]: Cases[K] extends (...args: Array) => Effect ? A : never + }[keyof Cases], + | Exclude + | { + [K in keyof Cases]: Cases[K] extends (...args: Array) => Effect ? E : never + }[keyof Cases], + | R + | { + [K in keyof Cases]: Cases[K] extends (...args: Array) => Effect ? R : never + }[keyof Cases] + > +} = effect.catchTags + +/** + * Retrieves the cause of a failure in an effect. + * + * **Details** + * + * This function allows you to expose the detailed cause of an effect, which + * includes a more precise representation of failures, such as error messages + * and defects. + * + * **When to Use** + * + * This function is helpful when you need to inspect the cause of a failure in + * an effect, giving you more information than just the error message. It can be + * used to log, handle, or analyze failures in more detail, including + * distinguishing between different types of defects (e.g., runtime exceptions, + * interruptions, etc.). + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.fail("Oh uh!").pipe(Effect.as(2)) + * + * // ┌─── Effect + * // ▼ + * const recovered = Effect.gen(function* () { + * const cause = yield* Effect.cause(program) + * yield* Console.log(cause) + * }) + * ``` + * + * @since 2.0.0 + * @category Error handling + */ +export const cause: (self: Effect) => Effect, never, R> = effect.cause + +/** + * Runs an effect repeatedly until it succeeds, ignoring errors. + * + * **Details** + * + * This function takes an effect and runs it repeatedly until the effect + * successfully completes. If the effect fails, it will ignore the error and + * retry the operation. This is useful when you need to perform a task that may + * fail occasionally, but you want to keep trying until it eventually succeeds. + * It works by repeatedly executing the effect until it no longer throws an + * error. + * + * **When to Use** + * + * Use this function when you want to retry an operation multiple times until it + * succeeds. It is helpful in cases where the operation may fail temporarily + * (e.g., a network request), and you want to keep trying without handling or + * worrying about the errors. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * let counter = 0 + * + * const effect = Effect.try(() => { + * counter++ + * if (counter < 3) { + * console.log("running effect") + * throw new Error("error") + * } else { + * console.log("effect done") + * return "some result" + * } + * }) + * + * const program = Effect.eventually(effect) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // running effect + * // running effect + * // effect done + * // some result + * ``` + * + * @since 2.0.0 + * @category Error handling + */ +export const eventually: (self: Effect) => Effect = effect.eventually + +/** + * Discards both the success and failure values of an effect. + * + * **When to Use** + * + * `ignore` allows you to run an effect without caring about its result, whether + * it succeeds or fails. This is useful when you only care about the side + * effects of the effect and do not need to handle or process its outcome. + * + * **Example** (Using Effect.ignore to Discard Values) + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const task = Effect.fail("Uh oh!").pipe(Effect.as(5)) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.ignore(task) + * ``` + * + * @see {@link ignoreLogged} to log failures while ignoring them. + * + * @since 2.0.0 + * @category Error handling + */ +export const ignore: (self: Effect) => Effect = effect.ignore + +/** + * Ignores the result of an effect but logs any failures. + * + * **Details** + * + * This function takes an effect and returns a new effect that ignores whether + * the original effect succeeds or fails. However, if the effect fails, it will + * log the failure at the Debug level, so you can keep track of any issues that + * arise. + * + * **When to Use** + * + * This is useful in scenarios where you want to continue with your program + * regardless of the result of the effect, but you still want to be aware of + * potential failures that may need attention later. + * + * @since 2.0.0 + * @category Error handling + */ +export const ignoreLogged: (self: Effect) => Effect = effect.ignoreLogged + +/** + * Combines all errors from concurrent operations into a single error. + * + * **Details** + * + * This function is used when you have multiple operations running at the same + * time, and you want to capture all the errors that occur across those + * operations. Instead of handling each error separately, it combines all the + * errors into one unified error. + * + * **When to Use** + * + * When using this function, any errors that occur in the concurrently running + * operations will be grouped together into a single error. This helps simplify + * error handling in cases where you don't need to differentiate between each + * failure, but simply want to know that multiple failures occurred. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const fail1 = Effect.fail("Oh uh!") + * const fail2 = Effect.fail("Oh no!") + * const die = Effect.dieMessage("Boom!") + * + * // Run all effects concurrently and capture all errors + * const program = Effect.all([fail1, fail2, die], { + * concurrency: "unbounded" + * }).pipe(Effect.asVoid, Effect.parallelErrors) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: [ 'Oh uh!', 'Oh no!' ] } + * // } + * ``` + * + * @since 2.0.0 + * @category Error handling + */ +export const parallelErrors: (self: Effect) => Effect, R> = effect.parallelErrors + +/** + * Transforms an effect to expose detailed error causes. + * + * **Details** + * + * This function enhances an effect by providing detailed information about any + * error, defect, or interruption that may occur during its execution. It + * modifies the error channel of the effect so that it includes a full cause of + * the failure, wrapped in a `Cause` type. + * + * After applying this function, you can use operators like {@link catchAll} and + * {@link catchTags} to handle specific types of errors. + * + * If you no longer need the detailed cause information, you can revert the + * changes using {@link unsandbox} to return to the original error-handling + * behavior. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // ┌─── Effect + * // ▼ + * const task = Effect.fail(new Error("Oh uh!")).pipe( + * Effect.as("primary result") + * ) + * + * // ┌─── Effect, never> + * // ▼ + * const sandboxed = Effect.sandbox(task) + * + * const program = Effect.catchTags(sandboxed, { + * Die: (cause) => + * Console.log(`Caught a defect: ${cause.defect}`).pipe( + * Effect.as("fallback result on defect") + * ), + * Interrupt: (cause) => + * Console.log(`Caught a defect: ${cause.fiberId}`).pipe( + * Effect.as("fallback result on fiber interruption") + * ), + * Fail: (cause) => + * Console.log(`Caught a defect: ${cause.error}`).pipe( + * Effect.as("fallback result on failure") + * ) + * }) + * + * // Restore the original error handling with unsandbox + * const main = Effect.unsandbox(program) + * + * Effect.runPromise(main).then(console.log) + * // Output: + * // Caught a defect: Oh uh! + * // fallback result on failure + * ``` + * + * @see {@link unsandbox} to restore the original error handling. + * + * @since 2.0.0 + * @category Error handling + */ +export const sandbox: (self: Effect) => Effect, R> = effect.sandbox + +/** + * @since 2.0.0 + * @category Error handling + */ +export declare namespace Retry { + /** + * @since 2.0.0 + * @category Error handling + */ + export type Return, O>> = Effect< + A, + | (O extends { schedule: Schedule.Schedule } ? E + : O extends { until: Refinement } ? E2 + : E) + | (O extends { while: (...args: Array) => Effect } ? E : never) + | (O extends { until: (...args: Array) => Effect } ? E : never), + | R + | (O extends { schedule: Schedule.Schedule } ? R : never) + | (O extends { while: (...args: Array) => Effect } ? R : never) + | (O extends { until: (...args: Array) => Effect } ? R : never) + > extends infer Z ? Z : never + + /** + * @since 2.0.0 + * @category Error handling + */ + export interface Options { + while?: ((error: E) => boolean | Effect) | undefined + until?: ((error: E) => boolean | Effect) | undefined + times?: number | undefined + schedule?: Schedule.Schedule | undefined + } +} + +/** + * Retries a failing effect based on a defined retry policy. + * + * **Details** + * + * The `Effect.retry` function takes an effect and a {@link Schedule} policy, + * and will automatically retry the effect if it fails, following the rules of + * the policy. + * + * If the effect ultimately succeeds, the result will be returned. + * + * If the maximum retries are exhausted and the effect still fails, the failure + * is propagated. + * + * **When to Use** + * + * This can be useful when dealing with intermittent failures, such as network + * issues or temporary resource unavailability. By defining a retry policy, you + * can control the number of retries, the delay between them, and when to stop + * retrying. + * + * **Example** (Retrying with a Fixed Delay) + * + * ```ts + * import { Effect, Schedule } from "effect" + * + * let count = 0 + * + * // Simulates an effect with possible failures + * const task = Effect.async((resume) => { + * if (count <= 2) { + * count++ + * console.log("failure") + * resume(Effect.fail(new Error())) + * } else { + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * // Define a repetition policy using a fixed delay between retries + * const policy = Schedule.fixed("100 millis") + * + * const repeated = Effect.retry(task, policy) + * + * Effect.runPromise(repeated).then(console.log) + * // Output: + * // failure + * // failure + * // failure + * // success + * // yay! + * ``` + * + * **Example** (Retrying a Task up to 5 times) + * + * ```ts + * import { Effect } from "effect" + * + * let count = 0 + * + * // Simulates an effect with possible failures + * const task = Effect.async((resume) => { + * if (count <= 2) { + * count++ + * console.log("failure") + * resume(Effect.fail(new Error())) + * } else { + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * // Retry the task up to 5 times + * Effect.runPromise(Effect.retry(task, { times: 5 })).then(console.log) + * // Output: + * // failure + * // failure + * // failure + * // success + * ``` + * + * **Example** (Retrying Until a Specific Condition is Met) + * + * ```ts + * import { Effect } from "effect" + * + * let count = 0 + * + * // Define an effect that simulates varying error on each invocation + * const action = Effect.failSync(() => { + * console.log(`Action called ${++count} time(s)`) + * return `Error ${count}` + * }) + * + * // Retry the action until a specific condition is met + * const program = Effect.retry(action, { + * until: (err) => err === "Error 3" + * }) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // Action called 1 time(s) + * // Action called 2 time(s) + * // Action called 3 time(s) + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Error 3' } + * // } + * ``` + * + * @see {@link retryOrElse} for a version that allows you to run a fallback. + * @see {@link repeat} if your retry condition is based on successful outcomes rather than errors. + * + * @since 2.0.0 + * @category Error handling + */ +export const retry: { + /** + * Retries a failing effect based on a defined retry policy. + * + * **Details** + * + * The `Effect.retry` function takes an effect and a {@link Schedule} policy, + * and will automatically retry the effect if it fails, following the rules of + * the policy. + * + * If the effect ultimately succeeds, the result will be returned. + * + * If the maximum retries are exhausted and the effect still fails, the failure + * is propagated. + * + * **When to Use** + * + * This can be useful when dealing with intermittent failures, such as network + * issues or temporary resource unavailability. By defining a retry policy, you + * can control the number of retries, the delay between them, and when to stop + * retrying. + * + * **Example** (Retrying with a Fixed Delay) + * + * ```ts + * import { Effect, Schedule } from "effect" + * + * let count = 0 + * + * // Simulates an effect with possible failures + * const task = Effect.async((resume) => { + * if (count <= 2) { + * count++ + * console.log("failure") + * resume(Effect.fail(new Error())) + * } else { + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * // Define a repetition policy using a fixed delay between retries + * const policy = Schedule.fixed("100 millis") + * + * const repeated = Effect.retry(task, policy) + * + * Effect.runPromise(repeated).then(console.log) + * // Output: + * // failure + * // failure + * // failure + * // success + * // yay! + * ``` + * + * **Example** (Retrying a Task up to 5 times) + * + * ```ts + * import { Effect } from "effect" + * + * let count = 0 + * + * // Simulates an effect with possible failures + * const task = Effect.async((resume) => { + * if (count <= 2) { + * count++ + * console.log("failure") + * resume(Effect.fail(new Error())) + * } else { + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * // Retry the task up to 5 times + * Effect.runPromise(Effect.retry(task, { times: 5 })).then(console.log) + * // Output: + * // failure + * // failure + * // failure + * // success + * ``` + * + * **Example** (Retrying Until a Specific Condition is Met) + * + * ```ts + * import { Effect } from "effect" + * + * let count = 0 + * + * // Define an effect that simulates varying error on each invocation + * const action = Effect.failSync(() => { + * console.log(`Action called ${++count} time(s)`) + * return `Error ${count}` + * }) + * + * // Retry the action until a specific condition is met + * const program = Effect.retry(action, { + * until: (err) => err === "Error 3" + * }) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // Action called 1 time(s) + * // Action called 2 time(s) + * // Action called 3 time(s) + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Error 3' } + * // } + * ``` + * + * @see {@link retryOrElse} for a version that allows you to run a fallback. + * @see {@link repeat} if your retry condition is based on successful outcomes rather than errors. + * + * @since 2.0.0 + * @category Error handling + */ + , O>>(options: O): (self: Effect) => Retry.Return + /** + * Retries a failing effect based on a defined retry policy. + * + * **Details** + * + * The `Effect.retry` function takes an effect and a {@link Schedule} policy, + * and will automatically retry the effect if it fails, following the rules of + * the policy. + * + * If the effect ultimately succeeds, the result will be returned. + * + * If the maximum retries are exhausted and the effect still fails, the failure + * is propagated. + * + * **When to Use** + * + * This can be useful when dealing with intermittent failures, such as network + * issues or temporary resource unavailability. By defining a retry policy, you + * can control the number of retries, the delay between them, and when to stop + * retrying. + * + * **Example** (Retrying with a Fixed Delay) + * + * ```ts + * import { Effect, Schedule } from "effect" + * + * let count = 0 + * + * // Simulates an effect with possible failures + * const task = Effect.async((resume) => { + * if (count <= 2) { + * count++ + * console.log("failure") + * resume(Effect.fail(new Error())) + * } else { + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * // Define a repetition policy using a fixed delay between retries + * const policy = Schedule.fixed("100 millis") + * + * const repeated = Effect.retry(task, policy) + * + * Effect.runPromise(repeated).then(console.log) + * // Output: + * // failure + * // failure + * // failure + * // success + * // yay! + * ``` + * + * **Example** (Retrying a Task up to 5 times) + * + * ```ts + * import { Effect } from "effect" + * + * let count = 0 + * + * // Simulates an effect with possible failures + * const task = Effect.async((resume) => { + * if (count <= 2) { + * count++ + * console.log("failure") + * resume(Effect.fail(new Error())) + * } else { + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * // Retry the task up to 5 times + * Effect.runPromise(Effect.retry(task, { times: 5 })).then(console.log) + * // Output: + * // failure + * // failure + * // failure + * // success + * ``` + * + * **Example** (Retrying Until a Specific Condition is Met) + * + * ```ts + * import { Effect } from "effect" + * + * let count = 0 + * + * // Define an effect that simulates varying error on each invocation + * const action = Effect.failSync(() => { + * console.log(`Action called ${++count} time(s)`) + * return `Error ${count}` + * }) + * + * // Retry the action until a specific condition is met + * const program = Effect.retry(action, { + * until: (err) => err === "Error 3" + * }) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // Action called 1 time(s) + * // Action called 2 time(s) + * // Action called 3 time(s) + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Error 3' } + * // } + * ``` + * + * @see {@link retryOrElse} for a version that allows you to run a fallback. + * @see {@link repeat} if your retry condition is based on successful outcomes rather than errors. + * + * @since 2.0.0 + * @category Error handling + */ + (policy: Schedule.Schedule, R1>): (self: Effect) => Effect + /** + * Retries a failing effect based on a defined retry policy. + * + * **Details** + * + * The `Effect.retry` function takes an effect and a {@link Schedule} policy, + * and will automatically retry the effect if it fails, following the rules of + * the policy. + * + * If the effect ultimately succeeds, the result will be returned. + * + * If the maximum retries are exhausted and the effect still fails, the failure + * is propagated. + * + * **When to Use** + * + * This can be useful when dealing with intermittent failures, such as network + * issues or temporary resource unavailability. By defining a retry policy, you + * can control the number of retries, the delay between them, and when to stop + * retrying. + * + * **Example** (Retrying with a Fixed Delay) + * + * ```ts + * import { Effect, Schedule } from "effect" + * + * let count = 0 + * + * // Simulates an effect with possible failures + * const task = Effect.async((resume) => { + * if (count <= 2) { + * count++ + * console.log("failure") + * resume(Effect.fail(new Error())) + * } else { + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * // Define a repetition policy using a fixed delay between retries + * const policy = Schedule.fixed("100 millis") + * + * const repeated = Effect.retry(task, policy) + * + * Effect.runPromise(repeated).then(console.log) + * // Output: + * // failure + * // failure + * // failure + * // success + * // yay! + * ``` + * + * **Example** (Retrying a Task up to 5 times) + * + * ```ts + * import { Effect } from "effect" + * + * let count = 0 + * + * // Simulates an effect with possible failures + * const task = Effect.async((resume) => { + * if (count <= 2) { + * count++ + * console.log("failure") + * resume(Effect.fail(new Error())) + * } else { + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * // Retry the task up to 5 times + * Effect.runPromise(Effect.retry(task, { times: 5 })).then(console.log) + * // Output: + * // failure + * // failure + * // failure + * // success + * ``` + * + * **Example** (Retrying Until a Specific Condition is Met) + * + * ```ts + * import { Effect } from "effect" + * + * let count = 0 + * + * // Define an effect that simulates varying error on each invocation + * const action = Effect.failSync(() => { + * console.log(`Action called ${++count} time(s)`) + * return `Error ${count}` + * }) + * + * // Retry the action until a specific condition is met + * const program = Effect.retry(action, { + * until: (err) => err === "Error 3" + * }) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // Action called 1 time(s) + * // Action called 2 time(s) + * // Action called 3 time(s) + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Error 3' } + * // } + * ``` + * + * @see {@link retryOrElse} for a version that allows you to run a fallback. + * @see {@link repeat} if your retry condition is based on successful outcomes rather than errors. + * + * @since 2.0.0 + * @category Error handling + */ + , O>>(self: Effect, options: O): Retry.Return + /** + * Retries a failing effect based on a defined retry policy. + * + * **Details** + * + * The `Effect.retry` function takes an effect and a {@link Schedule} policy, + * and will automatically retry the effect if it fails, following the rules of + * the policy. + * + * If the effect ultimately succeeds, the result will be returned. + * + * If the maximum retries are exhausted and the effect still fails, the failure + * is propagated. + * + * **When to Use** + * + * This can be useful when dealing with intermittent failures, such as network + * issues or temporary resource unavailability. By defining a retry policy, you + * can control the number of retries, the delay between them, and when to stop + * retrying. + * + * **Example** (Retrying with a Fixed Delay) + * + * ```ts + * import { Effect, Schedule } from "effect" + * + * let count = 0 + * + * // Simulates an effect with possible failures + * const task = Effect.async((resume) => { + * if (count <= 2) { + * count++ + * console.log("failure") + * resume(Effect.fail(new Error())) + * } else { + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * // Define a repetition policy using a fixed delay between retries + * const policy = Schedule.fixed("100 millis") + * + * const repeated = Effect.retry(task, policy) + * + * Effect.runPromise(repeated).then(console.log) + * // Output: + * // failure + * // failure + * // failure + * // success + * // yay! + * ``` + * + * **Example** (Retrying a Task up to 5 times) + * + * ```ts + * import { Effect } from "effect" + * + * let count = 0 + * + * // Simulates an effect with possible failures + * const task = Effect.async((resume) => { + * if (count <= 2) { + * count++ + * console.log("failure") + * resume(Effect.fail(new Error())) + * } else { + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * // Retry the task up to 5 times + * Effect.runPromise(Effect.retry(task, { times: 5 })).then(console.log) + * // Output: + * // failure + * // failure + * // failure + * // success + * ``` + * + * **Example** (Retrying Until a Specific Condition is Met) + * + * ```ts + * import { Effect } from "effect" + * + * let count = 0 + * + * // Define an effect that simulates varying error on each invocation + * const action = Effect.failSync(() => { + * console.log(`Action called ${++count} time(s)`) + * return `Error ${count}` + * }) + * + * // Retry the action until a specific condition is met + * const program = Effect.retry(action, { + * until: (err) => err === "Error 3" + * }) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // Action called 1 time(s) + * // Action called 2 time(s) + * // Action called 3 time(s) + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Error 3' } + * // } + * ``` + * + * @see {@link retryOrElse} for a version that allows you to run a fallback. + * @see {@link repeat} if your retry condition is based on successful outcomes rather than errors. + * + * @since 2.0.0 + * @category Error handling + */ + (self: Effect, policy: Schedule.Schedule, R1>): Effect +} = schedule_.retry_combined + +/** + * Apply an `ExecutionPlan` to the effect, which allows you to fallback to + * different resources in case of failure. + * + * @since 3.16.0 + * @category Error handling + * @experimental + */ +export const withExecutionPlan: { + /** + * Apply an `ExecutionPlan` to the effect, which allows you to fallback to + * different resources in case of failure. + * + * @since 3.16.0 + * @category Error handling + * @experimental + */ + ( + plan: ExecutionPlan<{ provides: Provides; input: Input; error: PlanE; requirements: PlanR }> + ): (effect: Effect) => Effect | PlanR> + /** + * Apply an `ExecutionPlan` to the effect, which allows you to fallback to + * different resources in case of failure. + * + * @since 3.16.0 + * @category Error handling + * @experimental + */ + ( + effect: Effect, + plan: ExecutionPlan<{ provides: Provides; input: Input; error: PlanE; requirements: PlanR }> + ): Effect | PlanR> +} = internalExecutionPlan.withExecutionPlan + +/** + * Retries a failing effect and runs a fallback effect if retries are exhausted. + * + * **Details** + * + * The `Effect.retryOrElse` function attempts to retry a failing effect multiple + * times according to a defined {@link Schedule} policy. + * + * If the retries are exhausted and the effect still fails, it runs a fallback + * effect instead. + * + * **When to Use** + * + * This function is useful when you want to handle failures gracefully by + * specifying an alternative action after repeated failures. + * + * **Example** (Retrying with Fallback) + * + * ```ts + * import { Effect, Schedule, Console } from "effect" + * + * let count = 0 + * + * // Simulates an effect with possible failures + * const task = Effect.async((resume) => { + * if (count <= 2) { + * count++ + * console.log("failure") + * resume(Effect.fail(new Error())) + * } else { + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * // Retry the task with a delay between retries and a maximum of 2 retries + * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") + * + * // If all retries fail, run the fallback effect + * const repeated = Effect.retryOrElse( + * task, + * policy, + * // fallback + * () => Console.log("orElse").pipe(Effect.as("default value")) + * ) + * + * Effect.runPromise(repeated).then(console.log) + * // Output: + * // failure + * // failure + * // failure + * // orElse + * // default value + * ``` + * + * @see {@link retry} for a version that does not run a fallback effect. + * + * @since 2.0.0 + * @category Error handling + */ +export const retryOrElse: { + /** + * Retries a failing effect and runs a fallback effect if retries are exhausted. + * + * **Details** + * + * The `Effect.retryOrElse` function attempts to retry a failing effect multiple + * times according to a defined {@link Schedule} policy. + * + * If the retries are exhausted and the effect still fails, it runs a fallback + * effect instead. + * + * **When to Use** + * + * This function is useful when you want to handle failures gracefully by + * specifying an alternative action after repeated failures. + * + * **Example** (Retrying with Fallback) + * + * ```ts + * import { Effect, Schedule, Console } from "effect" + * + * let count = 0 + * + * // Simulates an effect with possible failures + * const task = Effect.async((resume) => { + * if (count <= 2) { + * count++ + * console.log("failure") + * resume(Effect.fail(new Error())) + * } else { + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * // Retry the task with a delay between retries and a maximum of 2 retries + * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") + * + * // If all retries fail, run the fallback effect + * const repeated = Effect.retryOrElse( + * task, + * policy, + * // fallback + * () => Console.log("orElse").pipe(Effect.as("default value")) + * ) + * + * Effect.runPromise(repeated).then(console.log) + * // Output: + * // failure + * // failure + * // failure + * // orElse + * // default value + * ``` + * + * @see {@link retry} for a version that does not run a fallback effect. + * + * @since 2.0.0 + * @category Error handling + */ + ( + policy: Schedule.Schedule, R1>, + orElse: (e: NoInfer, out: A1) => Effect + ): (self: Effect) => Effect + /** + * Retries a failing effect and runs a fallback effect if retries are exhausted. + * + * **Details** + * + * The `Effect.retryOrElse` function attempts to retry a failing effect multiple + * times according to a defined {@link Schedule} policy. + * + * If the retries are exhausted and the effect still fails, it runs a fallback + * effect instead. + * + * **When to Use** + * + * This function is useful when you want to handle failures gracefully by + * specifying an alternative action after repeated failures. + * + * **Example** (Retrying with Fallback) + * + * ```ts + * import { Effect, Schedule, Console } from "effect" + * + * let count = 0 + * + * // Simulates an effect with possible failures + * const task = Effect.async((resume) => { + * if (count <= 2) { + * count++ + * console.log("failure") + * resume(Effect.fail(new Error())) + * } else { + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * // Retry the task with a delay between retries and a maximum of 2 retries + * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") + * + * // If all retries fail, run the fallback effect + * const repeated = Effect.retryOrElse( + * task, + * policy, + * // fallback + * () => Console.log("orElse").pipe(Effect.as("default value")) + * ) + * + * Effect.runPromise(repeated).then(console.log) + * // Output: + * // failure + * // failure + * // failure + * // orElse + * // default value + * ``` + * + * @see {@link retry} for a version that does not run a fallback effect. + * + * @since 2.0.0 + * @category Error handling + */ + ( + self: Effect, + policy: Schedule.Schedule, R1>, + orElse: (e: NoInfer, out: A1) => Effect + ): Effect +} = schedule_.retryOrElse_Effect + +const try_: { + (options: { readonly try: LazyArg; readonly catch: (error: unknown) => E }): Effect + (thunk: LazyArg): Effect +} = effect.try_ + +export { + /** + * Creates an `Effect` that represents a synchronous computation that might + * fail. + * + * **When to Use** + * + * In situations where you need to perform synchronous operations that might + * fail, such as parsing JSON, you can use the `try` constructor. This + * constructor is designed to handle operations that could throw exceptions by + * capturing those exceptions and transforming them into manageable errors. + * + * **Error Handling** + * + * There are two ways to handle errors with `try`: + * + * 1. If you don't provide a `catch` function, the error is caught and the + * effect fails with an `UnknownException`. + * 2. If you provide a `catch` function, the error is caught and the `catch` + * function maps it to an error of type `E`. + * + * **Example** (Safe JSON Parsing) + * + * ```ts + * import { Effect } from "effect" + * + * const parse = (input: string) => + * // This might throw an error if input is not valid JSON + * Effect.try(() => JSON.parse(input)) + * + * // ┌─── Effect + * // ▼ + * const program = parse("") + * + * ``` + * + * **Example** (Custom Error Handling) + * + * ```ts + * import { Effect } from "effect" + * + * const parse = (input: string) => + * Effect.try({ + * // JSON.parse may throw for bad input + * try: () => JSON.parse(input), + * // remap the error + * catch: (unknown) => new Error(`something went wrong ${unknown}`) + * }) + * + * // ┌─── Effect + * // ▼ + * const program = parse("") + * ``` + * + * @see {@link sync} if the effectful computation is synchronous and does not + * throw errors. + * + * @since 2.0.0 + * @category Creating Effects + */ + try_ as try +} + +/** + * Returns an effect that maps its success using the specified side-effecting + * `try` function, converting any errors into typed failed effects using the + * `catch` function. + * + * @see {@link tryPromise} for a version that works with asynchronous computations. + * + * @since 2.0.0 + * @category Error handling + */ +export const tryMap: { + /** + * Returns an effect that maps its success using the specified side-effecting + * `try` function, converting any errors into typed failed effects using the + * `catch` function. + * + * @see {@link tryPromise} for a version that works with asynchronous computations. + * + * @since 2.0.0 + * @category Error handling + */ + ( + options: { readonly try: (a: A) => B; readonly catch: (error: unknown) => E1 } + ): (self: Effect) => Effect + /** + * Returns an effect that maps its success using the specified side-effecting + * `try` function, converting any errors into typed failed effects using the + * `catch` function. + * + * @see {@link tryPromise} for a version that works with asynchronous computations. + * + * @since 2.0.0 + * @category Error handling + */ + ( + self: Effect, + options: { + readonly try: (a: A) => B + readonly catch: (error: unknown) => E1 + } + ): Effect +} = effect.tryMap + +/** + * Returns an effect that maps its success using the specified side-effecting + * `try` function, converting any promise rejections into typed failed effects + * using the `catch` function. + * + * An optional `AbortSignal` can be provided to allow for interruption of the + * wrapped `Promise` API. + * + * @see {@link tryMap} for a version that works with synchronous computations. + * + * @since 2.0.0 + * @category Error handling + */ +export const tryMapPromise: { + /** + * Returns an effect that maps its success using the specified side-effecting + * `try` function, converting any promise rejections into typed failed effects + * using the `catch` function. + * + * An optional `AbortSignal` can be provided to allow for interruption of the + * wrapped `Promise` API. + * + * @see {@link tryMap} for a version that works with synchronous computations. + * + * @since 2.0.0 + * @category Error handling + */ + ( + options: { readonly try: (a: A, signal: AbortSignal) => PromiseLike; readonly catch: (error: unknown) => E1 } + ): (self: Effect) => Effect + /** + * Returns an effect that maps its success using the specified side-effecting + * `try` function, converting any promise rejections into typed failed effects + * using the `catch` function. + * + * An optional `AbortSignal` can be provided to allow for interruption of the + * wrapped `Promise` API. + * + * @see {@link tryMap} for a version that works with synchronous computations. + * + * @since 2.0.0 + * @category Error handling + */ + ( + self: Effect, + options: { readonly try: (a: A, signal: AbortSignal) => PromiseLike; readonly catch: (error: unknown) => E1 } + ): Effect +} = effect.tryMapPromise + +/** + * Creates an `Effect` that represents an asynchronous computation that might + * fail. + * + * **When to Use** + * + * In situations where you need to perform asynchronous operations that might + * fail, such as fetching data from an API, you can use the `tryPromise` + * constructor. This constructor is designed to handle operations that could + * throw exceptions by capturing those exceptions and transforming them into + * manageable errors. + * + * **Error Handling** + * + * There are two ways to handle errors with `tryPromise`: + * + * 1. If you don't provide a `catch` function, the error is caught and the + * effect fails with an `UnknownException`. + * 2. If you provide a `catch` function, the error is caught and the `catch` + * function maps it to an error of type `E`. + * + * **Interruptions** + * + * An optional `AbortSignal` can be provided to allow for interruption of the + * wrapped `Promise` API. + * + * **Example** (Fetching a TODO Item) + * + * ```ts + * import { Effect } from "effect" + * + * const getTodo = (id: number) => + * // Will catch any errors and propagate them as UnknownException + * Effect.tryPromise(() => + * fetch(`https://jsonplaceholder.typicode.com/todos/${id}`) + * ) + * + * // ┌─── Effect + * // ▼ + * const program = getTodo(1) + * ``` + * + * **Example** (Custom Error Handling) + * + * ```ts + * import { Effect } from "effect" + * + * const getTodo = (id: number) => + * Effect.tryPromise({ + * try: () => fetch(`https://jsonplaceholder.typicode.com/todos/${id}`), + * // remap the error + * catch: (unknown) => new Error(`something went wrong ${unknown}`) + * }) + * + * // ┌─── Effect + * // ▼ + * const program = getTodo(1) + * ``` + * + * @see {@link promise} if the effectful computation is asynchronous and does not throw errors. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const tryPromise: { + /** + * Creates an `Effect` that represents an asynchronous computation that might + * fail. + * + * **When to Use** + * + * In situations where you need to perform asynchronous operations that might + * fail, such as fetching data from an API, you can use the `tryPromise` + * constructor. This constructor is designed to handle operations that could + * throw exceptions by capturing those exceptions and transforming them into + * manageable errors. + * + * **Error Handling** + * + * There are two ways to handle errors with `tryPromise`: + * + * 1. If you don't provide a `catch` function, the error is caught and the + * effect fails with an `UnknownException`. + * 2. If you provide a `catch` function, the error is caught and the `catch` + * function maps it to an error of type `E`. + * + * **Interruptions** + * + * An optional `AbortSignal` can be provided to allow for interruption of the + * wrapped `Promise` API. + * + * **Example** (Fetching a TODO Item) + * + * ```ts + * import { Effect } from "effect" + * + * const getTodo = (id: number) => + * // Will catch any errors and propagate them as UnknownException + * Effect.tryPromise(() => + * fetch(`https://jsonplaceholder.typicode.com/todos/${id}`) + * ) + * + * // ┌─── Effect + * // ▼ + * const program = getTodo(1) + * ``` + * + * **Example** (Custom Error Handling) + * + * ```ts + * import { Effect } from "effect" + * + * const getTodo = (id: number) => + * Effect.tryPromise({ + * try: () => fetch(`https://jsonplaceholder.typicode.com/todos/${id}`), + * // remap the error + * catch: (unknown) => new Error(`something went wrong ${unknown}`) + * }) + * + * // ┌─── Effect + * // ▼ + * const program = getTodo(1) + * ``` + * + * @see {@link promise} if the effectful computation is asynchronous and does not throw errors. + * + * @since 2.0.0 + * @category Creating Effects + */ + ( + options: { + readonly try: (signal: AbortSignal) => PromiseLike + readonly catch: (error: unknown) => E + } + ): Effect + /** + * Creates an `Effect` that represents an asynchronous computation that might + * fail. + * + * **When to Use** + * + * In situations where you need to perform asynchronous operations that might + * fail, such as fetching data from an API, you can use the `tryPromise` + * constructor. This constructor is designed to handle operations that could + * throw exceptions by capturing those exceptions and transforming them into + * manageable errors. + * + * **Error Handling** + * + * There are two ways to handle errors with `tryPromise`: + * + * 1. If you don't provide a `catch` function, the error is caught and the + * effect fails with an `UnknownException`. + * 2. If you provide a `catch` function, the error is caught and the `catch` + * function maps it to an error of type `E`. + * + * **Interruptions** + * + * An optional `AbortSignal` can be provided to allow for interruption of the + * wrapped `Promise` API. + * + * **Example** (Fetching a TODO Item) + * + * ```ts + * import { Effect } from "effect" + * + * const getTodo = (id: number) => + * // Will catch any errors and propagate them as UnknownException + * Effect.tryPromise(() => + * fetch(`https://jsonplaceholder.typicode.com/todos/${id}`) + * ) + * + * // ┌─── Effect + * // ▼ + * const program = getTodo(1) + * ``` + * + * **Example** (Custom Error Handling) + * + * ```ts + * import { Effect } from "effect" + * + * const getTodo = (id: number) => + * Effect.tryPromise({ + * try: () => fetch(`https://jsonplaceholder.typicode.com/todos/${id}`), + * // remap the error + * catch: (unknown) => new Error(`something went wrong ${unknown}`) + * }) + * + * // ┌─── Effect + * // ▼ + * const program = getTodo(1) + * ``` + * + * @see {@link promise} if the effectful computation is asynchronous and does not throw errors. + * + * @since 2.0.0 + * @category Creating Effects + */ + (evaluate: (signal: AbortSignal) => PromiseLike): Effect +} = effect.tryPromise + +/** + * The `unsandbox` function is used to revert an effect that has been + * sandboxed by {@link sandbox}. When you apply `unsandbox`, the + * effect's error channel is restored to its original state, without the + * detailed `Cause` information. This means that any underlying causes of + * errors, defects, or fiber interruptions are no longer exposed in the error + * channel. + * + * This function is useful when you want to remove the detailed error tracking + * provided by `sandbox` and return to the standard error handling for + * your effect. Once unsandboxed, the effect behaves as if `sandbox` was + * never applied. + * + * @see {@link sandbox} to expose the full cause of failures, defects, or interruptions. + * + * @since 2.0.0 + * @category Error handling + */ +export const unsandbox: (self: Effect, R>) => Effect = effect.unsandbox + +/** + * Allows interruption of the current fiber, even in uninterruptible regions. + * + * **Details** + * + * This effect checks whether any other fibers are attempting to interrupt the + * current fiber. If so, it allows the current fiber to perform a + * self-interruption. + * + * **When to Use** + * + * This is useful in situations where you want to allow interruption to happen + * even in regions of the code that are normally uninterruptible. + * + * @since 2.0.0 + * @category Interruption + */ +export const allowInterrupt: Effect = effect.allowInterrupt + +/** + * Checks if interruption is allowed and executes a callback accordingly. + * + * **Details** + * + * This function checks the current interrupt status of the running fiber. It + * then calls the provided callback, passing a boolean indicating whether + * interruption is allowed. + * + * **When to Use** + * + * This is useful for handling specific logic based on whether the current + * operation can be interrupted, such as when performing asynchronous operations + * or handling cancellation. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const program = Effect.gen(function*() { + * yield* Effect.checkInterruptible((isInterruptible) => { + * if (isInterruptible) { + * return Console.log("You can interrupt this operation.") + * } else { + * return Console.log("This operation cannot be interrupted.") + * } + * }) + * }) + * + * Effect.runPromise(program) + * // Output: You can interrupt this operation. + * + * Effect.runPromise(program.pipe(Effect.uninterruptible)) + * // Output: This operation cannot be interrupted. + * + * ``` + * + * @since 2.0.0 + * @category Interruption + */ +export const checkInterruptible: (f: (isInterruptible: boolean) => Effect) => Effect = + core.checkInterruptible + +/** + * Provides a way to handle timeouts in uninterruptible effects, allowing them + * to continue in the background while the main control flow proceeds with the + * timeout error. + * + * **Details** + * + * The `disconnect` function allows an uninterruptible effect to continue + * running in the background, while enabling the main control flow to + * immediately recognize a timeout condition. This is useful when you want to + * avoid blocking the program due to long-running tasks, especially when those + * tasks do not need to affect the flow of the rest of the program. + * + * Without `disconnect`, an uninterruptible effect will ignore the + * timeout and continue executing until it completes. The timeout error will + * only be assessed after the effect finishes, which can cause delays in + * recognizing a timeout. + * + * With `disconnect`, the uninterruptible effect proceeds in the + * background while the main program flow can immediately handle the timeout + * error or trigger alternative logic. This enables faster timeout handling + * without waiting for the completion of the long-running task. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const longRunningTask = Effect.gen(function* () { + * console.log("Start heavy processing...") + * yield* Effect.sleep("5 seconds") // Simulate a long process + * console.log("Heavy processing done.") + * return "Data processed" + * }) + * + * const timedEffect = longRunningTask.pipe( + * Effect.uninterruptible, + * // Allows the task to finish in the background if it times out + * Effect.disconnect, + * Effect.timeout("1 second") + * ) + * + * Effect.runPromiseExit(timedEffect).then(console.log) + * // Output: + * // Start heavy processing... + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: { _tag: 'TimeoutException' } + * // } + * // } + * // Heavy processing done. + * ``` + * + * @see {@link timeout} for a version that interrupts the effect. + * @see {@link uninterruptible} for creating an uninterruptible effect. + * + * @since 2.0.0 + * @category Interruption + */ +export const disconnect: (self: Effect) => Effect = fiberRuntime.disconnect + +/** + * Represents an effect that interrupts the current fiber. + * + * **Details** + * + * This effect models the explicit interruption of the fiber in which it runs. + * When executed, it causes the fiber to stop its operation immediately, + * capturing the interruption details such as the fiber's ID and its start time. + * The resulting interruption can be observed in the `Exit` type if the effect + * is run with functions like {@link runPromiseExit}. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function* () { + * console.log("start") + * yield* Effect.sleep("2 seconds") + * yield* Effect.interrupt + * console.log("done") + * return "some result" + * }) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // start + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Interrupt', + * // fiberId: { + * // _id: 'FiberId', + * // _tag: 'Runtime', + * // id: 0, + * // startTimeMillis: ... + * // } + * // } + * // } + * ``` + * + * @since 2.0.0 + * @category Interruption + */ +export const interrupt: Effect = core.interrupt + +/** + * @since 2.0.0 + * @category Interruption + */ +export const interruptWith: (fiberId: FiberId.FiberId) => Effect = core.interruptWith + +/** + * Marks an effect as interruptible. + * + * @since 2.0.0 + * @category Interruption + */ +export const interruptible: (self: Effect) => Effect = core.interruptible + +/** + * This function behaves like {@link interruptible}, but it also provides a + * `restore` function. This function can be used to restore the interruptibility + * of any specific region of code. + * + * @since 2.0.0 + * @category Interruption + */ +export const interruptibleMask: ( + f: (restore: (effect: Effect) => Effect) => Effect +) => Effect = core.interruptibleMask + +/** + * Registers a cleanup effect to run when an effect is interrupted. + * + * **Details** + * + * This function allows you to specify an effect to run when the fiber is + * interrupted. This effect will be executed when the fiber is interrupted, + * allowing you to perform cleanup or other actions. + * + * **Example** (Running a Cleanup Action on Interruption) + * + * ```ts + * import { Console, Effect } from "effect" + * + * // This handler is executed when the fiber is interrupted + * const handler = Effect.onInterrupt((_fibers) => Console.log("Cleanup completed")) + * + * const success = Console.log("Task completed").pipe(Effect.as("some result"), handler) + * + * Effect.runFork(success) + * // Output: + * // Task completed + * + * const failure = Console.log("Task failed").pipe(Effect.andThen(Effect.fail("some error")), handler) + * + * Effect.runFork(failure) + * // Output: + * // Task failed + * + * const interruption = Console.log("Task interrupted").pipe(Effect.andThen(Effect.interrupt), handler) + * + * Effect.runFork(interruption) + * // Output: + * // Task interrupted + * // Cleanup completed + * ``` + * + * @since 2.0.0 + * @category Interruption + */ +export const onInterrupt: { + /** + * Registers a cleanup effect to run when an effect is interrupted. + * + * **Details** + * + * This function allows you to specify an effect to run when the fiber is + * interrupted. This effect will be executed when the fiber is interrupted, + * allowing you to perform cleanup or other actions. + * + * **Example** (Running a Cleanup Action on Interruption) + * + * ```ts + * import { Console, Effect } from "effect" + * + * // This handler is executed when the fiber is interrupted + * const handler = Effect.onInterrupt((_fibers) => Console.log("Cleanup completed")) + * + * const success = Console.log("Task completed").pipe(Effect.as("some result"), handler) + * + * Effect.runFork(success) + * // Output: + * // Task completed + * + * const failure = Console.log("Task failed").pipe(Effect.andThen(Effect.fail("some error")), handler) + * + * Effect.runFork(failure) + * // Output: + * // Task failed + * + * const interruption = Console.log("Task interrupted").pipe(Effect.andThen(Effect.interrupt), handler) + * + * Effect.runFork(interruption) + * // Output: + * // Task interrupted + * // Cleanup completed + * ``` + * + * @since 2.0.0 + * @category Interruption + */ + ( + cleanup: (interruptors: HashSet.HashSet) => Effect + ): (self: Effect) => Effect + /** + * Registers a cleanup effect to run when an effect is interrupted. + * + * **Details** + * + * This function allows you to specify an effect to run when the fiber is + * interrupted. This effect will be executed when the fiber is interrupted, + * allowing you to perform cleanup or other actions. + * + * **Example** (Running a Cleanup Action on Interruption) + * + * ```ts + * import { Console, Effect } from "effect" + * + * // This handler is executed when the fiber is interrupted + * const handler = Effect.onInterrupt((_fibers) => Console.log("Cleanup completed")) + * + * const success = Console.log("Task completed").pipe(Effect.as("some result"), handler) + * + * Effect.runFork(success) + * // Output: + * // Task completed + * + * const failure = Console.log("Task failed").pipe(Effect.andThen(Effect.fail("some error")), handler) + * + * Effect.runFork(failure) + * // Output: + * // Task failed + * + * const interruption = Console.log("Task interrupted").pipe(Effect.andThen(Effect.interrupt), handler) + * + * Effect.runFork(interruption) + * // Output: + * // Task interrupted + * // Cleanup completed + * ``` + * + * @since 2.0.0 + * @category Interruption + */ + ( + self: Effect, + cleanup: (interruptors: HashSet.HashSet) => Effect + ): Effect +} = core.onInterrupt + +/** + * Marks an effect as uninterruptible. + * + * @since 2.0.0 + * @category Interruption + */ +export const uninterruptible: (self: Effect) => Effect = core.uninterruptible + +/** + * This function behaves like {@link uninterruptible}, but it also provides a + * `restore` function. This function can be used to restore the interruptibility + * of any specific region of code. + * + * @since 2.0.0 + * @category Interruption + */ +export const uninterruptibleMask: ( + f: (restore: (effect: Effect) => Effect) => Effect +) => Effect = core.uninterruptibleMask + +/** + * Transforms a `Predicate` function into an `Effect` returning the input value if the predicate returns `true` + * or failing with specified error if the predicate fails + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const isPositive = (n: number): boolean => n > 0 + * + * // succeeds with `1` + * Effect.liftPredicate(1, isPositive, n => `${n} is not positive`) + * + * // fails with `"0 is not positive"` + * Effect.liftPredicate(0, isPositive, n => `${n} is not positive`) + * ``` + * + * @category Condition Checking + * @since 3.4.0 + */ +export const liftPredicate: { + /** + * Transforms a `Predicate` function into an `Effect` returning the input value if the predicate returns `true` + * or failing with specified error if the predicate fails + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const isPositive = (n: number): boolean => n > 0 + * + * // succeeds with `1` + * Effect.liftPredicate(1, isPositive, n => `${n} is not positive`) + * + * // fails with `"0 is not positive"` + * Effect.liftPredicate(0, isPositive, n => `${n} is not positive`) + * ``` + * + * @category Condition Checking + * @since 3.4.0 + */ + ( + predicate: Refinement | Predicate, + orFailWith: (a: EqualsWith>) => E + ): (a: A) => Effect, E> + /** + * Transforms a `Predicate` function into an `Effect` returning the input value if the predicate returns `true` + * or failing with specified error if the predicate fails + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const isPositive = (n: number): boolean => n > 0 + * + * // succeeds with `1` + * Effect.liftPredicate(1, isPositive, n => `${n} is not positive`) + * + * // fails with `"0 is not positive"` + * Effect.liftPredicate(0, isPositive, n => `${n} is not positive`) + * ``` + * + * @category Condition Checking + * @since 3.4.0 + */ + ( + self: A, + predicate: Refinement | Predicate, + orFailWith: (a: EqualsWith>) => E + ): Effect +} = effect.liftPredicate + +/** + * Replaces the value inside an effect with a constant value. + * + * **Details** + * + * This function allows you to ignore the original value inside an effect and + * replace it with a constant value. + * + * **When to Use** + * + * It is useful when you no longer need the value produced by an effect but want + * to ensure that the effect completes successfully with a specific constant + * result instead. For instance, you can replace the value produced by a + * computation with a predefined value, ignoring what was calculated before. + * + * **Example** (Replacing a Value) + * + * ```ts + * import { pipe, Effect } from "effect" + * + * // Replaces the value 5 with the constant "new value" + * const program = pipe(Effect.succeed(5), Effect.as("new value")) + * + * Effect.runPromise(program).then(console.log) + * // Output: "new value" + * ``` + * + * @since 2.0.0 + * @category Mapping + */ +export const as: { + /** + * Replaces the value inside an effect with a constant value. + * + * **Details** + * + * This function allows you to ignore the original value inside an effect and + * replace it with a constant value. + * + * **When to Use** + * + * It is useful when you no longer need the value produced by an effect but want + * to ensure that the effect completes successfully with a specific constant + * result instead. For instance, you can replace the value produced by a + * computation with a predefined value, ignoring what was calculated before. + * + * **Example** (Replacing a Value) + * + * ```ts + * import { pipe, Effect } from "effect" + * + * // Replaces the value 5 with the constant "new value" + * const program = pipe(Effect.succeed(5), Effect.as("new value")) + * + * Effect.runPromise(program).then(console.log) + * // Output: "new value" + * ``` + * + * @since 2.0.0 + * @category Mapping + */ + (value: B): (self: Effect) => Effect + /** + * Replaces the value inside an effect with a constant value. + * + * **Details** + * + * This function allows you to ignore the original value inside an effect and + * replace it with a constant value. + * + * **When to Use** + * + * It is useful when you no longer need the value produced by an effect but want + * to ensure that the effect completes successfully with a specific constant + * result instead. For instance, you can replace the value produced by a + * computation with a predefined value, ignoring what was calculated before. + * + * **Example** (Replacing a Value) + * + * ```ts + * import { pipe, Effect } from "effect" + * + * // Replaces the value 5 with the constant "new value" + * const program = pipe(Effect.succeed(5), Effect.as("new value")) + * + * Effect.runPromise(program).then(console.log) + * // Output: "new value" + * ``` + * + * @since 2.0.0 + * @category Mapping + */ + (self: Effect, value: B): Effect +} = core.as + +/** + * This function maps the success value of an `Effect` value to a `Some` value + * in an `Option` value. If the original `Effect` value fails, the returned + * `Effect` value will also fail. + * + * @category Mapping + * @since 2.0.0 + */ +export const asSome: (self: Effect) => Effect, E, R> = effect.asSome + +/** + * This function maps the error value of an `Effect` value to a `Some` value + * in an `Option` value. If the original `Effect` value succeeds, the returned + * `Effect` value will also succeed. + * + * @category Mapping + * @since 2.0.0 + */ +export const asSomeError: (self: Effect) => Effect, R> = effect.asSomeError + +/** + * This function maps the success value of an `Effect` value to `void`. If the + * original `Effect` value succeeds, the returned `Effect` value will also + * succeed. If the original `Effect` value fails, the returned `Effect` value + * will fail with the same error. + * + * @since 2.0.0 + * @category Mapping + */ +export const asVoid: (self: Effect) => Effect = core.asVoid + +/** + * Swaps the success and error channels of an effect. + * + * **Details** + * + * This function reverses the flow of an effect by swapping its success and + * error channels. The success value becomes an error, and the error value + * becomes a success. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.fail("Oh uh!").pipe(Effect.as(2)) + * + * // ┌─── Effect + * // ▼ + * const flipped = Effect.flip(program) + * ``` + * + * @since 2.0.0 + * @category Mapping + */ +export const flip: (self: Effect) => Effect = core.flip + +/** + * Swaps the error/value parameters, applies the function `f` and flips the + * parameters back + * + * @since 2.0.0 + * @category Mapping + */ +export const flipWith: { + /** + * Swaps the error/value parameters, applies the function `f` and flips the + * parameters back + * + * @since 2.0.0 + * @category Mapping + */ + (f: (effect: Effect) => Effect): (self: Effect) => Effect + /** + * Swaps the error/value parameters, applies the function `f` and flips the + * parameters back + * + * @since 2.0.0 + * @category Mapping + */ + (self: Effect, f: (effect: Effect) => Effect): Effect +} = effect.flipWith + +/** + * Transforms the value inside an effect by applying a function to it. + * + * **Syntax** + * + * ```ts skip-type-checking + * const mappedEffect = pipe(myEffect, Effect.map(transformation)) + * // or + * const mappedEffect = Effect.map(myEffect, transformation) + * // or + * const mappedEffect = myEffect.pipe(Effect.map(transformation)) + * ``` + * + * **Details** + * + * `map` takes a function and applies it to the value contained within an + * effect, creating a new effect with the transformed value. + * + * It's important to note that effects are immutable, meaning that the original + * effect is not modified. Instead, a new effect is returned with the updated + * value. + * + * **Example** (Adding a Service Charge) + * + * ```ts + * import { pipe, Effect } from "effect" + * + * const addServiceCharge = (amount: number) => amount + 1 + * + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * Effect.map(addServiceCharge) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: 101 + * ``` + * + * @see {@link mapError} for a version that operates on the error channel. + * @see {@link mapBoth} for a version that operates on both channels. + * @see {@link flatMap} or {@link andThen} for a version that can return a new effect. + * + * @since 2.0.0 + * @category Mapping + */ +export const map: { + /** + * Transforms the value inside an effect by applying a function to it. + * + * **Syntax** + * + * ```ts skip-type-checking + * const mappedEffect = pipe(myEffect, Effect.map(transformation)) + * // or + * const mappedEffect = Effect.map(myEffect, transformation) + * // or + * const mappedEffect = myEffect.pipe(Effect.map(transformation)) + * ``` + * + * **Details** + * + * `map` takes a function and applies it to the value contained within an + * effect, creating a new effect with the transformed value. + * + * It's important to note that effects are immutable, meaning that the original + * effect is not modified. Instead, a new effect is returned with the updated + * value. + * + * **Example** (Adding a Service Charge) + * + * ```ts + * import { pipe, Effect } from "effect" + * + * const addServiceCharge = (amount: number) => amount + 1 + * + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * Effect.map(addServiceCharge) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: 101 + * ``` + * + * @see {@link mapError} for a version that operates on the error channel. + * @see {@link mapBoth} for a version that operates on both channels. + * @see {@link flatMap} or {@link andThen} for a version that can return a new effect. + * + * @since 2.0.0 + * @category Mapping + */ + (f: (a: A) => B): (self: Effect) => Effect + /** + * Transforms the value inside an effect by applying a function to it. + * + * **Syntax** + * + * ```ts skip-type-checking + * const mappedEffect = pipe(myEffect, Effect.map(transformation)) + * // or + * const mappedEffect = Effect.map(myEffect, transformation) + * // or + * const mappedEffect = myEffect.pipe(Effect.map(transformation)) + * ``` + * + * **Details** + * + * `map` takes a function and applies it to the value contained within an + * effect, creating a new effect with the transformed value. + * + * It's important to note that effects are immutable, meaning that the original + * effect is not modified. Instead, a new effect is returned with the updated + * value. + * + * **Example** (Adding a Service Charge) + * + * ```ts + * import { pipe, Effect } from "effect" + * + * const addServiceCharge = (amount: number) => amount + 1 + * + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * Effect.map(addServiceCharge) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: 101 + * ``` + * + * @see {@link mapError} for a version that operates on the error channel. + * @see {@link mapBoth} for a version that operates on both channels. + * @see {@link flatMap} or {@link andThen} for a version that can return a new effect. + * + * @since 2.0.0 + * @category Mapping + */ + (self: Effect, f: (a: A) => B): Effect +} = core.map + +/** + * Applies a stateful transformation to each element of a collection, producing + * new elements along with an updated state. + * + * **When to Use** + * + * Use `mapAccum` when you need to process each element of a collection while + * keeping track of some state across iterations. + * + * **Details** + * + * `mapAccum` takes an initial state (`initial`) and a function (`f`) that is + * applied to each element. This function returns a new state and a transformed + * element. The final effect produces both the accumulated state and the + * transformed collection. + * + * If the input collection is a non-empty array, the return type will match the + * input collection type. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // Define an initial state and a transformation function + * const initialState = 0 + * + * const transformation = (state: number, element: string) => + * Effect.succeed<[number, string]>([state + element.length, element.toUpperCase()]) + * + * // Apply mapAccum to transform an array of strings + * const program = Effect.mapAccum(["a", "bb", "ccc"], initialState, transformation) + * + * Effect.runPromise(program).then(([finalState, transformedCollection]) => { + * console.log(finalState) + * console.log(transformedCollection) + * }) + * // Output: + * // 6 + * // [ 'A', 'BB', 'CCC' ] + * ``` + * + * @since 2.0.0 + * @category Mapping + */ +export const mapAccum: { + /** + * Applies a stateful transformation to each element of a collection, producing + * new elements along with an updated state. + * + * **When to Use** + * + * Use `mapAccum` when you need to process each element of a collection while + * keeping track of some state across iterations. + * + * **Details** + * + * `mapAccum` takes an initial state (`initial`) and a function (`f`) that is + * applied to each element. This function returns a new state and a transformed + * element. The final effect produces both the accumulated state and the + * transformed collection. + * + * If the input collection is a non-empty array, the return type will match the + * input collection type. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // Define an initial state and a transformation function + * const initialState = 0 + * + * const transformation = (state: number, element: string) => + * Effect.succeed<[number, string]>([state + element.length, element.toUpperCase()]) + * + * // Apply mapAccum to transform an array of strings + * const program = Effect.mapAccum(["a", "bb", "ccc"], initialState, transformation) + * + * Effect.runPromise(program).then(([finalState, transformedCollection]) => { + * console.log(finalState) + * console.log(transformedCollection) + * }) + * // Output: + * // 6 + * // [ 'A', 'BB', 'CCC' ] + * ``` + * + * @since 2.0.0 + * @category Mapping + */ + = Iterable>( + initial: S, + f: (state: S, a: RA.ReadonlyArray.Infer, i: number) => Effect + ): (elements: I) => Effect<[S, RA.ReadonlyArray.With], E, R> + /** + * Applies a stateful transformation to each element of a collection, producing + * new elements along with an updated state. + * + * **When to Use** + * + * Use `mapAccum` when you need to process each element of a collection while + * keeping track of some state across iterations. + * + * **Details** + * + * `mapAccum` takes an initial state (`initial`) and a function (`f`) that is + * applied to each element. This function returns a new state and a transformed + * element. The final effect produces both the accumulated state and the + * transformed collection. + * + * If the input collection is a non-empty array, the return type will match the + * input collection type. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // Define an initial state and a transformation function + * const initialState = 0 + * + * const transformation = (state: number, element: string) => + * Effect.succeed<[number, string]>([state + element.length, element.toUpperCase()]) + * + * // Apply mapAccum to transform an array of strings + * const program = Effect.mapAccum(["a", "bb", "ccc"], initialState, transformation) + * + * Effect.runPromise(program).then(([finalState, transformedCollection]) => { + * console.log(finalState) + * console.log(transformedCollection) + * }) + * // Output: + * // 6 + * // [ 'A', 'BB', 'CCC' ] + * ``` + * + * @since 2.0.0 + * @category Mapping + */ + = Iterable>( + elements: I, + initial: S, + f: (state: S, a: RA.ReadonlyArray.Infer, i: number) => Effect + ): Effect<[S, RA.ReadonlyArray.With], E, R> +} = effect.mapAccum + +/** + * Applies transformations to both the success and error channels of an effect. + * + * **Details** + * + * This function takes two map functions as arguments: one for the error channel + * and one for the success channel. You can use it when you want to modify both + * the error and the success values without altering the overall success or + * failure status of the effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const simulatedTask = Effect.fail("Oh no!").pipe(Effect.as(1)) + * + * // ┌─── Effect + * // ▼ + * const modified = Effect.mapBoth(simulatedTask, { + * onFailure: (message) => new Error(message), + * onSuccess: (n) => n > 0 + * }) + * ``` + * + * @see {@link map} for a version that operates on the success channel. + * @see {@link mapError} for a version that operates on the error channel. + * + * @since 2.0.0 + * @category Mapping + */ +export const mapBoth: { + /** + * Applies transformations to both the success and error channels of an effect. + * + * **Details** + * + * This function takes two map functions as arguments: one for the error channel + * and one for the success channel. You can use it when you want to modify both + * the error and the success values without altering the overall success or + * failure status of the effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const simulatedTask = Effect.fail("Oh no!").pipe(Effect.as(1)) + * + * // ┌─── Effect + * // ▼ + * const modified = Effect.mapBoth(simulatedTask, { + * onFailure: (message) => new Error(message), + * onSuccess: (n) => n > 0 + * }) + * ``` + * + * @see {@link map} for a version that operates on the success channel. + * @see {@link mapError} for a version that operates on the error channel. + * + * @since 2.0.0 + * @category Mapping + */ + ( + options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } + ): (self: Effect) => Effect + /** + * Applies transformations to both the success and error channels of an effect. + * + * **Details** + * + * This function takes two map functions as arguments: one for the error channel + * and one for the success channel. You can use it when you want to modify both + * the error and the success values without altering the overall success or + * failure status of the effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const simulatedTask = Effect.fail("Oh no!").pipe(Effect.as(1)) + * + * // ┌─── Effect + * // ▼ + * const modified = Effect.mapBoth(simulatedTask, { + * onFailure: (message) => new Error(message), + * onSuccess: (n) => n > 0 + * }) + * ``` + * + * @see {@link map} for a version that operates on the success channel. + * @see {@link mapError} for a version that operates on the error channel. + * + * @since 2.0.0 + * @category Mapping + */ + ( + self: Effect, + options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } + ): Effect +} = core.mapBoth + +/** + * Transforms or modifies the error produced by an effect without affecting its + * success value. + * + * **When to Use** + * + * This function is helpful when you want to enhance the error with additional + * information, change the error type, or apply custom error handling while + * keeping the original behavior of the effect's success values intact. It only + * operates on the error channel and leaves the success channel unchanged. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const simulatedTask = Effect.fail("Oh no!").pipe(Effect.as(1)) + * + * // ┌─── Effect + * // ▼ + * const mapped = Effect.mapError( + * simulatedTask, + * (message) => new Error(message) + * ) + * ``` + * + * @see {@link map} for a version that operates on the success channel. + * @see {@link mapBoth} for a version that operates on both channels. + * @see {@link orElseFail} if you want to replace the error with a new one. + * + * @since 2.0.0 + * @category Mapping + */ +export const mapError: { + /** + * Transforms or modifies the error produced by an effect without affecting its + * success value. + * + * **When to Use** + * + * This function is helpful when you want to enhance the error with additional + * information, change the error type, or apply custom error handling while + * keeping the original behavior of the effect's success values intact. It only + * operates on the error channel and leaves the success channel unchanged. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const simulatedTask = Effect.fail("Oh no!").pipe(Effect.as(1)) + * + * // ┌─── Effect + * // ▼ + * const mapped = Effect.mapError( + * simulatedTask, + * (message) => new Error(message) + * ) + * ``` + * + * @see {@link map} for a version that operates on the success channel. + * @see {@link mapBoth} for a version that operates on both channels. + * @see {@link orElseFail} if you want to replace the error with a new one. + * + * @since 2.0.0 + * @category Mapping + */ + (f: (e: E) => E2): (self: Effect) => Effect + /** + * Transforms or modifies the error produced by an effect without affecting its + * success value. + * + * **When to Use** + * + * This function is helpful when you want to enhance the error with additional + * information, change the error type, or apply custom error handling while + * keeping the original behavior of the effect's success values intact. It only + * operates on the error channel and leaves the success channel unchanged. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const simulatedTask = Effect.fail("Oh no!").pipe(Effect.as(1)) + * + * // ┌─── Effect + * // ▼ + * const mapped = Effect.mapError( + * simulatedTask, + * (message) => new Error(message) + * ) + * ``` + * + * @see {@link map} for a version that operates on the success channel. + * @see {@link mapBoth} for a version that operates on both channels. + * @see {@link orElseFail} if you want to replace the error with a new one. + * + * @since 2.0.0 + * @category Mapping + */ + (self: Effect, f: (e: E) => E2): Effect +} = core.mapError + +/** + * Maps the cause of failure of an effect using a specified function. + * + * @see {@link sandbox} for a version that exposes the full cause of failures, defects, or interruptions. + * @see {@link catchAllCause} for a version that can recover from all types of defects. + * + * @since 2.0.0 + * @category Mapping + */ +export const mapErrorCause: { + /** + * Maps the cause of failure of an effect using a specified function. + * + * @see {@link sandbox} for a version that exposes the full cause of failures, defects, or interruptions. + * @see {@link catchAllCause} for a version that can recover from all types of defects. + * + * @since 2.0.0 + * @category Mapping + */ + (f: (cause: Cause.Cause) => Cause.Cause): (self: Effect) => Effect + /** + * Maps the cause of failure of an effect using a specified function. + * + * @see {@link sandbox} for a version that exposes the full cause of failures, defects, or interruptions. + * @see {@link catchAllCause} for a version that can recover from all types of defects. + * + * @since 2.0.0 + * @category Mapping + */ + (self: Effect, f: (cause: Cause.Cause) => Cause.Cause): Effect +} = effect.mapErrorCause + +/** + * Combines both success and error channels of an effect into a single outcome. + * + * **Details** + * + * This function transforms an effect that may fail into one that always returns + * a value, where both success and failure outcomes are handled as values in the + * success channel. + * + * **When to Use** + * + * This can be useful when you want to continue execution regardless of the + * error type and still capture both successful results and errors as part of + * the outcome. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.fail("Oh uh!").pipe(Effect.as(2)) + * + * // ┌─── Effect + * // ▼ + * const recovered = Effect.merge(program) + * ``` + * + * @since 2.0.0 + * @category Mapping + */ +export const merge: (self: Effect) => Effect = effect.merge + +/** + * Returns a new effect with the boolean value of this effect negated. + * + * @since 2.0.0 + * @category Mapping + */ +export const negate: (self: Effect) => Effect = effect.negate + +/** + * Creates a scoped resource using an `acquire` and `release` effect. + * + * **Details** + * + * This function helps manage resources by combining two `Effect` values: one + * for acquiring the resource and one for releasing it. + * + * `acquireRelease` does the following: + * + * 1. Ensures that the effect that acquires the resource will not be + * interrupted. Note that acquisition may still fail due to internal + * reasons (such as an uncaught exception). + * 2. Ensures that the `release` effect will not be interrupted, and will be + * executed as long as the acquisition effect successfully acquires the + * resource. + * + * If the `acquire` function succeeds, the `release` function is added to the + * list of finalizers for the scope. This ensures that the release will happen + * automatically when the scope is closed. + * + * Both `acquire` and `release` run uninterruptibly, meaning they cannot be + * interrupted while they are executing. + * + * Additionally, the `release` function can be influenced by the exit value when + * the scope closes, allowing for custom handling of how the resource is + * released based on the execution outcome. + * + * **When to Use** + * + * This function is used to ensure that an effect that represents the + * acquisition of a resource (for example, opening a file, launching a thread, + * etc.) will not be interrupted, and that the resource will always be released + * when the `Effect` completes execution. + * + * **Example** (Defining a Simple Resource) + * + * ```ts + * import { Effect } from "effect" + * + * // Define an interface for a resource + * interface MyResource { + * readonly contents: string + * readonly close: () => Promise + * } + * + * // Simulate resource acquisition + * const getMyResource = (): Promise => + * Promise.resolve({ + * contents: "lorem ipsum", + * close: () => + * new Promise((resolve) => { + * console.log("Resource released") + * resolve() + * }) + * }) + * + * // Define how the resource is acquired + * const acquire = Effect.tryPromise({ + * try: () => + * getMyResource().then((res) => { + * console.log("Resource acquired") + * return res + * }), + * catch: () => new Error("getMyResourceError") + * }) + * + * // Define how the resource is released + * const release = (res: MyResource) => Effect.promise(() => res.close()) + * + * // Create the resource management workflow + * // + * // ┌─── Effect + * // ▼ + * const resource = Effect.acquireRelease(acquire, release) + * ``` + * + * @see {@link acquireUseRelease} for a version that automatically handles the scoping of resources. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const acquireRelease: { + /** + * Creates a scoped resource using an `acquire` and `release` effect. + * + * **Details** + * + * This function helps manage resources by combining two `Effect` values: one + * for acquiring the resource and one for releasing it. + * + * `acquireRelease` does the following: + * + * 1. Ensures that the effect that acquires the resource will not be + * interrupted. Note that acquisition may still fail due to internal + * reasons (such as an uncaught exception). + * 2. Ensures that the `release` effect will not be interrupted, and will be + * executed as long as the acquisition effect successfully acquires the + * resource. + * + * If the `acquire` function succeeds, the `release` function is added to the + * list of finalizers for the scope. This ensures that the release will happen + * automatically when the scope is closed. + * + * Both `acquire` and `release` run uninterruptibly, meaning they cannot be + * interrupted while they are executing. + * + * Additionally, the `release` function can be influenced by the exit value when + * the scope closes, allowing for custom handling of how the resource is + * released based on the execution outcome. + * + * **When to Use** + * + * This function is used to ensure that an effect that represents the + * acquisition of a resource (for example, opening a file, launching a thread, + * etc.) will not be interrupted, and that the resource will always be released + * when the `Effect` completes execution. + * + * **Example** (Defining a Simple Resource) + * + * ```ts + * import { Effect } from "effect" + * + * // Define an interface for a resource + * interface MyResource { + * readonly contents: string + * readonly close: () => Promise + * } + * + * // Simulate resource acquisition + * const getMyResource = (): Promise => + * Promise.resolve({ + * contents: "lorem ipsum", + * close: () => + * new Promise((resolve) => { + * console.log("Resource released") + * resolve() + * }) + * }) + * + * // Define how the resource is acquired + * const acquire = Effect.tryPromise({ + * try: () => + * getMyResource().then((res) => { + * console.log("Resource acquired") + * return res + * }), + * catch: () => new Error("getMyResourceError") + * }) + * + * // Define how the resource is released + * const release = (res: MyResource) => Effect.promise(() => res.close()) + * + * // Create the resource management workflow + * // + * // ┌─── Effect + * // ▼ + * const resource = Effect.acquireRelease(acquire, release) + * ``` + * + * @see {@link acquireUseRelease} for a version that automatically handles the scoping of resources. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + (release: (a: A, exit: Exit.Exit) => Effect): (acquire: Effect) => Effect + /** + * Creates a scoped resource using an `acquire` and `release` effect. + * + * **Details** + * + * This function helps manage resources by combining two `Effect` values: one + * for acquiring the resource and one for releasing it. + * + * `acquireRelease` does the following: + * + * 1. Ensures that the effect that acquires the resource will not be + * interrupted. Note that acquisition may still fail due to internal + * reasons (such as an uncaught exception). + * 2. Ensures that the `release` effect will not be interrupted, and will be + * executed as long as the acquisition effect successfully acquires the + * resource. + * + * If the `acquire` function succeeds, the `release` function is added to the + * list of finalizers for the scope. This ensures that the release will happen + * automatically when the scope is closed. + * + * Both `acquire` and `release` run uninterruptibly, meaning they cannot be + * interrupted while they are executing. + * + * Additionally, the `release` function can be influenced by the exit value when + * the scope closes, allowing for custom handling of how the resource is + * released based on the execution outcome. + * + * **When to Use** + * + * This function is used to ensure that an effect that represents the + * acquisition of a resource (for example, opening a file, launching a thread, + * etc.) will not be interrupted, and that the resource will always be released + * when the `Effect` completes execution. + * + * **Example** (Defining a Simple Resource) + * + * ```ts + * import { Effect } from "effect" + * + * // Define an interface for a resource + * interface MyResource { + * readonly contents: string + * readonly close: () => Promise + * } + * + * // Simulate resource acquisition + * const getMyResource = (): Promise => + * Promise.resolve({ + * contents: "lorem ipsum", + * close: () => + * new Promise((resolve) => { + * console.log("Resource released") + * resolve() + * }) + * }) + * + * // Define how the resource is acquired + * const acquire = Effect.tryPromise({ + * try: () => + * getMyResource().then((res) => { + * console.log("Resource acquired") + * return res + * }), + * catch: () => new Error("getMyResourceError") + * }) + * + * // Define how the resource is released + * const release = (res: MyResource) => Effect.promise(() => res.close()) + * + * // Create the resource management workflow + * // + * // ┌─── Effect + * // ▼ + * const resource = Effect.acquireRelease(acquire, release) + * ``` + * + * @see {@link acquireUseRelease} for a version that automatically handles the scoping of resources. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + ( + acquire: Effect, + release: (a: A, exit: Exit.Exit) => Effect + ): Effect +} = fiberRuntime.acquireRelease + +/** + * Creates a scoped resource with an interruptible acquire action. + * + * **Details** + * + * This function is similar to {@link acquireRelease}, but it allows the + * acquisition of the resource to be interrupted. The `acquire` effect, which + * represents the process of obtaining the resource, can be interrupted if + * necessary. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const acquireReleaseInterruptible: { + /** + * Creates a scoped resource with an interruptible acquire action. + * + * **Details** + * + * This function is similar to {@link acquireRelease}, but it allows the + * acquisition of the resource to be interrupted. The `acquire` effect, which + * represents the process of obtaining the resource, can be interrupted if + * necessary. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + (release: (exit: Exit.Exit) => Effect): (acquire: Effect) => Effect + /** + * Creates a scoped resource with an interruptible acquire action. + * + * **Details** + * + * This function is similar to {@link acquireRelease}, but it allows the + * acquisition of the resource to be interrupted. The `acquire` effect, which + * represents the process of obtaining the resource, can be interrupted if + * necessary. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + ( + acquire: Effect, + release: (exit: Exit.Exit) => Effect + ): Effect +} = fiberRuntime.acquireReleaseInterruptible + +/** + * Many real-world operations involve working with resources that must be released when no longer needed, such as: + * + * - Database connections + * - File handles + * - Network requests + * + * This function ensures that a resource is: + * + * 1. **Acquired** properly. + * 2. **Used** for its intended purpose. + * 3. **Released** even if an error occurs. + * + * **Example** (Automatically Managing Resource Lifetime) + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Define an interface for a resource + * interface MyResource { + * readonly contents: string + * readonly close: () => Promise + * } + * + * // Simulate resource acquisition + * const getMyResource = (): Promise => + * Promise.resolve({ + * contents: "lorem ipsum", + * close: () => + * new Promise((resolve) => { + * console.log("Resource released") + * resolve() + * }) + * }) + * + * // Define how the resource is acquired + * const acquire = Effect.tryPromise({ + * try: () => + * getMyResource().then((res) => { + * console.log("Resource acquired") + * return res + * }), + * catch: () => new Error("getMyResourceError") + * }) + * + * // Define how the resource is released + * const release = (res: MyResource) => Effect.promise(() => res.close()) + * + * const use = (res: MyResource) => Console.log(`content is ${res.contents}`) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.acquireUseRelease(acquire, use, release) + * + * Effect.runPromise(program) + * // Output: + * // Resource acquired + * // content is lorem ipsum + * // Resource released + * ``` + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const acquireUseRelease: { + /** + * Many real-world operations involve working with resources that must be released when no longer needed, such as: + * + * - Database connections + * - File handles + * - Network requests + * + * This function ensures that a resource is: + * + * 1. **Acquired** properly. + * 2. **Used** for its intended purpose. + * 3. **Released** even if an error occurs. + * + * **Example** (Automatically Managing Resource Lifetime) + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Define an interface for a resource + * interface MyResource { + * readonly contents: string + * readonly close: () => Promise + * } + * + * // Simulate resource acquisition + * const getMyResource = (): Promise => + * Promise.resolve({ + * contents: "lorem ipsum", + * close: () => + * new Promise((resolve) => { + * console.log("Resource released") + * resolve() + * }) + * }) + * + * // Define how the resource is acquired + * const acquire = Effect.tryPromise({ + * try: () => + * getMyResource().then((res) => { + * console.log("Resource acquired") + * return res + * }), + * catch: () => new Error("getMyResourceError") + * }) + * + * // Define how the resource is released + * const release = (res: MyResource) => Effect.promise(() => res.close()) + * + * const use = (res: MyResource) => Console.log(`content is ${res.contents}`) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.acquireUseRelease(acquire, use, release) + * + * Effect.runPromise(program) + * // Output: + * // Resource acquired + * // content is lorem ipsum + * // Resource released + * ``` + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + ( + use: (a: A) => Effect, + release: (a: A, exit: Exit.Exit) => Effect + ): (acquire: Effect) => Effect + /** + * Many real-world operations involve working with resources that must be released when no longer needed, such as: + * + * - Database connections + * - File handles + * - Network requests + * + * This function ensures that a resource is: + * + * 1. **Acquired** properly. + * 2. **Used** for its intended purpose. + * 3. **Released** even if an error occurs. + * + * **Example** (Automatically Managing Resource Lifetime) + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Define an interface for a resource + * interface MyResource { + * readonly contents: string + * readonly close: () => Promise + * } + * + * // Simulate resource acquisition + * const getMyResource = (): Promise => + * Promise.resolve({ + * contents: "lorem ipsum", + * close: () => + * new Promise((resolve) => { + * console.log("Resource released") + * resolve() + * }) + * }) + * + * // Define how the resource is acquired + * const acquire = Effect.tryPromise({ + * try: () => + * getMyResource().then((res) => { + * console.log("Resource acquired") + * return res + * }), + * catch: () => new Error("getMyResourceError") + * }) + * + * // Define how the resource is released + * const release = (res: MyResource) => Effect.promise(() => res.close()) + * + * const use = (res: MyResource) => Console.log(`content is ${res.contents}`) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.acquireUseRelease(acquire, use, release) + * + * Effect.runPromise(program) + * // Output: + * // Resource acquired + * // content is lorem ipsum + * // Resource released + * ``` + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + ( + acquire: Effect, + use: (a: A) => Effect, + release: (a: A, exit: Exit.Exit) => Effect + ): Effect +} = core.acquireUseRelease + +/** + * Ensures a finalizer is added to the scope of the calling effect, guaranteeing + * it runs when the scope is closed. + * + * **Details** + * + * This function adds a finalizer that will execute whenever the scope of the + * effect is closed, regardless of whether the effect succeeds, fails, or is + * interrupted. The finalizer receives the `Exit` value of the effect's scope, + * allowing it to react differently depending on how the effect concludes. + * + * Finalizers are a reliable way to manage resource cleanup, ensuring that + * resources such as file handles, network connections, or database transactions + * are properly closed even in the event of an unexpected interruption or error. + * + * Finalizers operate in conjunction with Effect's scoped resources. If an + * effect with a finalizer is wrapped in a scope, the finalizer will execute + * automatically when the scope ends. + * + * **Example** (Adding a Finalizer on Success) + * + * ```ts + * import { Effect, Console } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * yield* Effect.addFinalizer((exit) => + * Console.log(`Finalizer executed. Exit status: ${exit._tag}`) + * ) + * return "some result" + * }) + * + * // Wrapping the effect in a scope + * // + * // ┌─── Effect + * // ▼ + * const runnable = Effect.scoped(program) + * + * Effect.runPromiseExit(runnable).then(console.log) + * // Output: + * // Finalizer executed. Exit status: Success + * // { _id: 'Exit', _tag: 'Success', value: 'some result' } + * ``` + * + * **Example** (Adding a Finalizer on Failure) + * + * ```ts + * import { Effect, Console } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * yield* Effect.addFinalizer((exit) => + * Console.log(`Finalizer executed. Exit status: ${exit._tag}`) + * ) + * return yield* Effect.fail("Uh oh!") + * }) + * + * // Wrapping the effect in a scope + * // + * // ┌─── Effect + * // ▼ + * const runnable = Effect.scoped(program) + * + * Effect.runPromiseExit(runnable).then(console.log) + * // Output: + * // Finalizer executed. Exit status: Failure + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Uh oh!' } + * // } + * ``` + * + * **Example** (Adding a Finalizer on Interruption) + * + * ```ts + * import { Effect, Console } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * yield* Effect.addFinalizer((exit) => + * Console.log(`Finalizer executed. Exit status: ${exit._tag}`) + * ) + * return yield* Effect.interrupt + * }) + * + * // Wrapping the effect in a scope + * // + * // ┌─── Effect + * // ▼ + * const runnable = Effect.scoped(program) + * + * Effect.runPromiseExit(runnable).then(console.log) + * // Output: + * // Finalizer executed. Exit status: Failure + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Interrupt', + * // fiberId: { + * // _id: 'FiberId', + * // _tag: 'Runtime', + * // id: 0, + * // startTimeMillis: ... + * // } + * // } + * // } + * ``` + * + * @see {@link onExit} for attaching a finalizer directly to an effect. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const addFinalizer: ( + finalizer: (exit: Exit.Exit) => Effect +) => Effect = fiberRuntime.addFinalizer + +/** + * Guarantees the execution of a finalizer when an effect starts execution. + * + * **Details** + * + * This function allows you to specify a `finalizer` effect that will always be + * run once the effect starts execution, regardless of whether the effect + * succeeds, fails, or is interrupted. + * + * **When to Use** + * + * This is useful when you need to ensure that certain cleanup or final steps + * are executed in all cases, such as releasing resources or performing + * necessary logging. + * + * While this function provides strong guarantees about executing the finalizer, + * it is considered a low-level tool, which may not be ideal for more complex + * resource management. For higher-level resource management with automatic + * acquisition and release, see the {@link acquireRelease} family of functions. + * For use cases where you need access to the result of an effect, consider + * using {@link onExit}. + * + * **Example** (Running a Finalizer in All Outcomes) + * + * ```ts + * import { Console, Effect } from "effect" + * + * // Define a cleanup effect + * const handler = Effect.ensuring(Console.log("Cleanup completed")) + * + * // Define a successful effect + * const success = Console.log("Task completed").pipe( + * Effect.as("some result"), + * handler + * ) + * + * Effect.runFork(success) + * // Output: + * // Task completed + * // Cleanup completed + * + * // Define a failing effect + * const failure = Console.log("Task failed").pipe( + * Effect.andThen(Effect.fail("some error")), + * handler + * ) + * + * Effect.runFork(failure) + * // Output: + * // Task failed + * // Cleanup completed + * + * // Define an interrupted effect + * const interruption = Console.log("Task interrupted").pipe( + * Effect.andThen(Effect.interrupt), + * handler + * ) + * + * Effect.runFork(interruption) + * // Output: + * // Task interrupted + * // Cleanup completed + * ``` + * + * @see {@link onExit} for a version that provides access to the result of an + * effect. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const ensuring: { + /** + * Guarantees the execution of a finalizer when an effect starts execution. + * + * **Details** + * + * This function allows you to specify a `finalizer` effect that will always be + * run once the effect starts execution, regardless of whether the effect + * succeeds, fails, or is interrupted. + * + * **When to Use** + * + * This is useful when you need to ensure that certain cleanup or final steps + * are executed in all cases, such as releasing resources or performing + * necessary logging. + * + * While this function provides strong guarantees about executing the finalizer, + * it is considered a low-level tool, which may not be ideal for more complex + * resource management. For higher-level resource management with automatic + * acquisition and release, see the {@link acquireRelease} family of functions. + * For use cases where you need access to the result of an effect, consider + * using {@link onExit}. + * + * **Example** (Running a Finalizer in All Outcomes) + * + * ```ts + * import { Console, Effect } from "effect" + * + * // Define a cleanup effect + * const handler = Effect.ensuring(Console.log("Cleanup completed")) + * + * // Define a successful effect + * const success = Console.log("Task completed").pipe( + * Effect.as("some result"), + * handler + * ) + * + * Effect.runFork(success) + * // Output: + * // Task completed + * // Cleanup completed + * + * // Define a failing effect + * const failure = Console.log("Task failed").pipe( + * Effect.andThen(Effect.fail("some error")), + * handler + * ) + * + * Effect.runFork(failure) + * // Output: + * // Task failed + * // Cleanup completed + * + * // Define an interrupted effect + * const interruption = Console.log("Task interrupted").pipe( + * Effect.andThen(Effect.interrupt), + * handler + * ) + * + * Effect.runFork(interruption) + * // Output: + * // Task interrupted + * // Cleanup completed + * ``` + * + * @see {@link onExit} for a version that provides access to the result of an + * effect. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + (finalizer: Effect): (self: Effect) => Effect + /** + * Guarantees the execution of a finalizer when an effect starts execution. + * + * **Details** + * + * This function allows you to specify a `finalizer` effect that will always be + * run once the effect starts execution, regardless of whether the effect + * succeeds, fails, or is interrupted. + * + * **When to Use** + * + * This is useful when you need to ensure that certain cleanup or final steps + * are executed in all cases, such as releasing resources or performing + * necessary logging. + * + * While this function provides strong guarantees about executing the finalizer, + * it is considered a low-level tool, which may not be ideal for more complex + * resource management. For higher-level resource management with automatic + * acquisition and release, see the {@link acquireRelease} family of functions. + * For use cases where you need access to the result of an effect, consider + * using {@link onExit}. + * + * **Example** (Running a Finalizer in All Outcomes) + * + * ```ts + * import { Console, Effect } from "effect" + * + * // Define a cleanup effect + * const handler = Effect.ensuring(Console.log("Cleanup completed")) + * + * // Define a successful effect + * const success = Console.log("Task completed").pipe( + * Effect.as("some result"), + * handler + * ) + * + * Effect.runFork(success) + * // Output: + * // Task completed + * // Cleanup completed + * + * // Define a failing effect + * const failure = Console.log("Task failed").pipe( + * Effect.andThen(Effect.fail("some error")), + * handler + * ) + * + * Effect.runFork(failure) + * // Output: + * // Task failed + * // Cleanup completed + * + * // Define an interrupted effect + * const interruption = Console.log("Task interrupted").pipe( + * Effect.andThen(Effect.interrupt), + * handler + * ) + * + * Effect.runFork(interruption) + * // Output: + * // Task interrupted + * // Cleanup completed + * ``` + * + * @see {@link onExit} for a version that provides access to the result of an + * effect. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + (self: Effect, finalizer: Effect): Effect +} = fiberRuntime.ensuring + +/** + * Ensures a cleanup effect runs whenever the calling effect fails, providing + * the failure cause to the cleanup effect. + * + * **Details** + * + * This function allows you to attach a cleanup effect that runs whenever the + * calling effect fails. The cleanup effect receives the cause of the failure, + * allowing you to perform actions such as logging, releasing resources, or + * executing additional recovery logic based on the error. The cleanup effect + * will execute even if the failure is due to interruption. + * + * Importantly, the cleanup effect itself is uninterruptible, ensuring that it + * completes regardless of external interruptions. + * + * **Example** (Running Cleanup Only on Failure) + * + * ```ts + * import { Console, Effect } from "effect" + * + * // This handler logs the failure cause when the effect fails + * const handler = Effect.onError((cause) => + * Console.log(`Cleanup completed: ${cause}`) + * ) + * + * // Define a successful effect + * const success = Console.log("Task completed").pipe( + * Effect.as("some result"), + * handler + * ) + * + * Effect.runFork(success) + * // Output: + * // Task completed + * + * // Define a failing effect + * const failure = Console.log("Task failed").pipe( + * Effect.andThen(Effect.fail("some error")), + * handler + * ) + * + * Effect.runFork(failure) + * // Output: + * // Task failed + * // Cleanup completed: Error: some error + * + * // Define a failing effect + * const defect = Console.log("Task failed with defect").pipe( + * Effect.andThen(Effect.die("Boom!")), + * handler + * ) + * + * Effect.runFork(defect) + * // Output: + * // Task failed with defect + * // Cleanup completed: Error: Boom! + * + * // Define an interrupted effect + * const interruption = Console.log("Task interrupted").pipe( + * Effect.andThen(Effect.interrupt), + * handler + * ) + * + * Effect.runFork(interruption) + * // Output: + * // Task interrupted + * // Cleanup completed: All fibers interrupted without errors. + * ``` + * + * @see {@link ensuring} for attaching a cleanup effect that runs on both success and failure. + * @see {@link onExit} for attaching a cleanup effect that runs on all possible exits. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const onError: { + /** + * Ensures a cleanup effect runs whenever the calling effect fails, providing + * the failure cause to the cleanup effect. + * + * **Details** + * + * This function allows you to attach a cleanup effect that runs whenever the + * calling effect fails. The cleanup effect receives the cause of the failure, + * allowing you to perform actions such as logging, releasing resources, or + * executing additional recovery logic based on the error. The cleanup effect + * will execute even if the failure is due to interruption. + * + * Importantly, the cleanup effect itself is uninterruptible, ensuring that it + * completes regardless of external interruptions. + * + * **Example** (Running Cleanup Only on Failure) + * + * ```ts + * import { Console, Effect } from "effect" + * + * // This handler logs the failure cause when the effect fails + * const handler = Effect.onError((cause) => + * Console.log(`Cleanup completed: ${cause}`) + * ) + * + * // Define a successful effect + * const success = Console.log("Task completed").pipe( + * Effect.as("some result"), + * handler + * ) + * + * Effect.runFork(success) + * // Output: + * // Task completed + * + * // Define a failing effect + * const failure = Console.log("Task failed").pipe( + * Effect.andThen(Effect.fail("some error")), + * handler + * ) + * + * Effect.runFork(failure) + * // Output: + * // Task failed + * // Cleanup completed: Error: some error + * + * // Define a failing effect + * const defect = Console.log("Task failed with defect").pipe( + * Effect.andThen(Effect.die("Boom!")), + * handler + * ) + * + * Effect.runFork(defect) + * // Output: + * // Task failed with defect + * // Cleanup completed: Error: Boom! + * + * // Define an interrupted effect + * const interruption = Console.log("Task interrupted").pipe( + * Effect.andThen(Effect.interrupt), + * handler + * ) + * + * Effect.runFork(interruption) + * // Output: + * // Task interrupted + * // Cleanup completed: All fibers interrupted without errors. + * ``` + * + * @see {@link ensuring} for attaching a cleanup effect that runs on both success and failure. + * @see {@link onExit} for attaching a cleanup effect that runs on all possible exits. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + (cleanup: (cause: Cause.Cause) => Effect): (self: Effect) => Effect + /** + * Ensures a cleanup effect runs whenever the calling effect fails, providing + * the failure cause to the cleanup effect. + * + * **Details** + * + * This function allows you to attach a cleanup effect that runs whenever the + * calling effect fails. The cleanup effect receives the cause of the failure, + * allowing you to perform actions such as logging, releasing resources, or + * executing additional recovery logic based on the error. The cleanup effect + * will execute even if the failure is due to interruption. + * + * Importantly, the cleanup effect itself is uninterruptible, ensuring that it + * completes regardless of external interruptions. + * + * **Example** (Running Cleanup Only on Failure) + * + * ```ts + * import { Console, Effect } from "effect" + * + * // This handler logs the failure cause when the effect fails + * const handler = Effect.onError((cause) => + * Console.log(`Cleanup completed: ${cause}`) + * ) + * + * // Define a successful effect + * const success = Console.log("Task completed").pipe( + * Effect.as("some result"), + * handler + * ) + * + * Effect.runFork(success) + * // Output: + * // Task completed + * + * // Define a failing effect + * const failure = Console.log("Task failed").pipe( + * Effect.andThen(Effect.fail("some error")), + * handler + * ) + * + * Effect.runFork(failure) + * // Output: + * // Task failed + * // Cleanup completed: Error: some error + * + * // Define a failing effect + * const defect = Console.log("Task failed with defect").pipe( + * Effect.andThen(Effect.die("Boom!")), + * handler + * ) + * + * Effect.runFork(defect) + * // Output: + * // Task failed with defect + * // Cleanup completed: Error: Boom! + * + * // Define an interrupted effect + * const interruption = Console.log("Task interrupted").pipe( + * Effect.andThen(Effect.interrupt), + * handler + * ) + * + * Effect.runFork(interruption) + * // Output: + * // Task interrupted + * // Cleanup completed: All fibers interrupted without errors. + * ``` + * + * @see {@link ensuring} for attaching a cleanup effect that runs on both success and failure. + * @see {@link onExit} for attaching a cleanup effect that runs on all possible exits. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + ( + self: Effect, + cleanup: (cause: Cause.Cause) => Effect + ): Effect +} = core.onError + +/** + * Guarantees that a cleanup function runs regardless of whether the effect + * succeeds, fails, or is interrupted. + * + * **Details** + * + * This function ensures that a provided cleanup function is executed after the + * effect completes, regardless of the outcome. The cleanup function is given + * the `Exit` value of the effect, which provides detailed information about the + * result: + * - If the effect succeeds, the `Exit` contains the success value. + * - If the effect fails, the `Exit` contains the error or failure cause. + * - If the effect is interrupted, the `Exit` reflects the interruption. + * + * The cleanup function is guaranteed to run uninterruptibly, ensuring reliable + * resource management even in complex or high-concurrency scenarios. + * + * **Example** (Running a Cleanup Function with the Effect’s Result) + * + * ```ts + * import { Console, Effect, Exit } from "effect" + * + * // Define a cleanup effect that logs the result + * const handler = Effect.onExit((exit) => + * Console.log(`Cleanup completed: ${Exit.getOrElse(exit, String)}`) + * ) + * + * // Define a successful effect + * const success = Console.log("Task completed").pipe( + * Effect.as("some result"), + * handler + * ) + * + * Effect.runFork(success) + * // Output: + * // Task completed + * // Cleanup completed: some result + * + * // Define a failing effect + * const failure = Console.log("Task failed").pipe( + * Effect.andThen(Effect.fail("some error")), + * handler + * ) + * + * Effect.runFork(failure) + * // Output: + * // Task failed + * // Cleanup completed: Error: some error + * + * // Define an interrupted effect + * const interruption = Console.log("Task interrupted").pipe( + * Effect.andThen(Effect.interrupt), + * handler + * ) + * + * Effect.runFork(interruption) + * // Output: + * // Task interrupted + * // Cleanup completed: All fibers interrupted without errors. + * ``` + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const onExit: { + /** + * Guarantees that a cleanup function runs regardless of whether the effect + * succeeds, fails, or is interrupted. + * + * **Details** + * + * This function ensures that a provided cleanup function is executed after the + * effect completes, regardless of the outcome. The cleanup function is given + * the `Exit` value of the effect, which provides detailed information about the + * result: + * - If the effect succeeds, the `Exit` contains the success value. + * - If the effect fails, the `Exit` contains the error or failure cause. + * - If the effect is interrupted, the `Exit` reflects the interruption. + * + * The cleanup function is guaranteed to run uninterruptibly, ensuring reliable + * resource management even in complex or high-concurrency scenarios. + * + * **Example** (Running a Cleanup Function with the Effect’s Result) + * + * ```ts + * import { Console, Effect, Exit } from "effect" + * + * // Define a cleanup effect that logs the result + * const handler = Effect.onExit((exit) => + * Console.log(`Cleanup completed: ${Exit.getOrElse(exit, String)}`) + * ) + * + * // Define a successful effect + * const success = Console.log("Task completed").pipe( + * Effect.as("some result"), + * handler + * ) + * + * Effect.runFork(success) + * // Output: + * // Task completed + * // Cleanup completed: some result + * + * // Define a failing effect + * const failure = Console.log("Task failed").pipe( + * Effect.andThen(Effect.fail("some error")), + * handler + * ) + * + * Effect.runFork(failure) + * // Output: + * // Task failed + * // Cleanup completed: Error: some error + * + * // Define an interrupted effect + * const interruption = Console.log("Task interrupted").pipe( + * Effect.andThen(Effect.interrupt), + * handler + * ) + * + * Effect.runFork(interruption) + * // Output: + * // Task interrupted + * // Cleanup completed: All fibers interrupted without errors. + * ``` + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + (cleanup: (exit: Exit.Exit) => Effect): (self: Effect) => Effect + /** + * Guarantees that a cleanup function runs regardless of whether the effect + * succeeds, fails, or is interrupted. + * + * **Details** + * + * This function ensures that a provided cleanup function is executed after the + * effect completes, regardless of the outcome. The cleanup function is given + * the `Exit` value of the effect, which provides detailed information about the + * result: + * - If the effect succeeds, the `Exit` contains the success value. + * - If the effect fails, the `Exit` contains the error or failure cause. + * - If the effect is interrupted, the `Exit` reflects the interruption. + * + * The cleanup function is guaranteed to run uninterruptibly, ensuring reliable + * resource management even in complex or high-concurrency scenarios. + * + * **Example** (Running a Cleanup Function with the Effect’s Result) + * + * ```ts + * import { Console, Effect, Exit } from "effect" + * + * // Define a cleanup effect that logs the result + * const handler = Effect.onExit((exit) => + * Console.log(`Cleanup completed: ${Exit.getOrElse(exit, String)}`) + * ) + * + * // Define a successful effect + * const success = Console.log("Task completed").pipe( + * Effect.as("some result"), + * handler + * ) + * + * Effect.runFork(success) + * // Output: + * // Task completed + * // Cleanup completed: some result + * + * // Define a failing effect + * const failure = Console.log("Task failed").pipe( + * Effect.andThen(Effect.fail("some error")), + * handler + * ) + * + * Effect.runFork(failure) + * // Output: + * // Task failed + * // Cleanup completed: Error: some error + * + * // Define an interrupted effect + * const interruption = Console.log("Task interrupted").pipe( + * Effect.andThen(Effect.interrupt), + * handler + * ) + * + * Effect.runFork(interruption) + * // Output: + * // Task interrupted + * // Cleanup completed: All fibers interrupted without errors. + * ``` + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + ( + self: Effect, + cleanup: (exit: Exit.Exit) => Effect + ): Effect +} = core.onExit + +/** + * Ensures that finalizers are run concurrently when the scope of an effect is + * closed. + * + * **Details** + * + * This function modifies the behavior of finalizers within a scoped workflow to + * allow them to run concurrently when the scope is closed. + * + * By default, finalizers are executed sequentially in reverse order of their + * addition, but this function changes that behavior to execute all finalizers + * concurrently. + * + * **When to Use** + * + * Running finalizers concurrently can improve performance when multiple + * independent cleanup tasks need to be performed. However, it requires that + * these tasks do not depend on the order of execution or introduce race + * conditions. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * // Define a program that adds multiple finalizers + * const program = Effect.gen(function*() { + * yield* Effect.addFinalizer(() => Console.log("Finalizer 1 executed").pipe(Effect.delay("300 millis"))) + * yield* Effect.addFinalizer(() => Console.log("Finalizer 2 executed").pipe(Effect.delay("100 millis"))) + * yield* Effect.addFinalizer(() => Console.log("Finalizer 3 executed").pipe(Effect.delay("200 millis"))) + * return "some result" + * }) + * + * // Modify the program to ensure finalizers run in parallel + * const modified = program.pipe(Effect.parallelFinalizers) + * + * const runnable = Effect.scoped(modified) + * + * Effect.runFork(runnable) + * // Output: + * // Finalizer 2 executed + * // Finalizer 3 executed + * // Finalizer 1 executed + * ``` + * + * @see {@link sequentialFinalizers} for a version that ensures finalizers are run sequentially. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const parallelFinalizers: (self: Effect) => Effect = fiberRuntime.parallelFinalizers + +/** + * Ensures that finalizers are run sequentially in reverse order of their + * addition. + * + * **Details** + * + * This function modifies the behavior of finalizers within a scoped workflow to + * ensure they are run sequentially in reverse order when the scope is closed. + * + * By default, finalizers are executed sequentially, so this only changes the + * behavior if the scope is configured to run finalizers concurrently. + * + * @see {@link parallelFinalizers} for a version that ensures finalizers are run concurrently. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const sequentialFinalizers: (self: Effect) => Effect = + fiberRuntime.sequentialFinalizers + +/** + * Applies a custom execution strategy to finalizers within a scoped workflow. + * + * **Details** + * + * This function allows you to control how finalizers are executed in a scope by + * applying a specified `ExecutionStrategy`. The `strategy` can dictate whether + * finalizers run (e.g., sequentially or in parallel). + * + * Additionally, the function provides a `restore` operation, which ensures that + * the effect passed to it is executed under the default execution strategy. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const finalizersMask: ( + strategy: ExecutionStrategy +) => ( + self: (restore: (self: Effect) => Effect) => Effect +) => Effect = fiberRuntime.finalizersMask + +/** + * Provides access to the current scope in a scoped workflow. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const scope: Effect = fiberRuntime.scope + +/** + * Accesses the current scope and uses it to perform the specified effect. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const scopeWith: (f: (scope: Scope.Scope) => Effect) => Effect = + fiberRuntime.scopeWith + +/** + * Creates a `Scope`, passes it to the specified effectful function, and closes + * the scope when the effect completes (whether through success, failure, or + * interruption). + * + * @since 3.11.0 + * @category Scoping, Resources & Finalization + */ +export const scopedWith: (f: (scope: Scope.Scope) => Effect) => Effect = + fiberRuntime.scopedWith + +/** + * Scopes all resources used in an effect to the lifetime of the effect. + * + * **Details** + * + * This function ensures that all resources used within an effect are tied to + * its lifetime. Finalizers for these resources are executed automatically when + * the effect completes, whether through success, failure, or interruption. This + * guarantees proper resource cleanup without requiring explicit management. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const scoped: (effect: Effect) => Effect> = + fiberRuntime.scopedEffect + +/** + * Scopes all resources acquired by one effect to the lifetime of another + * effect. + * + * **Details** + * + * This function allows you to scope the resources acquired by one effect + * (`self`) to the lifetime of another effect (`use`). This ensures that the + * resources are cleaned up as soon as the `use` effect completes, regardless of + * how the `use` effect ends (success, failure, or interruption). + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const acquire = Console.log("Acquiring resource").pipe( + * Effect.as(1), + * Effect.tap(Effect.addFinalizer(() => Console.log("Releasing resource"))) + * ) + * const use = (resource: number) => Console.log(`Using resource: ${resource}`) + * + * const program = acquire.pipe(Effect.using(use)) + * + * Effect.runFork(program) + * // Output: + * // Acquiring resource + * // Using resource: 1 + * // Releasing resource + * ``` + * + * @see {@link scopedWith} Manage scoped operations with a temporary scope. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const using: { + /** + * Scopes all resources acquired by one effect to the lifetime of another + * effect. + * + * **Details** + * + * This function allows you to scope the resources acquired by one effect + * (`self`) to the lifetime of another effect (`use`). This ensures that the + * resources are cleaned up as soon as the `use` effect completes, regardless of + * how the `use` effect ends (success, failure, or interruption). + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const acquire = Console.log("Acquiring resource").pipe( + * Effect.as(1), + * Effect.tap(Effect.addFinalizer(() => Console.log("Releasing resource"))) + * ) + * const use = (resource: number) => Console.log(`Using resource: ${resource}`) + * + * const program = acquire.pipe(Effect.using(use)) + * + * Effect.runFork(program) + * // Output: + * // Acquiring resource + * // Using resource: 1 + * // Releasing resource + * ``` + * + * @see {@link scopedWith} Manage scoped operations with a temporary scope. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + (use: (a: A) => Effect): (self: Effect) => Effect> + /** + * Scopes all resources acquired by one effect to the lifetime of another + * effect. + * + * **Details** + * + * This function allows you to scope the resources acquired by one effect + * (`self`) to the lifetime of another effect (`use`). This ensures that the + * resources are cleaned up as soon as the `use` effect completes, regardless of + * how the `use` effect ends (success, failure, or interruption). + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const acquire = Console.log("Acquiring resource").pipe( + * Effect.as(1), + * Effect.tap(Effect.addFinalizer(() => Console.log("Releasing resource"))) + * ) + * const use = (resource: number) => Console.log(`Using resource: ${resource}`) + * + * const program = acquire.pipe(Effect.using(use)) + * + * Effect.runFork(program) + * // Output: + * // Acquiring resource + * // Using resource: 1 + * // Releasing resource + * ``` + * + * @see {@link scopedWith} Manage scoped operations with a temporary scope. + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ + (self: Effect, use: (a: A) => Effect): Effect> +} = fiberRuntime.using + +/** + * Returns the result of the effect and a finalizer to close its scope. + * + * **Details** + * + * This function allows you to retrieve both the result of an effect and a + * finalizer that can be used to manually close its scope. This is useful for + * workflows where you need early access to the result while retaining control + * over the resource cleanup process. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const acquire = Console.log("Acquiring resource").pipe( + * Effect.as(1), + * Effect.tap(Effect.addFinalizer(() => Console.log("Releasing resource"))) + * ) + * const program = Effect.gen(function*() { + * const [finalizer, resource] = yield* Effect.withEarlyRelease(acquire) + * console.log(`Using resource: ${resource}`) + * yield* Effect.sleep("1 second") + * yield* finalizer + * }) + * + * Effect.runFork(program.pipe(Effect.scoped)) + * // Output: + * // Acquiring resource + * // Using resource: 1 + * // Releasing resource + * ``` + * + * @since 2.0.0 + * @category Scoping, Resources & Finalization + */ +export const withEarlyRelease: ( + self: Effect +) => Effect<[finalizer: Effect, result: A], E, R | Scope.Scope> = fiberRuntime.withEarlyRelease + +/** + * Returns a new effect that will not succeed with its value before first + * waiting for the end of all child fibers forked by the effect. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const awaitAllChildren: (self: Effect) => Effect = circular.awaitAllChildren + +/** + * Returns a new workflow that will not supervise any fibers forked by this + * workflow. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const daemonChildren: (self: Effect) => Effect = fiberRuntime.daemonChildren + +/** + * Constructs an effect with information about the current `Fiber`. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const descriptor: Effect = effect.descriptor + +/** + * Constructs an effect based on information about the current `Fiber`. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const descriptorWith: (f: (descriptor: Fiber.Fiber.Descriptor) => Effect) => Effect = + effect.descriptorWith + +/** + * Returns a new workflow that executes this one and captures the changes in + * `FiberRef` values. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const diffFiberRefs: ( + self: Effect +) => Effect<[FiberRefsPatch.FiberRefsPatch, A], E, R> = effect.diffFiberRefs + +/** + * Acts on the children of this fiber (collected into a single fiber), + * guaranteeing the specified callback will be invoked, whether or not this + * effect succeeds. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const ensuringChild: { + /** + * Acts on the children of this fiber (collected into a single fiber), + * guaranteeing the specified callback will be invoked, whether or not this + * effect succeeds. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + ( + f: (fiber: Fiber.Fiber, any>) => Effect + ): (self: Effect) => Effect + /** + * Acts on the children of this fiber (collected into a single fiber), + * guaranteeing the specified callback will be invoked, whether or not this + * effect succeeds. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + ( + self: Effect, + f: (fiber: Fiber.Fiber, any>) => Effect + ): Effect +} = circular.ensuringChild + +/** + * Acts on the children of this fiber, guaranteeing the specified callback + * will be invoked, whether or not this effect succeeds. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const ensuringChildren: { + /** + * Acts on the children of this fiber, guaranteeing the specified callback + * will be invoked, whether or not this effect succeeds. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + ( + children: (fibers: ReadonlyArray>) => Effect + ): (self: Effect) => Effect + /** + * Acts on the children of this fiber, guaranteeing the specified callback + * will be invoked, whether or not this effect succeeds. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + ( + self: Effect, + children: (fibers: ReadonlyArray>) => Effect + ): Effect +} = circular.ensuringChildren + +/** + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const fiberId: Effect = core.fiberId + +/** + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const fiberIdWith: (f: (descriptor: FiberId.Runtime) => Effect) => Effect = + core.fiberIdWith + +/** + * Creates a new fiber to run an effect concurrently. + * + * **Details** + * + * This function takes an effect and forks it into a separate fiber, allowing it + * to run concurrently without blocking the original effect. The new fiber + * starts execution immediately after being created, and the fiber object is + * returned immediately without waiting for the effect to begin. This is useful + * when you want to run tasks concurrently while continuing other tasks in the + * parent fiber. + * + * The forked fiber is attached to the parent fiber's scope. This means that + * when the parent fiber terminates, the child fiber will also be terminated + * automatically. This feature, known as "auto supervision," ensures that no + * fibers are left running unintentionally. If you prefer not to have this auto + * supervision behavior, you can use {@link forkDaemon} or {@link forkIn}. + * + * **When to Use** + * + * Use this function when you need to run an effect concurrently without + * blocking the current execution flow. For example, you might use it to launch + * background tasks or concurrent computations. However, working with fibers can + * be complex, so before using this function directly, you might want to explore + * higher-level functions like {@link raceWith}, {@link zip}, or others that can + * manage concurrency for you. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const fib = (n: number): Effect.Effect => + * n < 2 + * ? Effect.succeed(n) + * : Effect.zipWith(fib(n - 1), fib(n - 2), (a, b) => a + b) + * + * // ┌─── Effect, never, never> + * // ▼ + * const fib10Fiber = Effect.fork(fib(10)) + * ``` + * + * @see {@link forkWithErrorHandler} for a version that allows you to handle errors. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const fork: (self: Effect) => Effect, never, R> = fiberRuntime.fork + +/** + * Creates a long-running background fiber that is independent of its parent. + * + * **Details** + * + * This function creates a "daemon" fiber that runs in the background and is not + * tied to the lifecycle of its parent fiber. Unlike normal fibers that stop + * when the parent fiber terminates, a daemon fiber will continue running until + * the global scope closes or the fiber completes naturally. This makes it + * useful for tasks that need to run in the background independently, such as + * periodic logging, monitoring, or background data processing. + * + * **Example** (Creating a Daemon Fiber) + * + * ```ts + * import { Effect, Console, Schedule } from "effect" + * + * // Daemon fiber that logs a message repeatedly every second + * const daemon = Effect.repeat( + * Console.log("daemon: still running!"), + * Schedule.fixed("1 second") + * ) + * + * const parent = Effect.gen(function* () { + * console.log("parent: started!") + * // Daemon fiber running independently + * yield* Effect.forkDaemon(daemon) + * yield* Effect.sleep("3 seconds") + * console.log("parent: finished!") + * }) + * + * Effect.runFork(parent) + * // Output: + * // parent: started! + * // daemon: still running! + * // daemon: still running! + * // daemon: still running! + * // parent: finished! + * // daemon: still running! + * // daemon: still running! + * // daemon: still running! + * // daemon: still running! + * // daemon: still running! + * // ...etc... + * ``` + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const forkDaemon: (self: Effect) => Effect, never, R> = + fiberRuntime.forkDaemon + +/** + * Returns an effect that forks all of the specified values, and returns a + * composite fiber that produces a list of their results, in order. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const forkAll: { + /** + * Returns an effect that forks all of the specified values, and returns a + * composite fiber that produces a list of their results, in order. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + (options?: { readonly discard?: false | undefined } | undefined): >( + effects: Iterable + ) => Effect>, Effect.Error>, never, Effect.Context> + /** + * Returns an effect that forks all of the specified values, and returns a + * composite fiber that produces a list of their results, in order. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + (options: { readonly discard: true }): >(effects: Iterable) => Effect> + /** + * Returns an effect that forks all of the specified values, and returns a + * composite fiber that produces a list of their results, in order. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + >( + effects: Iterable, + options?: { readonly discard?: false | undefined } | undefined + ): Effect>, Effect.Error>, never, Effect.Context> + /** + * Returns an effect that forks all of the specified values, and returns a + * composite fiber that produces a list of their results, in order. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + >(effects: Iterable, options: { readonly discard: true }): Effect> +} = circular.forkAll + +/** + * Forks an effect in a specific scope, allowing finer control over its + * execution. + * + * **Details** + * + * There are some cases where we need more fine-grained control, so we want to + * fork a fiber in a specific scope. We can use the `Effect.forkIn` operator + * which takes the target scope as an argument. + * + * The fiber will be interrupted when the scope is closed. + * + * **Example** (Forking a Fiber in a Specific Scope) + * + * In this example, the child fiber is forked into the outerScope, + * allowing it to outlive the inner scope but still be terminated + * when the outerScope is closed. + * + * ```ts + * import { Console, Effect, Schedule } from "effect" + * + * // Child fiber that logs a message repeatedly every second + * const child = Effect.repeat( + * Console.log("child: still running!"), + * Schedule.fixed("1 second") + * ) + * + * const program = Effect.scoped( + * Effect.gen(function* () { + * yield* Effect.addFinalizer(() => + * Console.log("The outer scope is about to be closed!") + * ) + * + * // Capture the outer scope + * const outerScope = yield* Effect.scope + * + * // Create an inner scope + * yield* Effect.scoped( + * Effect.gen(function* () { + * yield* Effect.addFinalizer(() => + * Console.log("The inner scope is about to be closed!") + * ) + * // Fork the child fiber in the outer scope + * yield* Effect.forkIn(child, outerScope) + * yield* Effect.sleep("3 seconds") + * }) + * ) + * + * yield* Effect.sleep("5 seconds") + * }) + * ) + * + * Effect.runFork(program) + * // Output: + * // child: still running! + * // child: still running! + * // child: still running! + * // The inner scope is about to be closed! + * // child: still running! + * // child: still running! + * // child: still running! + * // child: still running! + * // child: still running! + * // child: still running! + * // The outer scope is about to be closed! + * ``` + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const forkIn: { + /** + * Forks an effect in a specific scope, allowing finer control over its + * execution. + * + * **Details** + * + * There are some cases where we need more fine-grained control, so we want to + * fork a fiber in a specific scope. We can use the `Effect.forkIn` operator + * which takes the target scope as an argument. + * + * The fiber will be interrupted when the scope is closed. + * + * **Example** (Forking a Fiber in a Specific Scope) + * + * In this example, the child fiber is forked into the outerScope, + * allowing it to outlive the inner scope but still be terminated + * when the outerScope is closed. + * + * ```ts + * import { Console, Effect, Schedule } from "effect" + * + * // Child fiber that logs a message repeatedly every second + * const child = Effect.repeat( + * Console.log("child: still running!"), + * Schedule.fixed("1 second") + * ) + * + * const program = Effect.scoped( + * Effect.gen(function* () { + * yield* Effect.addFinalizer(() => + * Console.log("The outer scope is about to be closed!") + * ) + * + * // Capture the outer scope + * const outerScope = yield* Effect.scope + * + * // Create an inner scope + * yield* Effect.scoped( + * Effect.gen(function* () { + * yield* Effect.addFinalizer(() => + * Console.log("The inner scope is about to be closed!") + * ) + * // Fork the child fiber in the outer scope + * yield* Effect.forkIn(child, outerScope) + * yield* Effect.sleep("3 seconds") + * }) + * ) + * + * yield* Effect.sleep("5 seconds") + * }) + * ) + * + * Effect.runFork(program) + * // Output: + * // child: still running! + * // child: still running! + * // child: still running! + * // The inner scope is about to be closed! + * // child: still running! + * // child: still running! + * // child: still running! + * // child: still running! + * // child: still running! + * // child: still running! + * // The outer scope is about to be closed! + * ``` + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + (scope: Scope.Scope): (self: Effect) => Effect, never, R> + /** + * Forks an effect in a specific scope, allowing finer control over its + * execution. + * + * **Details** + * + * There are some cases where we need more fine-grained control, so we want to + * fork a fiber in a specific scope. We can use the `Effect.forkIn` operator + * which takes the target scope as an argument. + * + * The fiber will be interrupted when the scope is closed. + * + * **Example** (Forking a Fiber in a Specific Scope) + * + * In this example, the child fiber is forked into the outerScope, + * allowing it to outlive the inner scope but still be terminated + * when the outerScope is closed. + * + * ```ts + * import { Console, Effect, Schedule } from "effect" + * + * // Child fiber that logs a message repeatedly every second + * const child = Effect.repeat( + * Console.log("child: still running!"), + * Schedule.fixed("1 second") + * ) + * + * const program = Effect.scoped( + * Effect.gen(function* () { + * yield* Effect.addFinalizer(() => + * Console.log("The outer scope is about to be closed!") + * ) + * + * // Capture the outer scope + * const outerScope = yield* Effect.scope + * + * // Create an inner scope + * yield* Effect.scoped( + * Effect.gen(function* () { + * yield* Effect.addFinalizer(() => + * Console.log("The inner scope is about to be closed!") + * ) + * // Fork the child fiber in the outer scope + * yield* Effect.forkIn(child, outerScope) + * yield* Effect.sleep("3 seconds") + * }) + * ) + * + * yield* Effect.sleep("5 seconds") + * }) + * ) + * + * Effect.runFork(program) + * // Output: + * // child: still running! + * // child: still running! + * // child: still running! + * // The inner scope is about to be closed! + * // child: still running! + * // child: still running! + * // child: still running! + * // child: still running! + * // child: still running! + * // child: still running! + * // The outer scope is about to be closed! + * ``` + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + (self: Effect, scope: Scope.Scope): Effect, never, R> +} = circular.forkIn + +/** + * Forks a fiber in a local scope, ensuring it outlives its parent. + * + * **Details** + * + * This function is used to create fibers that are tied to a local scope, + * meaning they are not dependent on their parent fiber's lifecycle. Instead, + * they will continue running until the scope they were created in is closed. + * This is particularly useful when you need a fiber to run independently of the + * parent fiber, but still want it to be terminated when the scope ends. + * + * Fibers created with this function are isolated from the parent fiber’s + * termination, so they can run for a longer period. This behavior is different + * from fibers created with {@link fork}, which are terminated when the parent fiber + * terminates. With `forkScoped`, the child fiber will keep running until the + * local scope ends, regardless of the state of the parent fiber. + * + * **Example** (Forking a Fiber in a Local Scope) + * + * In this example, the child fiber continues to run beyond the lifetime of the parent fiber. + * The child fiber is tied to the local scope and will be terminated only when the scope ends. + * + * ```ts + * import { Effect, Console, Schedule } from "effect" + * + * // Child fiber that logs a message repeatedly every second + * const child = Effect.repeat( + * Console.log("child: still running!"), + * Schedule.fixed("1 second") + * ) + * + * // ┌─── Effect + * // ▼ + * const parent = Effect.gen(function* () { + * console.log("parent: started!") + * // Child fiber attached to local scope + * yield* Effect.forkScoped(child) + * yield* Effect.sleep("3 seconds") + * console.log("parent: finished!") + * }) + * + * // Program runs within a local scope + * const program = Effect.scoped( + * Effect.gen(function* () { + * console.log("Local scope started!") + * yield* Effect.fork(parent) + * // Scope lasts for 5 seconds + * yield* Effect.sleep("5 seconds") + * console.log("Leaving the local scope!") + * }) + * ) + * + * Effect.runFork(program) + * // Output: + * // Local scope started! + * // parent: started! + * // child: still running! + * // child: still running! + * // child: still running! + * // parent: finished! + * // child: still running! + * // child: still running! + * // Leaving the local scope! + * ``` + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const forkScoped: (self: Effect) => Effect, never, Scope.Scope | R> = + circular.forkScoped + +/** + * Like {@link fork} but handles an error with the provided handler. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const forkWithErrorHandler: { + /** + * Like {@link fork} but handles an error with the provided handler. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + (handler: (e: E) => Effect): (self: Effect) => Effect, never, R> + /** + * Like {@link fork} but handles an error with the provided handler. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + (self: Effect, handler: (e: E) => Effect): Effect, never, R> +} = fiberRuntime.forkWithErrorHandler + +/** + * Creates an `Effect` value that represents the exit value of the specified + * fiber. + * + * @see {@link fromFiberEffect} for creating an effect from a fiber obtained from an effect. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const fromFiber: (fiber: Fiber.Fiber) => Effect = circular.fromFiber + +/** + * Creates an `Effect` value that represents the exit value of a fiber obtained + * from an effect. + * + * @see {@link fromFiber} for creating an effect from a fiber. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const fromFiberEffect: (fiber: Effect, E, R>) => Effect = + circular.fromFiberEffect + +/** + * Supervises child fibers by reporting them to a specified supervisor. + * + * **Details** + * + * This function takes a supervisor as an argument and returns an effect where + * all child fibers forked within it are supervised by the provided supervisor. + * This enables you to capture detailed information about these child fibers, + * such as their status, through the supervisor. + * + * **Example** (Monitoring Fiber Count) + * + * ```ts + * import { Effect, Supervisor, Schedule, Fiber, FiberStatus } from "effect" + * + * // Main program that monitors fibers while calculating a Fibonacci number + * const program = Effect.gen(function* () { + * // Create a supervisor to track child fibers + * const supervisor = yield* Supervisor.track + * + * // Start a Fibonacci calculation, supervised by the supervisor + * const fibFiber = yield* fib(20).pipe( + * Effect.supervised(supervisor), + * // Fork the Fibonacci effect into a fiber + * Effect.fork + * ) + * + * // Define a schedule to periodically monitor the fiber count every 500ms + * const policy = Schedule.spaced("500 millis").pipe( + * Schedule.whileInputEffect((_) => + * Fiber.status(fibFiber).pipe( + * // Continue while the Fibonacci fiber is not done + * Effect.andThen((status) => status !== FiberStatus.done) + * ) + * ) + * ) + * + * // Start monitoring the fibers, using the supervisor to track the count + * const monitorFiber = yield* monitorFibers(supervisor).pipe( + * // Repeat the monitoring according to the schedule + * Effect.repeat(policy), + * // Fork the monitoring into its own fiber + * Effect.fork + * ) + * + * // Join the monitor and Fibonacci fibers to ensure they complete + * yield* Fiber.join(monitorFiber) + * const result = yield* Fiber.join(fibFiber) + * + * console.log(`fibonacci result: ${result}`) + * }) + * + * // Function to monitor and log the number of active fibers + * const monitorFibers = ( + * supervisor: Supervisor.Supervisor>> + * ): Effect.Effect => + * Effect.gen(function* () { + * const fibers = yield* supervisor.value // Get the current set of fibers + * console.log(`number of fibers: ${fibers.length}`) + * }) + * + * // Recursive Fibonacci calculation, spawning fibers for each recursive step + * const fib = (n: number): Effect.Effect => + * Effect.gen(function* () { + * if (n <= 1) { + * return 1 + * } + * yield* Effect.sleep("500 millis") // Simulate work by delaying + * + * // Fork two fibers for the recursive Fibonacci calls + * const fiber1 = yield* Effect.fork(fib(n - 2)) + * const fiber2 = yield* Effect.fork(fib(n - 1)) + * + * // Join the fibers to retrieve their results + * const v1 = yield* Fiber.join(fiber1) + * const v2 = yield* Fiber.join(fiber2) + * + * return v1 + v2 // Combine the results + * }) + * + * Effect.runPromise(program) + * // Output: + * // number of fibers: 0 + * // number of fibers: 2 + * // number of fibers: 6 + * // number of fibers: 14 + * // number of fibers: 30 + * // number of fibers: 62 + * // number of fibers: 126 + * // number of fibers: 254 + * // number of fibers: 510 + * // number of fibers: 1022 + * // number of fibers: 2034 + * // number of fibers: 3795 + * // number of fibers: 5810 + * // number of fibers: 6474 + * // number of fibers: 4942 + * // number of fibers: 2515 + * // number of fibers: 832 + * // number of fibers: 170 + * // number of fibers: 18 + * // number of fibers: 0 + * // fibonacci result: 10946 + * ``` + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const supervised: { + /** + * Supervises child fibers by reporting them to a specified supervisor. + * + * **Details** + * + * This function takes a supervisor as an argument and returns an effect where + * all child fibers forked within it are supervised by the provided supervisor. + * This enables you to capture detailed information about these child fibers, + * such as their status, through the supervisor. + * + * **Example** (Monitoring Fiber Count) + * + * ```ts + * import { Effect, Supervisor, Schedule, Fiber, FiberStatus } from "effect" + * + * // Main program that monitors fibers while calculating a Fibonacci number + * const program = Effect.gen(function* () { + * // Create a supervisor to track child fibers + * const supervisor = yield* Supervisor.track + * + * // Start a Fibonacci calculation, supervised by the supervisor + * const fibFiber = yield* fib(20).pipe( + * Effect.supervised(supervisor), + * // Fork the Fibonacci effect into a fiber + * Effect.fork + * ) + * + * // Define a schedule to periodically monitor the fiber count every 500ms + * const policy = Schedule.spaced("500 millis").pipe( + * Schedule.whileInputEffect((_) => + * Fiber.status(fibFiber).pipe( + * // Continue while the Fibonacci fiber is not done + * Effect.andThen((status) => status !== FiberStatus.done) + * ) + * ) + * ) + * + * // Start monitoring the fibers, using the supervisor to track the count + * const monitorFiber = yield* monitorFibers(supervisor).pipe( + * // Repeat the monitoring according to the schedule + * Effect.repeat(policy), + * // Fork the monitoring into its own fiber + * Effect.fork + * ) + * + * // Join the monitor and Fibonacci fibers to ensure they complete + * yield* Fiber.join(monitorFiber) + * const result = yield* Fiber.join(fibFiber) + * + * console.log(`fibonacci result: ${result}`) + * }) + * + * // Function to monitor and log the number of active fibers + * const monitorFibers = ( + * supervisor: Supervisor.Supervisor>> + * ): Effect.Effect => + * Effect.gen(function* () { + * const fibers = yield* supervisor.value // Get the current set of fibers + * console.log(`number of fibers: ${fibers.length}`) + * }) + * + * // Recursive Fibonacci calculation, spawning fibers for each recursive step + * const fib = (n: number): Effect.Effect => + * Effect.gen(function* () { + * if (n <= 1) { + * return 1 + * } + * yield* Effect.sleep("500 millis") // Simulate work by delaying + * + * // Fork two fibers for the recursive Fibonacci calls + * const fiber1 = yield* Effect.fork(fib(n - 2)) + * const fiber2 = yield* Effect.fork(fib(n - 1)) + * + * // Join the fibers to retrieve their results + * const v1 = yield* Fiber.join(fiber1) + * const v2 = yield* Fiber.join(fiber2) + * + * return v1 + v2 // Combine the results + * }) + * + * Effect.runPromise(program) + * // Output: + * // number of fibers: 0 + * // number of fibers: 2 + * // number of fibers: 6 + * // number of fibers: 14 + * // number of fibers: 30 + * // number of fibers: 62 + * // number of fibers: 126 + * // number of fibers: 254 + * // number of fibers: 510 + * // number of fibers: 1022 + * // number of fibers: 2034 + * // number of fibers: 3795 + * // number of fibers: 5810 + * // number of fibers: 6474 + * // number of fibers: 4942 + * // number of fibers: 2515 + * // number of fibers: 832 + * // number of fibers: 170 + * // number of fibers: 18 + * // number of fibers: 0 + * // fibonacci result: 10946 + * ``` + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + (supervisor: Supervisor.Supervisor): (self: Effect) => Effect + /** + * Supervises child fibers by reporting them to a specified supervisor. + * + * **Details** + * + * This function takes a supervisor as an argument and returns an effect where + * all child fibers forked within it are supervised by the provided supervisor. + * This enables you to capture detailed information about these child fibers, + * such as their status, through the supervisor. + * + * **Example** (Monitoring Fiber Count) + * + * ```ts + * import { Effect, Supervisor, Schedule, Fiber, FiberStatus } from "effect" + * + * // Main program that monitors fibers while calculating a Fibonacci number + * const program = Effect.gen(function* () { + * // Create a supervisor to track child fibers + * const supervisor = yield* Supervisor.track + * + * // Start a Fibonacci calculation, supervised by the supervisor + * const fibFiber = yield* fib(20).pipe( + * Effect.supervised(supervisor), + * // Fork the Fibonacci effect into a fiber + * Effect.fork + * ) + * + * // Define a schedule to periodically monitor the fiber count every 500ms + * const policy = Schedule.spaced("500 millis").pipe( + * Schedule.whileInputEffect((_) => + * Fiber.status(fibFiber).pipe( + * // Continue while the Fibonacci fiber is not done + * Effect.andThen((status) => status !== FiberStatus.done) + * ) + * ) + * ) + * + * // Start monitoring the fibers, using the supervisor to track the count + * const monitorFiber = yield* monitorFibers(supervisor).pipe( + * // Repeat the monitoring according to the schedule + * Effect.repeat(policy), + * // Fork the monitoring into its own fiber + * Effect.fork + * ) + * + * // Join the monitor and Fibonacci fibers to ensure they complete + * yield* Fiber.join(monitorFiber) + * const result = yield* Fiber.join(fibFiber) + * + * console.log(`fibonacci result: ${result}`) + * }) + * + * // Function to monitor and log the number of active fibers + * const monitorFibers = ( + * supervisor: Supervisor.Supervisor>> + * ): Effect.Effect => + * Effect.gen(function* () { + * const fibers = yield* supervisor.value // Get the current set of fibers + * console.log(`number of fibers: ${fibers.length}`) + * }) + * + * // Recursive Fibonacci calculation, spawning fibers for each recursive step + * const fib = (n: number): Effect.Effect => + * Effect.gen(function* () { + * if (n <= 1) { + * return 1 + * } + * yield* Effect.sleep("500 millis") // Simulate work by delaying + * + * // Fork two fibers for the recursive Fibonacci calls + * const fiber1 = yield* Effect.fork(fib(n - 2)) + * const fiber2 = yield* Effect.fork(fib(n - 1)) + * + * // Join the fibers to retrieve their results + * const v1 = yield* Fiber.join(fiber1) + * const v2 = yield* Fiber.join(fiber2) + * + * return v1 + v2 // Combine the results + * }) + * + * Effect.runPromise(program) + * // Output: + * // number of fibers: 0 + * // number of fibers: 2 + * // number of fibers: 6 + * // number of fibers: 14 + * // number of fibers: 30 + * // number of fibers: 62 + * // number of fibers: 126 + * // number of fibers: 254 + * // number of fibers: 510 + * // number of fibers: 1022 + * // number of fibers: 2034 + * // number of fibers: 3795 + * // number of fibers: 5810 + * // number of fibers: 6474 + * // number of fibers: 4942 + * // number of fibers: 2515 + * // number of fibers: 832 + * // number of fibers: 170 + * // number of fibers: 18 + * // number of fibers: 0 + * // fibonacci result: 10946 + * ``` + * + * @since 2.0.0 + * @category Supervision & Fibers + */ + (self: Effect, supervisor: Supervisor.Supervisor): Effect +} = circular.supervised + +/** + * Transplants specified effects so that when those effects fork other + * effects, the forked effects will be governed by the scope of the fiber that + * executes this effect. + * + * This can be used to "graft" deep grandchildren onto a higher-level scope, + * effectively extending their lifespans into the parent scope. + * + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const transplant: ( + f: (grafter: (effect: Effect) => Effect) => Effect +) => Effect = core.transplant + +/** + * @since 2.0.0 + * @category Supervision & Fibers + */ +export const withConcurrency: { + /** + * @since 2.0.0 + * @category Supervision & Fibers + */ + (concurrency: number | "unbounded"): (self: Effect) => Effect + /** + * @since 2.0.0 + * @category Supervision & Fibers + */ + (self: Effect, concurrency: number | "unbounded"): Effect +} = core.withConcurrency + +/** + * Sets the provided scheduler for usage in the wrapped effect + * + * @since 2.0.0 + * @category Scheduler + */ +export const withScheduler: { + /** + * Sets the provided scheduler for usage in the wrapped effect + * + * @since 2.0.0 + * @category Scheduler + */ + (scheduler: Scheduler.Scheduler): (self: Effect) => Effect + /** + * Sets the provided scheduler for usage in the wrapped effect + * + * @since 2.0.0 + * @category Scheduler + */ + (self: Effect, scheduler: Scheduler.Scheduler): Effect +} = Scheduler.withScheduler + +/** + * Sets the scheduling priority used when yielding + * + * @since 2.0.0 + * @category Scheduler + */ +export const withSchedulingPriority: { + /** + * Sets the scheduling priority used when yielding + * + * @since 2.0.0 + * @category Scheduler + */ + (priority: number): (self: Effect) => Effect + /** + * Sets the scheduling priority used when yielding + * + * @since 2.0.0 + * @category Scheduler + */ + (self: Effect, priority: number): Effect +} = core.withSchedulingPriority + +/** + * Sets the maximum number of operations before yield by the default schedulers + * + * @since 2.0.0 + * @category Scheduler + */ +export const withMaxOpsBeforeYield: { + /** + * Sets the maximum number of operations before yield by the default schedulers + * + * @since 2.0.0 + * @category Scheduler + */ + (priority: number): (self: Effect) => Effect + /** + * Sets the maximum number of operations before yield by the default schedulers + * + * @since 2.0.0 + * @category Scheduler + */ + (self: Effect, priority: number): Effect +} = core.withMaxOpsBeforeYield + +/** + * Retrieves the `Clock` service from the context. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * const clock = yield* Effect.clock + * const currentTime = yield* clock.currentTimeMillis + * console.log(`Current time in milliseconds: ${currentTime}`) + * }) + * + * Effect.runFork(program) + * // Example Output: + * // Current time in milliseconds: 1735484796134 + * ``` + * + * @since 2.0.0 + * @category Clock + */ +export const clock: Effect = effect.clock + +/** + * Retrieves the `Clock` service from the context and provides it to the + * specified effectful function. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const program = Effect.clockWith((clock) => + * clock.currentTimeMillis.pipe( + * Effect.map((currentTime) => `Current time is: ${currentTime}`), + * Effect.tap(Console.log) + * ) + * ) + * + * Effect.runFork(program) + * // Example Output: + * // Current time is: 1735484929744 + * ``` + * + * @since 2.0.0 + * @category Clock + */ +export const clockWith: (f: (clock: Clock.Clock) => Effect) => Effect = effect.clockWith + +/** + * Sets the implementation of the `Clock` service to the specified value and + * restores it to its original value when the scope is closed. + * + * @since 2.0.0 + * @category Clock + */ +export const withClockScoped: (clock: C) => Effect = + fiberRuntime.withClockScoped + +/** + * Executes the specified workflow with the specified implementation of the + * `Clock` service. + * + * @since 2.0.0 + * @category Clock + */ +export const withClock: { + /** + * Executes the specified workflow with the specified implementation of the + * `Clock` service. + * + * @since 2.0.0 + * @category Clock + */ + (clock: C): (effect: Effect) => Effect + /** + * Executes the specified workflow with the specified implementation of the + * `Clock` service. + * + * @since 2.0.0 + * @category Clock + */ + (effect: Effect, clock: C): Effect +} = defaultServices.withClock + +/** + * Retreives the `Console` service from the context + * + * @since 2.0.0 + * @category Console + */ +export const console: Effect = console_.console + +/** + * Retreives the `Console` service from the context and provides it to the + * specified effectful function. + * + * @since 2.0.0 + * @category Console + */ +export const consoleWith: (f: (console: Console) => Effect) => Effect = console_.consoleWith + +/** + * Sets the implementation of the console service to the specified value and + * restores it to its original value when the scope is closed. + * + * @since 2.0.0 + * @category Creating Effects + */ +export const withConsoleScoped: (console: A) => Effect = + console_.withConsoleScoped + +/** + * Executes the specified workflow with the specified implementation of the + * console service. + * + * @since 2.0.0 + * @category Console + */ +export const withConsole: { + /** + * Executes the specified workflow with the specified implementation of the + * console service. + * + * @since 2.0.0 + * @category Console + */ + (console: C): (effect: Effect) => Effect + /** + * Executes the specified workflow with the specified implementation of the + * console service. + * + * @since 2.0.0 + * @category Console + */ + (effect: Effect, console: C): Effect +} = console_.withConsole + +/** + * Delays the execution of an effect by a specified `Duration`. + * + * **Details + * + * This function postpones the execution of the provided effect by the specified + * duration. The duration can be provided in various formats supported by the + * `Duration` module. + * + * Internally, this function does not block the thread; instead, it uses an + * efficient, non-blocking mechanism to introduce the delay. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const task = Console.log("Task executed") + * + * const program = Console.log("start").pipe( + * Effect.andThen( + * // Delays the log message by 2 seconds + * task.pipe(Effect.delay("2 seconds")) + * ) + * ) + * + * Effect.runFork(program) + * // Output: + * // start + * // Task executed + * ``` + * + * @since 2.0.0 + * @category Delays & Timeouts + */ +export const delay: { + /** + * Delays the execution of an effect by a specified `Duration`. + * + * **Details + * + * This function postpones the execution of the provided effect by the specified + * duration. The duration can be provided in various formats supported by the + * `Duration` module. + * + * Internally, this function does not block the thread; instead, it uses an + * efficient, non-blocking mechanism to introduce the delay. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const task = Console.log("Task executed") + * + * const program = Console.log("start").pipe( + * Effect.andThen( + * // Delays the log message by 2 seconds + * task.pipe(Effect.delay("2 seconds")) + * ) + * ) + * + * Effect.runFork(program) + * // Output: + * // start + * // Task executed + * ``` + * + * @since 2.0.0 + * @category Delays & Timeouts + */ + (duration: Duration.DurationInput): (self: Effect) => Effect + /** + * Delays the execution of an effect by a specified `Duration`. + * + * **Details + * + * This function postpones the execution of the provided effect by the specified + * duration. The duration can be provided in various formats supported by the + * `Duration` module. + * + * Internally, this function does not block the thread; instead, it uses an + * efficient, non-blocking mechanism to introduce the delay. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const task = Console.log("Task executed") + * + * const program = Console.log("start").pipe( + * Effect.andThen( + * // Delays the log message by 2 seconds + * task.pipe(Effect.delay("2 seconds")) + * ) + * ) + * + * Effect.runFork(program) + * // Output: + * // start + * // Task executed + * ``` + * + * @since 2.0.0 + * @category Delays & Timeouts + */ + (self: Effect, duration: Duration.DurationInput): Effect +} = effect.delay + +/** + * Suspends the execution of an effect for a specified `Duration`. + * + * **Details** + * + * This function pauses the execution of an effect for a given duration. It is + * asynchronous, meaning that it does not block the fiber executing the effect. + * Instead, the fiber is suspended during the delay period and can resume once + * the specified time has passed. + * + * The duration can be specified using various formats supported by the + * `Duration` module, such as a string (`"2 seconds"`) or numeric value + * representing milliseconds. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * console.log("Starting task...") + * yield* Effect.sleep("3 seconds") // Waits for 3 seconds + * console.log("Task completed!") + * }) + * + * Effect.runFork(program) + * // Output: + * // Starting task... + * // Task completed! + * ``` + * + * @since 2.0.0 + * @category Delays & Timeouts + */ +export const sleep: (duration: Duration.DurationInput) => Effect = effect.sleep + +/** + * Executes an effect and measures the time it takes to complete. + * + * **Details** + * + * This function wraps the provided effect and returns a new effect that, when + * executed, performs the original effect and calculates its execution duration. + * + * The result of the new effect includes both the execution time (as a + * `Duration`) and the original effect's result. This is useful for monitoring + * performance or gaining insights into the time taken by specific operations. + * + * The original effect's behavior (success, failure, or interruption) remains + * unchanged, and the timing information is provided alongside the result in a + * tuple. + * + * **Example** + * + * ```ts + * import { Duration, Effect } from "effect" + * + * const task = Effect.gen(function*() { + * yield* Effect.sleep("2 seconds") // Simulates some work + * return "some result" + * }) + * + * const timedTask = task.pipe(Effect.timed) + * + * const program = Effect.gen(function*() { + * const [duration, result] = yield* timedTask + * console.log(`Task completed in ${Duration.toMillis(duration)} ms with result: ${result}`) + * }) + * + * Effect.runFork(program) + * // Output: Task completed in 2003.749125 ms with result: some result + * ``` + * + * @since 2.0.0 + * @category Delays & Timeouts + */ +export const timed: (self: Effect) => Effect<[duration: Duration.Duration, result: A], E, R> = + effect.timed + +/** + * Executes an effect and measures its execution time using a custom clock. + * + * **Details** + * + * This function extends the functionality of {@link timed} by allowing you to + * specify a custom clock for measuring the execution duration. The provided + * effect (`nanoseconds`) represents the clock and should return the current + * time in nanoseconds. The timing information is computed using this custom + * clock instead of the default system clock. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ +export const timedWith: { + /** + * Executes an effect and measures its execution time using a custom clock. + * + * **Details** + * + * This function extends the functionality of {@link timed} by allowing you to + * specify a custom clock for measuring the execution duration. The provided + * effect (`nanoseconds`) represents the clock and should return the current + * time in nanoseconds. The timing information is computed using this custom + * clock instead of the default system clock. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ + (nanoseconds: Effect): (self: Effect) => Effect<[Duration.Duration, A], E1 | E, R1 | R> + /** + * Executes an effect and measures its execution time using a custom clock. + * + * **Details** + * + * This function extends the functionality of {@link timed} by allowing you to + * specify a custom clock for measuring the execution duration. The provided + * effect (`nanoseconds`) represents the clock and should return the current + * time in nanoseconds. The timing information is computed using this custom + * clock instead of the default system clock. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ + (self: Effect, nanoseconds: Effect): Effect<[Duration.Duration, A], E | E1, R | R1> +} = effect.timedWith + +/** + * Adds a time limit to an effect, triggering a timeout if the effect exceeds + * the duration. + * + * **Details** + * + * This function allows you to enforce a time limit on the execution of an + * effect. If the effect does not complete within the given duration, it fails + * with a `TimeoutException`. This is useful for preventing tasks from hanging + * indefinitely, especially in scenarios where responsiveness or resource limits + * are critical. + * + * The returned effect will either: + * - Succeed with the original effect's result if it completes within the + * specified duration. + * - Fail with a `TimeoutException` if the time limit is exceeded. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * // Output will show a TimeoutException as the task takes longer + * // than the specified timeout duration + * const timedEffect = task.pipe(Effect.timeout("1 second")) + * + * Effect.runPromiseExit(timedEffect).then(console.log) + * // Output: + * // Start processing... + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: { _tag: 'TimeoutException' } + * // } + * // } + * ``` + * + * @see {@link timeoutFail} for a version that raises a custom error. + * @see {@link timeoutFailCause} for a version that raises a custom defect. + * @see {@link timeoutTo} for a version that allows specifying both success and + * timeout handlers. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ +export const timeout: { + /** + * Adds a time limit to an effect, triggering a timeout if the effect exceeds + * the duration. + * + * **Details** + * + * This function allows you to enforce a time limit on the execution of an + * effect. If the effect does not complete within the given duration, it fails + * with a `TimeoutException`. This is useful for preventing tasks from hanging + * indefinitely, especially in scenarios where responsiveness or resource limits + * are critical. + * + * The returned effect will either: + * - Succeed with the original effect's result if it completes within the + * specified duration. + * - Fail with a `TimeoutException` if the time limit is exceeded. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * // Output will show a TimeoutException as the task takes longer + * // than the specified timeout duration + * const timedEffect = task.pipe(Effect.timeout("1 second")) + * + * Effect.runPromiseExit(timedEffect).then(console.log) + * // Output: + * // Start processing... + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: { _tag: 'TimeoutException' } + * // } + * // } + * ``` + * + * @see {@link timeoutFail} for a version that raises a custom error. + * @see {@link timeoutFailCause} for a version that raises a custom defect. + * @see {@link timeoutTo} for a version that allows specifying both success and + * timeout handlers. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ + (duration: Duration.DurationInput): (self: Effect) => Effect + /** + * Adds a time limit to an effect, triggering a timeout if the effect exceeds + * the duration. + * + * **Details** + * + * This function allows you to enforce a time limit on the execution of an + * effect. If the effect does not complete within the given duration, it fails + * with a `TimeoutException`. This is useful for preventing tasks from hanging + * indefinitely, especially in scenarios where responsiveness or resource limits + * are critical. + * + * The returned effect will either: + * - Succeed with the original effect's result if it completes within the + * specified duration. + * - Fail with a `TimeoutException` if the time limit is exceeded. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * // Output will show a TimeoutException as the task takes longer + * // than the specified timeout duration + * const timedEffect = task.pipe(Effect.timeout("1 second")) + * + * Effect.runPromiseExit(timedEffect).then(console.log) + * // Output: + * // Start processing... + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: { _tag: 'TimeoutException' } + * // } + * // } + * ``` + * + * @see {@link timeoutFail} for a version that raises a custom error. + * @see {@link timeoutFailCause} for a version that raises a custom defect. + * @see {@link timeoutTo} for a version that allows specifying both success and + * timeout handlers. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ + (self: Effect, duration: Duration.DurationInput): Effect +} = circular.timeout + +/** + * Gracefully handles timeouts by returning an `Option` that represents either + * the result or a timeout. + * + * **Details** + * + * This function wraps the outcome of an effect in an `Option` type. If the + * effect completes within the specified duration, it returns a `Some` + * containing the result. If the effect times out, it returns a `None`. Unlike + * other timeout methods, this approach does not raise errors or exceptions; + * instead, it allows you to treat timeouts as a regular outcome, simplifying + * the logic for handling delays. + * + * **When to Use** + * + * This is useful when you want to handle timeouts without causing the program + * to fail, making it easier to manage situations where you expect tasks might + * take too long but want to continue executing other tasks. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * const timedOutEffect = Effect.all([ + * task.pipe(Effect.timeoutOption("3 seconds")), + * task.pipe(Effect.timeoutOption("1 second")) + * ]) + * + * Effect.runPromise(timedOutEffect).then(console.log) + * // Output: + * // Start processing... + * // Processing complete. + * // Start processing... + * // [ + * // { _id: 'Option', _tag: 'Some', value: 'Result' }, + * // { _id: 'Option', _tag: 'None' } + * // ] + * ``` + * + * @see {@link timeout} for a version that raises a `TimeoutException`. + * @see {@link timeoutFail} for a version that raises a custom error. + * @see {@link timeoutFailCause} for a version that raises a custom defect. + * @see {@link timeoutTo} for a version that allows specifying both success and + * timeout handlers. + * + * @since 3.1.0 + * @category Delays & Timeouts + */ +export const timeoutOption: { + /** + * Gracefully handles timeouts by returning an `Option` that represents either + * the result or a timeout. + * + * **Details** + * + * This function wraps the outcome of an effect in an `Option` type. If the + * effect completes within the specified duration, it returns a `Some` + * containing the result. If the effect times out, it returns a `None`. Unlike + * other timeout methods, this approach does not raise errors or exceptions; + * instead, it allows you to treat timeouts as a regular outcome, simplifying + * the logic for handling delays. + * + * **When to Use** + * + * This is useful when you want to handle timeouts without causing the program + * to fail, making it easier to manage situations where you expect tasks might + * take too long but want to continue executing other tasks. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * const timedOutEffect = Effect.all([ + * task.pipe(Effect.timeoutOption("3 seconds")), + * task.pipe(Effect.timeoutOption("1 second")) + * ]) + * + * Effect.runPromise(timedOutEffect).then(console.log) + * // Output: + * // Start processing... + * // Processing complete. + * // Start processing... + * // [ + * // { _id: 'Option', _tag: 'Some', value: 'Result' }, + * // { _id: 'Option', _tag: 'None' } + * // ] + * ``` + * + * @see {@link timeout} for a version that raises a `TimeoutException`. + * @see {@link timeoutFail} for a version that raises a custom error. + * @see {@link timeoutFailCause} for a version that raises a custom defect. + * @see {@link timeoutTo} for a version that allows specifying both success and + * timeout handlers. + * + * @since 3.1.0 + * @category Delays & Timeouts + */ + (duration: Duration.DurationInput): (self: Effect) => Effect, E, R> + /** + * Gracefully handles timeouts by returning an `Option` that represents either + * the result or a timeout. + * + * **Details** + * + * This function wraps the outcome of an effect in an `Option` type. If the + * effect completes within the specified duration, it returns a `Some` + * containing the result. If the effect times out, it returns a `None`. Unlike + * other timeout methods, this approach does not raise errors or exceptions; + * instead, it allows you to treat timeouts as a regular outcome, simplifying + * the logic for handling delays. + * + * **When to Use** + * + * This is useful when you want to handle timeouts without causing the program + * to fail, making it easier to manage situations where you expect tasks might + * take too long but want to continue executing other tasks. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * const timedOutEffect = Effect.all([ + * task.pipe(Effect.timeoutOption("3 seconds")), + * task.pipe(Effect.timeoutOption("1 second")) + * ]) + * + * Effect.runPromise(timedOutEffect).then(console.log) + * // Output: + * // Start processing... + * // Processing complete. + * // Start processing... + * // [ + * // { _id: 'Option', _tag: 'Some', value: 'Result' }, + * // { _id: 'Option', _tag: 'None' } + * // ] + * ``` + * + * @see {@link timeout} for a version that raises a `TimeoutException`. + * @see {@link timeoutFail} for a version that raises a custom error. + * @see {@link timeoutFailCause} for a version that raises a custom defect. + * @see {@link timeoutTo} for a version that allows specifying both success and + * timeout handlers. + * + * @since 3.1.0 + * @category Delays & Timeouts + */ + (self: Effect, duration: Duration.DurationInput): Effect, E, R> +} = circular.timeoutOption + +/** + * Specifies a custom error to be produced when a timeout occurs. + * + * **Details** + * + * This function allows you to handle timeouts in a customized way by defining a + * specific error to be raised when an effect exceeds the given duration. Unlike + * default timeout behaviors that use generic exceptions, this function gives + * you the flexibility to specify a meaningful error type that aligns with your + * application's needs. + * + * When you apply this function, you provide: + * - A `duration`: The time limit for the effect. + * - An `onTimeout` function: A lazy evaluation function that generates the + * custom error if the timeout occurs. + * + * If the effect completes within the time limit, its result is returned + * normally. Otherwise, the `onTimeout` function is triggered, and its output is + * used as the error for the effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * class MyTimeoutError { + * readonly _tag = "MyTimeoutError" + * } + * + * const program = task.pipe( + * Effect.timeoutFail({ + * duration: "1 second", + * onTimeout: () => new MyTimeoutError() // Custom timeout error + * }) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // Start processing... + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: MyTimeoutError { _tag: 'MyTimeoutError' } + * // } + * // } + * ``` + * + * @see {@link timeout} for a version that raises a `TimeoutException`. + * @see {@link timeoutFailCause} for a version that raises a custom defect. + * @see {@link timeoutTo} for a version that allows specifying both success and + * timeout handlers. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ +export const timeoutFail: { + /** + * Specifies a custom error to be produced when a timeout occurs. + * + * **Details** + * + * This function allows you to handle timeouts in a customized way by defining a + * specific error to be raised when an effect exceeds the given duration. Unlike + * default timeout behaviors that use generic exceptions, this function gives + * you the flexibility to specify a meaningful error type that aligns with your + * application's needs. + * + * When you apply this function, you provide: + * - A `duration`: The time limit for the effect. + * - An `onTimeout` function: A lazy evaluation function that generates the + * custom error if the timeout occurs. + * + * If the effect completes within the time limit, its result is returned + * normally. Otherwise, the `onTimeout` function is triggered, and its output is + * used as the error for the effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * class MyTimeoutError { + * readonly _tag = "MyTimeoutError" + * } + * + * const program = task.pipe( + * Effect.timeoutFail({ + * duration: "1 second", + * onTimeout: () => new MyTimeoutError() // Custom timeout error + * }) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // Start processing... + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: MyTimeoutError { _tag: 'MyTimeoutError' } + * // } + * // } + * ``` + * + * @see {@link timeout} for a version that raises a `TimeoutException`. + * @see {@link timeoutFailCause} for a version that raises a custom defect. + * @see {@link timeoutTo} for a version that allows specifying both success and + * timeout handlers. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ + ( + options: { readonly onTimeout: LazyArg; readonly duration: Duration.DurationInput } + ): (self: Effect) => Effect + /** + * Specifies a custom error to be produced when a timeout occurs. + * + * **Details** + * + * This function allows you to handle timeouts in a customized way by defining a + * specific error to be raised when an effect exceeds the given duration. Unlike + * default timeout behaviors that use generic exceptions, this function gives + * you the flexibility to specify a meaningful error type that aligns with your + * application's needs. + * + * When you apply this function, you provide: + * - A `duration`: The time limit for the effect. + * - An `onTimeout` function: A lazy evaluation function that generates the + * custom error if the timeout occurs. + * + * If the effect completes within the time limit, its result is returned + * normally. Otherwise, the `onTimeout` function is triggered, and its output is + * used as the error for the effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * class MyTimeoutError { + * readonly _tag = "MyTimeoutError" + * } + * + * const program = task.pipe( + * Effect.timeoutFail({ + * duration: "1 second", + * onTimeout: () => new MyTimeoutError() // Custom timeout error + * }) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // Start processing... + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: MyTimeoutError { _tag: 'MyTimeoutError' } + * // } + * // } + * ``` + * + * @see {@link timeout} for a version that raises a `TimeoutException`. + * @see {@link timeoutFailCause} for a version that raises a custom defect. + * @see {@link timeoutTo} for a version that allows specifying both success and + * timeout handlers. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ + ( + self: Effect, + options: { readonly onTimeout: LazyArg; readonly duration: Duration.DurationInput } + ): Effect +} = circular.timeoutFail + +/** + * Specifies a custom defect to be thrown when a timeout occurs. + * + * **Details** + * + * This function allows you to handle timeouts as exceptional cases by + * generating a custom defect when an effect exceeds the specified duration. You + * provide: + * - A `duration`: The time limit for the effect. + * - An `onTimeout` function: A lazy evaluation function that generates the + * custom defect (typically created using `Cause.die`). + * + * If the effect completes within the time limit, its result is returned + * normally. Otherwise, the custom defect is triggered, and the effect fails + * with that defect. + * + * **When to Use** + * + * This is especially useful when you need to treat timeouts as critical + * failures in your application and wish to include meaningful information in + * the defect. + * + * **Example** + * + * ```ts + * import { Effect, Cause } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * const program = task.pipe( + * Effect.timeoutFailCause({ + * duration: "1 second", + * onTimeout: () => Cause.die("Timed out!") // Custom defect for timeout + * }) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // Start processing... + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Die', defect: 'Timed out!' } + * // } + * ``` + * + * @see {@link timeout} for a version that raises a `TimeoutException`. + * @see {@link timeoutFail} for a version that raises a custom error. + * @see {@link timeoutTo} for a version that allows specifying both success and + * timeout handlers. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ +export const timeoutFailCause: { + /** + * Specifies a custom defect to be thrown when a timeout occurs. + * + * **Details** + * + * This function allows you to handle timeouts as exceptional cases by + * generating a custom defect when an effect exceeds the specified duration. You + * provide: + * - A `duration`: The time limit for the effect. + * - An `onTimeout` function: A lazy evaluation function that generates the + * custom defect (typically created using `Cause.die`). + * + * If the effect completes within the time limit, its result is returned + * normally. Otherwise, the custom defect is triggered, and the effect fails + * with that defect. + * + * **When to Use** + * + * This is especially useful when you need to treat timeouts as critical + * failures in your application and wish to include meaningful information in + * the defect. + * + * **Example** + * + * ```ts + * import { Effect, Cause } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * const program = task.pipe( + * Effect.timeoutFailCause({ + * duration: "1 second", + * onTimeout: () => Cause.die("Timed out!") // Custom defect for timeout + * }) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // Start processing... + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Die', defect: 'Timed out!' } + * // } + * ``` + * + * @see {@link timeout} for a version that raises a `TimeoutException`. + * @see {@link timeoutFail} for a version that raises a custom error. + * @see {@link timeoutTo} for a version that allows specifying both success and + * timeout handlers. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ + ( + options: { readonly onTimeout: LazyArg>; readonly duration: Duration.DurationInput } + ): (self: Effect) => Effect + /** + * Specifies a custom defect to be thrown when a timeout occurs. + * + * **Details** + * + * This function allows you to handle timeouts as exceptional cases by + * generating a custom defect when an effect exceeds the specified duration. You + * provide: + * - A `duration`: The time limit for the effect. + * - An `onTimeout` function: A lazy evaluation function that generates the + * custom defect (typically created using `Cause.die`). + * + * If the effect completes within the time limit, its result is returned + * normally. Otherwise, the custom defect is triggered, and the effect fails + * with that defect. + * + * **When to Use** + * + * This is especially useful when you need to treat timeouts as critical + * failures in your application and wish to include meaningful information in + * the defect. + * + * **Example** + * + * ```ts + * import { Effect, Cause } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * const program = task.pipe( + * Effect.timeoutFailCause({ + * duration: "1 second", + * onTimeout: () => Cause.die("Timed out!") // Custom defect for timeout + * }) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // Start processing... + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Die', defect: 'Timed out!' } + * // } + * ``` + * + * @see {@link timeout} for a version that raises a `TimeoutException`. + * @see {@link timeoutFail} for a version that raises a custom error. + * @see {@link timeoutTo} for a version that allows specifying both success and + * timeout handlers. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ + ( + self: Effect, + options: { readonly onTimeout: LazyArg>; readonly duration: Duration.DurationInput } + ): Effect +} = circular.timeoutFailCause + +/** + * Provides custom behavior for successful and timed-out operations. + * + * **Details** + * + * This function allows you to define distinct outcomes for an effect depending + * on whether it completes within a specified time frame or exceeds the timeout + * duration. You can provide: + * - `onSuccess`: A handler for processing the result of the effect if it + * completes successfully within the time limit. + * - `onTimeout`: A handler for generating a result when the effect times out. + * - `duration`: The maximum allowed time for the effect to complete. + * + * **When to Use** + * + * Unlike {@link timeout}, which raises an exception for timeouts, this function + * gives you full control over the behavior for both success and timeout + * scenarios. It is particularly useful when you want to encapsulate timeouts + * and successes into a specific data structure, like an `Either` type, to + * represent these outcomes in a meaningful way. + * + * **Example** + * + * ```ts + * import { Effect, Either } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * const program = task.pipe( + * Effect.timeoutTo({ + * duration: "1 second", + * onSuccess: (result): Either.Either => + * Either.right(result), + * onTimeout: (): Either.Either => + * Either.left("Timed out!") + * }) + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Start processing... + * // { + * // _id: "Either", + * // _tag: "Left", + * // left: "Timed out!" + * // } + * ``` + * + * @see {@link timeout} for a version that raises a `TimeoutException`. + * @see {@link timeoutFail} for a version that raises a custom error. + * @see {@link timeoutFailCause} for a version that raises a custom defect. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ +export const timeoutTo: { + /** + * Provides custom behavior for successful and timed-out operations. + * + * **Details** + * + * This function allows you to define distinct outcomes for an effect depending + * on whether it completes within a specified time frame or exceeds the timeout + * duration. You can provide: + * - `onSuccess`: A handler for processing the result of the effect if it + * completes successfully within the time limit. + * - `onTimeout`: A handler for generating a result when the effect times out. + * - `duration`: The maximum allowed time for the effect to complete. + * + * **When to Use** + * + * Unlike {@link timeout}, which raises an exception for timeouts, this function + * gives you full control over the behavior for both success and timeout + * scenarios. It is particularly useful when you want to encapsulate timeouts + * and successes into a specific data structure, like an `Either` type, to + * represent these outcomes in a meaningful way. + * + * **Example** + * + * ```ts + * import { Effect, Either } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * const program = task.pipe( + * Effect.timeoutTo({ + * duration: "1 second", + * onSuccess: (result): Either.Either => + * Either.right(result), + * onTimeout: (): Either.Either => + * Either.left("Timed out!") + * }) + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Start processing... + * // { + * // _id: "Either", + * // _tag: "Left", + * // left: "Timed out!" + * // } + * ``` + * + * @see {@link timeout} for a version that raises a `TimeoutException`. + * @see {@link timeoutFail} for a version that raises a custom error. + * @see {@link timeoutFailCause} for a version that raises a custom defect. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ + ( + options: { + readonly onTimeout: LazyArg + readonly onSuccess: (a: A) => B + readonly duration: Duration.DurationInput + } + ): (self: Effect) => Effect + /** + * Provides custom behavior for successful and timed-out operations. + * + * **Details** + * + * This function allows you to define distinct outcomes for an effect depending + * on whether it completes within a specified time frame or exceeds the timeout + * duration. You can provide: + * - `onSuccess`: A handler for processing the result of the effect if it + * completes successfully within the time limit. + * - `onTimeout`: A handler for generating a result when the effect times out. + * - `duration`: The maximum allowed time for the effect to complete. + * + * **When to Use** + * + * Unlike {@link timeout}, which raises an exception for timeouts, this function + * gives you full control over the behavior for both success and timeout + * scenarios. It is particularly useful when you want to encapsulate timeouts + * and successes into a specific data structure, like an `Either` type, to + * represent these outcomes in a meaningful way. + * + * **Example** + * + * ```ts + * import { Effect, Either } from "effect" + * + * const task = Effect.gen(function* () { + * console.log("Start processing...") + * yield* Effect.sleep("2 seconds") // Simulates a delay in processing + * console.log("Processing complete.") + * return "Result" + * }) + * + * const program = task.pipe( + * Effect.timeoutTo({ + * duration: "1 second", + * onSuccess: (result): Either.Either => + * Either.right(result), + * onTimeout: (): Either.Either => + * Either.left("Timed out!") + * }) + * ) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // Start processing... + * // { + * // _id: "Either", + * // _tag: "Left", + * // left: "Timed out!" + * // } + * ``` + * + * @see {@link timeout} for a version that raises a `TimeoutException`. + * @see {@link timeoutFail} for a version that raises a custom error. + * @see {@link timeoutFailCause} for a version that raises a custom defect. + * + * @since 2.0.0 + * @category Delays & Timeouts + */ + ( + self: Effect, + options: { + readonly onTimeout: LazyArg + readonly onSuccess: (a: A) => B + readonly duration: Duration.DurationInput + } + ): Effect +} = circular.timeoutTo + +/** + * Allows working with the default configuration provider. + * + * **Details** + * + * This function retrieves the default configuration provider and passes it to + * the provided function, which can use it to perform computations or retrieve + * configuration values. The function can return an effect that leverages the + * configuration provider for its operations. + * + * @since 2.0.0 + * @category Config + */ +export const configProviderWith: (f: (provider: ConfigProvider) => Effect) => Effect = + defaultServices.configProviderWith + +/** + * Executes an effect using a specific configuration provider. + * + * **Details** + * + * This function lets you run an effect with a specified configuration provider. + * The custom provider will override the default configuration provider for the + * duration of the effect's execution. + * + * **When to Use** + * + * This is particularly useful when you need to use a different set of + * configuration values or sources for specific parts of your application. + * + * **Example** + * + * ```ts + * import { Config, ConfigProvider, Effect } from "effect" + * + * const customProvider: ConfigProvider.ConfigProvider = ConfigProvider.fromMap( + * new Map([["custom-key", "custom-value"]]) + * ) + * + * const program = Effect.withConfigProvider(customProvider)( + * Effect.gen(function*() { + * const value = yield* Config.string("custom-key") + * console.log(`Config value: ${value}`) + * }) + * ) + * + * Effect.runPromise(program) + * // Output: + * // Config value: custom-value + * ``` + * + * @since 2.0.0 + * @category Config + */ +export const withConfigProvider: { + /** + * Executes an effect using a specific configuration provider. + * + * **Details** + * + * This function lets you run an effect with a specified configuration provider. + * The custom provider will override the default configuration provider for the + * duration of the effect's execution. + * + * **When to Use** + * + * This is particularly useful when you need to use a different set of + * configuration values or sources for specific parts of your application. + * + * **Example** + * + * ```ts + * import { Config, ConfigProvider, Effect } from "effect" + * + * const customProvider: ConfigProvider.ConfigProvider = ConfigProvider.fromMap( + * new Map([["custom-key", "custom-value"]]) + * ) + * + * const program = Effect.withConfigProvider(customProvider)( + * Effect.gen(function*() { + * const value = yield* Config.string("custom-key") + * console.log(`Config value: ${value}`) + * }) + * ) + * + * Effect.runPromise(program) + * // Output: + * // Config value: custom-value + * ``` + * + * @since 2.0.0 + * @category Config + */ + (provider: ConfigProvider): (self: Effect) => Effect + /** + * Executes an effect using a specific configuration provider. + * + * **Details** + * + * This function lets you run an effect with a specified configuration provider. + * The custom provider will override the default configuration provider for the + * duration of the effect's execution. + * + * **When to Use** + * + * This is particularly useful when you need to use a different set of + * configuration values or sources for specific parts of your application. + * + * **Example** + * + * ```ts + * import { Config, ConfigProvider, Effect } from "effect" + * + * const customProvider: ConfigProvider.ConfigProvider = ConfigProvider.fromMap( + * new Map([["custom-key", "custom-value"]]) + * ) + * + * const program = Effect.withConfigProvider(customProvider)( + * Effect.gen(function*() { + * const value = yield* Config.string("custom-key") + * console.log(`Config value: ${value}`) + * }) + * ) + * + * Effect.runPromise(program) + * // Output: + * // Config value: custom-value + * ``` + * + * @since 2.0.0 + * @category Config + */ + (self: Effect, provider: ConfigProvider): Effect +} = defaultServices.withConfigProvider + +/** + * Sets a configuration provider within a scope. + * + * **Details** + * + * This function sets the configuration provider to a specified value and + * ensures that it is restored to its original value when the scope is closed. + * + * @since 2.0.0 + * @category Config + */ +export const withConfigProviderScoped: (provider: ConfigProvider) => Effect = + fiberRuntime.withConfigProviderScoped + +/** + * Accesses the full context of the effect. + * + * **Details** + * + * This function provides the ability to access the entire context required by + * an effect. The context is a container that holds dependencies or environment + * values needed by an effect to run. By using this function, you can retrieve + * and work with the context directly within an effect. + * + * @since 2.0.0 + * @category Context + */ +export const context: () => Effect, never, R> = core.context + +/** + * Accesses the context and applies a transformation function. + * + * **Details** + * + * This function retrieves the context of the effect and applies a pure + * transformation function to it. The result of the transformation is then + * returned within the effect. + * + * @see {@link contextWithEffect} for a version that allows effectful transformations. + * + * @since 2.0.0 + * @category Context + */ +export const contextWith: (f: (context: Context.Context) => A) => Effect = effect.contextWith + +/** + * Accesses the context and performs an effectful transformation. + * + * **Details** + * + * This function retrieves the context and allows you to transform it + * effectually using another effect. It is useful when the transformation + * involves asynchronous or effectful operations. + * + * @see {@link contextWith} for a version that allows pure transformations. + * + * @since 2.0.0 + * @category Context + */ +export const contextWithEffect: ( + f: (context: Context.Context) => Effect +) => Effect = core.contextWithEffect + +/** + * Provides part of the required context while leaving the rest unchanged. + * + * **Details** + * + * This function allows you to transform the context required by an effect, + * providing part of the context and leaving the rest to be fulfilled later. + * + * **Example** + * + * ```ts + * import { Context, Effect } from "effect" + * + * class Service1 extends Context.Tag("Service1")() {} + * class Service2 extends Context.Tag("Service2")() {} + * + * const program = Effect.gen(function*() { + * const service1 = yield* Service1 + * console.log(service1.port) + * const service2 = yield* Service2 + * console.log(service2.connection) + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const programWithService1 = Effect.mapInputContext( + * program, + * (ctx: Context.Context) => Context.add(ctx, Service1, { port: 3000 }) + * ) + * + * const runnable = programWithService1.pipe( + * Effect.provideService(Service2, { connection: "localhost" }), + * Effect.provideService(Service1, { port: 3001 }) + * ) + * + * Effect.runPromise(runnable) + * // Output: + * // 3000 + * // localhost + * ``` + * + * @since 2.0.0 + * @category Context + */ +export const mapInputContext: { + /** + * Provides part of the required context while leaving the rest unchanged. + * + * **Details** + * + * This function allows you to transform the context required by an effect, + * providing part of the context and leaving the rest to be fulfilled later. + * + * **Example** + * + * ```ts + * import { Context, Effect } from "effect" + * + * class Service1 extends Context.Tag("Service1")() {} + * class Service2 extends Context.Tag("Service2")() {} + * + * const program = Effect.gen(function*() { + * const service1 = yield* Service1 + * console.log(service1.port) + * const service2 = yield* Service2 + * console.log(service2.connection) + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const programWithService1 = Effect.mapInputContext( + * program, + * (ctx: Context.Context) => Context.add(ctx, Service1, { port: 3000 }) + * ) + * + * const runnable = programWithService1.pipe( + * Effect.provideService(Service2, { connection: "localhost" }), + * Effect.provideService(Service1, { port: 3001 }) + * ) + * + * Effect.runPromise(runnable) + * // Output: + * // 3000 + * // localhost + * ``` + * + * @since 2.0.0 + * @category Context + */ + (f: (context: Context.Context) => Context.Context): (self: Effect) => Effect + /** + * Provides part of the required context while leaving the rest unchanged. + * + * **Details** + * + * This function allows you to transform the context required by an effect, + * providing part of the context and leaving the rest to be fulfilled later. + * + * **Example** + * + * ```ts + * import { Context, Effect } from "effect" + * + * class Service1 extends Context.Tag("Service1")() {} + * class Service2 extends Context.Tag("Service2")() {} + * + * const program = Effect.gen(function*() { + * const service1 = yield* Service1 + * console.log(service1.port) + * const service2 = yield* Service2 + * console.log(service2.connection) + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const programWithService1 = Effect.mapInputContext( + * program, + * (ctx: Context.Context) => Context.add(ctx, Service1, { port: 3000 }) + * ) + * + * const runnable = programWithService1.pipe( + * Effect.provideService(Service2, { connection: "localhost" }), + * Effect.provideService(Service1, { port: 3001 }) + * ) + * + * Effect.runPromise(runnable) + * // Output: + * // 3000 + * // localhost + * ``` + * + * @since 2.0.0 + * @category Context + */ + ( + self: Effect, + f: (context: Context.Context) => Context.Context + ): Effect +} = core.mapInputContext + +/** + * Provides necessary dependencies to an effect, removing its environmental + * requirements. + * + * **Details** + * + * This function allows you to supply the required environment for an effect. + * The environment can be provided in the form of one or more `Layer`s, a + * `Context`, a `Runtime`, or a `ManagedRuntime`. Once the environment is + * provided, the effect can run without requiring external dependencies. + * + * You can compose layers to create a modular and reusable way of setting up the + * environment for effects. For example, layers can be used to configure + * databases, logging services, or any other required dependencies. + * + * **Example** + * + * ```ts + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Tag("Database")< + * Database, + * { readonly query: (sql: string) => Effect.Effect> } + * >() {} + * + * const DatabaseLive = Layer.succeed( + * Database, + * { + * // Simulate a database query + * query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([])) + * } + * ) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function*() { + * const database = yield* Database + * const result = yield* database.query("SELECT * FROM users") + * return result + * }) + * + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provide(program, DatabaseLive) + * + * Effect.runPromise(runnable).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users" + * // [] + * ``` + * + * @see {@link provideService} for providing a service to an effect. + * + * @since 2.0.0 + * @category Context + */ +export const provide: { + /** + * Provides necessary dependencies to an effect, removing its environmental + * requirements. + * + * **Details** + * + * This function allows you to supply the required environment for an effect. + * The environment can be provided in the form of one or more `Layer`s, a + * `Context`, a `Runtime`, or a `ManagedRuntime`. Once the environment is + * provided, the effect can run without requiring external dependencies. + * + * You can compose layers to create a modular and reusable way of setting up the + * environment for effects. For example, layers can be used to configure + * databases, logging services, or any other required dependencies. + * + * **Example** + * + * ```ts + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Tag("Database")< + * Database, + * { readonly query: (sql: string) => Effect.Effect> } + * >() {} + * + * const DatabaseLive = Layer.succeed( + * Database, + * { + * // Simulate a database query + * query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([])) + * } + * ) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function*() { + * const database = yield* Database + * const result = yield* database.query("SELECT * FROM users") + * return result + * }) + * + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provide(program, DatabaseLive) + * + * Effect.runPromise(runnable).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users" + * // [] + * ``` + * + * @see {@link provideService} for providing a service to an effect. + * + * @since 2.0.0 + * @category Context + */ + ]>(layers: Layers): ( + self: Effect + ) => Effect< + A, + E | { [k in keyof Layers]: Layer.Layer.Error }[number], + | { [k in keyof Layers]: Layer.Layer.Context }[number] + | Exclude }[number]> + > + /** + * Provides necessary dependencies to an effect, removing its environmental + * requirements. + * + * **Details** + * + * This function allows you to supply the required environment for an effect. + * The environment can be provided in the form of one or more `Layer`s, a + * `Context`, a `Runtime`, or a `ManagedRuntime`. Once the environment is + * provided, the effect can run without requiring external dependencies. + * + * You can compose layers to create a modular and reusable way of setting up the + * environment for effects. For example, layers can be used to configure + * databases, logging services, or any other required dependencies. + * + * **Example** + * + * ```ts + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Tag("Database")< + * Database, + * { readonly query: (sql: string) => Effect.Effect> } + * >() {} + * + * const DatabaseLive = Layer.succeed( + * Database, + * { + * // Simulate a database query + * query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([])) + * } + * ) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function*() { + * const database = yield* Database + * const result = yield* database.query("SELECT * FROM users") + * return result + * }) + * + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provide(program, DatabaseLive) + * + * Effect.runPromise(runnable).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users" + * // [] + * ``` + * + * @see {@link provideService} for providing a service to an effect. + * + * @since 2.0.0 + * @category Context + */ + (layer: Layer.Layer): (self: Effect) => Effect> + /** + * Provides necessary dependencies to an effect, removing its environmental + * requirements. + * + * **Details** + * + * This function allows you to supply the required environment for an effect. + * The environment can be provided in the form of one or more `Layer`s, a + * `Context`, a `Runtime`, or a `ManagedRuntime`. Once the environment is + * provided, the effect can run without requiring external dependencies. + * + * You can compose layers to create a modular and reusable way of setting up the + * environment for effects. For example, layers can be used to configure + * databases, logging services, or any other required dependencies. + * + * **Example** + * + * ```ts + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Tag("Database")< + * Database, + * { readonly query: (sql: string) => Effect.Effect> } + * >() {} + * + * const DatabaseLive = Layer.succeed( + * Database, + * { + * // Simulate a database query + * query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([])) + * } + * ) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function*() { + * const database = yield* Database + * const result = yield* database.query("SELECT * FROM users") + * return result + * }) + * + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provide(program, DatabaseLive) + * + * Effect.runPromise(runnable).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users" + * // [] + * ``` + * + * @see {@link provideService} for providing a service to an effect. + * + * @since 2.0.0 + * @category Context + */ + (context: Context.Context): (self: Effect) => Effect> + /** + * Provides necessary dependencies to an effect, removing its environmental + * requirements. + * + * **Details** + * + * This function allows you to supply the required environment for an effect. + * The environment can be provided in the form of one or more `Layer`s, a + * `Context`, a `Runtime`, or a `ManagedRuntime`. Once the environment is + * provided, the effect can run without requiring external dependencies. + * + * You can compose layers to create a modular and reusable way of setting up the + * environment for effects. For example, layers can be used to configure + * databases, logging services, or any other required dependencies. + * + * **Example** + * + * ```ts + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Tag("Database")< + * Database, + * { readonly query: (sql: string) => Effect.Effect> } + * >() {} + * + * const DatabaseLive = Layer.succeed( + * Database, + * { + * // Simulate a database query + * query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([])) + * } + * ) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function*() { + * const database = yield* Database + * const result = yield* database.query("SELECT * FROM users") + * return result + * }) + * + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provide(program, DatabaseLive) + * + * Effect.runPromise(runnable).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users" + * // [] + * ``` + * + * @see {@link provideService} for providing a service to an effect. + * + * @since 2.0.0 + * @category Context + */ + (runtime: Runtime.Runtime): (self: Effect) => Effect> + /** + * Provides necessary dependencies to an effect, removing its environmental + * requirements. + * + * **Details** + * + * This function allows you to supply the required environment for an effect. + * The environment can be provided in the form of one or more `Layer`s, a + * `Context`, a `Runtime`, or a `ManagedRuntime`. Once the environment is + * provided, the effect can run without requiring external dependencies. + * + * You can compose layers to create a modular and reusable way of setting up the + * environment for effects. For example, layers can be used to configure + * databases, logging services, or any other required dependencies. + * + * **Example** + * + * ```ts + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Tag("Database")< + * Database, + * { readonly query: (sql: string) => Effect.Effect> } + * >() {} + * + * const DatabaseLive = Layer.succeed( + * Database, + * { + * // Simulate a database query + * query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([])) + * } + * ) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function*() { + * const database = yield* Database + * const result = yield* database.query("SELECT * FROM users") + * return result + * }) + * + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provide(program, DatabaseLive) + * + * Effect.runPromise(runnable).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users" + * // [] + * ``` + * + * @see {@link provideService} for providing a service to an effect. + * + * @since 2.0.0 + * @category Context + */ + (managedRuntime: ManagedRuntime.ManagedRuntime): (self: Effect) => Effect> + /** + * Provides necessary dependencies to an effect, removing its environmental + * requirements. + * + * **Details** + * + * This function allows you to supply the required environment for an effect. + * The environment can be provided in the form of one or more `Layer`s, a + * `Context`, a `Runtime`, or a `ManagedRuntime`. Once the environment is + * provided, the effect can run without requiring external dependencies. + * + * You can compose layers to create a modular and reusable way of setting up the + * environment for effects. For example, layers can be used to configure + * databases, logging services, or any other required dependencies. + * + * **Example** + * + * ```ts + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Tag("Database")< + * Database, + * { readonly query: (sql: string) => Effect.Effect> } + * >() {} + * + * const DatabaseLive = Layer.succeed( + * Database, + * { + * // Simulate a database query + * query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([])) + * } + * ) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function*() { + * const database = yield* Database + * const result = yield* database.query("SELECT * FROM users") + * return result + * }) + * + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provide(program, DatabaseLive) + * + * Effect.runPromise(runnable).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users" + * // [] + * ``` + * + * @see {@link provideService} for providing a service to an effect. + * + * @since 2.0.0 + * @category Context + */ + ]>(self: Effect, layers: Layers): Effect< + A, + E | { [k in keyof Layers]: Layer.Layer.Error }[number], + | { [k in keyof Layers]: Layer.Layer.Context }[number] + | Exclude }[number]> + > + /** + * Provides necessary dependencies to an effect, removing its environmental + * requirements. + * + * **Details** + * + * This function allows you to supply the required environment for an effect. + * The environment can be provided in the form of one or more `Layer`s, a + * `Context`, a `Runtime`, or a `ManagedRuntime`. Once the environment is + * provided, the effect can run without requiring external dependencies. + * + * You can compose layers to create a modular and reusable way of setting up the + * environment for effects. For example, layers can be used to configure + * databases, logging services, or any other required dependencies. + * + * **Example** + * + * ```ts + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Tag("Database")< + * Database, + * { readonly query: (sql: string) => Effect.Effect> } + * >() {} + * + * const DatabaseLive = Layer.succeed( + * Database, + * { + * // Simulate a database query + * query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([])) + * } + * ) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function*() { + * const database = yield* Database + * const result = yield* database.query("SELECT * FROM users") + * return result + * }) + * + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provide(program, DatabaseLive) + * + * Effect.runPromise(runnable).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users" + * // [] + * ``` + * + * @see {@link provideService} for providing a service to an effect. + * + * @since 2.0.0 + * @category Context + */ + (self: Effect, layer: Layer.Layer): Effect> + /** + * Provides necessary dependencies to an effect, removing its environmental + * requirements. + * + * **Details** + * + * This function allows you to supply the required environment for an effect. + * The environment can be provided in the form of one or more `Layer`s, a + * `Context`, a `Runtime`, or a `ManagedRuntime`. Once the environment is + * provided, the effect can run without requiring external dependencies. + * + * You can compose layers to create a modular and reusable way of setting up the + * environment for effects. For example, layers can be used to configure + * databases, logging services, or any other required dependencies. + * + * **Example** + * + * ```ts + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Tag("Database")< + * Database, + * { readonly query: (sql: string) => Effect.Effect> } + * >() {} + * + * const DatabaseLive = Layer.succeed( + * Database, + * { + * // Simulate a database query + * query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([])) + * } + * ) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function*() { + * const database = yield* Database + * const result = yield* database.query("SELECT * FROM users") + * return result + * }) + * + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provide(program, DatabaseLive) + * + * Effect.runPromise(runnable).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users" + * // [] + * ``` + * + * @see {@link provideService} for providing a service to an effect. + * + * @since 2.0.0 + * @category Context + */ + (self: Effect, context: Context.Context): Effect> + /** + * Provides necessary dependencies to an effect, removing its environmental + * requirements. + * + * **Details** + * + * This function allows you to supply the required environment for an effect. + * The environment can be provided in the form of one or more `Layer`s, a + * `Context`, a `Runtime`, or a `ManagedRuntime`. Once the environment is + * provided, the effect can run without requiring external dependencies. + * + * You can compose layers to create a modular and reusable way of setting up the + * environment for effects. For example, layers can be used to configure + * databases, logging services, or any other required dependencies. + * + * **Example** + * + * ```ts + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Tag("Database")< + * Database, + * { readonly query: (sql: string) => Effect.Effect> } + * >() {} + * + * const DatabaseLive = Layer.succeed( + * Database, + * { + * // Simulate a database query + * query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([])) + * } + * ) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function*() { + * const database = yield* Database + * const result = yield* database.query("SELECT * FROM users") + * return result + * }) + * + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provide(program, DatabaseLive) + * + * Effect.runPromise(runnable).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users" + * // [] + * ``` + * + * @see {@link provideService} for providing a service to an effect. + * + * @since 2.0.0 + * @category Context + */ + (self: Effect, runtime: Runtime.Runtime): Effect> + /** + * Provides necessary dependencies to an effect, removing its environmental + * requirements. + * + * **Details** + * + * This function allows you to supply the required environment for an effect. + * The environment can be provided in the form of one or more `Layer`s, a + * `Context`, a `Runtime`, or a `ManagedRuntime`. Once the environment is + * provided, the effect can run without requiring external dependencies. + * + * You can compose layers to create a modular and reusable way of setting up the + * environment for effects. For example, layers can be used to configure + * databases, logging services, or any other required dependencies. + * + * **Example** + * + * ```ts + * import { Context, Effect, Layer } from "effect" + * + * class Database extends Context.Tag("Database")< + * Database, + * { readonly query: (sql: string) => Effect.Effect> } + * >() {} + * + * const DatabaseLive = Layer.succeed( + * Database, + * { + * // Simulate a database query + * query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([])) + * } + * ) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function*() { + * const database = yield* Database + * const result = yield* database.query("SELECT * FROM users") + * return result + * }) + * + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provide(program, DatabaseLive) + * + * Effect.runPromise(runnable).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users" + * // [] + * ``` + * + * @see {@link provideService} for providing a service to an effect. + * + * @since 2.0.0 + * @category Context + */ + (self: Effect, runtime: ManagedRuntime.ManagedRuntime): Effect> +} = layer.effect_provide + +/** + * Provides an implementation for a service in the context of an effect. + * + * **Details** + * + * This function allows you to supply a specific implementation for a service + * required by an effect. Services are typically defined using `Context.Tag`, + * which acts as a unique identifier for the service. By using this function, + * you link the service to its concrete implementation, enabling the effect to + * execute successfully without additional requirements. + * + * For example, you can use this function to provide a random number generator, + * a logger, or any other service your effect depends on. Once the service is + * provided, all parts of the effect that rely on the service will automatically + * use the implementation you supplied. + * + * **Example** + * + * ```ts + * import { Effect, Context } from "effect" + * + * // Declaring a tag for a service that generates random numbers + * class Random extends Context.Tag("MyRandomService")< + * Random, + * { readonly next: Effect.Effect } + * >() {} + * + * // Using the service + * const program = Effect.gen(function* () { + * const random = yield* Random + * const randomNumber = yield* random.next + * console.log(`random number: ${randomNumber}`) + * }) + * + * // Providing the implementation + * // + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provideService(program, Random, { + * next: Effect.sync(() => Math.random()) + * }) + * + * // Run successfully + * Effect.runPromise(runnable) + * // Example Output: + * // random number: 0.8241872233134417 + * ``` + * + * @see {@link provide} for providing multiple layers to an effect. + * + * @since 2.0.0 + * @category Context + */ +export const provideService: { + /** + * Provides an implementation for a service in the context of an effect. + * + * **Details** + * + * This function allows you to supply a specific implementation for a service + * required by an effect. Services are typically defined using `Context.Tag`, + * which acts as a unique identifier for the service. By using this function, + * you link the service to its concrete implementation, enabling the effect to + * execute successfully without additional requirements. + * + * For example, you can use this function to provide a random number generator, + * a logger, or any other service your effect depends on. Once the service is + * provided, all parts of the effect that rely on the service will automatically + * use the implementation you supplied. + * + * **Example** + * + * ```ts + * import { Effect, Context } from "effect" + * + * // Declaring a tag for a service that generates random numbers + * class Random extends Context.Tag("MyRandomService")< + * Random, + * { readonly next: Effect.Effect } + * >() {} + * + * // Using the service + * const program = Effect.gen(function* () { + * const random = yield* Random + * const randomNumber = yield* random.next + * console.log(`random number: ${randomNumber}`) + * }) + * + * // Providing the implementation + * // + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provideService(program, Random, { + * next: Effect.sync(() => Math.random()) + * }) + * + * // Run successfully + * Effect.runPromise(runnable) + * // Example Output: + * // random number: 0.8241872233134417 + * ``` + * + * @see {@link provide} for providing multiple layers to an effect. + * + * @since 2.0.0 + * @category Context + */ + (tag: Context.Tag, service: NoInfer): (self: Effect) => Effect> + /** + * Provides an implementation for a service in the context of an effect. + * + * **Details** + * + * This function allows you to supply a specific implementation for a service + * required by an effect. Services are typically defined using `Context.Tag`, + * which acts as a unique identifier for the service. By using this function, + * you link the service to its concrete implementation, enabling the effect to + * execute successfully without additional requirements. + * + * For example, you can use this function to provide a random number generator, + * a logger, or any other service your effect depends on. Once the service is + * provided, all parts of the effect that rely on the service will automatically + * use the implementation you supplied. + * + * **Example** + * + * ```ts + * import { Effect, Context } from "effect" + * + * // Declaring a tag for a service that generates random numbers + * class Random extends Context.Tag("MyRandomService")< + * Random, + * { readonly next: Effect.Effect } + * >() {} + * + * // Using the service + * const program = Effect.gen(function* () { + * const random = yield* Random + * const randomNumber = yield* random.next + * console.log(`random number: ${randomNumber}`) + * }) + * + * // Providing the implementation + * // + * // ┌─── Effect + * // ▼ + * const runnable = Effect.provideService(program, Random, { + * next: Effect.sync(() => Math.random()) + * }) + * + * // Run successfully + * Effect.runPromise(runnable) + * // Example Output: + * // random number: 0.8241872233134417 + * ``` + * + * @see {@link provide} for providing multiple layers to an effect. + * + * @since 2.0.0 + * @category Context + */ + (self: Effect, tag: Context.Tag, service: NoInfer): Effect> +} = effect.provideService + +/** + * Dynamically provides an implementation for a service using an effect. + * + * **Details** + * + * This function allows you to provide an implementation for a service + * dynamically by using another effect. The provided effect is executed to + * produce the service implementation, which is then made available to the + * consuming effect. This is particularly useful when the service implementation + * itself requires asynchronous or resource-intensive initialization. + * + * For example, you can use this function to lazily initialize a database + * connection or fetch configuration values from an external source before + * making the service available to your effect. + * + * @since 2.0.0 + * @category Context + */ +export const provideServiceEffect: { + /** + * Dynamically provides an implementation for a service using an effect. + * + * **Details** + * + * This function allows you to provide an implementation for a service + * dynamically by using another effect. The provided effect is executed to + * produce the service implementation, which is then made available to the + * consuming effect. This is particularly useful when the service implementation + * itself requires asynchronous or resource-intensive initialization. + * + * For example, you can use this function to lazily initialize a database + * connection or fetch configuration values from an external source before + * making the service available to your effect. + * + * @since 2.0.0 + * @category Context + */ + (tag: Context.Tag, effect: Effect, E1, R1>): (self: Effect) => Effect> + /** + * Dynamically provides an implementation for a service using an effect. + * + * **Details** + * + * This function allows you to provide an implementation for a service + * dynamically by using another effect. The provided effect is executed to + * produce the service implementation, which is then made available to the + * consuming effect. This is particularly useful when the service implementation + * itself requires asynchronous or resource-intensive initialization. + * + * For example, you can use this function to lazily initialize a database + * connection or fetch configuration values from an external source before + * making the service available to your effect. + * + * @since 2.0.0 + * @category Context + */ + ( + self: Effect, + tag: Context.Tag, + effect: Effect, E1, R1> + ): Effect> +} = effect.provideServiceEffect + +/** + * Creates a function that uses a service from the context to produce a value. + * + * @see {@link serviceFunctionEffect} for a version that returns an effect. + * + * @since 2.0.0 + * @category Context + */ +export const serviceFunction: , Args extends Array, A>( + getService: T, + f: (_: Effect.Success) => (...args: Args) => A +) => (...args: Args) => Effect, Effect.Context> = effect.serviceFunction + +/** + * Creates a function that uses a service from the context to produce an effect. + * + * @see {@link serviceFunction} for a version that returns a value. + * + * @since 2.0.0 + * @category Context + */ +export const serviceFunctionEffect: , Args extends Array, A, E, R>( + getService: T, + f: (_: Effect.Success) => (...args: Args) => Effect +) => (...args: Args) => Effect, R | Effect.Context> = effect.serviceFunctionEffect + +/** + * @since 2.0.0 + * @category Context + */ +export const serviceFunctions: ( + getService: Effect +) => { + [k in keyof S as S[k] extends (...args: Array) => Effect ? k : never]: S[k] extends + (...args: infer Args) => Effect ? (...args: Args) => Effect + : never +} = effect.serviceFunctions as any + +/** + * @since 2.0.0 + * @category Context + */ +export const serviceConstants: ( + getService: Effect +) => { + [k in { [k in keyof S]: k }[keyof S]]: S[k] extends Effect ? Effect + : Effect +} = effect.serviceConstants + +/** + * @since 2.0.0 + * @category Context + */ +export const serviceMembers: ( + getService: Effect +) => { + functions: { + [k in keyof S as S[k] extends (...args: Array) => Effect ? k : never]: S[k] extends + (...args: infer Args) => Effect ? (...args: Args) => Effect + : never + } + constants: { + [k in { [k in keyof S]: k }[keyof S]]: S[k] extends Effect ? Effect + : Effect + } +} = effect.serviceMembers as any + +/** + * Retrieves an optional service from the context as an `Option`. + * + * **Details** + * + * This function retrieves a service from the context and wraps it in an + * `Option`. If the service is available, it returns a `Some` containing the + * service. If the service is not found, it returns a `None`. This approach is + * useful when you want to handle the absence of a service gracefully without + * causing an error. + * + * **When to Use** + * + * Use this function when: + * - You need to access a service that may or may not be present in the context. + * - You want to handle the absence of a service using the `Option` type instead + * of throwing an error. + * + * @see {@link serviceOptional} for a version that throws an error if the service is missing. + * + * @since 2.0.0 + * @category Context + */ +export const serviceOption: (tag: Context.Tag) => Effect> = effect.serviceOption + +/** + * Retrieves a service from the context, throwing an error if it is missing. + * + * **Details** + * + * This function retrieves a required service from the context. If the service + * is available, it returns the service. If the service is missing, it throws a + * `NoSuchElementException`, which can be handled using Effect's error-handling + * mechanisms. This is useful for services that are critical to the execution of + * your effect. + * + * @see {@link serviceOption} for a version that returns an `Option` instead of throwing an error. + * + * @since 2.0.0 + * @category Context + */ +export const serviceOptional: (tag: Context.Tag) => Effect = + effect.serviceOptional + +/** + * Updates a service in the context with a new implementation. + * + * **Details** + * + * This function modifies the existing implementation of a service in the + * context. It retrieves the current service, applies the provided + * transformation function `f`, and replaces the old service with the + * transformed one. + * + * **When to Use** + * + * This is useful for adapting or extending a service's behavior during the + * execution of an effect. + * + * @since 2.0.0 + * @category Context + */ +export const updateService: { + /** + * Updates a service in the context with a new implementation. + * + * **Details** + * + * This function modifies the existing implementation of a service in the + * context. It retrieves the current service, applies the provided + * transformation function `f`, and replaces the old service with the + * transformed one. + * + * **When to Use** + * + * This is useful for adapting or extending a service's behavior during the + * execution of an effect. + * + * @since 2.0.0 + * @category Context + */ + (tag: Context.Tag, f: (service: NoInfer) => NoInfer): (self: Effect) => Effect + /** + * Updates a service in the context with a new implementation. + * + * **Details** + * + * This function modifies the existing implementation of a service in the + * context. It retrieves the current service, applies the provided + * transformation function `f`, and replaces the old service with the + * transformed one. + * + * **When to Use** + * + * This is useful for adapting or extending a service's behavior during the + * execution of an effect. + * + * @since 2.0.0 + * @category Context + */ + ( + self: Effect, + tag: Context.Tag, + f: (service: NoInfer) => NoInfer + ): Effect +} = effect.updateService + +/** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Effect` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Effect, pipe } from "effect" + * + * const result = pipe( + * Effect.Do, + * Effect.bind("x", () => Effect.succeed(2)), + * Effect.bind("y", () => Effect.succeed(3)), + * Effect.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(Effect.runSync(result), { x: 2, y: 3, sum: 5 }) + * ``` + * + * @see {@link bind} + * @see {@link bindTo} + * @see {@link let_ let} + * + * @category Do notation + * @since 2.0.0 + */ +export const Do: Effect<{}> = effect.Do + +/** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Effect` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Effect, pipe } from "effect" + * + * const result = pipe( + * Effect.Do, + * Effect.bind("x", () => Effect.succeed(2)), + * Effect.bind("y", () => Effect.succeed(3)), + * Effect.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(Effect.runSync(result), { x: 2, y: 3, sum: 5 }) + * ``` + * + * @see {@link Do} + * @see {@link bindTo} + * @see {@link let_ let} + * + * @category Do notation + * @since 2.0.0 + */ +export const bind: { + /** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Effect` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Effect, pipe } from "effect" + * + * const result = pipe( + * Effect.Do, + * Effect.bind("x", () => Effect.succeed(2)), + * Effect.bind("y", () => Effect.succeed(3)), + * Effect.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(Effect.runSync(result), { x: 2, y: 3, sum: 5 }) + * ``` + * + * @see {@link Do} + * @see {@link bindTo} + * @see {@link let_ let} + * + * @category Do notation + * @since 2.0.0 + */ + (name: Exclude, f: (a: NoInfer) => Effect): (self: Effect) => Effect<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, E2 | E1, R2 | R1> + /** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Effect` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Effect, pipe } from "effect" + * + * const result = pipe( + * Effect.Do, + * Effect.bind("x", () => Effect.succeed(2)), + * Effect.bind("y", () => Effect.succeed(3)), + * Effect.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(Effect.runSync(result), { x: 2, y: 3, sum: 5 }) + * ``` + * + * @see {@link Do} + * @see {@link bindTo} + * @see {@link let_ let} + * + * @category Do notation + * @since 2.0.0 + */ + ( + self: Effect, + name: Exclude, + f: (a: NoInfer) => Effect + ): Effect<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, E1 | E2, R1 | R2> +} = effect.bind + +/** + * `bindAll` combines `all` with `bind`. It is useful + * when you want to concurrently run multiple effects and then combine their + * results in a Do notation pipeline. + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Effect, Either, pipe } from "effect" + * + * const result = pipe( + * Effect.Do, + * Effect.bind("x", () => Effect.succeed(2)), + * Effect.bindAll(({ x }) => ({ + * a: Effect.succeed(x), + * b: Effect.fail("oops"), + * }), { concurrency: 2, mode: "either" }) + * ) + * assert.deepStrictEqual(Effect.runSync(result), { x: 2, a: Either.right(2), b: Either.left("oops") }) + * ``` + * + * @category Do notation + * @since 3.7.0 + */ +export const bindAll: { + /** + * `bindAll` combines `all` with `bind`. It is useful + * when you want to concurrently run multiple effects and then combine their + * results in a Do notation pipeline. + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Effect, Either, pipe } from "effect" + * + * const result = pipe( + * Effect.Do, + * Effect.bind("x", () => Effect.succeed(2)), + * Effect.bindAll(({ x }) => ({ + * a: Effect.succeed(x), + * b: Effect.fail("oops"), + * }), { concurrency: 2, mode: "either" }) + * ) + * assert.deepStrictEqual(Effect.runSync(result), { x: 2, a: Either.right(2), b: Either.left("oops") }) + * ``` + * + * @category Do notation + * @since 3.7.0 + */ + < + A extends object, + X extends Record>, + O extends NoExcessProperties<{ + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly mode?: "default" | "validate" | "either" | undefined + readonly concurrentFinalizers?: boolean | undefined + }, O> + >( + f: (a: NoInfer) => [Extract] extends [never] ? X : `Duplicate keys`, + options?: undefined | O + ): ( + self: Effect + ) => [All.ReturnObject>] extends [Effect] + ? Effect< + { [K in keyof A | keyof Success]: K extends keyof A ? A[K] : K extends keyof Success ? Success[K] : never }, + E1 | Error, + R1 | Context + > + : never + /** + * `bindAll` combines `all` with `bind`. It is useful + * when you want to concurrently run multiple effects and then combine their + * results in a Do notation pipeline. + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Effect, Either, pipe } from "effect" + * + * const result = pipe( + * Effect.Do, + * Effect.bind("x", () => Effect.succeed(2)), + * Effect.bindAll(({ x }) => ({ + * a: Effect.succeed(x), + * b: Effect.fail("oops"), + * }), { concurrency: 2, mode: "either" }) + * ) + * assert.deepStrictEqual(Effect.runSync(result), { x: 2, a: Either.right(2), b: Either.left("oops") }) + * ``` + * + * @category Do notation + * @since 3.7.0 + */ + < + A extends object, + X extends Record>, + O extends NoExcessProperties<{ + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly mode?: "default" | "validate" | "either" | undefined + readonly concurrentFinalizers?: boolean | undefined + }, O>, + E1, + R1 + >( + self: Effect, + f: (a: NoInfer) => [Extract] extends [never] ? X : `Duplicate keys`, + options?: undefined | { + readonly concurrency?: Concurrency | undefined + readonly batching?: boolean | "inherit" | undefined + readonly mode?: "default" | "validate" | "either" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + ): [All.ReturnObject>] extends [Effect] + ? Effect< + { [K in keyof A | keyof Success]: K extends keyof A ? A[K] : K extends keyof Success ? Success[K] : never }, + E1 | Error, + R1 | Context + > + : never +} = circular.bindAll + +/** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Effect` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Effect, pipe } from "effect" + * + * const result = pipe( + * Effect.Do, + * Effect.bind("x", () => Effect.succeed(2)), + * Effect.bind("y", () => Effect.succeed(3)), + * Effect.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(Effect.runSync(result), { x: 2, y: 3, sum: 5 }) + * ``` + * + * @see {@link Do} + * @see {@link bind} + * @see {@link let_ let} + * + * @category Do notation + * @since 2.0.0 + */ +export const bindTo: { + /** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Effect` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Effect, pipe } from "effect" + * + * const result = pipe( + * Effect.Do, + * Effect.bind("x", () => Effect.succeed(2)), + * Effect.bind("y", () => Effect.succeed(3)), + * Effect.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(Effect.runSync(result), { x: 2, y: 3, sum: 5 }) + * ``` + * + * @see {@link Do} + * @see {@link bind} + * @see {@link let_ let} + * + * @category Do notation + * @since 2.0.0 + */ + (name: N): (self: Effect) => Effect<{ [K in N]: A }, E, R> + /** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Effect` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Effect, pipe } from "effect" + * + * const result = pipe( + * Effect.Do, + * Effect.bind("x", () => Effect.succeed(2)), + * Effect.bind("y", () => Effect.succeed(3)), + * Effect.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(Effect.runSync(result), { x: 2, y: 3, sum: 5 }) + * ``` + * + * @see {@link Do} + * @see {@link bind} + * @see {@link let_ let} + * + * @category Do notation + * @since 2.0.0 + */ + (self: Effect, name: N): Effect<{ [K in N]: A }, E, R> +} = effect.bindTo + +const let_: { + ( + name: Exclude, + f: (a: NoInfer) => B + ): (self: Effect) => Effect<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, E, R> + ( + self: Effect, + name: Exclude, + f: (a: NoInfer) => B + ): Effect<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, E, R> +} = effect.let_ + +export { + /** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Effect` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * **Example** + * + * ```ts + * import * as assert from "node:assert" + * import { Effect, pipe } from "effect" + * + * const result = pipe( + * Effect.Do, + * Effect.bind("x", () => Effect.succeed(2)), + * Effect.bind("y", () => Effect.succeed(3)), + * Effect.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(Effect.runSync(result), { x: 2, y: 3, sum: 5 }) + * + * ``` + * + * @see {@link Do} + * @see {@link bind} + * @see {@link bindTo} + * + * @category Do notation + * @since 2.0.0 + */ + let_ as let +} + +/** + * Encapsulates the result of an effect in an `Option`. + * + * **Details** + * + * This function wraps the outcome of an effect in an `Option` type. If the + * original effect succeeds, the success value is wrapped in `Option.some`. If + * the effect fails, the failure is converted to `Option.none`. + * + * This is particularly useful for scenarios where you want to represent the + * absence of a value explicitly, without causing the resulting effect to fail. + * The resulting effect has an error type of `never`, meaning it cannot fail + * directly. However, unrecoverable errors, also referred to as defects, are + * not captured and will still result in failure. + * + * **Example** (Using Effect.option to Handle Errors) + * + * ```ts + * import { Effect } from "effect" + * + * const maybe1 = Effect.option(Effect.succeed(1)) + * + * Effect.runPromiseExit(maybe1).then(console.log) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Success', + * // value: { _id: 'Option', _tag: 'Some', value: 1 } + * // } + * + * const maybe2 = Effect.option(Effect.fail("Uh oh!")) + * + * Effect.runPromiseExit(maybe2).then(console.log) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Success', + * // value: { _id: 'Option', _tag: 'None' } + * // } + * + * const maybe3 = Effect.option(Effect.die("Boom!")) + * + * Effect.runPromiseExit(maybe3).then(console.log) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Die', defect: 'Boom!' } + * // } + * ``` + * + * @see {@link either} for a version that uses `Either` instead. + * @see {@link exit} for a version that encapsulates both recoverable errors and defects in an `Exit`. + * + * @since 2.0.0 + * @category Outcome Encapsulation + */ +export const option: (self: Effect) => Effect, never, R> = effect.option + +/** + * Encapsulates both success and failure of an `Effect` into an `Either` type. + * + * **Details** + * + * This function converts an effect that may fail into an effect that always + * succeeds, wrapping the outcome in an `Either` type. The result will be + * `Either.Left` if the effect fails, containing the recoverable error, or + * `Either.Right` if it succeeds, containing the result. + * + * Using this function, you can handle recoverable errors explicitly without + * causing the effect to fail. This is particularly useful in scenarios where + * you want to chain effects and manage both success and failure in the same + * logical flow. + * + * It's important to note that unrecoverable errors, often referred to as + * "defects," are still thrown and not captured within the `Either` type. Only + * failures that are explicitly represented as recoverable errors in the effect + * are encapsulated. + * + * The resulting effect cannot fail directly because all recoverable failures + * are represented inside the `Either` type. + * + * **Example** + * + * ```ts + * import { Effect, Either, Random } from "effect" + * + * class HttpError { + * readonly _tag = "HttpError" + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * } + * + * // ┌─── Effect + * // ▼ + * const program = Effect.gen(function* () { + * const n1 = yield* Random.next + * const n2 = yield* Random.next + * if (n1 < 0.5) { + * yield* Effect.fail(new HttpError()) + * } + * if (n2 < 0.5) { + * yield* Effect.fail(new ValidationError()) + * } + * return "some result" + * }) + * + * // ┌─── Effect + * // ▼ + * const recovered = Effect.gen(function* () { + * // ┌─── Either + * // ▼ + * const failureOrSuccess = yield* Effect.either(program) + * return Either.match(failureOrSuccess, { + * onLeft: (error) => `Recovering from ${error._tag}`, + * onRight: (value) => value // Do nothing in case of success + * }) + * }) + * ``` + * + * @see {@link option} for a version that uses `Option` instead. + * @see {@link exit} for a version that encapsulates both recoverable errors and defects in an `Exit`. + * + * @since 2.0.0 + * @category Outcome Encapsulation + */ +export const either: (self: Effect) => Effect, never, R> = core.either + +/** + * Encapsulates both success and failure of an `Effect` using the `Exit` type. + * + * **Details** + * + * This function converts an effect into one that always succeeds, wrapping its + * outcome in the `Exit` type. The `Exit` type provides explicit handling of + * both success (`Exit.Success`) and failure (`Exit.Failure`) cases, including + * defects (unrecoverable errors). + * + * Unlike {@link either} or {@link option}, this function also encapsulates + * defects, which are typically unrecoverable and would otherwise terminate the + * effect. With the `Exit` type, defects are represented in `Exit.Failure`, + * allowing for detailed introspection and structured error handling. + * + * This makes the resulting effect robust and incapable of direct failure (its + * error type is `never`). It is particularly useful for workflows where all + * outcomes, including unexpected defects, must be managed and analyzed. + * + * **Example** + * + * ```ts + * import { Effect, Cause, Console, Exit } from "effect" + * + * // Simulating a runtime error + * const task = Effect.dieMessage("Boom!") + * + * const program = Effect.gen(function* () { + * const exit = yield* Effect.exit(task) + * if (Exit.isFailure(exit)) { + * const cause = exit.cause + * if ( + * Cause.isDieType(cause) && + * Cause.isRuntimeException(cause.defect) + * ) { + * yield* Console.log( + * `RuntimeException defect caught: ${cause.defect.message}` + * ) + * } else { + * yield* Console.log("Unknown failure caught.") + * } + * } + * }) + * + * // We get an Exit.Success because we caught all failures + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // RuntimeException defect caught: Boom! + * // { + * // _id: "Exit", + * // _tag: "Success", + * // value: undefined + * // } + * ``` + * + * @see {@link option} for a version that uses `Option` instead. + * @see {@link either} for a version that uses `Either` instead. + * + * @since 2.0.0 + * @category Outcome Encapsulation + */ +export const exit: (self: Effect) => Effect, never, R> = core.exit + +/** + * Converts an `Effect` into an operation that completes a `Deferred` with its result. + * + * **Details** + * + * The `intoDeferred` function takes an effect and a `Deferred` and ensures that the `Deferred` + * is completed based on the outcome of the effect. If the effect succeeds, the `Deferred` is + * completed with the success value. If the effect fails, the `Deferred` is completed with the + * failure. Additionally, if the effect is interrupted, the `Deferred` will also be interrupted. + * + * **Example** + * + * ```ts + * import { Deferred, Effect } from "effect" + * + * // Define an effect that succeeds + * const successEffect = Effect.succeed(42) + * + * const program = Effect.gen(function*() { + * // Create a deferred + * const deferred = yield* Deferred.make() + * + * // Complete the deferred using the successEffect + * const isCompleted = yield* Effect.intoDeferred(successEffect, deferred) + * + * // Access the value of the deferred + * const value = yield* Deferred.await(deferred) + * console.log(value) + * + * return isCompleted + * }) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // 42 + * // true + * ``` + * + * @since 2.0.0 + * @category Synchronization Utilities + */ +export const intoDeferred: { + /** + * Converts an `Effect` into an operation that completes a `Deferred` with its result. + * + * **Details** + * + * The `intoDeferred` function takes an effect and a `Deferred` and ensures that the `Deferred` + * is completed based on the outcome of the effect. If the effect succeeds, the `Deferred` is + * completed with the success value. If the effect fails, the `Deferred` is completed with the + * failure. Additionally, if the effect is interrupted, the `Deferred` will also be interrupted. + * + * **Example** + * + * ```ts + * import { Deferred, Effect } from "effect" + * + * // Define an effect that succeeds + * const successEffect = Effect.succeed(42) + * + * const program = Effect.gen(function*() { + * // Create a deferred + * const deferred = yield* Deferred.make() + * + * // Complete the deferred using the successEffect + * const isCompleted = yield* Effect.intoDeferred(successEffect, deferred) + * + * // Access the value of the deferred + * const value = yield* Deferred.await(deferred) + * console.log(value) + * + * return isCompleted + * }) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // 42 + * // true + * ``` + * + * @since 2.0.0 + * @category Synchronization Utilities + */ + (deferred: Deferred.Deferred): (self: Effect) => Effect + /** + * Converts an `Effect` into an operation that completes a `Deferred` with its result. + * + * **Details** + * + * The `intoDeferred` function takes an effect and a `Deferred` and ensures that the `Deferred` + * is completed based on the outcome of the effect. If the effect succeeds, the `Deferred` is + * completed with the success value. If the effect fails, the `Deferred` is completed with the + * failure. Additionally, if the effect is interrupted, the `Deferred` will also be interrupted. + * + * **Example** + * + * ```ts + * import { Deferred, Effect } from "effect" + * + * // Define an effect that succeeds + * const successEffect = Effect.succeed(42) + * + * const program = Effect.gen(function*() { + * // Create a deferred + * const deferred = yield* Deferred.make() + * + * // Complete the deferred using the successEffect + * const isCompleted = yield* Effect.intoDeferred(successEffect, deferred) + * + * // Access the value of the deferred + * const value = yield* Deferred.await(deferred) + * console.log(value) + * + * return isCompleted + * }) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // 42 + * // true + * ``` + * + * @since 2.0.0 + * @category Synchronization Utilities + */ + (self: Effect, deferred: Deferred.Deferred): Effect +} = core.intoDeferred + +const if_: { + ( + options: { readonly onTrue: LazyArg>; readonly onFalse: LazyArg> } + ): (self: boolean | Effect) => Effect + ( + self: boolean | Effect, + options: { readonly onTrue: LazyArg>; readonly onFalse: LazyArg> } + ): Effect +} = core.if_ + +export { + /** + * Executes one of two effects based on a condition evaluated by an effectful predicate. + * + * Use `if` to run one of two effects depending on whether the predicate effect + * evaluates to `true` or `false`. If the predicate is `true`, the `onTrue` effect + * is executed. If it is `false`, the `onFalse` effect is executed instead. + * + * **Example** (Simulating a Coin Flip) + * + * ```ts + * import { Effect, Random, Console } from "effect" + * + * const flipTheCoin = Effect.if(Random.nextBoolean, { + * onTrue: () => Console.log("Head"), // Runs if the predicate is true + * onFalse: () => Console.log("Tail") // Runs if the predicate is false + * }) + * + * Effect.runFork(flipTheCoin) + * ``` + * + * @since 2.0.0 + * @category Conditional Operators + */ + if_ as if +} + +/** + * Filters an effect, dying with a custom defect if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect dies with a custom defect + * generated by the `orDieWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints on values and treating violations as + * fatal program errors. + * + * @since 2.0.0 + * @category Filtering + */ +export const filterOrDie: { + /** + * Filters an effect, dying with a custom defect if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect dies with a custom defect + * generated by the `orDieWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints on values and treating violations as + * fatal program errors. + * + * @since 2.0.0 + * @category Filtering + */ + ( + refinement: Refinement, B>, + orDieWith: (a: EqualsWith>) => unknown + ): (self: Effect) => Effect + /** + * Filters an effect, dying with a custom defect if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect dies with a custom defect + * generated by the `orDieWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints on values and treating violations as + * fatal program errors. + * + * @since 2.0.0 + * @category Filtering + */ + (predicate: Predicate>, orDieWith: (a: NoInfer) => unknown): (self: Effect) => Effect + /** + * Filters an effect, dying with a custom defect if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect dies with a custom defect + * generated by the `orDieWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints on values and treating violations as + * fatal program errors. + * + * @since 2.0.0 + * @category Filtering + */ + ( + self: Effect, + refinement: Refinement, + orDieWith: (a: EqualsWith>) => unknown + ): Effect + /** + * Filters an effect, dying with a custom defect if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect dies with a custom defect + * generated by the `orDieWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints on values and treating violations as + * fatal program errors. + * + * @since 2.0.0 + * @category Filtering + */ + ( + self: Effect, + predicate: Predicate, + orDieWith: (a: A) => unknown + ): Effect +} = effect.filterOrDie + +/** + * Filters an effect, dying with a custom message if the predicate fails. + * + * **Details** + * + * This function works like {@link filterOrDie} but allows you to specify a + * custom error message to describe the reason for the failure. The message is + * included in the defect when the predicate evaluates to `false`. + * + * @since 2.0.0 + * @category Filtering + */ +export const filterOrDieMessage: { + /** + * Filters an effect, dying with a custom message if the predicate fails. + * + * **Details** + * + * This function works like {@link filterOrDie} but allows you to specify a + * custom error message to describe the reason for the failure. The message is + * included in the defect when the predicate evaluates to `false`. + * + * @since 2.0.0 + * @category Filtering + */ + (refinement: Refinement, B>, message: string): (self: Effect) => Effect + /** + * Filters an effect, dying with a custom message if the predicate fails. + * + * **Details** + * + * This function works like {@link filterOrDie} but allows you to specify a + * custom error message to describe the reason for the failure. The message is + * included in the defect when the predicate evaluates to `false`. + * + * @since 2.0.0 + * @category Filtering + */ + (predicate: Predicate>, message: string): (self: Effect) => Effect + /** + * Filters an effect, dying with a custom message if the predicate fails. + * + * **Details** + * + * This function works like {@link filterOrDie} but allows you to specify a + * custom error message to describe the reason for the failure. The message is + * included in the defect when the predicate evaluates to `false`. + * + * @since 2.0.0 + * @category Filtering + */ + (self: Effect, refinement: Refinement, message: string): Effect + /** + * Filters an effect, dying with a custom message if the predicate fails. + * + * **Details** + * + * This function works like {@link filterOrDie} but allows you to specify a + * custom error message to describe the reason for the failure. The message is + * included in the defect when the predicate evaluates to `false`. + * + * @since 2.0.0 + * @category Filtering + */ + (self: Effect, predicate: Predicate, message: string): Effect +} = effect.filterOrDieMessage + +/** + * Filters an effect, providing an alternative effect if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, it executes the `orElse` effect instead. The + * `orElse` effect can produce an alternative value or perform additional + * computations. + * + * @since 2.0.0 + * @category Filtering + */ +export const filterOrElse: { + /** + * Filters an effect, providing an alternative effect if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, it executes the `orElse` effect instead. The + * `orElse` effect can produce an alternative value or perform additional + * computations. + * + * @since 2.0.0 + * @category Filtering + */ + ( + refinement: Refinement, B>, + orElse: (a: EqualsWith, Exclude, B>>) => Effect + ): (self: Effect) => Effect + /** + * Filters an effect, providing an alternative effect if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, it executes the `orElse` effect instead. The + * `orElse` effect can produce an alternative value or perform additional + * computations. + * + * @since 2.0.0 + * @category Filtering + */ + ( + predicate: Predicate>, + orElse: (a: NoInfer) => Effect + ): (self: Effect) => Effect + /** + * Filters an effect, providing an alternative effect if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, it executes the `orElse` effect instead. The + * `orElse` effect can produce an alternative value or perform additional + * computations. + * + * @since 2.0.0 + * @category Filtering + */ + ( + self: Effect, + refinement: Refinement, + orElse: (a: EqualsWith>) => Effect + ): Effect + /** + * Filters an effect, providing an alternative effect if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, it executes the `orElse` effect instead. The + * `orElse` effect can produce an alternative value or perform additional + * computations. + * + * @since 2.0.0 + * @category Filtering + */ + ( + self: Effect, + predicate: Predicate, + orElse: (a: A) => Effect + ): Effect +} = effect.filterOrElse + +/** + * Filters an effect, failing with a custom error if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect fails with a custom error + * generated by the `orFailWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints and treating violations as + * recoverable errors. + * + * **Providing a Guard** + * + * In addition to the filtering capabilities discussed earlier, you have the + * option to further refine and narrow down the type of the success channel by + * providing a [user-defined type + * guard](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). + * Let's explore this concept through an example: + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterOrFail with a custom type guard to ensure user is not null + * Effect.filterOrFail( + * (user): user is User => user !== null, // Type guard + * () => new Error("Unauthorized") + * ), + * // 'user' now has the type `User` (not `User | null`) + * Effect.andThen((user) => user.name) + * ) + * ``` + * + * @since 2.0.0 + * @category Filtering + */ +export const filterOrFail: { + /** + * Filters an effect, failing with a custom error if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect fails with a custom error + * generated by the `orFailWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints and treating violations as + * recoverable errors. + * + * **Providing a Guard** + * + * In addition to the filtering capabilities discussed earlier, you have the + * option to further refine and narrow down the type of the success channel by + * providing a [user-defined type + * guard](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). + * Let's explore this concept through an example: + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterOrFail with a custom type guard to ensure user is not null + * Effect.filterOrFail( + * (user): user is User => user !== null, // Type guard + * () => new Error("Unauthorized") + * ), + * // 'user' now has the type `User` (not `User | null`) + * Effect.andThen((user) => user.name) + * ) + * ``` + * + * @since 2.0.0 + * @category Filtering + */ + ( + refinement: Refinement, B>, + orFailWith: (a: EqualsWith, Exclude, B>>) => E2 + ): (self: Effect) => Effect, E2 | E, R> + /** + * Filters an effect, failing with a custom error if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect fails with a custom error + * generated by the `orFailWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints and treating violations as + * recoverable errors. + * + * **Providing a Guard** + * + * In addition to the filtering capabilities discussed earlier, you have the + * option to further refine and narrow down the type of the success channel by + * providing a [user-defined type + * guard](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). + * Let's explore this concept through an example: + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterOrFail with a custom type guard to ensure user is not null + * Effect.filterOrFail( + * (user): user is User => user !== null, // Type guard + * () => new Error("Unauthorized") + * ), + * // 'user' now has the type `User` (not `User | null`) + * Effect.andThen((user) => user.name) + * ) + * ``` + * + * @since 2.0.0 + * @category Filtering + */ + (predicate: Predicate>, orFailWith: (a: NoInfer) => E2): (self: Effect) => Effect + /** + * Filters an effect, failing with a custom error if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect fails with a custom error + * generated by the `orFailWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints and treating violations as + * recoverable errors. + * + * **Providing a Guard** + * + * In addition to the filtering capabilities discussed earlier, you have the + * option to further refine and narrow down the type of the success channel by + * providing a [user-defined type + * guard](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). + * Let's explore this concept through an example: + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterOrFail with a custom type guard to ensure user is not null + * Effect.filterOrFail( + * (user): user is User => user !== null, // Type guard + * () => new Error("Unauthorized") + * ), + * // 'user' now has the type `User` (not `User | null`) + * Effect.andThen((user) => user.name) + * ) + * ``` + * + * @since 2.0.0 + * @category Filtering + */ + ( + self: Effect, + refinement: Refinement, + orFailWith: (a: EqualsWith>) => E2 + ): Effect, E2 | E, R> + /** + * Filters an effect, failing with a custom error if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect fails with a custom error + * generated by the `orFailWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints and treating violations as + * recoverable errors. + * + * **Providing a Guard** + * + * In addition to the filtering capabilities discussed earlier, you have the + * option to further refine and narrow down the type of the success channel by + * providing a [user-defined type + * guard](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). + * Let's explore this concept through an example: + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterOrFail with a custom type guard to ensure user is not null + * Effect.filterOrFail( + * (user): user is User => user !== null, // Type guard + * () => new Error("Unauthorized") + * ), + * // 'user' now has the type `User` (not `User | null`) + * Effect.andThen((user) => user.name) + * ) + * ``` + * + * @since 2.0.0 + * @category Filtering + */ + (self: Effect, predicate: Predicate, orFailWith: (a: A) => E2): Effect + /** + * Filters an effect, failing with a custom error if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect fails with a custom error + * generated by the `orFailWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints and treating violations as + * recoverable errors. + * + * **Providing a Guard** + * + * In addition to the filtering capabilities discussed earlier, you have the + * option to further refine and narrow down the type of the success channel by + * providing a [user-defined type + * guard](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). + * Let's explore this concept through an example: + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterOrFail with a custom type guard to ensure user is not null + * Effect.filterOrFail( + * (user): user is User => user !== null, // Type guard + * () => new Error("Unauthorized") + * ), + * // 'user' now has the type `User` (not `User | null`) + * Effect.andThen((user) => user.name) + * ) + * ``` + * + * @since 2.0.0 + * @category Filtering + */ + (refinement: Refinement, B>): (self: Effect) => Effect, Cause.NoSuchElementException | E, R> + /** + * Filters an effect, failing with a custom error if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect fails with a custom error + * generated by the `orFailWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints and treating violations as + * recoverable errors. + * + * **Providing a Guard** + * + * In addition to the filtering capabilities discussed earlier, you have the + * option to further refine and narrow down the type of the success channel by + * providing a [user-defined type + * guard](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). + * Let's explore this concept through an example: + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterOrFail with a custom type guard to ensure user is not null + * Effect.filterOrFail( + * (user): user is User => user !== null, // Type guard + * () => new Error("Unauthorized") + * ), + * // 'user' now has the type `User` (not `User | null`) + * Effect.andThen((user) => user.name) + * ) + * ``` + * + * @since 2.0.0 + * @category Filtering + */ + (predicate: Predicate>): (self: Effect) => Effect + /** + * Filters an effect, failing with a custom error if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect fails with a custom error + * generated by the `orFailWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints and treating violations as + * recoverable errors. + * + * **Providing a Guard** + * + * In addition to the filtering capabilities discussed earlier, you have the + * option to further refine and narrow down the type of the success channel by + * providing a [user-defined type + * guard](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). + * Let's explore this concept through an example: + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterOrFail with a custom type guard to ensure user is not null + * Effect.filterOrFail( + * (user): user is User => user !== null, // Type guard + * () => new Error("Unauthorized") + * ), + * // 'user' now has the type `User` (not `User | null`) + * Effect.andThen((user) => user.name) + * ) + * ``` + * + * @since 2.0.0 + * @category Filtering + */ + (self: Effect, refinement: Refinement): Effect, E | Cause.NoSuchElementException, R> + /** + * Filters an effect, failing with a custom error if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect fails with a custom error + * generated by the `orFailWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints and treating violations as + * recoverable errors. + * + * **Providing a Guard** + * + * In addition to the filtering capabilities discussed earlier, you have the + * option to further refine and narrow down the type of the success channel by + * providing a [user-defined type + * guard](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates). + * Let's explore this concept through an example: + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterOrFail with a custom type guard to ensure user is not null + * Effect.filterOrFail( + * (user): user is User => user !== null, // Type guard + * () => new Error("Unauthorized") + * ), + * // 'user' now has the type `User` (not `User | null`) + * Effect.andThen((user) => user.name) + * ) + * ``` + * + * @since 2.0.0 + * @category Filtering + */ + (self: Effect, predicate: Predicate): Effect +} = effect.filterOrFail + +/** + * Filters an effect with an effectful predicate, falling back to an alternative + * effect if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect falls back to the `orElse` + * effect. The `orElse` effect can produce an alternative value or perform + * additional computations. + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterEffectOrElse with an effectful predicate + * Effect.filterEffectOrElse({ + * predicate: (user) => Effect.succeed(user !== null), + * orElse: (user) => Effect.fail(new Error(`Unauthorized user: ${user}`)) + * }), + * ) + * ``` + * + * @since 3.13.0 + * @category Filtering + */ +export const filterEffectOrElse: { + /** + * Filters an effect with an effectful predicate, falling back to an alternative + * effect if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect falls back to the `orElse` + * effect. The `orElse` effect can produce an alternative value or perform + * additional computations. + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterEffectOrElse with an effectful predicate + * Effect.filterEffectOrElse({ + * predicate: (user) => Effect.succeed(user !== null), + * orElse: (user) => Effect.fail(new Error(`Unauthorized user: ${user}`)) + * }), + * ) + * ``` + * + * @since 3.13.0 + * @category Filtering + */ + ( + options: { + readonly predicate: (a: NoInfer) => Effect + readonly orElse: (a: NoInfer) => Effect + } + ): (self: Effect) => Effect + /** + * Filters an effect with an effectful predicate, falling back to an alternative + * effect if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect falls back to the `orElse` + * effect. The `orElse` effect can produce an alternative value or perform + * additional computations. + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterEffectOrElse with an effectful predicate + * Effect.filterEffectOrElse({ + * predicate: (user) => Effect.succeed(user !== null), + * orElse: (user) => Effect.fail(new Error(`Unauthorized user: ${user}`)) + * }), + * ) + * ``` + * + * @since 3.13.0 + * @category Filtering + */ + ( + self: Effect, + options: { + readonly predicate: (a: A) => Effect + readonly orElse: (a: A) => Effect + } + ): Effect +} = core.filterEffectOrElse + +/** + * Filters an effect with an effectful predicate, failing with a custom error if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect fails with a custom error + * generated by the `orFailWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints and treating violations as + * recoverable errors. + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterEffectOrFail with an effectful predicate + * Effect.filterEffectOrFail({ + * predicate: (user) => Effect.succeed(user !== null), + * orFailWith: () => new Error("Unauthorized") + * }), + * ) + * ``` + * + * @since 3.13.0 + * @category Filtering + */ +export const filterEffectOrFail: { + /** + * Filters an effect with an effectful predicate, failing with a custom error if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect fails with a custom error + * generated by the `orFailWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints and treating violations as + * recoverable errors. + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterEffectOrFail with an effectful predicate + * Effect.filterEffectOrFail({ + * predicate: (user) => Effect.succeed(user !== null), + * orFailWith: () => new Error("Unauthorized") + * }), + * ) + * ``` + * + * @since 3.13.0 + * @category Filtering + */ + ( + options: { + readonly predicate: (a: NoInfer) => Effect + readonly orFailWith: (a: NoInfer) => E3 + } + ): (self: Effect) => Effect + /** + * Filters an effect with an effectful predicate, failing with a custom error if the predicate fails. + * + * **Details** + * + * This function applies a predicate to the result of an effect. If the + * predicate evaluates to `false`, the effect fails with a custom error + * generated by the `orFailWith` function. + * + * **When to Use** + * + * This is useful for enforcing constraints and treating violations as + * recoverable errors. + * + * **Example** + * + * ```ts + * import { Effect, pipe } from "effect" + * + * // Define a user interface + * interface User { + * readonly name: string + * } + * + * // Simulate an asynchronous authentication function + * declare const auth: () => Promise + * + * const program = pipe( + * Effect.promise(() => auth()), + * // Use filterEffectOrFail with an effectful predicate + * Effect.filterEffectOrFail({ + * predicate: (user) => Effect.succeed(user !== null), + * orFailWith: () => new Error("Unauthorized") + * }), + * ) + * ``` + * + * @since 3.13.0 + * @category Filtering + */ + ( + self: Effect, + options: { + readonly predicate: (a: A) => Effect + readonly orFailWith: (a: A) => E3 + } + ): Effect +} = core.filterEffectOrFail + +/** + * Executes an effect only if the condition is `false`. + * + * @see {@link unlessEffect} for a version that allows the condition to be an effect. + * @see {@link when} for a version that executes the effect when the condition is `true`. + * + * @since 2.0.0 + * @category Conditional Operators + */ +export const unless: { + /** + * Executes an effect only if the condition is `false`. + * + * @see {@link unlessEffect} for a version that allows the condition to be an effect. + * @see {@link when} for a version that executes the effect when the condition is `true`. + * + * @since 2.0.0 + * @category Conditional Operators + */ + (condition: LazyArg): (self: Effect) => Effect, E, R> + /** + * Executes an effect only if the condition is `false`. + * + * @see {@link unlessEffect} for a version that allows the condition to be an effect. + * @see {@link when} for a version that executes the effect when the condition is `true`. + * + * @since 2.0.0 + * @category Conditional Operators + */ + (self: Effect, condition: LazyArg): Effect, E, R> +} = effect.unless + +/** + * Conditionally execute an effect based on the result of another effect. + * + * @see {@link unless} for a version that allows the condition to be a boolean. + * @see {@link whenEffect} for a version that executes the effect when the condition is `true`. + * + * @since 2.0.0 + * @category Conditional Operators + */ +export const unlessEffect: { + /** + * Conditionally execute an effect based on the result of another effect. + * + * @see {@link unless} for a version that allows the condition to be a boolean. + * @see {@link whenEffect} for a version that executes the effect when the condition is `true`. + * + * @since 2.0.0 + * @category Conditional Operators + */ + (condition: Effect): (self: Effect) => Effect, E2 | E, R2 | R> + /** + * Conditionally execute an effect based on the result of another effect. + * + * @see {@link unless} for a version that allows the condition to be a boolean. + * @see {@link whenEffect} for a version that executes the effect when the condition is `true`. + * + * @since 2.0.0 + * @category Conditional Operators + */ + (self: Effect, condition: Effect): Effect, E | E2, R | R2> +} = effect.unlessEffect + +/** + * Conditionally executes an effect based on a boolean condition. + * + * **Details** + * + * This function allows you to run an effect only if a given condition evaluates + * to `true`. If the condition is `true`, the effect is executed, and its result + * is wrapped in an `Option.some`. If the condition is `false`, the effect is + * skipped, and the result is `Option.none`. + * + * **When to Use** + * + * This function is useful for scenarios where you need to dynamically decide + * whether to execute an effect based on runtime logic, while also representing + * the skipped case explicitly. + * + * **Example** (Conditional Effect Execution) + * + * ```ts + * import { Effect, Option } from "effect" + * + * const validateWeightOption = ( + * weight: number + * ): Effect.Effect> => + * // Conditionally execute the effect if the weight is non-negative + * Effect.succeed(weight).pipe(Effect.when(() => weight >= 0)) + * + * // Run with a valid weight + * Effect.runPromise(validateWeightOption(100)).then(console.log) + * // Output: + * // { + * // _id: "Option", + * // _tag: "Some", + * // value: 100 + * // } + * + * // Run with an invalid weight + * Effect.runPromise(validateWeightOption(-5)).then(console.log) + * // Output: + * // { + * // _id: "Option", + * // _tag: "None" + * // } + * ``` + * + * @see {@link whenEffect} for a version that allows the condition to be an effect. + * @see {@link unless} for a version that executes the effect when the condition is `false`. + * + * @since 2.0.0 + * @category Conditional Operators + */ +export const when: { + /** + * Conditionally executes an effect based on a boolean condition. + * + * **Details** + * + * This function allows you to run an effect only if a given condition evaluates + * to `true`. If the condition is `true`, the effect is executed, and its result + * is wrapped in an `Option.some`. If the condition is `false`, the effect is + * skipped, and the result is `Option.none`. + * + * **When to Use** + * + * This function is useful for scenarios where you need to dynamically decide + * whether to execute an effect based on runtime logic, while also representing + * the skipped case explicitly. + * + * **Example** (Conditional Effect Execution) + * + * ```ts + * import { Effect, Option } from "effect" + * + * const validateWeightOption = ( + * weight: number + * ): Effect.Effect> => + * // Conditionally execute the effect if the weight is non-negative + * Effect.succeed(weight).pipe(Effect.when(() => weight >= 0)) + * + * // Run with a valid weight + * Effect.runPromise(validateWeightOption(100)).then(console.log) + * // Output: + * // { + * // _id: "Option", + * // _tag: "Some", + * // value: 100 + * // } + * + * // Run with an invalid weight + * Effect.runPromise(validateWeightOption(-5)).then(console.log) + * // Output: + * // { + * // _id: "Option", + * // _tag: "None" + * // } + * ``` + * + * @see {@link whenEffect} for a version that allows the condition to be an effect. + * @see {@link unless} for a version that executes the effect when the condition is `false`. + * + * @since 2.0.0 + * @category Conditional Operators + */ + (condition: LazyArg): (self: Effect) => Effect, E, R> + /** + * Conditionally executes an effect based on a boolean condition. + * + * **Details** + * + * This function allows you to run an effect only if a given condition evaluates + * to `true`. If the condition is `true`, the effect is executed, and its result + * is wrapped in an `Option.some`. If the condition is `false`, the effect is + * skipped, and the result is `Option.none`. + * + * **When to Use** + * + * This function is useful for scenarios where you need to dynamically decide + * whether to execute an effect based on runtime logic, while also representing + * the skipped case explicitly. + * + * **Example** (Conditional Effect Execution) + * + * ```ts + * import { Effect, Option } from "effect" + * + * const validateWeightOption = ( + * weight: number + * ): Effect.Effect> => + * // Conditionally execute the effect if the weight is non-negative + * Effect.succeed(weight).pipe(Effect.when(() => weight >= 0)) + * + * // Run with a valid weight + * Effect.runPromise(validateWeightOption(100)).then(console.log) + * // Output: + * // { + * // _id: "Option", + * // _tag: "Some", + * // value: 100 + * // } + * + * // Run with an invalid weight + * Effect.runPromise(validateWeightOption(-5)).then(console.log) + * // Output: + * // { + * // _id: "Option", + * // _tag: "None" + * // } + * ``` + * + * @see {@link whenEffect} for a version that allows the condition to be an effect. + * @see {@link unless} for a version that executes the effect when the condition is `false`. + * + * @since 2.0.0 + * @category Conditional Operators + */ + (self: Effect, condition: LazyArg): Effect, E, R> +} = effect.when + +/** + * Conditionally executes an effect based on the result of another effect. + * + * **Details** + * + * This function allows you to run an effect only if a conditional effect + * evaluating to a boolean resolves to `true`. If the conditional effect + * evaluates to `true`, the specified effect is executed, and its result is + * wrapped in `Option.some`. If the conditional effect evaluates to `false`, the + * effect is skipped, and the result is `Option.none`. + * + * **When to Use** + * + * This function is particularly useful when the decision to execute an effect + * depends on the result of another effect, such as a random value, a + * user-provided input, or a network request result. + * + * **Example** (Using an Effect as a Condition) + * + * ```ts + * import { Effect, Random } from "effect" + * + * const randomIntOption = Random.nextInt.pipe( + * Effect.whenEffect(Random.nextBoolean) + * ) + * + * console.log(Effect.runSync(randomIntOption)) + * // Example Output: + * // { _id: 'Option', _tag: 'Some', value: 8609104974198840 } + * ``` + * + * @see {@link when} for a version that allows the condition to be a boolean. + * @see {@link unlessEffect} for a version that executes the effect when the condition is `false`. + * + * @since 2.0.0 + * @category Conditional Operators + */ +export const whenEffect: { + /** + * Conditionally executes an effect based on the result of another effect. + * + * **Details** + * + * This function allows you to run an effect only if a conditional effect + * evaluating to a boolean resolves to `true`. If the conditional effect + * evaluates to `true`, the specified effect is executed, and its result is + * wrapped in `Option.some`. If the conditional effect evaluates to `false`, the + * effect is skipped, and the result is `Option.none`. + * + * **When to Use** + * + * This function is particularly useful when the decision to execute an effect + * depends on the result of another effect, such as a random value, a + * user-provided input, or a network request result. + * + * **Example** (Using an Effect as a Condition) + * + * ```ts + * import { Effect, Random } from "effect" + * + * const randomIntOption = Random.nextInt.pipe( + * Effect.whenEffect(Random.nextBoolean) + * ) + * + * console.log(Effect.runSync(randomIntOption)) + * // Example Output: + * // { _id: 'Option', _tag: 'Some', value: 8609104974198840 } + * ``` + * + * @see {@link when} for a version that allows the condition to be a boolean. + * @see {@link unlessEffect} for a version that executes the effect when the condition is `false`. + * + * @since 2.0.0 + * @category Conditional Operators + */ + (condition: Effect): (effect: Effect) => Effect, E | E2, R | R2> + /** + * Conditionally executes an effect based on the result of another effect. + * + * **Details** + * + * This function allows you to run an effect only if a conditional effect + * evaluating to a boolean resolves to `true`. If the conditional effect + * evaluates to `true`, the specified effect is executed, and its result is + * wrapped in `Option.some`. If the conditional effect evaluates to `false`, the + * effect is skipped, and the result is `Option.none`. + * + * **When to Use** + * + * This function is particularly useful when the decision to execute an effect + * depends on the result of another effect, such as a random value, a + * user-provided input, or a network request result. + * + * **Example** (Using an Effect as a Condition) + * + * ```ts + * import { Effect, Random } from "effect" + * + * const randomIntOption = Random.nextInt.pipe( + * Effect.whenEffect(Random.nextBoolean) + * ) + * + * console.log(Effect.runSync(randomIntOption)) + * // Example Output: + * // { _id: 'Option', _tag: 'Some', value: 8609104974198840 } + * ``` + * + * @see {@link when} for a version that allows the condition to be a boolean. + * @see {@link unlessEffect} for a version that executes the effect when the condition is `false`. + * + * @since 2.0.0 + * @category Conditional Operators + */ + (self: Effect, condition: Effect): Effect, E2 | E, R2 | R> +} = core.whenEffect + +/** + * Executes an effect conditionally based on the value of a `FiberRef` that + * satisfies a predicate. + * + * **Details** + * + * This function enables you to execute an effect only when the value of a + * specified `FiberRef` meets a certain condition defined by a predicate. If the + * value satisfies the predicate, the effect is executed, and the result is + * wrapped in an `Option.some`. If the predicate is not satisfied, the effect is + * skipped, and the result is `Option.none`. In both cases, the current value of + * the `FiberRef` is included in the result. + * + * @since 2.0.0 + * @category Conditional Operators + */ +export const whenFiberRef: { + /** + * Executes an effect conditionally based on the value of a `FiberRef` that + * satisfies a predicate. + * + * **Details** + * + * This function enables you to execute an effect only when the value of a + * specified `FiberRef` meets a certain condition defined by a predicate. If the + * value satisfies the predicate, the effect is executed, and the result is + * wrapped in an `Option.some`. If the predicate is not satisfied, the effect is + * skipped, and the result is `Option.none`. In both cases, the current value of + * the `FiberRef` is included in the result. + * + * @since 2.0.0 + * @category Conditional Operators + */ + (fiberRef: FiberRef.FiberRef, predicate: Predicate): (self: Effect) => Effect<[S, Option.Option], E, R> + /** + * Executes an effect conditionally based on the value of a `FiberRef` that + * satisfies a predicate. + * + * **Details** + * + * This function enables you to execute an effect only when the value of a + * specified `FiberRef` meets a certain condition defined by a predicate. If the + * value satisfies the predicate, the effect is executed, and the result is + * wrapped in an `Option.some`. If the predicate is not satisfied, the effect is + * skipped, and the result is `Option.none`. In both cases, the current value of + * the `FiberRef` is included in the result. + * + * @since 2.0.0 + * @category Conditional Operators + */ + ( + self: Effect, + fiberRef: FiberRef.FiberRef, + predicate: Predicate + ): Effect<[S, Option.Option], E, R> +} = effect.whenFiberRef + +/** + * Executes an effect conditionally based on the value of a `Ref` that satisfies + * a predicate. + * + * **Details** + * + * This function allows you to execute an effect only when the value of a + * specified `Ref` meets a condition defined by a predicate. If the value + * satisfies the predicate, the effect is executed, and the result is wrapped in + * an `Option.some`. If the predicate is not satisfied, the effect is skipped, + * and the result is `Option.none`. In both cases, the current value of the + * `Ref` is included in the result. + * + * @since 2.0.0 + * @category Conditional Operators + */ +export const whenRef: { + /** + * Executes an effect conditionally based on the value of a `Ref` that satisfies + * a predicate. + * + * **Details** + * + * This function allows you to execute an effect only when the value of a + * specified `Ref` meets a condition defined by a predicate. If the value + * satisfies the predicate, the effect is executed, and the result is wrapped in + * an `Option.some`. If the predicate is not satisfied, the effect is skipped, + * and the result is `Option.none`. In both cases, the current value of the + * `Ref` is included in the result. + * + * @since 2.0.0 + * @category Conditional Operators + */ + (ref: Ref.Ref, predicate: Predicate): (self: Effect) => Effect<[S, Option.Option], E, R> + /** + * Executes an effect conditionally based on the value of a `Ref` that satisfies + * a predicate. + * + * **Details** + * + * This function allows you to execute an effect only when the value of a + * specified `Ref` meets a condition defined by a predicate. If the value + * satisfies the predicate, the effect is executed, and the result is wrapped in + * an `Option.some`. If the predicate is not satisfied, the effect is skipped, + * and the result is `Option.none`. In both cases, the current value of the + * `Ref` is included in the result. + * + * @since 2.0.0 + * @category Conditional Operators + */ + (self: Effect, ref: Ref.Ref, predicate: Predicate): Effect<[S, Option.Option], E, R> +} = effect.whenRef + +/** + * Chains effects to produce new `Effect` instances, useful for combining + * operations that depend on previous results. + * + * **Syntax** + * + * ```ts skip-type-checking + * const flatMappedEffect = pipe(myEffect, Effect.flatMap(transformation)) + * // or + * const flatMappedEffect = Effect.flatMap(myEffect, transformation) + * // or + * const flatMappedEffect = myEffect.pipe(Effect.flatMap(transformation)) + * ``` + * + * **Details** + * + * `flatMap` lets you sequence effects so that the result of one effect can be + * used in the next step. It is similar to `flatMap` used with arrays but works + * specifically with `Effect` instances, allowing you to avoid deeply nested + * effect structures. + * + * Since effects are immutable, `flatMap` always returns a new effect instead of + * changing the original one. + * + * **When to Use** + * + * Use `flatMap` when you need to chain multiple effects, ensuring that each + * step produces a new `Effect` while flattening any nested effects that may + * occur. + * + * **Example** + * + * ```ts + * import { pipe, Effect } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * // Chaining the fetch and discount application using `flatMap` + * const finalAmount = pipe( + * fetchTransactionAmount, + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: 95 + * ``` + * + * @see {@link tap} for a version that ignores the result of the effect. + * + * @since 2.0.0 + * @category Sequencing + */ +export const flatMap: { + /** + * Chains effects to produce new `Effect` instances, useful for combining + * operations that depend on previous results. + * + * **Syntax** + * + * ```ts skip-type-checking + * const flatMappedEffect = pipe(myEffect, Effect.flatMap(transformation)) + * // or + * const flatMappedEffect = Effect.flatMap(myEffect, transformation) + * // or + * const flatMappedEffect = myEffect.pipe(Effect.flatMap(transformation)) + * ``` + * + * **Details** + * + * `flatMap` lets you sequence effects so that the result of one effect can be + * used in the next step. It is similar to `flatMap` used with arrays but works + * specifically with `Effect` instances, allowing you to avoid deeply nested + * effect structures. + * + * Since effects are immutable, `flatMap` always returns a new effect instead of + * changing the original one. + * + * **When to Use** + * + * Use `flatMap` when you need to chain multiple effects, ensuring that each + * step produces a new `Effect` while flattening any nested effects that may + * occur. + * + * **Example** + * + * ```ts + * import { pipe, Effect } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * // Chaining the fetch and discount application using `flatMap` + * const finalAmount = pipe( + * fetchTransactionAmount, + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: 95 + * ``` + * + * @see {@link tap} for a version that ignores the result of the effect. + * + * @since 2.0.0 + * @category Sequencing + */ + (f: (a: A) => Effect): (self: Effect) => Effect + /** + * Chains effects to produce new `Effect` instances, useful for combining + * operations that depend on previous results. + * + * **Syntax** + * + * ```ts skip-type-checking + * const flatMappedEffect = pipe(myEffect, Effect.flatMap(transformation)) + * // or + * const flatMappedEffect = Effect.flatMap(myEffect, transformation) + * // or + * const flatMappedEffect = myEffect.pipe(Effect.flatMap(transformation)) + * ``` + * + * **Details** + * + * `flatMap` lets you sequence effects so that the result of one effect can be + * used in the next step. It is similar to `flatMap` used with arrays but works + * specifically with `Effect` instances, allowing you to avoid deeply nested + * effect structures. + * + * Since effects are immutable, `flatMap` always returns a new effect instead of + * changing the original one. + * + * **When to Use** + * + * Use `flatMap` when you need to chain multiple effects, ensuring that each + * step produces a new `Effect` while flattening any nested effects that may + * occur. + * + * **Example** + * + * ```ts + * import { pipe, Effect } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * // Chaining the fetch and discount application using `flatMap` + * const finalAmount = pipe( + * fetchTransactionAmount, + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: 95 + * ``` + * + * @see {@link tap} for a version that ignores the result of the effect. + * + * @since 2.0.0 + * @category Sequencing + */ + (self: Effect, f: (a: A) => Effect): Effect +} = core.flatMap + +/** + * Chains two actions, where the second action can depend on the result of the + * first. + * + * **Syntax** + * + * ```ts skip-type-checking + * const transformedEffect = pipe(myEffect, Effect.andThen(anotherEffect)) + * // or + * const transformedEffect = Effect.andThen(myEffect, anotherEffect) + * // or + * const transformedEffect = myEffect.pipe(Effect.andThen(anotherEffect)) + * ``` + * + * **When to Use** + * + * Use `andThen` when you need to run multiple actions in sequence, with the + * second action depending on the result of the first. This is useful for + * combining effects or handling computations that must happen in order. + * + * **Details** + * + * The second action can be: + * + * - A constant value (similar to {@link as}) + * - A function returning a value (similar to {@link map}) + * - A `Promise` + * - A function returning a `Promise` + * - An `Effect` + * - A function returning an `Effect` (similar to {@link flatMap}) + * + * **Note:** `andThen` works well with both `Option` and `Either` types, + * treating them as effects. + * + * **Example** (Applying a Discount Based on Fetched Amount) + * + * ```ts + * import { pipe, Effect } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * // Using Effect.map and Effect.flatMap + * const result1 = pipe( + * fetchTransactionAmount, + * Effect.map((amount) => amount * 2), + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(result1).then(console.log) + * // Output: 190 + * + * // Using Effect.andThen + * const result2 = pipe( + * fetchTransactionAmount, + * Effect.andThen((amount) => amount * 2), + * Effect.andThen((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(result2).then(console.log) + * // Output: 190 + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ +export const andThen: { + /** + * Chains two actions, where the second action can depend on the result of the + * first. + * + * **Syntax** + * + * ```ts skip-type-checking + * const transformedEffect = pipe(myEffect, Effect.andThen(anotherEffect)) + * // or + * const transformedEffect = Effect.andThen(myEffect, anotherEffect) + * // or + * const transformedEffect = myEffect.pipe(Effect.andThen(anotherEffect)) + * ``` + * + * **When to Use** + * + * Use `andThen` when you need to run multiple actions in sequence, with the + * second action depending on the result of the first. This is useful for + * combining effects or handling computations that must happen in order. + * + * **Details** + * + * The second action can be: + * + * - A constant value (similar to {@link as}) + * - A function returning a value (similar to {@link map}) + * - A `Promise` + * - A function returning a `Promise` + * - An `Effect` + * - A function returning an `Effect` (similar to {@link flatMap}) + * + * **Note:** `andThen` works well with both `Option` and `Either` types, + * treating them as effects. + * + * **Example** (Applying a Discount Based on Fetched Amount) + * + * ```ts + * import { pipe, Effect } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * // Using Effect.map and Effect.flatMap + * const result1 = pipe( + * fetchTransactionAmount, + * Effect.map((amount) => amount * 2), + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(result1).then(console.log) + * // Output: 190 + * + * // Using Effect.andThen + * const result2 = pipe( + * fetchTransactionAmount, + * Effect.andThen((amount) => amount * 2), + * Effect.andThen((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(result2).then(console.log) + * // Output: 190 + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + (f: (a: NoInfer) => X): ( + self: Effect + ) => [X] extends [Effect] ? Effect + : [X] extends [PromiseLike] ? Effect + : Effect + /** + * Chains two actions, where the second action can depend on the result of the + * first. + * + * **Syntax** + * + * ```ts skip-type-checking + * const transformedEffect = pipe(myEffect, Effect.andThen(anotherEffect)) + * // or + * const transformedEffect = Effect.andThen(myEffect, anotherEffect) + * // or + * const transformedEffect = myEffect.pipe(Effect.andThen(anotherEffect)) + * ``` + * + * **When to Use** + * + * Use `andThen` when you need to run multiple actions in sequence, with the + * second action depending on the result of the first. This is useful for + * combining effects or handling computations that must happen in order. + * + * **Details** + * + * The second action can be: + * + * - A constant value (similar to {@link as}) + * - A function returning a value (similar to {@link map}) + * - A `Promise` + * - A function returning a `Promise` + * - An `Effect` + * - A function returning an `Effect` (similar to {@link flatMap}) + * + * **Note:** `andThen` works well with both `Option` and `Either` types, + * treating them as effects. + * + * **Example** (Applying a Discount Based on Fetched Amount) + * + * ```ts + * import { pipe, Effect } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * // Using Effect.map and Effect.flatMap + * const result1 = pipe( + * fetchTransactionAmount, + * Effect.map((amount) => amount * 2), + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(result1).then(console.log) + * // Output: 190 + * + * // Using Effect.andThen + * const result2 = pipe( + * fetchTransactionAmount, + * Effect.andThen((amount) => amount * 2), + * Effect.andThen((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(result2).then(console.log) + * // Output: 190 + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + (f: NotFunction): ( + self: Effect + ) => [X] extends [Effect] ? Effect + : [X] extends [PromiseLike] ? Effect + : Effect + /** + * Chains two actions, where the second action can depend on the result of the + * first. + * + * **Syntax** + * + * ```ts skip-type-checking + * const transformedEffect = pipe(myEffect, Effect.andThen(anotherEffect)) + * // or + * const transformedEffect = Effect.andThen(myEffect, anotherEffect) + * // or + * const transformedEffect = myEffect.pipe(Effect.andThen(anotherEffect)) + * ``` + * + * **When to Use** + * + * Use `andThen` when you need to run multiple actions in sequence, with the + * second action depending on the result of the first. This is useful for + * combining effects or handling computations that must happen in order. + * + * **Details** + * + * The second action can be: + * + * - A constant value (similar to {@link as}) + * - A function returning a value (similar to {@link map}) + * - A `Promise` + * - A function returning a `Promise` + * - An `Effect` + * - A function returning an `Effect` (similar to {@link flatMap}) + * + * **Note:** `andThen` works well with both `Option` and `Either` types, + * treating them as effects. + * + * **Example** (Applying a Discount Based on Fetched Amount) + * + * ```ts + * import { pipe, Effect } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * // Using Effect.map and Effect.flatMap + * const result1 = pipe( + * fetchTransactionAmount, + * Effect.map((amount) => amount * 2), + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(result1).then(console.log) + * // Output: 190 + * + * // Using Effect.andThen + * const result2 = pipe( + * fetchTransactionAmount, + * Effect.andThen((amount) => amount * 2), + * Effect.andThen((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(result2).then(console.log) + * // Output: 190 + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + (self: Effect, f: (a: NoInfer) => X): [X] extends [Effect] ? Effect + : [X] extends [PromiseLike] ? Effect + : Effect + /** + * Chains two actions, where the second action can depend on the result of the + * first. + * + * **Syntax** + * + * ```ts skip-type-checking + * const transformedEffect = pipe(myEffect, Effect.andThen(anotherEffect)) + * // or + * const transformedEffect = Effect.andThen(myEffect, anotherEffect) + * // or + * const transformedEffect = myEffect.pipe(Effect.andThen(anotherEffect)) + * ``` + * + * **When to Use** + * + * Use `andThen` when you need to run multiple actions in sequence, with the + * second action depending on the result of the first. This is useful for + * combining effects or handling computations that must happen in order. + * + * **Details** + * + * The second action can be: + * + * - A constant value (similar to {@link as}) + * - A function returning a value (similar to {@link map}) + * - A `Promise` + * - A function returning a `Promise` + * - An `Effect` + * - A function returning an `Effect` (similar to {@link flatMap}) + * + * **Note:** `andThen` works well with both `Option` and `Either` types, + * treating them as effects. + * + * **Example** (Applying a Discount Based on Fetched Amount) + * + * ```ts + * import { pipe, Effect } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * // Using Effect.map and Effect.flatMap + * const result1 = pipe( + * fetchTransactionAmount, + * Effect.map((amount) => amount * 2), + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(result1).then(console.log) + * // Output: 190 + * + * // Using Effect.andThen + * const result2 = pipe( + * fetchTransactionAmount, + * Effect.andThen((amount) => amount * 2), + * Effect.andThen((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(result2).then(console.log) + * // Output: 190 + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + (self: Effect, f: NotFunction): [X] extends [Effect] ? Effect + : [X] extends [PromiseLike] ? Effect + : Effect +} = core.andThen + +/** + * @since 2.0.0 + * @category Sequencing + */ +export const flatten: (self: Effect, E, R>) => Effect = + core.flatten + +/** + * Races two effects and returns the result of the first successful one. + * + * **Details** + * + * This function takes two effects and runs them concurrently. The first effect + * that successfully completes will determine the result of the race, and the + * other effect will be interrupted. + * + * If neither effect succeeds, the function will fail with a `Cause` + * containing all the errors. + * + * **When to Use** + * + * This is useful when you want to run two effects concurrently, but only care + * about the first one to succeed. It is commonly used in cases like timeouts, + * retries, or when you want to optimize for the faster response without + * worrying about the other effect. + * + * **Handling Success or Failure with Either** + * + * If you want to handle the result of whichever task completes first, whether + * it succeeds or fails, you can use the `Effect.either` function. This function + * wraps the result in an `Either` type, allowing you to see if the result + * was a success (`Right`) or a failure (`Left`). + * + * **Example** (Both Tasks Succeed) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.succeed("task1").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * const program = Effect.race(task1, task2) + * + * Effect.runFork(program) + * // Output: + * // task1 done + * // task2 interrupted + * ``` + * + * **Example** (One Task Fails, One Succeeds) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * const program = Effect.race(task1, task2) + * + * Effect.runFork(program) + * // Output: + * // task2 done + * ``` + * + * **Example** (Both Tasks Fail) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.fail("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * const program = Effect.race(task1, task2) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Parallel', + * // left: { _id: 'Cause', _tag: 'Fail', failure: 'task1' }, + * // right: { _id: 'Cause', _tag: 'Fail', failure: 'task2' } + * // } + * // } + * ``` + * + * **Example** (Handling Success or Failure with Either) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * // Run both tasks concurrently, wrapping the result + * // in Either to capture success or failure + * const program = Effect.race(Effect.either(task1), Effect.either(task2)) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // task2 interrupted + * // { _id: 'Either', _tag: 'Left', left: 'task1' } + * ``` + * + * @see {@link raceAll} for a version that handles multiple effects. + * @see {@link raceFirst} for a version that returns the result of the first effect to complete. + * + * @since 2.0.0 + * @category Racing + */ +export const race: { + /** + * Races two effects and returns the result of the first successful one. + * + * **Details** + * + * This function takes two effects and runs them concurrently. The first effect + * that successfully completes will determine the result of the race, and the + * other effect will be interrupted. + * + * If neither effect succeeds, the function will fail with a `Cause` + * containing all the errors. + * + * **When to Use** + * + * This is useful when you want to run two effects concurrently, but only care + * about the first one to succeed. It is commonly used in cases like timeouts, + * retries, or when you want to optimize for the faster response without + * worrying about the other effect. + * + * **Handling Success or Failure with Either** + * + * If you want to handle the result of whichever task completes first, whether + * it succeeds or fails, you can use the `Effect.either` function. This function + * wraps the result in an `Either` type, allowing you to see if the result + * was a success (`Right`) or a failure (`Left`). + * + * **Example** (Both Tasks Succeed) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.succeed("task1").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * const program = Effect.race(task1, task2) + * + * Effect.runFork(program) + * // Output: + * // task1 done + * // task2 interrupted + * ``` + * + * **Example** (One Task Fails, One Succeeds) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * const program = Effect.race(task1, task2) + * + * Effect.runFork(program) + * // Output: + * // task2 done + * ``` + * + * **Example** (Both Tasks Fail) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.fail("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * const program = Effect.race(task1, task2) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Parallel', + * // left: { _id: 'Cause', _tag: 'Fail', failure: 'task1' }, + * // right: { _id: 'Cause', _tag: 'Fail', failure: 'task2' } + * // } + * // } + * ``` + * + * **Example** (Handling Success or Failure with Either) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * // Run both tasks concurrently, wrapping the result + * // in Either to capture success or failure + * const program = Effect.race(Effect.either(task1), Effect.either(task2)) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // task2 interrupted + * // { _id: 'Either', _tag: 'Left', left: 'task1' } + * ``` + * + * @see {@link raceAll} for a version that handles multiple effects. + * @see {@link raceFirst} for a version that returns the result of the first effect to complete. + * + * @since 2.0.0 + * @category Racing + */ + (that: Effect): (self: Effect) => Effect + /** + * Races two effects and returns the result of the first successful one. + * + * **Details** + * + * This function takes two effects and runs them concurrently. The first effect + * that successfully completes will determine the result of the race, and the + * other effect will be interrupted. + * + * If neither effect succeeds, the function will fail with a `Cause` + * containing all the errors. + * + * **When to Use** + * + * This is useful when you want to run two effects concurrently, but only care + * about the first one to succeed. It is commonly used in cases like timeouts, + * retries, or when you want to optimize for the faster response without + * worrying about the other effect. + * + * **Handling Success or Failure with Either** + * + * If you want to handle the result of whichever task completes first, whether + * it succeeds or fails, you can use the `Effect.either` function. This function + * wraps the result in an `Either` type, allowing you to see if the result + * was a success (`Right`) or a failure (`Left`). + * + * **Example** (Both Tasks Succeed) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.succeed("task1").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * const program = Effect.race(task1, task2) + * + * Effect.runFork(program) + * // Output: + * // task1 done + * // task2 interrupted + * ``` + * + * **Example** (One Task Fails, One Succeeds) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * const program = Effect.race(task1, task2) + * + * Effect.runFork(program) + * // Output: + * // task2 done + * ``` + * + * **Example** (Both Tasks Fail) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.fail("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * const program = Effect.race(task1, task2) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Parallel', + * // left: { _id: 'Cause', _tag: 'Fail', failure: 'task1' }, + * // right: { _id: 'Cause', _tag: 'Fail', failure: 'task2' } + * // } + * // } + * ``` + * + * **Example** (Handling Success or Failure with Either) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * // Run both tasks concurrently, wrapping the result + * // in Either to capture success or failure + * const program = Effect.race(Effect.either(task1), Effect.either(task2)) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // task2 interrupted + * // { _id: 'Either', _tag: 'Left', left: 'task1' } + * ``` + * + * @see {@link raceAll} for a version that handles multiple effects. + * @see {@link raceFirst} for a version that returns the result of the first effect to complete. + * + * @since 2.0.0 + * @category Racing + */ + (self: Effect, that: Effect): Effect +} = fiberRuntime.race + +/** + * Races multiple effects and returns the first successful result. + * + * **Details** + * + * This function runs multiple effects concurrently and returns the result of + * the first one to succeed. If one effect succeeds, the others will be + * interrupted. + * + * If none of the effects succeed, the function will fail with the last error + * encountered. + * + * **When to Use** + * + * This is useful when you want to race multiple effects, but only care about + * the first one to succeed. It is commonly used in cases like timeouts, + * retries, or when you want to optimize for the faster response without + * worrying about the other effects. + * + * **Example** (All Tasks Succeed) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.succeed("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * const task3 = Effect.succeed("task3").pipe( + * Effect.delay("150 millis"), + * Effect.tap(Console.log("task3 done")), + * Effect.onInterrupt(() => Console.log("task3 interrupted")) + * ) + * + * const program = Effect.raceAll([task1, task2, task3]) + * + * Effect.runFork(program) + * // Output: + * // task1 done + * // task2 interrupted + * // task3 interrupted + * ``` + * + * **Example** (One Task Fails, Two Tasks Succeed) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * const task3 = Effect.succeed("task3").pipe( + * Effect.delay("150 millis"), + * Effect.tap(Console.log("task3 done")), + * Effect.onInterrupt(() => Console.log("task3 interrupted")) + * ) + * + * const program = Effect.raceAll([task1, task2, task3]) + * + * Effect.runFork(program) + * // Output: + * // task3 done + * // task2 interrupted + * ``` + * + * **Example** (All Tasks Fail) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => Console.log("task1 interrupted")) + * ) + * const task2 = Effect.fail("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => Console.log("task2 interrupted")) + * ) + * + * const task3 = Effect.fail("task3").pipe( + * Effect.delay("150 millis"), + * Effect.tap(Console.log("task3 done")), + * Effect.onInterrupt(() => Console.log("task3 interrupted")) + * ) + * + * const program = Effect.raceAll([task1, task2, task3]) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'task2' } + * // } + * ``` + * + * @see {@link race} for a version that handles only two effects. + * + * @since 2.0.0 + * @category Racing + */ +export const raceAll: >( + all: Iterable +) => Effect, Effect.Error, Effect.Context> = fiberRuntime.raceAll + +/** + * Races two effects and returns the result of the first one to complete. + * + * **Details** + * + * This function takes two effects and runs them concurrently, returning the + * result of the first one that completes, regardless of whether it succeeds or + * fails. + * + * **When to Use** + * + * This function is useful when you want to race two operations, and you want to + * proceed with whichever one finishes first, regardless of whether it succeeds + * or fails. + * + * **Disconnecting Effects** + * + * The `Effect.raceFirst` function safely interrupts the “loser” effect once the other completes, but it will not resume until the loser is cleanly terminated. + * + * If you want a quicker return, you can disconnect the interrupt signal for both effects. Instead of calling: + * + * ```ts skip-type-checking + * Effect.raceFirst(task1, task2) + * ``` + * + * You can use: + * + * ```ts skip-type-checking + * Effect.raceFirst(Effect.disconnect(task1), Effect.disconnect(task2)) + * ``` + * + * This allows both effects to complete independently while still terminating the losing effect in the background. + * + * **Example** (Both Tasks Succeed) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.succeed("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => + * Console.log("task1 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => + * Console.log("task2 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * + * const program = Effect.raceFirst(task1, task2).pipe( + * Effect.tap(Console.log("more work...")) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // task1 done + * // task2 interrupted + * // more work... + * // { _id: 'Exit', _tag: 'Success', value: 'task1' } + * ``` + * + * **Example** (One Task Fails, One Succeeds) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => + * Console.log("task1 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => + * Console.log("task2 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * + * const program = Effect.raceFirst(task1, task2).pipe( + * Effect.tap(Console.log("more work...")) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // task2 interrupted + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'task1' } + * // } + * ``` + * + * **Example** (Using Effect.disconnect for Quicker Return) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.succeed("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => + * Console.log("task1 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => + * Console.log("task2 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * + * // Race the two tasks with disconnect to allow quicker return + * const program = Effect.raceFirst( + * Effect.disconnect(task1), + * Effect.disconnect(task2) + * ).pipe(Effect.tap(Console.log("more work..."))) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // task1 done + * // more work... + * // { _id: 'Exit', _tag: 'Success', value: 'task1' } + * // task2 interrupted + * ``` + * + * @since 2.0.0 + * @category Racing + */ +export const raceFirst: { + /** + * Races two effects and returns the result of the first one to complete. + * + * **Details** + * + * This function takes two effects and runs them concurrently, returning the + * result of the first one that completes, regardless of whether it succeeds or + * fails. + * + * **When to Use** + * + * This function is useful when you want to race two operations, and you want to + * proceed with whichever one finishes first, regardless of whether it succeeds + * or fails. + * + * **Disconnecting Effects** + * + * The `Effect.raceFirst` function safely interrupts the “loser” effect once the other completes, but it will not resume until the loser is cleanly terminated. + * + * If you want a quicker return, you can disconnect the interrupt signal for both effects. Instead of calling: + * + * ```ts skip-type-checking + * Effect.raceFirst(task1, task2) + * ``` + * + * You can use: + * + * ```ts skip-type-checking + * Effect.raceFirst(Effect.disconnect(task1), Effect.disconnect(task2)) + * ``` + * + * This allows both effects to complete independently while still terminating the losing effect in the background. + * + * **Example** (Both Tasks Succeed) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.succeed("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => + * Console.log("task1 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => + * Console.log("task2 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * + * const program = Effect.raceFirst(task1, task2).pipe( + * Effect.tap(Console.log("more work...")) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // task1 done + * // task2 interrupted + * // more work... + * // { _id: 'Exit', _tag: 'Success', value: 'task1' } + * ``` + * + * **Example** (One Task Fails, One Succeeds) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => + * Console.log("task1 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => + * Console.log("task2 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * + * const program = Effect.raceFirst(task1, task2).pipe( + * Effect.tap(Console.log("more work...")) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // task2 interrupted + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'task1' } + * // } + * ``` + * + * **Example** (Using Effect.disconnect for Quicker Return) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.succeed("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => + * Console.log("task1 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => + * Console.log("task2 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * + * // Race the two tasks with disconnect to allow quicker return + * const program = Effect.raceFirst( + * Effect.disconnect(task1), + * Effect.disconnect(task2) + * ).pipe(Effect.tap(Console.log("more work..."))) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // task1 done + * // more work... + * // { _id: 'Exit', _tag: 'Success', value: 'task1' } + * // task2 interrupted + * ``` + * + * @since 2.0.0 + * @category Racing + */ + (that: Effect): (self: Effect) => Effect + /** + * Races two effects and returns the result of the first one to complete. + * + * **Details** + * + * This function takes two effects and runs them concurrently, returning the + * result of the first one that completes, regardless of whether it succeeds or + * fails. + * + * **When to Use** + * + * This function is useful when you want to race two operations, and you want to + * proceed with whichever one finishes first, regardless of whether it succeeds + * or fails. + * + * **Disconnecting Effects** + * + * The `Effect.raceFirst` function safely interrupts the “loser” effect once the other completes, but it will not resume until the loser is cleanly terminated. + * + * If you want a quicker return, you can disconnect the interrupt signal for both effects. Instead of calling: + * + * ```ts skip-type-checking + * Effect.raceFirst(task1, task2) + * ``` + * + * You can use: + * + * ```ts skip-type-checking + * Effect.raceFirst(Effect.disconnect(task1), Effect.disconnect(task2)) + * ``` + * + * This allows both effects to complete independently while still terminating the losing effect in the background. + * + * **Example** (Both Tasks Succeed) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.succeed("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => + * Console.log("task1 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => + * Console.log("task2 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * + * const program = Effect.raceFirst(task1, task2).pipe( + * Effect.tap(Console.log("more work...")) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // task1 done + * // task2 interrupted + * // more work... + * // { _id: 'Exit', _tag: 'Success', value: 'task1' } + * ``` + * + * **Example** (One Task Fails, One Succeeds) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.fail("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => + * Console.log("task1 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => + * Console.log("task2 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * + * const program = Effect.raceFirst(task1, task2).pipe( + * Effect.tap(Console.log("more work...")) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // task2 interrupted + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'task1' } + * // } + * ``` + * + * **Example** (Using Effect.disconnect for Quicker Return) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.succeed("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => + * Console.log("task1 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => + * Console.log("task2 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * + * // Race the two tasks with disconnect to allow quicker return + * const program = Effect.raceFirst( + * Effect.disconnect(task1), + * Effect.disconnect(task2) + * ).pipe(Effect.tap(Console.log("more work..."))) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // task1 done + * // more work... + * // { _id: 'Exit', _tag: 'Success', value: 'task1' } + * // task2 interrupted + * ``` + * + * @since 2.0.0 + * @category Racing + */ + (self: Effect, that: Effect): Effect +} = circular.raceFirst + +/** + * Races two effects and calls a finisher when the first one completes. + * + * **Details** + * + * This function runs two effects concurrently and calls a specified “finisher” + * function once one of the effects completes, regardless of whether it succeeds + * or fails. + * + * The finisher functions for each effect allow you to handle the results of + * each effect as soon as they complete. + * + * The function takes two finisher callbacks, one for each effect, and allows + * you to specify how to handle the result of the race. + * + * **When to Use** + * + * This function is useful when you need to react to the completion of either + * effect without waiting for both to finish. It can be used whenever you want + * to take action based on the first available result. + * + * **Example** (Handling Results of Concurrent Tasks) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.succeed("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => + * Console.log("task1 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => + * Console.log("task2 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * + * const program = Effect.raceWith(task1, task2, { + * onSelfDone: (exit) => Console.log(`task1 exited with ${exit}`), + * onOtherDone: (exit) => Console.log(`task2 exited with ${exit}`) + * }) + * + * Effect.runFork(program) + * // Output: + * // task1 done + * // task1 exited with { + * // "_id": "Exit", + * // "_tag": "Success", + * // "value": "task1" + * // } + * // task2 interrupted + * ``` + * + * @since 2.0.0 + * @category Racing + */ +export const raceWith: { + /** + * Races two effects and calls a finisher when the first one completes. + * + * **Details** + * + * This function runs two effects concurrently and calls a specified “finisher” + * function once one of the effects completes, regardless of whether it succeeds + * or fails. + * + * The finisher functions for each effect allow you to handle the results of + * each effect as soon as they complete. + * + * The function takes two finisher callbacks, one for each effect, and allows + * you to specify how to handle the result of the race. + * + * **When to Use** + * + * This function is useful when you need to react to the completion of either + * effect without waiting for both to finish. It can be used whenever you want + * to take action based on the first available result. + * + * **Example** (Handling Results of Concurrent Tasks) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.succeed("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => + * Console.log("task1 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => + * Console.log("task2 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * + * const program = Effect.raceWith(task1, task2, { + * onSelfDone: (exit) => Console.log(`task1 exited with ${exit}`), + * onOtherDone: (exit) => Console.log(`task2 exited with ${exit}`) + * }) + * + * Effect.runFork(program) + * // Output: + * // task1 done + * // task1 exited with { + * // "_id": "Exit", + * // "_tag": "Success", + * // "value": "task1" + * // } + * // task2 interrupted + * ``` + * + * @since 2.0.0 + * @category Racing + */ + ( + other: Effect, + options: { + readonly onSelfDone: (exit: Exit.Exit, fiber: Fiber.Fiber) => Effect + readonly onOtherDone: (exit: Exit.Exit, fiber: Fiber.Fiber) => Effect + } + ): (self: Effect) => Effect + /** + * Races two effects and calls a finisher when the first one completes. + * + * **Details** + * + * This function runs two effects concurrently and calls a specified “finisher” + * function once one of the effects completes, regardless of whether it succeeds + * or fails. + * + * The finisher functions for each effect allow you to handle the results of + * each effect as soon as they complete. + * + * The function takes two finisher callbacks, one for each effect, and allows + * you to specify how to handle the result of the race. + * + * **When to Use** + * + * This function is useful when you need to react to the completion of either + * effect without waiting for both to finish. It can be used whenever you want + * to take action based on the first available result. + * + * **Example** (Handling Results of Concurrent Tasks) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Effect.succeed("task1").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Console.log("task1 done")), + * Effect.onInterrupt(() => + * Console.log("task1 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * const task2 = Effect.succeed("task2").pipe( + * Effect.delay("200 millis"), + * Effect.tap(Console.log("task2 done")), + * Effect.onInterrupt(() => + * Console.log("task2 interrupted").pipe(Effect.delay("100 millis")) + * ) + * ) + * + * const program = Effect.raceWith(task1, task2, { + * onSelfDone: (exit) => Console.log(`task1 exited with ${exit}`), + * onOtherDone: (exit) => Console.log(`task2 exited with ${exit}`) + * }) + * + * Effect.runFork(program) + * // Output: + * // task1 done + * // task1 exited with { + * // "_id": "Exit", + * // "_tag": "Success", + * // "value": "task1" + * // } + * // task2 interrupted + * ``` + * + * @since 2.0.0 + * @category Racing + */ + ( + self: Effect, + other: Effect, + options: { + readonly onSelfDone: (exit: Exit.Exit, fiber: Fiber.Fiber) => Effect + readonly onOtherDone: (exit: Exit.Exit, fiber: Fiber.Fiber) => Effect + } + ): Effect +} = fiberRuntime.raceWith + +/** + * Summarizes a effect by computing some value before and after execution, and + * then combining the values to produce a summary, together with the result of + * execution. + * + * @since 2.0.0 + * @category Sequencing + */ +export const summarized: { + /** + * Summarizes a effect by computing some value before and after execution, and + * then combining the values to produce a summary, together with the result of + * execution. + * + * @since 2.0.0 + * @category Sequencing + */ + (summary: Effect, f: (start: B, end: B) => C): (self: Effect) => Effect<[C, A], E2 | E, R2 | R> + /** + * Summarizes a effect by computing some value before and after execution, and + * then combining the values to produce a summary, together with the result of + * execution. + * + * @since 2.0.0 + * @category Sequencing + */ + ( + self: Effect, + summary: Effect, + f: (start: B, end: B) => C + ): Effect<[C, A], E2 | E, R2 | R> +} = effect.summarized + +/** + * Runs a side effect with the result of an effect without changing the original + * value. + * + * **Details** + * + * This function works similarly to `flatMap`, but it ignores the result of the + * function passed to it. The value from the previous effect remains available + * for the next part of the chain. Note that if the side effect fails, the + * entire chain will fail too. + * + * **When to Use** + * + * Use this function when you want to perform a side effect, like logging or + * tracking, without modifying the main value. This is useful when you need to + * observe or record an action but want the original value to be passed to the + * next step. + * + * **Example** (Logging a step in a pipeline) + * + * ```ts + * import { Console, Effect, pipe } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * // Log the fetched transaction amount + * Effect.tap((amount) => Console.log(`Apply a discount to: ${amount}`)), + * // `amount` is still available! + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: + * // Apply a discount to: 100 + * // 95 + * ``` + * + * @see {@link flatMap} for a version that allows you to change the value. + * + * @since 2.0.0 + * @category Sequencing + */ +export const tap: { + /** + * Runs a side effect with the result of an effect without changing the original + * value. + * + * **Details** + * + * This function works similarly to `flatMap`, but it ignores the result of the + * function passed to it. The value from the previous effect remains available + * for the next part of the chain. Note that if the side effect fails, the + * entire chain will fail too. + * + * **When to Use** + * + * Use this function when you want to perform a side effect, like logging or + * tracking, without modifying the main value. This is useful when you need to + * observe or record an action but want the original value to be passed to the + * next step. + * + * **Example** (Logging a step in a pipeline) + * + * ```ts + * import { Console, Effect, pipe } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * // Log the fetched transaction amount + * Effect.tap((amount) => Console.log(`Apply a discount to: ${amount}`)), + * // `amount` is still available! + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: + * // Apply a discount to: 100 + * // 95 + * ``` + * + * @see {@link flatMap} for a version that allows you to change the value. + * + * @since 2.0.0 + * @category Sequencing + */ + (f: (a: NoInfer) => X): ( + self: Effect + ) => [X] extends [Effect] ? Effect + : [X] extends [PromiseLike] ? Effect + : Effect + /** + * Runs a side effect with the result of an effect without changing the original + * value. + * + * **Details** + * + * This function works similarly to `flatMap`, but it ignores the result of the + * function passed to it. The value from the previous effect remains available + * for the next part of the chain. Note that if the side effect fails, the + * entire chain will fail too. + * + * **When to Use** + * + * Use this function when you want to perform a side effect, like logging or + * tracking, without modifying the main value. This is useful when you need to + * observe or record an action but want the original value to be passed to the + * next step. + * + * **Example** (Logging a step in a pipeline) + * + * ```ts + * import { Console, Effect, pipe } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * // Log the fetched transaction amount + * Effect.tap((amount) => Console.log(`Apply a discount to: ${amount}`)), + * // `amount` is still available! + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: + * // Apply a discount to: 100 + * // 95 + * ``` + * + * @see {@link flatMap} for a version that allows you to change the value. + * + * @since 2.0.0 + * @category Sequencing + */ + (f: (a: NoInfer) => Effect, options: { onlyEffect: true }): ( + self: Effect + ) => Effect + /** + * Runs a side effect with the result of an effect without changing the original + * value. + * + * **Details** + * + * This function works similarly to `flatMap`, but it ignores the result of the + * function passed to it. The value from the previous effect remains available + * for the next part of the chain. Note that if the side effect fails, the + * entire chain will fail too. + * + * **When to Use** + * + * Use this function when you want to perform a side effect, like logging or + * tracking, without modifying the main value. This is useful when you need to + * observe or record an action but want the original value to be passed to the + * next step. + * + * **Example** (Logging a step in a pipeline) + * + * ```ts + * import { Console, Effect, pipe } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * // Log the fetched transaction amount + * Effect.tap((amount) => Console.log(`Apply a discount to: ${amount}`)), + * // `amount` is still available! + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: + * // Apply a discount to: 100 + * // 95 + * ``` + * + * @see {@link flatMap} for a version that allows you to change the value. + * + * @since 2.0.0 + * @category Sequencing + */ + (f: NotFunction): ( + self: Effect + ) => [X] extends [Effect] ? Effect + : [X] extends [PromiseLike] ? Effect + : Effect + /** + * Runs a side effect with the result of an effect without changing the original + * value. + * + * **Details** + * + * This function works similarly to `flatMap`, but it ignores the result of the + * function passed to it. The value from the previous effect remains available + * for the next part of the chain. Note that if the side effect fails, the + * entire chain will fail too. + * + * **When to Use** + * + * Use this function when you want to perform a side effect, like logging or + * tracking, without modifying the main value. This is useful when you need to + * observe or record an action but want the original value to be passed to the + * next step. + * + * **Example** (Logging a step in a pipeline) + * + * ```ts + * import { Console, Effect, pipe } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * // Log the fetched transaction amount + * Effect.tap((amount) => Console.log(`Apply a discount to: ${amount}`)), + * // `amount` is still available! + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: + * // Apply a discount to: 100 + * // 95 + * ``` + * + * @see {@link flatMap} for a version that allows you to change the value. + * + * @since 2.0.0 + * @category Sequencing + */ + (f: Effect, options: { onlyEffect: true }): ( + self: Effect + ) => Effect + /** + * Runs a side effect with the result of an effect without changing the original + * value. + * + * **Details** + * + * This function works similarly to `flatMap`, but it ignores the result of the + * function passed to it. The value from the previous effect remains available + * for the next part of the chain. Note that if the side effect fails, the + * entire chain will fail too. + * + * **When to Use** + * + * Use this function when you want to perform a side effect, like logging or + * tracking, without modifying the main value. This is useful when you need to + * observe or record an action but want the original value to be passed to the + * next step. + * + * **Example** (Logging a step in a pipeline) + * + * ```ts + * import { Console, Effect, pipe } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * // Log the fetched transaction amount + * Effect.tap((amount) => Console.log(`Apply a discount to: ${amount}`)), + * // `amount` is still available! + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: + * // Apply a discount to: 100 + * // 95 + * ``` + * + * @see {@link flatMap} for a version that allows you to change the value. + * + * @since 2.0.0 + * @category Sequencing + */ + (self: Effect, f: (a: NoInfer) => X): [X] extends [Effect] ? Effect + : [X] extends [PromiseLike] ? Effect + : Effect + /** + * Runs a side effect with the result of an effect without changing the original + * value. + * + * **Details** + * + * This function works similarly to `flatMap`, but it ignores the result of the + * function passed to it. The value from the previous effect remains available + * for the next part of the chain. Note that if the side effect fails, the + * entire chain will fail too. + * + * **When to Use** + * + * Use this function when you want to perform a side effect, like logging or + * tracking, without modifying the main value. This is useful when you need to + * observe or record an action but want the original value to be passed to the + * next step. + * + * **Example** (Logging a step in a pipeline) + * + * ```ts + * import { Console, Effect, pipe } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * // Log the fetched transaction amount + * Effect.tap((amount) => Console.log(`Apply a discount to: ${amount}`)), + * // `amount` is still available! + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: + * // Apply a discount to: 100 + * // 95 + * ``` + * + * @see {@link flatMap} for a version that allows you to change the value. + * + * @since 2.0.0 + * @category Sequencing + */ + ( + self: Effect, + f: (a: NoInfer) => Effect, + options: { onlyEffect: true } + ): Effect + /** + * Runs a side effect with the result of an effect without changing the original + * value. + * + * **Details** + * + * This function works similarly to `flatMap`, but it ignores the result of the + * function passed to it. The value from the previous effect remains available + * for the next part of the chain. Note that if the side effect fails, the + * entire chain will fail too. + * + * **When to Use** + * + * Use this function when you want to perform a side effect, like logging or + * tracking, without modifying the main value. This is useful when you need to + * observe or record an action but want the original value to be passed to the + * next step. + * + * **Example** (Logging a step in a pipeline) + * + * ```ts + * import { Console, Effect, pipe } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * // Log the fetched transaction amount + * Effect.tap((amount) => Console.log(`Apply a discount to: ${amount}`)), + * // `amount` is still available! + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: + * // Apply a discount to: 100 + * // 95 + * ``` + * + * @see {@link flatMap} for a version that allows you to change the value. + * + * @since 2.0.0 + * @category Sequencing + */ + (self: Effect, f: NotFunction): [X] extends [Effect] ? Effect + : [X] extends [PromiseLike] ? Effect + : Effect + /** + * Runs a side effect with the result of an effect without changing the original + * value. + * + * **Details** + * + * This function works similarly to `flatMap`, but it ignores the result of the + * function passed to it. The value from the previous effect remains available + * for the next part of the chain. Note that if the side effect fails, the + * entire chain will fail too. + * + * **When to Use** + * + * Use this function when you want to perform a side effect, like logging or + * tracking, without modifying the main value. This is useful when you need to + * observe or record an action but want the original value to be passed to the + * next step. + * + * **Example** (Logging a step in a pipeline) + * + * ```ts + * import { Console, Effect, pipe } from "effect" + * + * // Function to apply a discount safely to a transaction amount + * const applyDiscount = ( + * total: number, + * discountRate: number + * ): Effect.Effect => + * discountRate === 0 + * ? Effect.fail(new Error("Discount rate cannot be zero")) + * : Effect.succeed(total - (total * discountRate) / 100) + * + * // Simulated asynchronous task to fetch a transaction amount from database + * const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) + * + * const finalAmount = pipe( + * fetchTransactionAmount, + * // Log the fetched transaction amount + * Effect.tap((amount) => Console.log(`Apply a discount to: ${amount}`)), + * // `amount` is still available! + * Effect.flatMap((amount) => applyDiscount(amount, 5)) + * ) + * + * Effect.runPromise(finalAmount).then(console.log) + * // Output: + * // Apply a discount to: 100 + * // 95 + * ``` + * + * @see {@link flatMap} for a version that allows you to change the value. + * + * @since 2.0.0 + * @category Sequencing + */ + (self: Effect, f: Effect, options: { onlyEffect: true }): Effect +} = core.tap + +/** + * Allows you to inspect both success and failure outcomes of an effect and + * perform side effects for each. + * + * **Details** + * + * This function enables you to handle both success and failure cases + * separately, without modifying the main effect's result. It is particularly + * useful for scenarios where you need to log, monitor, or perform additional + * actions depending on whether the effect succeeded or failed. + * + * When the effect succeeds, the `onSuccess` handler is executed with the + * success value. When the effect fails, the `onFailure` handler is executed + * with the failure value. Both handlers can include side effects such as + * logging or analytics, and neither modifies the original effect's output. + * + * If either the success or failure handler fails, the overall effect will also + * fail. + * + * **Example** + * + * ```ts + * import { Effect, Random, Console } from "effect" + * + * // Simulate a task that might fail + * const task = Effect.filterOrFail( + * Random.nextRange(-1, 1), + * (n) => n >= 0, + * () => "random number is negative" + * ) + * + * // Use tapBoth to log both success and failure outcomes + * const tapping = Effect.tapBoth(task, { + * onFailure: (error) => Console.log(`failure: ${error}`), + * onSuccess: (randomNumber) => + * Console.log(`random number: ${randomNumber}`) + * }) + * + * Effect.runFork(tapping) + * // Example Output: + * // failure: random number is negative + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ +export const tapBoth: { + /** + * Allows you to inspect both success and failure outcomes of an effect and + * perform side effects for each. + * + * **Details** + * + * This function enables you to handle both success and failure cases + * separately, without modifying the main effect's result. It is particularly + * useful for scenarios where you need to log, monitor, or perform additional + * actions depending on whether the effect succeeded or failed. + * + * When the effect succeeds, the `onSuccess` handler is executed with the + * success value. When the effect fails, the `onFailure` handler is executed + * with the failure value. Both handlers can include side effects such as + * logging or analytics, and neither modifies the original effect's output. + * + * If either the success or failure handler fails, the overall effect will also + * fail. + * + * **Example** + * + * ```ts + * import { Effect, Random, Console } from "effect" + * + * // Simulate a task that might fail + * const task = Effect.filterOrFail( + * Random.nextRange(-1, 1), + * (n) => n >= 0, + * () => "random number is negative" + * ) + * + * // Use tapBoth to log both success and failure outcomes + * const tapping = Effect.tapBoth(task, { + * onFailure: (error) => Console.log(`failure: ${error}`), + * onSuccess: (randomNumber) => + * Console.log(`random number: ${randomNumber}`) + * }) + * + * Effect.runFork(tapping) + * // Example Output: + * // failure: random number is negative + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + ( + options: { + readonly onFailure: (e: NoInfer) => Effect + readonly onSuccess: (a: NoInfer) => Effect + } + ): (self: Effect) => Effect + /** + * Allows you to inspect both success and failure outcomes of an effect and + * perform side effects for each. + * + * **Details** + * + * This function enables you to handle both success and failure cases + * separately, without modifying the main effect's result. It is particularly + * useful for scenarios where you need to log, monitor, or perform additional + * actions depending on whether the effect succeeded or failed. + * + * When the effect succeeds, the `onSuccess` handler is executed with the + * success value. When the effect fails, the `onFailure` handler is executed + * with the failure value. Both handlers can include side effects such as + * logging or analytics, and neither modifies the original effect's output. + * + * If either the success or failure handler fails, the overall effect will also + * fail. + * + * **Example** + * + * ```ts + * import { Effect, Random, Console } from "effect" + * + * // Simulate a task that might fail + * const task = Effect.filterOrFail( + * Random.nextRange(-1, 1), + * (n) => n >= 0, + * () => "random number is negative" + * ) + * + * // Use tapBoth to log both success and failure outcomes + * const tapping = Effect.tapBoth(task, { + * onFailure: (error) => Console.log(`failure: ${error}`), + * onSuccess: (randomNumber) => + * Console.log(`random number: ${randomNumber}`) + * }) + * + * Effect.runFork(tapping) + * // Example Output: + * // failure: random number is negative + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + ( + self: Effect, + options: { + readonly onFailure: (e: E) => Effect + readonly onSuccess: (a: A) => Effect + } + ): Effect +} = effect.tapBoth + +/** + * Inspect severe errors or defects (non-recoverable failures) in an effect. + * + * **Details** + * + * This function is specifically designed to handle and inspect defects, which + * are critical failures in your program, such as unexpected runtime exceptions + * or system-level errors. Unlike normal recoverable errors, defects typically + * indicate serious issues that cannot be addressed through standard error + * handling. + * + * When a defect occurs in an effect, the function you provide to this function + * will be executed, allowing you to log, monitor, or handle the defect in some + * way. Importantly, this does not alter the main result of the effect. If no + * defect occurs, the effect behaves as if this function was not used. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Simulate a task that fails with a recoverable error + * const task1: Effect.Effect = Effect.fail("NetworkError") + * + * // tapDefect won't log anything because NetworkError is not a defect + * const tapping1 = Effect.tapDefect(task1, (cause) => + * Console.log(`defect: ${cause}`) + * ) + * + * Effect.runFork(tapping1) + * // No Output + * + * // Simulate a severe failure in the system + * const task2: Effect.Effect = Effect.dieMessage( + * "Something went wrong" + * ) + * + * // Log the defect using tapDefect + * const tapping2 = Effect.tapDefect(task2, (cause) => + * Console.log(`defect: ${cause}`) + * ) + * + * Effect.runFork(tapping2) + * // Output: + * // defect: RuntimeException: Something went wrong + * // ... stack trace ... + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ +export const tapDefect: { + /** + * Inspect severe errors or defects (non-recoverable failures) in an effect. + * + * **Details** + * + * This function is specifically designed to handle and inspect defects, which + * are critical failures in your program, such as unexpected runtime exceptions + * or system-level errors. Unlike normal recoverable errors, defects typically + * indicate serious issues that cannot be addressed through standard error + * handling. + * + * When a defect occurs in an effect, the function you provide to this function + * will be executed, allowing you to log, monitor, or handle the defect in some + * way. Importantly, this does not alter the main result of the effect. If no + * defect occurs, the effect behaves as if this function was not used. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Simulate a task that fails with a recoverable error + * const task1: Effect.Effect = Effect.fail("NetworkError") + * + * // tapDefect won't log anything because NetworkError is not a defect + * const tapping1 = Effect.tapDefect(task1, (cause) => + * Console.log(`defect: ${cause}`) + * ) + * + * Effect.runFork(tapping1) + * // No Output + * + * // Simulate a severe failure in the system + * const task2: Effect.Effect = Effect.dieMessage( + * "Something went wrong" + * ) + * + * // Log the defect using tapDefect + * const tapping2 = Effect.tapDefect(task2, (cause) => + * Console.log(`defect: ${cause}`) + * ) + * + * Effect.runFork(tapping2) + * // Output: + * // defect: RuntimeException: Something went wrong + * // ... stack trace ... + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + (f: (cause: Cause.Cause) => Effect): (self: Effect) => Effect + /** + * Inspect severe errors or defects (non-recoverable failures) in an effect. + * + * **Details** + * + * This function is specifically designed to handle and inspect defects, which + * are critical failures in your program, such as unexpected runtime exceptions + * or system-level errors. Unlike normal recoverable errors, defects typically + * indicate serious issues that cannot be addressed through standard error + * handling. + * + * When a defect occurs in an effect, the function you provide to this function + * will be executed, allowing you to log, monitor, or handle the defect in some + * way. Importantly, this does not alter the main result of the effect. If no + * defect occurs, the effect behaves as if this function was not used. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Simulate a task that fails with a recoverable error + * const task1: Effect.Effect = Effect.fail("NetworkError") + * + * // tapDefect won't log anything because NetworkError is not a defect + * const tapping1 = Effect.tapDefect(task1, (cause) => + * Console.log(`defect: ${cause}`) + * ) + * + * Effect.runFork(tapping1) + * // No Output + * + * // Simulate a severe failure in the system + * const task2: Effect.Effect = Effect.dieMessage( + * "Something went wrong" + * ) + * + * // Log the defect using tapDefect + * const tapping2 = Effect.tapDefect(task2, (cause) => + * Console.log(`defect: ${cause}`) + * ) + * + * Effect.runFork(tapping2) + * // Output: + * // defect: RuntimeException: Something went wrong + * // ... stack trace ... + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + (self: Effect, f: (cause: Cause.Cause) => Effect): Effect +} = effect.tapDefect + +/** + * Execute a side effect on failure without modifying the original effect. + * + * **Details** + * + * This function allows you to inspect and react to the failure of an effect by + * executing an additional effect. The failure value is passed to the provided + * function, enabling you to log it, track it, or perform any other operation. + * Importantly, the original failure remains intact and is re-propagated, so the + * effect's behavior is unchanged. + * + * The side effect you provide is only executed when the effect fails. If the + * effect succeeds, the function is ignored, and the success value is propagated + * as usual. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Simulate a task that fails with an error + * const task: Effect.Effect = Effect.fail("NetworkError") + * + * // Use tapError to log the error message when the task fails + * const tapping = Effect.tapError(task, (error) => + * Console.log(`expected error: ${error}`) + * ) + * + * Effect.runFork(tapping) + * // Output: + * // expected error: NetworkError + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ +export const tapError: { + /** + * Execute a side effect on failure without modifying the original effect. + * + * **Details** + * + * This function allows you to inspect and react to the failure of an effect by + * executing an additional effect. The failure value is passed to the provided + * function, enabling you to log it, track it, or perform any other operation. + * Importantly, the original failure remains intact and is re-propagated, so the + * effect's behavior is unchanged. + * + * The side effect you provide is only executed when the effect fails. If the + * effect succeeds, the function is ignored, and the success value is propagated + * as usual. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Simulate a task that fails with an error + * const task: Effect.Effect = Effect.fail("NetworkError") + * + * // Use tapError to log the error message when the task fails + * const tapping = Effect.tapError(task, (error) => + * Console.log(`expected error: ${error}`) + * ) + * + * Effect.runFork(tapping) + * // Output: + * // expected error: NetworkError + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + (f: (e: NoInfer) => Effect): (self: Effect) => Effect + /** + * Execute a side effect on failure without modifying the original effect. + * + * **Details** + * + * This function allows you to inspect and react to the failure of an effect by + * executing an additional effect. The failure value is passed to the provided + * function, enabling you to log it, track it, or perform any other operation. + * Importantly, the original failure remains intact and is re-propagated, so the + * effect's behavior is unchanged. + * + * The side effect you provide is only executed when the effect fails. If the + * effect succeeds, the function is ignored, and the success value is propagated + * as usual. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Simulate a task that fails with an error + * const task: Effect.Effect = Effect.fail("NetworkError") + * + * // Use tapError to log the error message when the task fails + * const tapping = Effect.tapError(task, (error) => + * Console.log(`expected error: ${error}`) + * ) + * + * Effect.runFork(tapping) + * // Output: + * // expected error: NetworkError + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + (self: Effect, f: (e: E) => Effect): Effect +} = effect.tapError + +/** + * Inspect errors matching a specific tag without altering the original effect. + * + * **Details** + * + * This function allows you to inspect and handle specific error types based on + * their `_tag` property. It is particularly useful in applications where errors + * are modeled with tagged types (e.g., union types with discriminating tags). + * By targeting errors with a specific `_tag`, you can log or perform actions on + * them while leaving the error channel and overall effect unchanged. + * + * If the error doesn't match the specified tag, this function does nothing, and + * the effect proceeds as usual. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * class NetworkError { + * readonly _tag = "NetworkError" + * constructor(readonly statusCode: number) {} + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * constructor(readonly field: string) {} + * } + * + * // Create a task that fails with a NetworkError + * const task: Effect.Effect = + * Effect.fail(new NetworkError(504)) + * + * // Use tapErrorTag to inspect only NetworkError types and log the status code + * const tapping = Effect.tapErrorTag(task, "NetworkError", (error) => + * Console.log(`expected error: ${error.statusCode}`) + * ) + * + * Effect.runFork(tapping) + * // Output: + * // expected error: 504 + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ +export const tapErrorTag: { + /** + * Inspect errors matching a specific tag without altering the original effect. + * + * **Details** + * + * This function allows you to inspect and handle specific error types based on + * their `_tag` property. It is particularly useful in applications where errors + * are modeled with tagged types (e.g., union types with discriminating tags). + * By targeting errors with a specific `_tag`, you can log or perform actions on + * them while leaving the error channel and overall effect unchanged. + * + * If the error doesn't match the specified tag, this function does nothing, and + * the effect proceeds as usual. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * class NetworkError { + * readonly _tag = "NetworkError" + * constructor(readonly statusCode: number) {} + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * constructor(readonly field: string) {} + * } + * + * // Create a task that fails with a NetworkError + * const task: Effect.Effect = + * Effect.fail(new NetworkError(504)) + * + * // Use tapErrorTag to inspect only NetworkError types and log the status code + * const tapping = Effect.tapErrorTag(task, "NetworkError", (error) => + * Console.log(`expected error: ${error.statusCode}`) + * ) + * + * Effect.runFork(tapping) + * // Output: + * // expected error: 504 + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + (k: K, f: (e: NoInfer>) => Effect): (self: Effect) => Effect + /** + * Inspect errors matching a specific tag without altering the original effect. + * + * **Details** + * + * This function allows you to inspect and handle specific error types based on + * their `_tag` property. It is particularly useful in applications where errors + * are modeled with tagged types (e.g., union types with discriminating tags). + * By targeting errors with a specific `_tag`, you can log or perform actions on + * them while leaving the error channel and overall effect unchanged. + * + * If the error doesn't match the specified tag, this function does nothing, and + * the effect proceeds as usual. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * class NetworkError { + * readonly _tag = "NetworkError" + * constructor(readonly statusCode: number) {} + * } + * + * class ValidationError { + * readonly _tag = "ValidationError" + * constructor(readonly field: string) {} + * } + * + * // Create a task that fails with a NetworkError + * const task: Effect.Effect = + * Effect.fail(new NetworkError(504)) + * + * // Use tapErrorTag to inspect only NetworkError types and log the status code + * const tapping = Effect.tapErrorTag(task, "NetworkError", (error) => + * Console.log(`expected error: ${error.statusCode}`) + * ) + * + * Effect.runFork(tapping) + * // Output: + * // expected error: 504 + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + ( + self: Effect, + k: K, + f: (e: Extract) => Effect + ): Effect +} = effect.tapErrorTag + +/** + * Inspect the complete cause of an error, including failures and defects. + * + * **Details** + * + * This function provides access to the full cause of an error, including both + * recoverable failures and irrecoverable defects. It allows you to handle, log, + * or monitor specific error causes without modifying the result of the effect. + * The full `Cause` object encapsulates the error and its contextual + * information, making it useful for debugging and understanding failure + * scenarios in complex workflows. + * + * The effect itself is not modified, and any errors or defects remain in the + * error channel of the original effect. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Create a task that fails with a NetworkError + * const task1: Effect.Effect = Effect.fail("NetworkError") + * + * const tapping1 = Effect.tapErrorCause(task1, (cause) => + * Console.log(`error cause: ${cause}`) + * ) + * + * Effect.runFork(tapping1) + * // Output: + * // error cause: Error: NetworkError + * + * // Simulate a severe failure in the system + * const task2: Effect.Effect = Effect.dieMessage( + * "Something went wrong" + * ) + * + * const tapping2 = Effect.tapErrorCause(task2, (cause) => + * Console.log(`error cause: ${cause}`) + * ) + * + * Effect.runFork(tapping2) + * // Output: + * // error cause: RuntimeException: Something went wrong + * // ... stack trace ... + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ +export const tapErrorCause: { + /** + * Inspect the complete cause of an error, including failures and defects. + * + * **Details** + * + * This function provides access to the full cause of an error, including both + * recoverable failures and irrecoverable defects. It allows you to handle, log, + * or monitor specific error causes without modifying the result of the effect. + * The full `Cause` object encapsulates the error and its contextual + * information, making it useful for debugging and understanding failure + * scenarios in complex workflows. + * + * The effect itself is not modified, and any errors or defects remain in the + * error channel of the original effect. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Create a task that fails with a NetworkError + * const task1: Effect.Effect = Effect.fail("NetworkError") + * + * const tapping1 = Effect.tapErrorCause(task1, (cause) => + * Console.log(`error cause: ${cause}`) + * ) + * + * Effect.runFork(tapping1) + * // Output: + * // error cause: Error: NetworkError + * + * // Simulate a severe failure in the system + * const task2: Effect.Effect = Effect.dieMessage( + * "Something went wrong" + * ) + * + * const tapping2 = Effect.tapErrorCause(task2, (cause) => + * Console.log(`error cause: ${cause}`) + * ) + * + * Effect.runFork(tapping2) + * // Output: + * // error cause: RuntimeException: Something went wrong + * // ... stack trace ... + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + (f: (cause: Cause.Cause>) => Effect): (self: Effect) => Effect + /** + * Inspect the complete cause of an error, including failures and defects. + * + * **Details** + * + * This function provides access to the full cause of an error, including both + * recoverable failures and irrecoverable defects. It allows you to handle, log, + * or monitor specific error causes without modifying the result of the effect. + * The full `Cause` object encapsulates the error and its contextual + * information, making it useful for debugging and understanding failure + * scenarios in complex workflows. + * + * The effect itself is not modified, and any errors or defects remain in the + * error channel of the original effect. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * // Create a task that fails with a NetworkError + * const task1: Effect.Effect = Effect.fail("NetworkError") + * + * const tapping1 = Effect.tapErrorCause(task1, (cause) => + * Console.log(`error cause: ${cause}`) + * ) + * + * Effect.runFork(tapping1) + * // Output: + * // error cause: Error: NetworkError + * + * // Simulate a severe failure in the system + * const task2: Effect.Effect = Effect.dieMessage( + * "Something went wrong" + * ) + * + * const tapping2 = Effect.tapErrorCause(task2, (cause) => + * Console.log(`error cause: ${cause}`) + * ) + * + * Effect.runFork(tapping2) + * // Output: + * // error cause: RuntimeException: Something went wrong + * // ... stack trace ... + * ``` + * + * @since 2.0.0 + * @category Sequencing + */ + (self: Effect, f: (cause: Cause.Cause) => Effect): Effect +} = effect.tapErrorCause + +/** + * Repeats an effect indefinitely until an error occurs. + * + * **Details** + * + * This function executes an effect repeatedly in an infinite loop. Each + * iteration is executed sequentially, and the loop continues until the first + * error occurs. If the effect succeeds, it starts over from the beginning. If + * the effect fails, the error is propagated, and the loop stops. + * + * Be cautious when using this function, as it will run indefinitely unless an + * error interrupts it. This makes it suitable for long-running processes or + * continuous polling tasks, but you should ensure proper error handling or + * combine it with other operators like `timeout` or `schedule` to prevent + * unintentional infinite loops. + * + * @since 2.0.0 + * @category Repetition / Recursion + */ +export const forever: (self: Effect) => Effect = effect.forever + +/** + * Repeatedly updates a state through an effectful operation until a condition + * is no longer met. + * + * **Details** + * + * This function provides a way to implement effectful loops, similar to a + * `while` loop in JavaScript. + * + * ```ts skip-type-checking + * let result = initial + * + * while (options.while(result)) { + * result = options.body(result) + * } + * + * return result + * ``` + * + * It starts with an initial state, checks a + * condition (`while`), and executes a body operation to update the state if the + * condition evaluates to `true`. The process repeats until the condition + * returns `false`. + * + * The state is passed between iterations, allowing the body operation to modify + * it dynamically. The final state after the loop ends is returned as the result + * of the effect. + * + * **When to Use** + * + * This is particularly useful for scenarios where looping logic involves + * asynchronous or side-effectful operations, such as polling or iterative + * computations that depend on external factors. + * + * **Example** (Effectful Iteration) + * + * ```ts + * import { Effect } from "effect" + * + * const result = Effect.iterate( + * // Initial result + * 1, + * { + * // Condition to continue iterating + * while: (result) => result <= 5, + * // Operation to change the result + * body: (result) => Effect.succeed(result + 1) + * } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: 6 + * ``` + * + * @since 2.0.0 + * @category Looping + */ +export const iterate: { + /** + * Repeatedly updates a state through an effectful operation until a condition + * is no longer met. + * + * **Details** + * + * This function provides a way to implement effectful loops, similar to a + * `while` loop in JavaScript. + * + * ```ts skip-type-checking + * let result = initial + * + * while (options.while(result)) { + * result = options.body(result) + * } + * + * return result + * ``` + * + * It starts with an initial state, checks a + * condition (`while`), and executes a body operation to update the state if the + * condition evaluates to `true`. The process repeats until the condition + * returns `false`. + * + * The state is passed between iterations, allowing the body operation to modify + * it dynamically. The final state after the loop ends is returned as the result + * of the effect. + * + * **When to Use** + * + * This is particularly useful for scenarios where looping logic involves + * asynchronous or side-effectful operations, such as polling or iterative + * computations that depend on external factors. + * + * **Example** (Effectful Iteration) + * + * ```ts + * import { Effect } from "effect" + * + * const result = Effect.iterate( + * // Initial result + * 1, + * { + * // Condition to continue iterating + * while: (result) => result <= 5, + * // Operation to change the result + * body: (result) => Effect.succeed(result + 1) + * } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: 6 + * ``` + * + * @since 2.0.0 + * @category Looping + */ + ( + initial: A, + options: { + readonly while: Refinement + readonly body: (b: B) => Effect + } + ): Effect + /** + * Repeatedly updates a state through an effectful operation until a condition + * is no longer met. + * + * **Details** + * + * This function provides a way to implement effectful loops, similar to a + * `while` loop in JavaScript. + * + * ```ts skip-type-checking + * let result = initial + * + * while (options.while(result)) { + * result = options.body(result) + * } + * + * return result + * ``` + * + * It starts with an initial state, checks a + * condition (`while`), and executes a body operation to update the state if the + * condition evaluates to `true`. The process repeats until the condition + * returns `false`. + * + * The state is passed between iterations, allowing the body operation to modify + * it dynamically. The final state after the loop ends is returned as the result + * of the effect. + * + * **When to Use** + * + * This is particularly useful for scenarios where looping logic involves + * asynchronous or side-effectful operations, such as polling or iterative + * computations that depend on external factors. + * + * **Example** (Effectful Iteration) + * + * ```ts + * import { Effect } from "effect" + * + * const result = Effect.iterate( + * // Initial result + * 1, + * { + * // Condition to continue iterating + * while: (result) => result <= 5, + * // Operation to change the result + * body: (result) => Effect.succeed(result + 1) + * } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: 6 + * ``` + * + * @since 2.0.0 + * @category Looping + */ + ( + initial: A, + options: { + readonly while: Predicate + readonly body: (a: A) => Effect + } + ): Effect +} = effect.iterate + +/** + * Repeatedly executes a loop with a state, collecting results or discarding + * them based on configuration. + * + * **Details** + * + * This function performs an effectful loop, starting with an initial state and + * iterating as long as the `while` condition evaluates to `true`, similar to a + * `while` loop in JavaScript. + * + * ```ts skip-type-checking + * let state = initial + * const result = [] + * + * while (options.while(state)) { + * result.push(options.body(state)) // Perform the effectful operation + * state = options.step(state) // Update the state + * } + * + * return result + * ``` + * + * During each iteration, the `step` function updates the state, and the `body` + * effect is executed. + * + * The results of the body effect can be collected in an array or discarded + * based on the `discard` option. + * + * **Discarding Intermediate Results** + * + * - If `discard` is `false` or not provided, the intermediate results are + * collected into an array and returned as the final result. + * - If `discard` is `true`, the intermediate results are ignored, and the + * effect returns `void`. + * + * **When to Use** + * + * This is useful for implementing loops where you need to perform effectful + * computations repeatedly, such as processing items in a list, generating + * values, or performing iterative updates. + * + * **Example** (Looping with Collected Results) + * + * ```ts + * import { Effect } from "effect" + * + * // A loop that runs 5 times, collecting each iteration's result + * const result = Effect.loop( + * // Initial state + * 1, + * { + * // Condition to continue looping + * while: (state) => state <= 5, + * // State update function + * step: (state) => state + 1, + * // Effect to be performed on each iteration + * body: (state) => Effect.succeed(state) + * } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: [1, 2, 3, 4, 5] + * ``` + * + * **Example** (Loop with Discarded Results) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const result = Effect.loop( + * // Initial state + * 1, + * { + * // Condition to continue looping + * while: (state) => state <= 5, + * // State update function + * step: (state) => state + 1, + * // Effect to be performed on each iteration + * body: (state) => Console.log(`Currently at state ${state}`), + * // Discard intermediate results + * discard: true + * } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at state 1 + * // Currently at state 2 + * // Currently at state 3 + * // Currently at state 4 + * // Currently at state 5 + * // undefined + * ``` + * + * @since 2.0.0 + * @category Looping + */ +export const loop: { + /** + * Repeatedly executes a loop with a state, collecting results or discarding + * them based on configuration. + * + * **Details** + * + * This function performs an effectful loop, starting with an initial state and + * iterating as long as the `while` condition evaluates to `true`, similar to a + * `while` loop in JavaScript. + * + * ```ts skip-type-checking + * let state = initial + * const result = [] + * + * while (options.while(state)) { + * result.push(options.body(state)) // Perform the effectful operation + * state = options.step(state) // Update the state + * } + * + * return result + * ``` + * + * During each iteration, the `step` function updates the state, and the `body` + * effect is executed. + * + * The results of the body effect can be collected in an array or discarded + * based on the `discard` option. + * + * **Discarding Intermediate Results** + * + * - If `discard` is `false` or not provided, the intermediate results are + * collected into an array and returned as the final result. + * - If `discard` is `true`, the intermediate results are ignored, and the + * effect returns `void`. + * + * **When to Use** + * + * This is useful for implementing loops where you need to perform effectful + * computations repeatedly, such as processing items in a list, generating + * values, or performing iterative updates. + * + * **Example** (Looping with Collected Results) + * + * ```ts + * import { Effect } from "effect" + * + * // A loop that runs 5 times, collecting each iteration's result + * const result = Effect.loop( + * // Initial state + * 1, + * { + * // Condition to continue looping + * while: (state) => state <= 5, + * // State update function + * step: (state) => state + 1, + * // Effect to be performed on each iteration + * body: (state) => Effect.succeed(state) + * } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: [1, 2, 3, 4, 5] + * ``` + * + * **Example** (Loop with Discarded Results) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const result = Effect.loop( + * // Initial state + * 1, + * { + * // Condition to continue looping + * while: (state) => state <= 5, + * // State update function + * step: (state) => state + 1, + * // Effect to be performed on each iteration + * body: (state) => Console.log(`Currently at state ${state}`), + * // Discard intermediate results + * discard: true + * } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at state 1 + * // Currently at state 2 + * // Currently at state 3 + * // Currently at state 4 + * // Currently at state 5 + * // undefined + * ``` + * + * @since 2.0.0 + * @category Looping + */ + ( + initial: A, + options: { + readonly while: Refinement + readonly step: (b: B) => A + readonly body: (b: B) => Effect + readonly discard?: false | undefined + } + ): Effect, E, R> + /** + * Repeatedly executes a loop with a state, collecting results or discarding + * them based on configuration. + * + * **Details** + * + * This function performs an effectful loop, starting with an initial state and + * iterating as long as the `while` condition evaluates to `true`, similar to a + * `while` loop in JavaScript. + * + * ```ts skip-type-checking + * let state = initial + * const result = [] + * + * while (options.while(state)) { + * result.push(options.body(state)) // Perform the effectful operation + * state = options.step(state) // Update the state + * } + * + * return result + * ``` + * + * During each iteration, the `step` function updates the state, and the `body` + * effect is executed. + * + * The results of the body effect can be collected in an array or discarded + * based on the `discard` option. + * + * **Discarding Intermediate Results** + * + * - If `discard` is `false` or not provided, the intermediate results are + * collected into an array and returned as the final result. + * - If `discard` is `true`, the intermediate results are ignored, and the + * effect returns `void`. + * + * **When to Use** + * + * This is useful for implementing loops where you need to perform effectful + * computations repeatedly, such as processing items in a list, generating + * values, or performing iterative updates. + * + * **Example** (Looping with Collected Results) + * + * ```ts + * import { Effect } from "effect" + * + * // A loop that runs 5 times, collecting each iteration's result + * const result = Effect.loop( + * // Initial state + * 1, + * { + * // Condition to continue looping + * while: (state) => state <= 5, + * // State update function + * step: (state) => state + 1, + * // Effect to be performed on each iteration + * body: (state) => Effect.succeed(state) + * } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: [1, 2, 3, 4, 5] + * ``` + * + * **Example** (Loop with Discarded Results) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const result = Effect.loop( + * // Initial state + * 1, + * { + * // Condition to continue looping + * while: (state) => state <= 5, + * // State update function + * step: (state) => state + 1, + * // Effect to be performed on each iteration + * body: (state) => Console.log(`Currently at state ${state}`), + * // Discard intermediate results + * discard: true + * } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at state 1 + * // Currently at state 2 + * // Currently at state 3 + * // Currently at state 4 + * // Currently at state 5 + * // undefined + * ``` + * + * @since 2.0.0 + * @category Looping + */ + ( + initial: A, + options: { + readonly while: (a: A) => boolean + readonly step: (a: A) => A + readonly body: (a: A) => Effect + readonly discard?: false | undefined + } + ): Effect, E, R> + /** + * Repeatedly executes a loop with a state, collecting results or discarding + * them based on configuration. + * + * **Details** + * + * This function performs an effectful loop, starting with an initial state and + * iterating as long as the `while` condition evaluates to `true`, similar to a + * `while` loop in JavaScript. + * + * ```ts skip-type-checking + * let state = initial + * const result = [] + * + * while (options.while(state)) { + * result.push(options.body(state)) // Perform the effectful operation + * state = options.step(state) // Update the state + * } + * + * return result + * ``` + * + * During each iteration, the `step` function updates the state, and the `body` + * effect is executed. + * + * The results of the body effect can be collected in an array or discarded + * based on the `discard` option. + * + * **Discarding Intermediate Results** + * + * - If `discard` is `false` or not provided, the intermediate results are + * collected into an array and returned as the final result. + * - If `discard` is `true`, the intermediate results are ignored, and the + * effect returns `void`. + * + * **When to Use** + * + * This is useful for implementing loops where you need to perform effectful + * computations repeatedly, such as processing items in a list, generating + * values, or performing iterative updates. + * + * **Example** (Looping with Collected Results) + * + * ```ts + * import { Effect } from "effect" + * + * // A loop that runs 5 times, collecting each iteration's result + * const result = Effect.loop( + * // Initial state + * 1, + * { + * // Condition to continue looping + * while: (state) => state <= 5, + * // State update function + * step: (state) => state + 1, + * // Effect to be performed on each iteration + * body: (state) => Effect.succeed(state) + * } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: [1, 2, 3, 4, 5] + * ``` + * + * **Example** (Loop with Discarded Results) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const result = Effect.loop( + * // Initial state + * 1, + * { + * // Condition to continue looping + * while: (state) => state <= 5, + * // State update function + * step: (state) => state + 1, + * // Effect to be performed on each iteration + * body: (state) => Console.log(`Currently at state ${state}`), + * // Discard intermediate results + * discard: true + * } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at state 1 + * // Currently at state 2 + * // Currently at state 3 + * // Currently at state 4 + * // Currently at state 5 + * // undefined + * ``` + * + * @since 2.0.0 + * @category Looping + */ + ( + initial: A, + options: { + readonly while: Refinement + readonly step: (b: B) => A + readonly body: (b: B) => Effect + readonly discard: true + } + ): Effect + /** + * Repeatedly executes a loop with a state, collecting results or discarding + * them based on configuration. + * + * **Details** + * + * This function performs an effectful loop, starting with an initial state and + * iterating as long as the `while` condition evaluates to `true`, similar to a + * `while` loop in JavaScript. + * + * ```ts skip-type-checking + * let state = initial + * const result = [] + * + * while (options.while(state)) { + * result.push(options.body(state)) // Perform the effectful operation + * state = options.step(state) // Update the state + * } + * + * return result + * ``` + * + * During each iteration, the `step` function updates the state, and the `body` + * effect is executed. + * + * The results of the body effect can be collected in an array or discarded + * based on the `discard` option. + * + * **Discarding Intermediate Results** + * + * - If `discard` is `false` or not provided, the intermediate results are + * collected into an array and returned as the final result. + * - If `discard` is `true`, the intermediate results are ignored, and the + * effect returns `void`. + * + * **When to Use** + * + * This is useful for implementing loops where you need to perform effectful + * computations repeatedly, such as processing items in a list, generating + * values, or performing iterative updates. + * + * **Example** (Looping with Collected Results) + * + * ```ts + * import { Effect } from "effect" + * + * // A loop that runs 5 times, collecting each iteration's result + * const result = Effect.loop( + * // Initial state + * 1, + * { + * // Condition to continue looping + * while: (state) => state <= 5, + * // State update function + * step: (state) => state + 1, + * // Effect to be performed on each iteration + * body: (state) => Effect.succeed(state) + * } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: [1, 2, 3, 4, 5] + * ``` + * + * **Example** (Loop with Discarded Results) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const result = Effect.loop( + * // Initial state + * 1, + * { + * // Condition to continue looping + * while: (state) => state <= 5, + * // State update function + * step: (state) => state + 1, + * // Effect to be performed on each iteration + * body: (state) => Console.log(`Currently at state ${state}`), + * // Discard intermediate results + * discard: true + * } + * ) + * + * Effect.runPromise(result).then(console.log) + * // Output: + * // Currently at state 1 + * // Currently at state 2 + * // Currently at state 3 + * // Currently at state 4 + * // Currently at state 5 + * // undefined + * ``` + * + * @since 2.0.0 + * @category Looping + */ + ( + initial: A, + options: { + readonly while: (a: A) => boolean + readonly step: (a: A) => A + readonly body: (a: A) => Effect + readonly discard: true + } + ): Effect +} = effect.loop + +/** + * @since 2.0.0 + * @category Repetition / Recursion + */ +export declare namespace Repeat { + /** + * @since 2.0.0 + * @category Repetition / Recursion + */ + export type Return, O>> = Effect< + (O extends { schedule: Schedule.Schedule } ? Out + : O extends { until: Refinement } ? B + : A), + | E + | (O extends { while: (...args: Array) => Effect } ? E : never) + | (O extends { until: (...args: Array) => Effect } ? E : never), + | R + | (O extends { schedule: Schedule.Schedule } ? R : never) + | (O extends { while: (...args: Array) => Effect } ? R : never) + | (O extends { until: (...args: Array) => Effect } ? R : never) + > extends infer Z ? Z : never + + /** + * @since 2.0.0 + * @category Repetition / Recursion + */ + export interface Options { + while?: ((_: A) => boolean | Effect) | undefined + until?: ((_: A) => boolean | Effect) | undefined + times?: number | undefined + schedule?: Schedule.Schedule | undefined + } +} + +/** + * Repeats an effect based on a specified schedule or until the first failure. + * + * **Details** + * + * This function executes an effect repeatedly according to the given schedule. + * Each repetition occurs after the initial execution of the effect, meaning + * that the schedule determines the number of additional repetitions. For + * example, using `Schedule.once` will result in the effect being executed twice + * (once initially and once as part of the repetition). + * + * If the effect succeeds, it is repeated according to the schedule. If it + * fails, the repetition stops immediately, and the failure is returned. + * + * The schedule can also specify delays between repetitions, making it useful + * for tasks like retrying operations with backoff, periodic execution, or + * performing a series of dependent actions. + * + * You can combine schedules for more advanced repetition logic, such as adding + * delays, limiting recursions, or dynamically adjusting based on the outcome of + * each execution. + * + * **Example** (Success Example) + * + * ```ts + * import { Effect, Schedule, Console } from "effect" + * + * const action = Console.log("success") + * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") + * const program = Effect.repeat(action, policy) + * + * Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`)) + * ``` + * + * **Example** (Failure Example) + * + * ```ts + * import { Effect, Schedule } from "effect" + * + * let count = 0 + * + * // Define an async effect that simulates an action with possible failures + * const action = Effect.async((resume) => { + * if (count > 1) { + * console.log("failure") + * resume(Effect.fail("Uh oh!")) + * } else { + * count++ + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") + * const program = Effect.repeat(action, policy) + * + * Effect.runPromiseExit(program).then(console.log) + * ``` + * + * @since 2.0.0 + * @category Repetition / Recursion + */ +export const repeat: { + /** + * Repeats an effect based on a specified schedule or until the first failure. + * + * **Details** + * + * This function executes an effect repeatedly according to the given schedule. + * Each repetition occurs after the initial execution of the effect, meaning + * that the schedule determines the number of additional repetitions. For + * example, using `Schedule.once` will result in the effect being executed twice + * (once initially and once as part of the repetition). + * + * If the effect succeeds, it is repeated according to the schedule. If it + * fails, the repetition stops immediately, and the failure is returned. + * + * The schedule can also specify delays between repetitions, making it useful + * for tasks like retrying operations with backoff, periodic execution, or + * performing a series of dependent actions. + * + * You can combine schedules for more advanced repetition logic, such as adding + * delays, limiting recursions, or dynamically adjusting based on the outcome of + * each execution. + * + * **Example** (Success Example) + * + * ```ts + * import { Effect, Schedule, Console } from "effect" + * + * const action = Console.log("success") + * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") + * const program = Effect.repeat(action, policy) + * + * Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`)) + * ``` + * + * **Example** (Failure Example) + * + * ```ts + * import { Effect, Schedule } from "effect" + * + * let count = 0 + * + * // Define an async effect that simulates an action with possible failures + * const action = Effect.async((resume) => { + * if (count > 1) { + * console.log("failure") + * resume(Effect.fail("Uh oh!")) + * } else { + * count++ + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") + * const program = Effect.repeat(action, policy) + * + * Effect.runPromiseExit(program).then(console.log) + * ``` + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + , O>, A>(options: O): ( + self: Effect + ) => Repeat.Return + /** + * Repeats an effect based on a specified schedule or until the first failure. + * + * **Details** + * + * This function executes an effect repeatedly according to the given schedule. + * Each repetition occurs after the initial execution of the effect, meaning + * that the schedule determines the number of additional repetitions. For + * example, using `Schedule.once` will result in the effect being executed twice + * (once initially and once as part of the repetition). + * + * If the effect succeeds, it is repeated according to the schedule. If it + * fails, the repetition stops immediately, and the failure is returned. + * + * The schedule can also specify delays between repetitions, making it useful + * for tasks like retrying operations with backoff, periodic execution, or + * performing a series of dependent actions. + * + * You can combine schedules for more advanced repetition logic, such as adding + * delays, limiting recursions, or dynamically adjusting based on the outcome of + * each execution. + * + * **Example** (Success Example) + * + * ```ts + * import { Effect, Schedule, Console } from "effect" + * + * const action = Console.log("success") + * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") + * const program = Effect.repeat(action, policy) + * + * Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`)) + * ``` + * + * **Example** (Failure Example) + * + * ```ts + * import { Effect, Schedule } from "effect" + * + * let count = 0 + * + * // Define an async effect that simulates an action with possible failures + * const action = Effect.async((resume) => { + * if (count > 1) { + * console.log("failure") + * resume(Effect.fail("Uh oh!")) + * } else { + * count++ + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") + * const program = Effect.repeat(action, policy) + * + * Effect.runPromiseExit(program).then(console.log) + * ``` + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + (schedule: Schedule.Schedule): (self: Effect) => Effect + /** + * Repeats an effect based on a specified schedule or until the first failure. + * + * **Details** + * + * This function executes an effect repeatedly according to the given schedule. + * Each repetition occurs after the initial execution of the effect, meaning + * that the schedule determines the number of additional repetitions. For + * example, using `Schedule.once` will result in the effect being executed twice + * (once initially and once as part of the repetition). + * + * If the effect succeeds, it is repeated according to the schedule. If it + * fails, the repetition stops immediately, and the failure is returned. + * + * The schedule can also specify delays between repetitions, making it useful + * for tasks like retrying operations with backoff, periodic execution, or + * performing a series of dependent actions. + * + * You can combine schedules for more advanced repetition logic, such as adding + * delays, limiting recursions, or dynamically adjusting based on the outcome of + * each execution. + * + * **Example** (Success Example) + * + * ```ts + * import { Effect, Schedule, Console } from "effect" + * + * const action = Console.log("success") + * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") + * const program = Effect.repeat(action, policy) + * + * Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`)) + * ``` + * + * **Example** (Failure Example) + * + * ```ts + * import { Effect, Schedule } from "effect" + * + * let count = 0 + * + * // Define an async effect that simulates an action with possible failures + * const action = Effect.async((resume) => { + * if (count > 1) { + * console.log("failure") + * resume(Effect.fail("Uh oh!")) + * } else { + * count++ + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") + * const program = Effect.repeat(action, policy) + * + * Effect.runPromiseExit(program).then(console.log) + * ``` + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + , O>>(self: Effect, options: O): Repeat.Return + /** + * Repeats an effect based on a specified schedule or until the first failure. + * + * **Details** + * + * This function executes an effect repeatedly according to the given schedule. + * Each repetition occurs after the initial execution of the effect, meaning + * that the schedule determines the number of additional repetitions. For + * example, using `Schedule.once` will result in the effect being executed twice + * (once initially and once as part of the repetition). + * + * If the effect succeeds, it is repeated according to the schedule. If it + * fails, the repetition stops immediately, and the failure is returned. + * + * The schedule can also specify delays between repetitions, making it useful + * for tasks like retrying operations with backoff, periodic execution, or + * performing a series of dependent actions. + * + * You can combine schedules for more advanced repetition logic, such as adding + * delays, limiting recursions, or dynamically adjusting based on the outcome of + * each execution. + * + * **Example** (Success Example) + * + * ```ts + * import { Effect, Schedule, Console } from "effect" + * + * const action = Console.log("success") + * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") + * const program = Effect.repeat(action, policy) + * + * Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`)) + * ``` + * + * **Example** (Failure Example) + * + * ```ts + * import { Effect, Schedule } from "effect" + * + * let count = 0 + * + * // Define an async effect that simulates an action with possible failures + * const action = Effect.async((resume) => { + * if (count > 1) { + * console.log("failure") + * resume(Effect.fail("Uh oh!")) + * } else { + * count++ + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis") + * const program = Effect.repeat(action, policy) + * + * Effect.runPromiseExit(program).then(console.log) + * ``` + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + (self: Effect, schedule: Schedule.Schedule): Effect +} = schedule_.repeat_combined + +/** + * Repeats an effect a specified number of times or until the first failure. + * + * **Details** + * + * This function executes an effect initially and then repeats it the specified + * number of times, as long as it succeeds. For example, calling + * `repeatN(action, 2)` will execute `action` once initially and then repeat it + * two additional times if there are no failures. + * + * If the effect fails during any repetition, the failure is returned, and no + * further repetitions are attempted. + * + * **When to Use** + * + * This function is useful for tasks that need to be retried a fixed number of + * times or for performing repeated actions without requiring a schedule. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * const action = Console.log("success") + * const program = Effect.repeatN(action, 2) + * + * Effect.runPromise(program) + * ``` + * + * @since 2.0.0 + * @category Repetition / Recursion + */ +export const repeatN: { + /** + * Repeats an effect a specified number of times or until the first failure. + * + * **Details** + * + * This function executes an effect initially and then repeats it the specified + * number of times, as long as it succeeds. For example, calling + * `repeatN(action, 2)` will execute `action` once initially and then repeat it + * two additional times if there are no failures. + * + * If the effect fails during any repetition, the failure is returned, and no + * further repetitions are attempted. + * + * **When to Use** + * + * This function is useful for tasks that need to be retried a fixed number of + * times or for performing repeated actions without requiring a schedule. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * const action = Console.log("success") + * const program = Effect.repeatN(action, 2) + * + * Effect.runPromise(program) + * ``` + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + (n: number): (self: Effect) => Effect + /** + * Repeats an effect a specified number of times or until the first failure. + * + * **Details** + * + * This function executes an effect initially and then repeats it the specified + * number of times, as long as it succeeds. For example, calling + * `repeatN(action, 2)` will execute `action` once initially and then repeat it + * two additional times if there are no failures. + * + * If the effect fails during any repetition, the failure is returned, and no + * further repetitions are attempted. + * + * **When to Use** + * + * This function is useful for tasks that need to be retried a fixed number of + * times or for performing repeated actions without requiring a schedule. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * const action = Console.log("success") + * const program = Effect.repeatN(action, 2) + * + * Effect.runPromise(program) + * ``` + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + (self: Effect, n: number): Effect +} = effect.repeatN + +/** + * Repeats an effect with a schedule, handling failures using a custom handler. + * + * **Details** + * + * This function allows you to execute an effect repeatedly based on a specified + * schedule. If the effect fails at any point, a custom failure handler is + * invoked. The handler is provided with both the failure value and the output + * of the schedule at the time of failure. This enables advanced error recovery + * or alternative fallback logic while maintaining flexibility in how + * repetitions are handled. + * + * For example, using a schedule with `recurs(2)` will allow for two additional + * repetitions after the initial execution, provided the effect succeeds. If a + * failure occurs during any iteration, the failure handler is invoked to handle + * the situation. + * + * **Example** + * + * ```ts + * import { Effect, Schedule } from "effect" + * + * let count = 0 + * + * // Define an async effect that simulates an action with possible failures + * const action = Effect.async((resume) => { + * if (count > 1) { + * console.log("failure") + * resume(Effect.fail("Uh oh!")) + * } else { + * count++ + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * const policy = Schedule.addDelay( + * Schedule.recurs(2), // Repeat for a maximum of 2 times + * () => "100 millis" // Add a delay of 100 milliseconds between repetitions + * ) + * + * const program = Effect.repeatOrElse(action, policy, () => + * Effect.sync(() => { + * console.log("orElse") + * return count - 1 + * }) + * ) + * + * Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`)) + * ``` + * + * @since 2.0.0 + * @category Repetition / Recursion + */ +export const repeatOrElse: { + /** + * Repeats an effect with a schedule, handling failures using a custom handler. + * + * **Details** + * + * This function allows you to execute an effect repeatedly based on a specified + * schedule. If the effect fails at any point, a custom failure handler is + * invoked. The handler is provided with both the failure value and the output + * of the schedule at the time of failure. This enables advanced error recovery + * or alternative fallback logic while maintaining flexibility in how + * repetitions are handled. + * + * For example, using a schedule with `recurs(2)` will allow for two additional + * repetitions after the initial execution, provided the effect succeeds. If a + * failure occurs during any iteration, the failure handler is invoked to handle + * the situation. + * + * **Example** + * + * ```ts + * import { Effect, Schedule } from "effect" + * + * let count = 0 + * + * // Define an async effect that simulates an action with possible failures + * const action = Effect.async((resume) => { + * if (count > 1) { + * console.log("failure") + * resume(Effect.fail("Uh oh!")) + * } else { + * count++ + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * const policy = Schedule.addDelay( + * Schedule.recurs(2), // Repeat for a maximum of 2 times + * () => "100 millis" // Add a delay of 100 milliseconds between repetitions + * ) + * + * const program = Effect.repeatOrElse(action, policy, () => + * Effect.sync(() => { + * console.log("orElse") + * return count - 1 + * }) + * ) + * + * Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`)) + * ``` + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + ( + schedule: Schedule.Schedule, + orElse: (error: E, option: Option.Option) => Effect + ): (self: Effect) => Effect + /** + * Repeats an effect with a schedule, handling failures using a custom handler. + * + * **Details** + * + * This function allows you to execute an effect repeatedly based on a specified + * schedule. If the effect fails at any point, a custom failure handler is + * invoked. The handler is provided with both the failure value and the output + * of the schedule at the time of failure. This enables advanced error recovery + * or alternative fallback logic while maintaining flexibility in how + * repetitions are handled. + * + * For example, using a schedule with `recurs(2)` will allow for two additional + * repetitions after the initial execution, provided the effect succeeds. If a + * failure occurs during any iteration, the failure handler is invoked to handle + * the situation. + * + * **Example** + * + * ```ts + * import { Effect, Schedule } from "effect" + * + * let count = 0 + * + * // Define an async effect that simulates an action with possible failures + * const action = Effect.async((resume) => { + * if (count > 1) { + * console.log("failure") + * resume(Effect.fail("Uh oh!")) + * } else { + * count++ + * console.log("success") + * resume(Effect.succeed("yay!")) + * } + * }) + * + * const policy = Schedule.addDelay( + * Schedule.recurs(2), // Repeat for a maximum of 2 times + * () => "100 millis" // Add a delay of 100 milliseconds between repetitions + * ) + * + * const program = Effect.repeatOrElse(action, policy, () => + * Effect.sync(() => { + * console.log("orElse") + * return count - 1 + * }) + * ) + * + * Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`)) + * ``` + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + ( + self: Effect, + schedule: Schedule.Schedule, + orElse: (error: E, option: Option.Option) => Effect + ): Effect +} = schedule_.repeatOrElse_Effect + +/** + * Repeats an effect based on a specified schedule. + * + * **Details** + * + * This function allows you to execute an effect repeatedly according to a given + * schedule. The schedule determines the timing and number of repetitions. Each + * repetition can also depend on the decision of the schedule, providing + * flexibility for complex workflows. This function does not modify the effect's + * success or failure; it only controls its repetition. + * + * For example, you can use a schedule that recurs a specific number of times, + * adds delays between repetitions, or customizes repetition behavior based on + * external inputs. The effect runs initially and is repeated according to the + * schedule. + * + * @see {@link scheduleFrom} for a variant that allows the schedule's decision + * to depend on the result of this effect. + * + * @since 2.0.0 + * @category Repetition / Recursion + */ +export const schedule: { + /** + * Repeats an effect based on a specified schedule. + * + * **Details** + * + * This function allows you to execute an effect repeatedly according to a given + * schedule. The schedule determines the timing and number of repetitions. Each + * repetition can also depend on the decision of the schedule, providing + * flexibility for complex workflows. This function does not modify the effect's + * success or failure; it only controls its repetition. + * + * For example, you can use a schedule that recurs a specific number of times, + * adds delays between repetitions, or customizes repetition behavior based on + * external inputs. The effect runs initially and is repeated according to the + * schedule. + * + * @see {@link scheduleFrom} for a variant that allows the schedule's decision + * to depend on the result of this effect. + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + (schedule: Schedule.Schedule | undefined, R2>): (self: Effect) => Effect + /** + * Repeats an effect based on a specified schedule. + * + * **Details** + * + * This function allows you to execute an effect repeatedly according to a given + * schedule. The schedule determines the timing and number of repetitions. Each + * repetition can also depend on the decision of the schedule, providing + * flexibility for complex workflows. This function does not modify the effect's + * success or failure; it only controls its repetition. + * + * For example, you can use a schedule that recurs a specific number of times, + * adds delays between repetitions, or customizes repetition behavior based on + * external inputs. The effect runs initially and is repeated according to the + * schedule. + * + * @see {@link scheduleFrom} for a variant that allows the schedule's decision + * to depend on the result of this effect. + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + (self: Effect, schedule: Schedule.Schedule): Effect +} = schedule_.schedule_Effect + +/** + * Runs an effect repeatedly on a new fiber according to a given schedule. + * + * **Details** + * + * This function starts the provided effect on a new fiber and runs it + * repeatedly based on the specified schedule. The repetitions are managed by + * the schedule's rules, which define the timing and number of iterations. The + * fiber is attached to the current scope, meaning it is automatically managed + * and cleaned up when the scope is closed. + * + * The function returns a `RuntimeFiber` that allows you to monitor or interact + * with the running fiber. + * + * **When to Use** + * + * This is particularly useful for concurrent execution of scheduled tasks or + * when you want to continue processing without waiting for the repetitions to + * complete. + * + * @since 2.0.0 + * @category Repetition / Recursion + */ +export const scheduleForked: { + /** + * Runs an effect repeatedly on a new fiber according to a given schedule. + * + * **Details** + * + * This function starts the provided effect on a new fiber and runs it + * repeatedly based on the specified schedule. The repetitions are managed by + * the schedule's rules, which define the timing and number of iterations. The + * fiber is attached to the current scope, meaning it is automatically managed + * and cleaned up when the scope is closed. + * + * The function returns a `RuntimeFiber` that allows you to monitor or interact + * with the running fiber. + * + * **When to Use** + * + * This is particularly useful for concurrent execution of scheduled tasks or + * when you want to continue processing without waiting for the repetitions to + * complete. + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + (schedule: Schedule.Schedule): (self: Effect) => Effect, never, Scope.Scope | R2 | R> + /** + * Runs an effect repeatedly on a new fiber according to a given schedule. + * + * **Details** + * + * This function starts the provided effect on a new fiber and runs it + * repeatedly based on the specified schedule. The repetitions are managed by + * the schedule's rules, which define the timing and number of iterations. The + * fiber is attached to the current scope, meaning it is automatically managed + * and cleaned up when the scope is closed. + * + * The function returns a `RuntimeFiber` that allows you to monitor or interact + * with the running fiber. + * + * **When to Use** + * + * This is particularly useful for concurrent execution of scheduled tasks or + * when you want to continue processing without waiting for the repetitions to + * complete. + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + (self: Effect, schedule: Schedule.Schedule): Effect, never, Scope.Scope | R | R2> +} = schedule_.scheduleForked + +/** + * Runs an effect repeatedly according to a schedule, starting from a specified + * input value. + * + * **Details** + * + * This function allows you to repeatedly execute an effect based on a schedule. + * The schedule starts with the given `initial` input value, which is passed to + * the first execution. Subsequent executions of the effect are controlled by + * the schedule's rules, using the output of the previous iteration as the input + * for the next one. + * + * The returned effect will complete when the schedule ends or the effect fails, + * propagating the error. + * + * @since 2.0.0 + * @category Repetition / Recursion + */ +export const scheduleFrom: { + /** + * Runs an effect repeatedly according to a schedule, starting from a specified + * input value. + * + * **Details** + * + * This function allows you to repeatedly execute an effect based on a schedule. + * The schedule starts with the given `initial` input value, which is passed to + * the first execution. Subsequent executions of the effect are controlled by + * the schedule's rules, using the output of the previous iteration as the input + * for the next one. + * + * The returned effect will complete when the schedule ends or the effect fails, + * propagating the error. + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + (initial: In, schedule: Schedule.Schedule): (self: Effect) => Effect + /** + * Runs an effect repeatedly according to a schedule, starting from a specified + * input value. + * + * **Details** + * + * This function allows you to repeatedly execute an effect based on a schedule. + * The schedule starts with the given `initial` input value, which is passed to + * the first execution. Subsequent executions of the effect are controlled by + * the schedule's rules, using the output of the previous iteration as the input + * for the next one. + * + * The returned effect will complete when the schedule ends or the effect fails, + * propagating the error. + * + * @since 2.0.0 + * @category Repetition / Recursion + */ + ( + self: Effect, + initial: In, + schedule: Schedule.Schedule + ): Effect +} = schedule_.scheduleFrom_Effect + +/** + * @since 2.0.0 + * @category Repetition / Recursion + */ +export const whileLoop: ( + options: { + readonly while: LazyArg + readonly body: LazyArg> + readonly step: (a: A) => void + } +) => Effect = core.whileLoop + +/** + * Returns a collection of all `FiberRef` values for the fiber running this + * effect. + * + * @since 2.0.0 + * @category Fiber Refs + */ +export const getFiberRefs: Effect = effect.fiberRefs + +/** + * Inherits values from all `FiberRef` instances into current fiber. + * + * @since 2.0.0 + * @category Fiber Refs + */ +export const inheritFiberRefs: (childFiberRefs: FiberRefs.FiberRefs) => Effect = effect.inheritFiberRefs + +/** + * @since 2.0.0 + * @category Fiber Refs + */ +export const locally: { + /** + * @since 2.0.0 + * @category Fiber Refs + */ + (self: FiberRef.FiberRef, value: A): (use: Effect) => Effect + /** + * @since 2.0.0 + * @category Fiber Refs + */ + (use: Effect, self: FiberRef.FiberRef, value: A): Effect +} = core.fiberRefLocally + +/** + * @since 2.0.0 + * @category Fiber Refs + */ +export const locallyWith: { + /** + * @since 2.0.0 + * @category Fiber Refs + */ + (self: FiberRef.FiberRef, f: (a: A) => A): (use: Effect) => Effect + /** + * @since 2.0.0 + * @category Fiber Refs + */ + (use: Effect, self: FiberRef.FiberRef, f: (a: A) => A): Effect +} = core.fiberRefLocallyWith + +/** + * @since 2.0.0 + * @category Fiber Refs + */ +export const locallyScoped: { + /** + * @since 2.0.0 + * @category Fiber Refs + */ + (value: A): (self: FiberRef.FiberRef) => Effect + /** + * @since 2.0.0 + * @category Fiber Refs + */ + (self: FiberRef.FiberRef, value: A): Effect +} = fiberRuntime.fiberRefLocallyScoped + +/** + * @since 2.0.0 + * @category Fiber Refs + */ +export const locallyScopedWith: { + /** + * @since 2.0.0 + * @category Fiber Refs + */ + (f: (a: A) => A): (self: FiberRef.FiberRef) => Effect + /** + * @since 2.0.0 + * @category Fiber Refs + */ + (self: FiberRef.FiberRef, f: (a: A) => A): Effect +} = fiberRuntime.fiberRefLocallyScopedWith + +/** + * Applies the specified changes to the `FiberRef` values for the fiber + * running this workflow. + * + * @since 2.0.0 + * @category Fiber Refs + */ +export const patchFiberRefs: (patch: FiberRefsPatch.FiberRefsPatch) => Effect = effect.patchFiberRefs + +/** + * Sets the `FiberRef` values for the fiber running this effect to the values + * in the specified collection of `FiberRef` values. + * + * @since 2.0.0 + * @category Fiber Refs + */ +export const setFiberRefs: (fiberRefs: FiberRefs.FiberRefs) => Effect = effect.setFiberRefs + +/** + * Updates the `FiberRef` values for the fiber running this effect using the + * specified function. + * + * @since 2.0.0 + * @category Fiber Refs + */ +export const updateFiberRefs: ( + f: (fiberId: FiberId.Runtime, fiberRefs: FiberRefs.FiberRefs) => FiberRefs.FiberRefs +) => Effect = effect.updateFiberRefs + +/** + * Checks if an effect has failed. + * + * **Details** + * + * This function evaluates whether an effect has resulted in a failure. It + * returns a boolean value wrapped in an effect, with `true` indicating the + * effect failed and `false` otherwise. + * + * The resulting effect cannot fail (`never` in the error channel) but retains + * the context of the original effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const failure = Effect.fail("Uh oh!") + * + * console.log(Effect.runSync(Effect.isFailure(failure))) + * // Output: true + * + * const defect = Effect.dieMessage("BOOM!") + * + * Effect.runSync(Effect.isFailure(defect)) + * // throws: BOOM! + * ``` + * + * @since 2.0.0 + * @category Condition Checking + */ +export const isFailure: (self: Effect) => Effect = effect.isFailure + +/** + * Checks if an effect has succeeded. + * + * **Details** + * + * This function evaluates whether an effect has resulted in a success. It + * returns a boolean value wrapped in an effect, with `true` indicating the + * effect succeeded and `false` otherwise. + * + * The resulting effect cannot fail (`never` in the error channel) but retains + * the context of the original effect. + * + * @since 2.0.0 + * @category Condition Checking + */ +export const isSuccess: (self: Effect) => Effect = effect.isSuccess + +/** + * Handles both success and failure cases of an effect without performing side + * effects. + * + * **Details** + * + * `match` lets you define custom handlers for both success and failure + * scenarios. You provide separate functions to handle each case, allowing you + * to process the result if the effect succeeds, or handle the error if the + * effect fails. + * + * **When to Use** + * + * This is useful for structuring your code to respond differently to success or + * failure without triggering side effects. + * + * **Example** (Handling Both Success and Failure Cases) + * + * ```ts + * import { Effect } from "effect" + * + * const success: Effect.Effect = Effect.succeed(42) + * + * const program1 = Effect.match(success, { + * onFailure: (error) => `failure: ${error.message}`, + * onSuccess: (value) => `success: ${value}` + * }) + * + * // Run and log the result of the successful effect + * Effect.runPromise(program1).then(console.log) + * // Output: "success: 42" + * + * const failure: Effect.Effect = Effect.fail( + * new Error("Uh oh!") + * ) + * + * const program2 = Effect.match(failure, { + * onFailure: (error) => `failure: ${error.message}`, + * onSuccess: (value) => `success: ${value}` + * }) + * + * // Run and log the result of the failed effect + * Effect.runPromise(program2).then(console.log) + * // Output: "failure: Uh oh!" + * ``` + * + * @see {@link matchEffect} if you need to perform side effects in the handlers. + * + * @since 2.0.0 + * @category Matching + */ +export const match: { + /** + * Handles both success and failure cases of an effect without performing side + * effects. + * + * **Details** + * + * `match` lets you define custom handlers for both success and failure + * scenarios. You provide separate functions to handle each case, allowing you + * to process the result if the effect succeeds, or handle the error if the + * effect fails. + * + * **When to Use** + * + * This is useful for structuring your code to respond differently to success or + * failure without triggering side effects. + * + * **Example** (Handling Both Success and Failure Cases) + * + * ```ts + * import { Effect } from "effect" + * + * const success: Effect.Effect = Effect.succeed(42) + * + * const program1 = Effect.match(success, { + * onFailure: (error) => `failure: ${error.message}`, + * onSuccess: (value) => `success: ${value}` + * }) + * + * // Run and log the result of the successful effect + * Effect.runPromise(program1).then(console.log) + * // Output: "success: 42" + * + * const failure: Effect.Effect = Effect.fail( + * new Error("Uh oh!") + * ) + * + * const program2 = Effect.match(failure, { + * onFailure: (error) => `failure: ${error.message}`, + * onSuccess: (value) => `success: ${value}` + * }) + * + * // Run and log the result of the failed effect + * Effect.runPromise(program2).then(console.log) + * // Output: "failure: Uh oh!" + * ``` + * + * @see {@link matchEffect} if you need to perform side effects in the handlers. + * + * @since 2.0.0 + * @category Matching + */ + ( + options: { + readonly onFailure: (error: E) => A2 + readonly onSuccess: (value: A) => A3 + } + ): (self: Effect) => Effect + /** + * Handles both success and failure cases of an effect without performing side + * effects. + * + * **Details** + * + * `match` lets you define custom handlers for both success and failure + * scenarios. You provide separate functions to handle each case, allowing you + * to process the result if the effect succeeds, or handle the error if the + * effect fails. + * + * **When to Use** + * + * This is useful for structuring your code to respond differently to success or + * failure without triggering side effects. + * + * **Example** (Handling Both Success and Failure Cases) + * + * ```ts + * import { Effect } from "effect" + * + * const success: Effect.Effect = Effect.succeed(42) + * + * const program1 = Effect.match(success, { + * onFailure: (error) => `failure: ${error.message}`, + * onSuccess: (value) => `success: ${value}` + * }) + * + * // Run and log the result of the successful effect + * Effect.runPromise(program1).then(console.log) + * // Output: "success: 42" + * + * const failure: Effect.Effect = Effect.fail( + * new Error("Uh oh!") + * ) + * + * const program2 = Effect.match(failure, { + * onFailure: (error) => `failure: ${error.message}`, + * onSuccess: (value) => `success: ${value}` + * }) + * + * // Run and log the result of the failed effect + * Effect.runPromise(program2).then(console.log) + * // Output: "failure: Uh oh!" + * ``` + * + * @see {@link matchEffect} if you need to perform side effects in the handlers. + * + * @since 2.0.0 + * @category Matching + */ + ( + self: Effect, + options: { + readonly onFailure: (error: E) => A2 + readonly onSuccess: (value: A) => A3 + } + ): Effect +} = effect.match + +/** + * Handles failures by matching the cause of failure. + * + * **Details** + * + * The `matchCause` function allows you to handle failures with access to the + * full cause of the failure within a fiber. + * + * **When to Use** + * + * This is useful for differentiating between different types of errors, such as + * regular failures, defects, or interruptions. You can provide specific + * handling logic for each failure type based on the cause. + * + * **Example** (Handling Different Failure Causes) + * + * ```ts + * import { Effect } from "effect" + * + * const task: Effect.Effect = Effect.die("Uh oh!") + * + * const program = Effect.matchCause(task, { + * onFailure: (cause) => { + * switch (cause._tag) { + * case "Fail": + * // Handle standard failure + * return `Fail: ${cause.error.message}` + * case "Die": + * // Handle defects (unexpected errors) + * return `Die: ${cause.defect}` + * case "Interrupt": + * // Handle interruption + * return `${cause.fiberId} interrupted!` + * } + * // Fallback for other causes + * return "failed due to other causes" + * }, + * onSuccess: (value) => + * // task completes successfully + * `succeeded with ${value} value` + * }) + * + * Effect.runPromise(program).then(console.log) + * // Output: "Die: Uh oh!" + * ``` + * + * @see {@link matchCauseEffect} if you need to perform side effects in the + * handlers. + * @see {@link match} if you don't need to handle the cause of the failure. + * + * @since 2.0.0 + * @category Matching + */ +export const matchCause: { + /** + * Handles failures by matching the cause of failure. + * + * **Details** + * + * The `matchCause` function allows you to handle failures with access to the + * full cause of the failure within a fiber. + * + * **When to Use** + * + * This is useful for differentiating between different types of errors, such as + * regular failures, defects, or interruptions. You can provide specific + * handling logic for each failure type based on the cause. + * + * **Example** (Handling Different Failure Causes) + * + * ```ts + * import { Effect } from "effect" + * + * const task: Effect.Effect = Effect.die("Uh oh!") + * + * const program = Effect.matchCause(task, { + * onFailure: (cause) => { + * switch (cause._tag) { + * case "Fail": + * // Handle standard failure + * return `Fail: ${cause.error.message}` + * case "Die": + * // Handle defects (unexpected errors) + * return `Die: ${cause.defect}` + * case "Interrupt": + * // Handle interruption + * return `${cause.fiberId} interrupted!` + * } + * // Fallback for other causes + * return "failed due to other causes" + * }, + * onSuccess: (value) => + * // task completes successfully + * `succeeded with ${value} value` + * }) + * + * Effect.runPromise(program).then(console.log) + * // Output: "Die: Uh oh!" + * ``` + * + * @see {@link matchCauseEffect} if you need to perform side effects in the + * handlers. + * @see {@link match} if you don't need to handle the cause of the failure. + * + * @since 2.0.0 + * @category Matching + */ + ( + options: { + readonly onFailure: (cause: Cause.Cause) => A2 + readonly onSuccess: (a: A) => A3 + } + ): (self: Effect) => Effect + /** + * Handles failures by matching the cause of failure. + * + * **Details** + * + * The `matchCause` function allows you to handle failures with access to the + * full cause of the failure within a fiber. + * + * **When to Use** + * + * This is useful for differentiating between different types of errors, such as + * regular failures, defects, or interruptions. You can provide specific + * handling logic for each failure type based on the cause. + * + * **Example** (Handling Different Failure Causes) + * + * ```ts + * import { Effect } from "effect" + * + * const task: Effect.Effect = Effect.die("Uh oh!") + * + * const program = Effect.matchCause(task, { + * onFailure: (cause) => { + * switch (cause._tag) { + * case "Fail": + * // Handle standard failure + * return `Fail: ${cause.error.message}` + * case "Die": + * // Handle defects (unexpected errors) + * return `Die: ${cause.defect}` + * case "Interrupt": + * // Handle interruption + * return `${cause.fiberId} interrupted!` + * } + * // Fallback for other causes + * return "failed due to other causes" + * }, + * onSuccess: (value) => + * // task completes successfully + * `succeeded with ${value} value` + * }) + * + * Effect.runPromise(program).then(console.log) + * // Output: "Die: Uh oh!" + * ``` + * + * @see {@link matchCauseEffect} if you need to perform side effects in the + * handlers. + * @see {@link match} if you don't need to handle the cause of the failure. + * + * @since 2.0.0 + * @category Matching + */ + ( + self: Effect, + options: { + readonly onFailure: (cause: Cause.Cause) => A2 + readonly onSuccess: (a: A) => A3 + } + ): Effect +} = core.matchCause + +/** + * Handles failures with access to the cause and allows performing side effects. + * + * **Details** + * + * The `matchCauseEffect` function works similarly to {@link matchCause}, but it + * also allows you to perform additional side effects based on the failure + * cause. This function provides access to the complete cause of the failure, + * making it possible to differentiate between various failure types, and allows + * you to respond accordingly while performing side effects (like logging or + * other operations). + * + * **Example** (Handling Different Failure Causes with Side Effects) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task: Effect.Effect = Effect.die("Uh oh!") + * + * const program = Effect.matchCauseEffect(task, { + * onFailure: (cause) => { + * switch (cause._tag) { + * case "Fail": + * // Handle standard failure with a logged message + * return Console.log(`Fail: ${cause.error.message}`) + * case "Die": + * // Handle defects (unexpected errors) by logging the defect + * return Console.log(`Die: ${cause.defect}`) + * case "Interrupt": + * // Handle interruption and log the fiberId that was interrupted + * return Console.log(`${cause.fiberId} interrupted!`) + * } + * // Fallback for other causes + * return Console.log("failed due to other causes") + * }, + * onSuccess: (value) => + * // Log success if the task completes successfully + * Console.log(`succeeded with ${value} value`) + * }) + * + * Effect.runPromise(program) + * // Output: "Die: Uh oh!" + * ``` + * + * @see {@link matchCause} if you don't need side effects and only want to handle the result or failure. + * @see {@link matchEffect} if you don't need to handle the cause of the failure. + * + * @since 2.0.0 + * @category Matching + */ +export const matchCauseEffect: { + /** + * Handles failures with access to the cause and allows performing side effects. + * + * **Details** + * + * The `matchCauseEffect` function works similarly to {@link matchCause}, but it + * also allows you to perform additional side effects based on the failure + * cause. This function provides access to the complete cause of the failure, + * making it possible to differentiate between various failure types, and allows + * you to respond accordingly while performing side effects (like logging or + * other operations). + * + * **Example** (Handling Different Failure Causes with Side Effects) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task: Effect.Effect = Effect.die("Uh oh!") + * + * const program = Effect.matchCauseEffect(task, { + * onFailure: (cause) => { + * switch (cause._tag) { + * case "Fail": + * // Handle standard failure with a logged message + * return Console.log(`Fail: ${cause.error.message}`) + * case "Die": + * // Handle defects (unexpected errors) by logging the defect + * return Console.log(`Die: ${cause.defect}`) + * case "Interrupt": + * // Handle interruption and log the fiberId that was interrupted + * return Console.log(`${cause.fiberId} interrupted!`) + * } + * // Fallback for other causes + * return Console.log("failed due to other causes") + * }, + * onSuccess: (value) => + * // Log success if the task completes successfully + * Console.log(`succeeded with ${value} value`) + * }) + * + * Effect.runPromise(program) + * // Output: "Die: Uh oh!" + * ``` + * + * @see {@link matchCause} if you don't need side effects and only want to handle the result or failure. + * @see {@link matchEffect} if you don't need to handle the cause of the failure. + * + * @since 2.0.0 + * @category Matching + */ + ( + options: { + readonly onFailure: (cause: Cause.Cause) => Effect + readonly onSuccess: (a: A) => Effect + } + ): (self: Effect) => Effect + /** + * Handles failures with access to the cause and allows performing side effects. + * + * **Details** + * + * The `matchCauseEffect` function works similarly to {@link matchCause}, but it + * also allows you to perform additional side effects based on the failure + * cause. This function provides access to the complete cause of the failure, + * making it possible to differentiate between various failure types, and allows + * you to respond accordingly while performing side effects (like logging or + * other operations). + * + * **Example** (Handling Different Failure Causes with Side Effects) + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task: Effect.Effect = Effect.die("Uh oh!") + * + * const program = Effect.matchCauseEffect(task, { + * onFailure: (cause) => { + * switch (cause._tag) { + * case "Fail": + * // Handle standard failure with a logged message + * return Console.log(`Fail: ${cause.error.message}`) + * case "Die": + * // Handle defects (unexpected errors) by logging the defect + * return Console.log(`Die: ${cause.defect}`) + * case "Interrupt": + * // Handle interruption and log the fiberId that was interrupted + * return Console.log(`${cause.fiberId} interrupted!`) + * } + * // Fallback for other causes + * return Console.log("failed due to other causes") + * }, + * onSuccess: (value) => + * // Log success if the task completes successfully + * Console.log(`succeeded with ${value} value`) + * }) + * + * Effect.runPromise(program) + * // Output: "Die: Uh oh!" + * ``` + * + * @see {@link matchCause} if you don't need side effects and only want to handle the result or failure. + * @see {@link matchEffect} if you don't need to handle the cause of the failure. + * + * @since 2.0.0 + * @category Matching + */ + ( + self: Effect, + options: { + readonly onFailure: (cause: Cause.Cause) => Effect + readonly onSuccess: (a: A) => Effect + } + ): Effect +} = core.matchCauseEffect + +/** + * Handles both success and failure cases of an effect, allowing for additional + * side effects. + * + * **Details** + * + * The `matchEffect` function is similar to {@link match}, but it enables you to + * perform side effects in the handlers for both success and failure outcomes. + * + * **When to Use** + * + * This is useful when you need to execute additional actions, like logging or + * notifying users, based on whether an effect succeeds or fails. + * + * **Example** (Handling Both Success and Failure Cases with Side Effects) + * + * ```ts + * import { Effect } from "effect" + * + * const success: Effect.Effect = Effect.succeed(42) + * const failure: Effect.Effect = Effect.fail( + * new Error("Uh oh!") + * ) + * + * const program1 = Effect.matchEffect(success, { + * onFailure: (error) => + * Effect.succeed(`failure: ${error.message}`).pipe( + * Effect.tap(Effect.log) + * ), + * onSuccess: (value) => + * Effect.succeed(`success: ${value}`).pipe(Effect.tap(Effect.log)) + * }) + * + * console.log(Effect.runSync(program1)) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="success: 42" + * // success: 42 + * + * const program2 = Effect.matchEffect(failure, { + * onFailure: (error) => + * Effect.succeed(`failure: ${error.message}`).pipe( + * Effect.tap(Effect.log) + * ), + * onSuccess: (value) => + * Effect.succeed(`success: ${value}`).pipe(Effect.tap(Effect.log)) + * }) + * + * console.log(Effect.runSync(program2)) + * // Output: + * // timestamp=... level=INFO fiber=#1 message="failure: Uh oh!" + * // failure: Uh oh! + * ``` + * + * @see {@link match} if you don't need side effects and only want to handle the + * result or failure. + * + * @since 2.0.0 + * @category Matching + */ +export const matchEffect: { + /** + * Handles both success and failure cases of an effect, allowing for additional + * side effects. + * + * **Details** + * + * The `matchEffect` function is similar to {@link match}, but it enables you to + * perform side effects in the handlers for both success and failure outcomes. + * + * **When to Use** + * + * This is useful when you need to execute additional actions, like logging or + * notifying users, based on whether an effect succeeds or fails. + * + * **Example** (Handling Both Success and Failure Cases with Side Effects) + * + * ```ts + * import { Effect } from "effect" + * + * const success: Effect.Effect = Effect.succeed(42) + * const failure: Effect.Effect = Effect.fail( + * new Error("Uh oh!") + * ) + * + * const program1 = Effect.matchEffect(success, { + * onFailure: (error) => + * Effect.succeed(`failure: ${error.message}`).pipe( + * Effect.tap(Effect.log) + * ), + * onSuccess: (value) => + * Effect.succeed(`success: ${value}`).pipe(Effect.tap(Effect.log)) + * }) + * + * console.log(Effect.runSync(program1)) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="success: 42" + * // success: 42 + * + * const program2 = Effect.matchEffect(failure, { + * onFailure: (error) => + * Effect.succeed(`failure: ${error.message}`).pipe( + * Effect.tap(Effect.log) + * ), + * onSuccess: (value) => + * Effect.succeed(`success: ${value}`).pipe(Effect.tap(Effect.log)) + * }) + * + * console.log(Effect.runSync(program2)) + * // Output: + * // timestamp=... level=INFO fiber=#1 message="failure: Uh oh!" + * // failure: Uh oh! + * ``` + * + * @see {@link match} if you don't need side effects and only want to handle the + * result or failure. + * + * @since 2.0.0 + * @category Matching + */ + ( + options: { + readonly onFailure: (e: E) => Effect + readonly onSuccess: (a: A) => Effect + } + ): (self: Effect) => Effect + /** + * Handles both success and failure cases of an effect, allowing for additional + * side effects. + * + * **Details** + * + * The `matchEffect` function is similar to {@link match}, but it enables you to + * perform side effects in the handlers for both success and failure outcomes. + * + * **When to Use** + * + * This is useful when you need to execute additional actions, like logging or + * notifying users, based on whether an effect succeeds or fails. + * + * **Example** (Handling Both Success and Failure Cases with Side Effects) + * + * ```ts + * import { Effect } from "effect" + * + * const success: Effect.Effect = Effect.succeed(42) + * const failure: Effect.Effect = Effect.fail( + * new Error("Uh oh!") + * ) + * + * const program1 = Effect.matchEffect(success, { + * onFailure: (error) => + * Effect.succeed(`failure: ${error.message}`).pipe( + * Effect.tap(Effect.log) + * ), + * onSuccess: (value) => + * Effect.succeed(`success: ${value}`).pipe(Effect.tap(Effect.log)) + * }) + * + * console.log(Effect.runSync(program1)) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="success: 42" + * // success: 42 + * + * const program2 = Effect.matchEffect(failure, { + * onFailure: (error) => + * Effect.succeed(`failure: ${error.message}`).pipe( + * Effect.tap(Effect.log) + * ), + * onSuccess: (value) => + * Effect.succeed(`success: ${value}`).pipe(Effect.tap(Effect.log)) + * }) + * + * console.log(Effect.runSync(program2)) + * // Output: + * // timestamp=... level=INFO fiber=#1 message="failure: Uh oh!" + * // failure: Uh oh! + * ``` + * + * @see {@link match} if you don't need side effects and only want to handle the + * result or failure. + * + * @since 2.0.0 + * @category Matching + */ + ( + self: Effect, + options: { + readonly onFailure: (e: E) => Effect + readonly onSuccess: (a: A) => Effect + } + ): Effect +} = core.matchEffect + +/** + * Logs one or more messages or error causes at the current log level. + * + * **Details** + * + * This function provides a simple way to log messages or error causes during + * the execution of your effects. By default, logs are recorded at the `INFO` + * level, but this can be adjusted using other logging utilities + * (`Logger.withMinimumLogLevel`). Multiple items, including `Cause` instances, + * can be logged in a single call. When logging `Cause` instances, detailed + * error information is included in the log output. + * + * The log output includes useful metadata like the current timestamp, log + * level, and fiber ID, making it suitable for debugging and tracking purposes. + * This function does not interrupt or alter the effect's execution flow. + * + * **Example** + * + * ```ts + * import { Cause, Effect } from "effect" + * + * const program = Effect.log( + * "message1", + * "message2", + * Cause.die("Oh no!"), + * Cause.die("Oh uh!") + * ) + * + * Effect.runFork(program) + * // Output: + * // timestamp=... level=INFO fiber=#0 message=message1 message=message2 cause="Error: Oh no! + * // Error: Oh uh!" + * ``` + * + * @since 2.0.0 + * @category Logging + */ +export const log: (...message: ReadonlyArray) => Effect = effect.log + +/** + * Logs messages or error causes at a specified log level. + * + * **Details** + * + * This function allows you to log one or more messages or error causes while + * specifying the desired log level (e.g., DEBUG, INFO, ERROR). It provides + * flexibility in categorizing logs based on their importance or severity, + * making it easier to filter logs during debugging or production monitoring. + * + * **Example** + * + * ```ts + * import { Cause, Effect, LogLevel } from "effect" + * + * const program = Effect.logWithLevel( + * LogLevel.Error, + * "Critical error encountered", + * Cause.die("System failure!") + * ) + * + * Effect.runFork(program) + * // Output: + * // timestamp=... level=ERROR fiber=#0 message=Critical error encountered cause="Error: System failure!" + * ``` + * + * @since 2.0.0 + * @category Logging + */ +export const logWithLevel = ( + level: LogLevel.LogLevel, + ...message: ReadonlyArray +): Effect => effect.logWithLevel(level)(...message) + +/** + * Logs messages at the TRACE log level. + * + * **Details** + * + * This function logs the specified messages at the TRACE level. TRACE logs are + * typically used for very detailed diagnostic information. These messages are + * not displayed by default. To view them, you must adjust the logging + * configuration by setting the minimum log level to `LogLevel.Trace` using + * `Logger.withMinimumLogLevel`. + * + * **Example** + * + * ```ts + * import { Effect, Logger, LogLevel } from "effect" + * + * const program = Effect.logTrace("message1").pipe(Logger.withMinimumLogLevel(LogLevel.Trace)) + * + * Effect.runFork(program) + * // timestamp=... level=TRACE fiber=#0 message=message1 + * ``` + * + * @since 2.0.0 + * @category Logging + */ +export const logTrace: (...message: ReadonlyArray) => Effect = effect.logTrace + +/** + * Logs messages at the DEBUG log level. + * + * **Details** + * + * This function logs messages at the DEBUG level, which is typically used for + * diagnosing application behavior during development. DEBUG messages provide + * less detailed information than TRACE logs but are still not shown by default. + * To view these logs, adjust the log level using `Logger.withMinimumLogLevel`. + * + * **Example** + * + * ```ts + * import { Effect, Logger, LogLevel } from "effect" + * + * const program = Effect.logDebug("message1").pipe(Logger.withMinimumLogLevel(LogLevel.Debug)) + * + * Effect.runFork(program) + * // timestamp=... level=DEBUG fiber=#0 message=message1 + * ``` + * + * @since 2.0.0 + * @category Logging + */ +export const logDebug: (...message: ReadonlyArray) => Effect = effect.logDebug + +/** + * Logs messages at the INFO log level. + * + * **Details** + * + * This function logs messages at the INFO level, suitable for general + * application events or operational messages. INFO logs are shown by default + * and are commonly used for highlighting normal, non-error operations. + * + * @since 2.0.0 + * @category Logging + */ +export const logInfo: (...message: ReadonlyArray) => Effect = effect.logInfo + +/** + * Logs messages at the WARNING log level. + * + * **Details** + * + * This function logs messages at the WARNING level, suitable for highlighting + * potential issues that are not errors but may require attention. These + * messages indicate that something unexpected occurred or might lead to errors + * in the future. + * + * @since 2.0.0 + * @category Logging + */ +export const logWarning: (...message: ReadonlyArray) => Effect = effect.logWarning + +/** + * Logs messages at the ERROR log level. + * + * **Details** + * + * This function logs messages at the ERROR level, suitable for reporting + * application errors or failures. These logs are typically used for unexpected + * issues that need immediate attention. + * + * @since 2.0.0 + * @category Logging + */ +export const logError: (...message: ReadonlyArray) => Effect = effect.logError + +/** + * Logs messages at the FATAL log level. + * + * **Details** + * + * This function logs messages at the FATAL level, suitable for reporting + * critical errors that cause the application to terminate or stop functioning. + * These logs are typically used for unrecoverable errors that require immediate + * attention. + * + * @since 2.0.0 + * @category Logging + */ +export const logFatal: (...message: ReadonlyArray) => Effect = effect.logFatal + +/** + * Adds a log span to an effect for tracking and logging its execution duration. + * + * **Details** + * + * This function wraps an effect with a log span, providing performance + * monitoring and debugging capabilities. The log span tracks the duration of + * the wrapped effect and logs it with the specified label. This is particularly + * useful when analyzing time-sensitive operations or understanding the + * execution time of specific tasks in your application. + * + * The logged output will include the label and the total time taken for the + * operation. The span information is included in the log metadata, making it + * easy to trace performance metrics in logs. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * yield* Effect.sleep("1 second") + * yield* Effect.log("The job is finished!") + * }).pipe(Effect.withLogSpan("myspan")) + * + * Effect.runFork(program) + * // timestamp=... level=INFO fiber=#0 message="The job is finished!" myspan=1011ms + * ``` + * + * @since 2.0.0 + * @category Logging + */ +export const withLogSpan: { + /** + * Adds a log span to an effect for tracking and logging its execution duration. + * + * **Details** + * + * This function wraps an effect with a log span, providing performance + * monitoring and debugging capabilities. The log span tracks the duration of + * the wrapped effect and logs it with the specified label. This is particularly + * useful when analyzing time-sensitive operations or understanding the + * execution time of specific tasks in your application. + * + * The logged output will include the label and the total time taken for the + * operation. The span information is included in the log metadata, making it + * easy to trace performance metrics in logs. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * yield* Effect.sleep("1 second") + * yield* Effect.log("The job is finished!") + * }).pipe(Effect.withLogSpan("myspan")) + * + * Effect.runFork(program) + * // timestamp=... level=INFO fiber=#0 message="The job is finished!" myspan=1011ms + * ``` + * + * @since 2.0.0 + * @category Logging + */ + (label: string): (effect: Effect) => Effect + /** + * Adds a log span to an effect for tracking and logging its execution duration. + * + * **Details** + * + * This function wraps an effect with a log span, providing performance + * monitoring and debugging capabilities. The log span tracks the duration of + * the wrapped effect and logs it with the specified label. This is particularly + * useful when analyzing time-sensitive operations or understanding the + * execution time of specific tasks in your application. + * + * The logged output will include the label and the total time taken for the + * operation. The span information is included in the log metadata, making it + * easy to trace performance metrics in logs. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * yield* Effect.sleep("1 second") + * yield* Effect.log("The job is finished!") + * }).pipe(Effect.withLogSpan("myspan")) + * + * Effect.runFork(program) + * // timestamp=... level=INFO fiber=#0 message="The job is finished!" myspan=1011ms + * ``` + * + * @since 2.0.0 + * @category Logging + */ + (effect: Effect, label: string): Effect +} = effect.withLogSpan + +/** + * Adds custom annotations to log entries generated within an effect. + * + * **Details** + * + * This function allows you to enhance log messages by appending additional + * context in the form of key-value pairs. These annotations are included in + * every log message created during the execution of the effect, making the logs + * more informative and easier to trace. + * + * The annotations can be specified as a single key-value pair or as a record of + * multiple key-value pairs. This is particularly useful for tracking + * operations, debugging, or associating specific metadata with logs for better + * observability. + * + * The annotated key-value pairs will appear alongside the log message in the + * output. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * yield* Effect.log("message1") + * yield* Effect.log("message2") + * }).pipe(Effect.annotateLogs("taskId", "1234")) // Annotation as key/value pair + * + * Effect.runFork(program) + * // timestamp=... level=INFO fiber=#0 message=message1 taskId=1234 + * // timestamp=... level=INFO fiber=#0 message=message2 taskId=1234 + * ``` + * + * @see {@link annotateLogsScoped} to add log annotations with a limited scope. + * + * @since 2.0.0 + * @category Logging + */ +export const annotateLogs: { + /** + * Adds custom annotations to log entries generated within an effect. + * + * **Details** + * + * This function allows you to enhance log messages by appending additional + * context in the form of key-value pairs. These annotations are included in + * every log message created during the execution of the effect, making the logs + * more informative and easier to trace. + * + * The annotations can be specified as a single key-value pair or as a record of + * multiple key-value pairs. This is particularly useful for tracking + * operations, debugging, or associating specific metadata with logs for better + * observability. + * + * The annotated key-value pairs will appear alongside the log message in the + * output. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * yield* Effect.log("message1") + * yield* Effect.log("message2") + * }).pipe(Effect.annotateLogs("taskId", "1234")) // Annotation as key/value pair + * + * Effect.runFork(program) + * // timestamp=... level=INFO fiber=#0 message=message1 taskId=1234 + * // timestamp=... level=INFO fiber=#0 message=message2 taskId=1234 + * ``` + * + * @see {@link annotateLogsScoped} to add log annotations with a limited scope. + * + * @since 2.0.0 + * @category Logging + */ + (key: string, value: unknown): (effect: Effect) => Effect + /** + * Adds custom annotations to log entries generated within an effect. + * + * **Details** + * + * This function allows you to enhance log messages by appending additional + * context in the form of key-value pairs. These annotations are included in + * every log message created during the execution of the effect, making the logs + * more informative and easier to trace. + * + * The annotations can be specified as a single key-value pair or as a record of + * multiple key-value pairs. This is particularly useful for tracking + * operations, debugging, or associating specific metadata with logs for better + * observability. + * + * The annotated key-value pairs will appear alongside the log message in the + * output. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * yield* Effect.log("message1") + * yield* Effect.log("message2") + * }).pipe(Effect.annotateLogs("taskId", "1234")) // Annotation as key/value pair + * + * Effect.runFork(program) + * // timestamp=... level=INFO fiber=#0 message=message1 taskId=1234 + * // timestamp=... level=INFO fiber=#0 message=message2 taskId=1234 + * ``` + * + * @see {@link annotateLogsScoped} to add log annotations with a limited scope. + * + * @since 2.0.0 + * @category Logging + */ + (values: Record): (effect: Effect) => Effect + /** + * Adds custom annotations to log entries generated within an effect. + * + * **Details** + * + * This function allows you to enhance log messages by appending additional + * context in the form of key-value pairs. These annotations are included in + * every log message created during the execution of the effect, making the logs + * more informative and easier to trace. + * + * The annotations can be specified as a single key-value pair or as a record of + * multiple key-value pairs. This is particularly useful for tracking + * operations, debugging, or associating specific metadata with logs for better + * observability. + * + * The annotated key-value pairs will appear alongside the log message in the + * output. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * yield* Effect.log("message1") + * yield* Effect.log("message2") + * }).pipe(Effect.annotateLogs("taskId", "1234")) // Annotation as key/value pair + * + * Effect.runFork(program) + * // timestamp=... level=INFO fiber=#0 message=message1 taskId=1234 + * // timestamp=... level=INFO fiber=#0 message=message2 taskId=1234 + * ``` + * + * @see {@link annotateLogsScoped} to add log annotations with a limited scope. + * + * @since 2.0.0 + * @category Logging + */ + (effect: Effect, key: string, value: unknown): Effect + /** + * Adds custom annotations to log entries generated within an effect. + * + * **Details** + * + * This function allows you to enhance log messages by appending additional + * context in the form of key-value pairs. These annotations are included in + * every log message created during the execution of the effect, making the logs + * more informative and easier to trace. + * + * The annotations can be specified as a single key-value pair or as a record of + * multiple key-value pairs. This is particularly useful for tracking + * operations, debugging, or associating specific metadata with logs for better + * observability. + * + * The annotated key-value pairs will appear alongside the log message in the + * output. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * yield* Effect.log("message1") + * yield* Effect.log("message2") + * }).pipe(Effect.annotateLogs("taskId", "1234")) // Annotation as key/value pair + * + * Effect.runFork(program) + * // timestamp=... level=INFO fiber=#0 message=message1 taskId=1234 + * // timestamp=... level=INFO fiber=#0 message=message2 taskId=1234 + * ``` + * + * @see {@link annotateLogsScoped} to add log annotations with a limited scope. + * + * @since 2.0.0 + * @category Logging + */ + (effect: Effect, values: Record): Effect +} = effect.annotateLogs + +/** + * Adds log annotations with a limited scope to enhance contextual logging. + * + * **Details** + * + * This function allows you to apply key-value annotations to log entries + * generated within a specific scope of your effect computations. The + * annotations are restricted to the defined `Scope`, ensuring that they are + * only applied to logs produced during that scope. Once the scope ends, the + * annotations are automatically removed, making it easier to manage + * context-specific logging without affecting other parts of your application. + * + * The annotations can be provided as a single key-value pair or as a record of + * multiple key-value pairs. This flexibility enables fine-grained control over + * the additional metadata included in logs for specific tasks or operations. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * yield* Effect.log("no annotations") + * yield* Effect.annotateLogsScoped({ key: "value" }) + * yield* Effect.log("message1") // Annotation is applied to this log + * yield* Effect.log("message2") // Annotation is applied to this log + * }).pipe(Effect.scoped, Effect.andThen(Effect.log("no annotations again"))) + * + * Effect.runFork(program) + * // timestamp=... level=INFO fiber=#0 message="no annotations" + * // timestamp=... level=INFO fiber=#0 message=message1 key=value + * // timestamp=... level=INFO fiber=#0 message=message2 key=value + * // timestamp=... level=INFO fiber=#0 message="no annotations again" + * ``` + * + * @see {@link annotateLogs} to add custom annotations to log entries generated within an effect. + * + * @since 3.1.0 + * @category Logging + */ +export const annotateLogsScoped: { + /** + * Adds log annotations with a limited scope to enhance contextual logging. + * + * **Details** + * + * This function allows you to apply key-value annotations to log entries + * generated within a specific scope of your effect computations. The + * annotations are restricted to the defined `Scope`, ensuring that they are + * only applied to logs produced during that scope. Once the scope ends, the + * annotations are automatically removed, making it easier to manage + * context-specific logging without affecting other parts of your application. + * + * The annotations can be provided as a single key-value pair or as a record of + * multiple key-value pairs. This flexibility enables fine-grained control over + * the additional metadata included in logs for specific tasks or operations. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * yield* Effect.log("no annotations") + * yield* Effect.annotateLogsScoped({ key: "value" }) + * yield* Effect.log("message1") // Annotation is applied to this log + * yield* Effect.log("message2") // Annotation is applied to this log + * }).pipe(Effect.scoped, Effect.andThen(Effect.log("no annotations again"))) + * + * Effect.runFork(program) + * // timestamp=... level=INFO fiber=#0 message="no annotations" + * // timestamp=... level=INFO fiber=#0 message=message1 key=value + * // timestamp=... level=INFO fiber=#0 message=message2 key=value + * // timestamp=... level=INFO fiber=#0 message="no annotations again" + * ``` + * + * @see {@link annotateLogs} to add custom annotations to log entries generated within an effect. + * + * @since 3.1.0 + * @category Logging + */ + (key: string, value: unknown): Effect + /** + * Adds log annotations with a limited scope to enhance contextual logging. + * + * **Details** + * + * This function allows you to apply key-value annotations to log entries + * generated within a specific scope of your effect computations. The + * annotations are restricted to the defined `Scope`, ensuring that they are + * only applied to logs produced during that scope. Once the scope ends, the + * annotations are automatically removed, making it easier to manage + * context-specific logging without affecting other parts of your application. + * + * The annotations can be provided as a single key-value pair or as a record of + * multiple key-value pairs. This flexibility enables fine-grained control over + * the additional metadata included in logs for specific tasks or operations. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.gen(function*() { + * yield* Effect.log("no annotations") + * yield* Effect.annotateLogsScoped({ key: "value" }) + * yield* Effect.log("message1") // Annotation is applied to this log + * yield* Effect.log("message2") // Annotation is applied to this log + * }).pipe(Effect.scoped, Effect.andThen(Effect.log("no annotations again"))) + * + * Effect.runFork(program) + * // timestamp=... level=INFO fiber=#0 message="no annotations" + * // timestamp=... level=INFO fiber=#0 message=message1 key=value + * // timestamp=... level=INFO fiber=#0 message=message2 key=value + * // timestamp=... level=INFO fiber=#0 message="no annotations again" + * ``` + * + * @see {@link annotateLogs} to add custom annotations to log entries generated within an effect. + * + * @since 3.1.0 + * @category Logging + */ + (values: Record): Effect +} = fiberRuntime.annotateLogsScoped + +/** + * Retrieves the current log annotations for the current scope. + * + * **Details** + * + * This function provides access to the log annotations associated with the + * current scope. Log annotations are key-value pairs that provide additional + * context to log entries. They are often used to add metadata such as tags, + * identifiers, or extra debugging information to logs. + * + * By using this function, you can inspect or utilize the annotations applied to + * the current scope, making it easier to trace and debug specific sections of + * your application. + * + * @see {@link annotateLogs} to add custom annotations to log entries generated within an effect. + * @see {@link annotateLogsScoped} to add log annotations with a limited scope. + * + * @since 2.0.0 + * @category Logging + */ +export const logAnnotations: Effect> = effect.logAnnotations + +/** + * Configures whether child fibers will log unhandled errors and at what log + * level. + * + * **Details** + * + * This function allows you to control whether unhandled errors from child + * fibers are logged and to specify the log level for these errors. By default, + * unhandled errors are reported via the logger. However, using this function, + * you can choose to suppress these logs by passing `Option.none` or adjust the + * log level to a specific severity, such as `Error`, `Warning`, or `Info`. + * + * This configuration is scoped to the effect it is applied to, meaning the + * changes only apply to the child fibers created within that effect's context. + * It is especially useful when you want to reduce noise in logs or prioritize + * certain types of errors. + * + * **Example** + * + * ```ts + * import { Effect, Fiber, LogLevel, Option } from "effect" + * + * const program = Effect.gen(function*() { + * const fiber = yield* Effect.fork(Effect.fail("Unhandled error!")) + * yield* Fiber.join(fiber) + * }) + * + * Effect.runFork(program.pipe(Effect.withUnhandledErrorLogLevel(Option.some(LogLevel.Error)))) + * // Output: + * // timestamp=... level=ERROR fiber=#1 message="Fiber terminated with an unhandled error" cause="Error: Unhandled error!" + * ``` + * + * @since 2.0.0 + * @category Logging + */ +export const withUnhandledErrorLogLevel: { + /** + * Configures whether child fibers will log unhandled errors and at what log + * level. + * + * **Details** + * + * This function allows you to control whether unhandled errors from child + * fibers are logged and to specify the log level for these errors. By default, + * unhandled errors are reported via the logger. However, using this function, + * you can choose to suppress these logs by passing `Option.none` or adjust the + * log level to a specific severity, such as `Error`, `Warning`, or `Info`. + * + * This configuration is scoped to the effect it is applied to, meaning the + * changes only apply to the child fibers created within that effect's context. + * It is especially useful when you want to reduce noise in logs or prioritize + * certain types of errors. + * + * **Example** + * + * ```ts + * import { Effect, Fiber, LogLevel, Option } from "effect" + * + * const program = Effect.gen(function*() { + * const fiber = yield* Effect.fork(Effect.fail("Unhandled error!")) + * yield* Fiber.join(fiber) + * }) + * + * Effect.runFork(program.pipe(Effect.withUnhandledErrorLogLevel(Option.some(LogLevel.Error)))) + * // Output: + * // timestamp=... level=ERROR fiber=#1 message="Fiber terminated with an unhandled error" cause="Error: Unhandled error!" + * ``` + * + * @since 2.0.0 + * @category Logging + */ + (level: Option.Option): (self: Effect) => Effect + /** + * Configures whether child fibers will log unhandled errors and at what log + * level. + * + * **Details** + * + * This function allows you to control whether unhandled errors from child + * fibers are logged and to specify the log level for these errors. By default, + * unhandled errors are reported via the logger. However, using this function, + * you can choose to suppress these logs by passing `Option.none` or adjust the + * log level to a specific severity, such as `Error`, `Warning`, or `Info`. + * + * This configuration is scoped to the effect it is applied to, meaning the + * changes only apply to the child fibers created within that effect's context. + * It is especially useful when you want to reduce noise in logs or prioritize + * certain types of errors. + * + * **Example** + * + * ```ts + * import { Effect, Fiber, LogLevel, Option } from "effect" + * + * const program = Effect.gen(function*() { + * const fiber = yield* Effect.fork(Effect.fail("Unhandled error!")) + * yield* Fiber.join(fiber) + * }) + * + * Effect.runFork(program.pipe(Effect.withUnhandledErrorLogLevel(Option.some(LogLevel.Error)))) + * // Output: + * // timestamp=... level=ERROR fiber=#1 message="Fiber terminated with an unhandled error" cause="Error: Unhandled error!" + * ``` + * + * @since 2.0.0 + * @category Logging + */ + (self: Effect, level: Option.Option): Effect +} = core.withUnhandledErrorLogLevel + +/** + * Conditionally executes an effect based on the specified log level and currently enabled log level. + * + * **Details** + * + * This function runs the provided effect only if the specified log level is + * enabled. If the log level is enabled, the effect is executed and its result + * is wrapped in `Some`. If the log level is not enabled, the effect is not + * executed and `None` is returned. + * + * This function is useful for conditionally executing logging-related effects + * or other operations that depend on the current log level configuration. + * + * **Example** + * + * ```ts + * import { Effect, Logger, LogLevel } from "effect" + * + * const program = Effect.gen(function* () { + * yield* Effect.whenLogLevel(Effect.logTrace("message1"), LogLevel.Trace); // returns `None` + * yield* Effect.whenLogLevel(Effect.logDebug("message2"), LogLevel.Debug); // returns `Some` + * }).pipe(Logger.withMinimumLogLevel(LogLevel.Debug)); + * + * Effect.runFork(program) + * // timestamp=... level=DEBUG fiber=#0 message=message2 + * ``` + * + * @see {@link FiberRef.currentMinimumLogLevel} to retrieve the current minimum log level. + * + * @since 3.13.0 + * @category Logging + */ +export const whenLogLevel: { + /** + * Conditionally executes an effect based on the specified log level and currently enabled log level. + * + * **Details** + * + * This function runs the provided effect only if the specified log level is + * enabled. If the log level is enabled, the effect is executed and its result + * is wrapped in `Some`. If the log level is not enabled, the effect is not + * executed and `None` is returned. + * + * This function is useful for conditionally executing logging-related effects + * or other operations that depend on the current log level configuration. + * + * **Example** + * + * ```ts + * import { Effect, Logger, LogLevel } from "effect" + * + * const program = Effect.gen(function* () { + * yield* Effect.whenLogLevel(Effect.logTrace("message1"), LogLevel.Trace); // returns `None` + * yield* Effect.whenLogLevel(Effect.logDebug("message2"), LogLevel.Debug); // returns `Some` + * }).pipe(Logger.withMinimumLogLevel(LogLevel.Debug)); + * + * Effect.runFork(program) + * // timestamp=... level=DEBUG fiber=#0 message=message2 + * ``` + * + * @see {@link FiberRef.currentMinimumLogLevel} to retrieve the current minimum log level. + * + * @since 3.13.0 + * @category Logging + */ + (level: LogLevel.LogLevel | LogLevel.Literal): (self: Effect) => Effect, E, R> + /** + * Conditionally executes an effect based on the specified log level and currently enabled log level. + * + * **Details** + * + * This function runs the provided effect only if the specified log level is + * enabled. If the log level is enabled, the effect is executed and its result + * is wrapped in `Some`. If the log level is not enabled, the effect is not + * executed and `None` is returned. + * + * This function is useful for conditionally executing logging-related effects + * or other operations that depend on the current log level configuration. + * + * **Example** + * + * ```ts + * import { Effect, Logger, LogLevel } from "effect" + * + * const program = Effect.gen(function* () { + * yield* Effect.whenLogLevel(Effect.logTrace("message1"), LogLevel.Trace); // returns `None` + * yield* Effect.whenLogLevel(Effect.logDebug("message2"), LogLevel.Debug); // returns `Some` + * }).pipe(Logger.withMinimumLogLevel(LogLevel.Debug)); + * + * Effect.runFork(program) + * // timestamp=... level=DEBUG fiber=#0 message=message2 + * ``` + * + * @see {@link FiberRef.currentMinimumLogLevel} to retrieve the current minimum log level. + * + * @since 3.13.0 + * @category Logging + */ + (self: Effect, level: LogLevel.LogLevel | LogLevel.Literal): Effect, E, R> +} = fiberRuntime.whenLogLevel + +/** + * Converts an effect's failure into a fiber termination, removing the error + * from the effect's type. + * + * **Details** + * + * The `orDie` function is used when you encounter errors that you do not want + * to handle or recover from. It removes the error type from the effect and + * ensures that any failure will terminate the fiber. This is useful for + * propagating failures as defects, signaling that they should not be handled + * within the effect. + * + * **When to Use* + * + * Use `orDie` when failures should be treated as unrecoverable defects and no + * error handling is required. + * + * **Example** (Propagating an Error as a Defect) + * + * ```ts + * import { Effect } from "effect" + * + * const divide = (a: number, b: number) => + * b === 0 + * ? Effect.fail(new Error("Cannot divide by zero")) + * : Effect.succeed(a / b) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.orDie(divide(1, 0)) + * + * Effect.runPromise(program).catch(console.error) + * // Output: + * // (FiberFailure) Error: Cannot divide by zero + * // ...stack trace... + * ``` + * + * @see {@link orDieWith} if you need to customize the error. + * + * @since 2.0.0 + * @category Converting Failures to Defects + */ +export const orDie: (self: Effect) => Effect = core.orDie + +/** + * Converts an effect's failure into a fiber termination with a custom error. + * + * **Details** + * + * The `orDieWith` function behaves like {@link orDie}, but it allows you to provide a mapping + * function to transform the error before terminating the fiber. This is useful for cases where + * you want to include a more detailed or user-friendly error when the failure is propagated + * as a defect. + * + * **When to Use** + * + * Use `orDieWith` when failures should terminate the fiber as defects, and you want to customize + * the error for clarity or debugging purposes. + * + * **Example** (Customizing Defect) + * + * ```ts + * import { Effect } from "effect" + * + * const divide = (a: number, b: number) => + * b === 0 + * ? Effect.fail(new Error("Cannot divide by zero")) + * : Effect.succeed(a / b) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.orDieWith( + * divide(1, 0), + * (error) => new Error(`defect: ${error.message}`) + * ) + * + * Effect.runPromise(program).catch(console.error) + * // Output: + * // (FiberFailure) Error: defect: Cannot divide by zero + * // ...stack trace... + * ``` + * + * @see {@link orDie} if you don't need to customize the error. + * + * @since 2.0.0 + * @category Converting Failures to Defects + */ +export const orDieWith: { + /** + * Converts an effect's failure into a fiber termination with a custom error. + * + * **Details** + * + * The `orDieWith` function behaves like {@link orDie}, but it allows you to provide a mapping + * function to transform the error before terminating the fiber. This is useful for cases where + * you want to include a more detailed or user-friendly error when the failure is propagated + * as a defect. + * + * **When to Use** + * + * Use `orDieWith` when failures should terminate the fiber as defects, and you want to customize + * the error for clarity or debugging purposes. + * + * **Example** (Customizing Defect) + * + * ```ts + * import { Effect } from "effect" + * + * const divide = (a: number, b: number) => + * b === 0 + * ? Effect.fail(new Error("Cannot divide by zero")) + * : Effect.succeed(a / b) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.orDieWith( + * divide(1, 0), + * (error) => new Error(`defect: ${error.message}`) + * ) + * + * Effect.runPromise(program).catch(console.error) + * // Output: + * // (FiberFailure) Error: defect: Cannot divide by zero + * // ...stack trace... + * ``` + * + * @see {@link orDie} if you don't need to customize the error. + * + * @since 2.0.0 + * @category Converting Failures to Defects + */ + (f: (error: E) => unknown): (self: Effect) => Effect + /** + * Converts an effect's failure into a fiber termination with a custom error. + * + * **Details** + * + * The `orDieWith` function behaves like {@link orDie}, but it allows you to provide a mapping + * function to transform the error before terminating the fiber. This is useful for cases where + * you want to include a more detailed or user-friendly error when the failure is propagated + * as a defect. + * + * **When to Use** + * + * Use `orDieWith` when failures should terminate the fiber as defects, and you want to customize + * the error for clarity or debugging purposes. + * + * **Example** (Customizing Defect) + * + * ```ts + * import { Effect } from "effect" + * + * const divide = (a: number, b: number) => + * b === 0 + * ? Effect.fail(new Error("Cannot divide by zero")) + * : Effect.succeed(a / b) + * + * // ┌─── Effect + * // ▼ + * const program = Effect.orDieWith( + * divide(1, 0), + * (error) => new Error(`defect: ${error.message}`) + * ) + * + * Effect.runPromise(program).catch(console.error) + * // Output: + * // (FiberFailure) Error: defect: Cannot divide by zero + * // ...stack trace... + * ``` + * + * @see {@link orDie} if you don't need to customize the error. + * + * @since 2.0.0 + * @category Converting Failures to Defects + */ + (self: Effect, f: (error: E) => unknown): Effect +} = core.orDieWith + +/** + * Attempts one effect, and if it fails, falls back to another effect. + * + * **Details** + * + * This function allows you to try executing an effect, and if it fails + * (produces an error), a fallback effect is executed instead. The fallback + * effect is defined as a lazy argument, meaning it will only be evaluated if + * the first effect fails. This provides a way to recover from errors by + * specifying an alternative path of execution. + * + * The error type of the resulting effect will be that of the fallback effect, + * as the first effect's error is replaced when the fallback is executed. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const success = Effect.succeed("success") + * const failure = Effect.fail("failure") + * const fallback = Effect.succeed("fallback") + * + * // Try the success effect first, fallback is not used + * const program1 = Effect.orElse(success, () => fallback) + * console.log(Effect.runSync(program1)) + * // Output: "success" + * + * // Try the failure effect first, fallback is used + * const program2 = Effect.orElse(failure, () => fallback) + * console.log(Effect.runSync(program2)) + * // Output: "fallback" + * ``` + * + * @see {@link catchAll} if you need to access the error in the fallback effect. + * + * @since 2.0.0 + * @category Fallback + */ +export const orElse: { + /** + * Attempts one effect, and if it fails, falls back to another effect. + * + * **Details** + * + * This function allows you to try executing an effect, and if it fails + * (produces an error), a fallback effect is executed instead. The fallback + * effect is defined as a lazy argument, meaning it will only be evaluated if + * the first effect fails. This provides a way to recover from errors by + * specifying an alternative path of execution. + * + * The error type of the resulting effect will be that of the fallback effect, + * as the first effect's error is replaced when the fallback is executed. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const success = Effect.succeed("success") + * const failure = Effect.fail("failure") + * const fallback = Effect.succeed("fallback") + * + * // Try the success effect first, fallback is not used + * const program1 = Effect.orElse(success, () => fallback) + * console.log(Effect.runSync(program1)) + * // Output: "success" + * + * // Try the failure effect first, fallback is used + * const program2 = Effect.orElse(failure, () => fallback) + * console.log(Effect.runSync(program2)) + * // Output: "fallback" + * ``` + * + * @see {@link catchAll} if you need to access the error in the fallback effect. + * + * @since 2.0.0 + * @category Fallback + */ + (that: LazyArg>): (self: Effect) => Effect + /** + * Attempts one effect, and if it fails, falls back to another effect. + * + * **Details** + * + * This function allows you to try executing an effect, and if it fails + * (produces an error), a fallback effect is executed instead. The fallback + * effect is defined as a lazy argument, meaning it will only be evaluated if + * the first effect fails. This provides a way to recover from errors by + * specifying an alternative path of execution. + * + * The error type of the resulting effect will be that of the fallback effect, + * as the first effect's error is replaced when the fallback is executed. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const success = Effect.succeed("success") + * const failure = Effect.fail("failure") + * const fallback = Effect.succeed("fallback") + * + * // Try the success effect first, fallback is not used + * const program1 = Effect.orElse(success, () => fallback) + * console.log(Effect.runSync(program1)) + * // Output: "success" + * + * // Try the failure effect first, fallback is used + * const program2 = Effect.orElse(failure, () => fallback) + * console.log(Effect.runSync(program2)) + * // Output: "fallback" + * ``` + * + * @see {@link catchAll} if you need to access the error in the fallback effect. + * + * @since 2.0.0 + * @category Fallback + */ + (self: Effect, that: LazyArg>): Effect +} = core.orElse + +/** + * Replaces the failure of an effect with a custom failure value. + * + * **Details** + * + * This function allows you to handle the failure of an effect by replacing it + * with a predefined failure value. If the effect fails, the new failure value + * provided by the `evaluate` function will be returned instead of the original + * failure. If the effect succeeds, the original success value is returned + * unchanged. + * + * **When to Use** + * + * This is particularly useful when you want to standardize error handling or + * provide a consistent failure value for specific operations. It simplifies + * error management by ensuring that all failures are replaced with a controlled + * alternative. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const validate = (age: number): Effect.Effect => { + * if (age < 0) { + * return Effect.fail("NegativeAgeError") + * } else if (age < 18) { + * return Effect.fail("IllegalAgeError") + * } else { + * return Effect.succeed(age) + * } + * } + * + * const program = Effect.orElseFail(validate(-1), () => "invalid age") + * + * console.log(Effect.runSyncExit(program)) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'invalid age' } + * // } + * ``` + * + * @see {@link mapError} if you need to access the error to transform it. + * + * @since 2.0.0 + * @category Fallback + */ +export const orElseFail: { + /** + * Replaces the failure of an effect with a custom failure value. + * + * **Details** + * + * This function allows you to handle the failure of an effect by replacing it + * with a predefined failure value. If the effect fails, the new failure value + * provided by the `evaluate` function will be returned instead of the original + * failure. If the effect succeeds, the original success value is returned + * unchanged. + * + * **When to Use** + * + * This is particularly useful when you want to standardize error handling or + * provide a consistent failure value for specific operations. It simplifies + * error management by ensuring that all failures are replaced with a controlled + * alternative. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const validate = (age: number): Effect.Effect => { + * if (age < 0) { + * return Effect.fail("NegativeAgeError") + * } else if (age < 18) { + * return Effect.fail("IllegalAgeError") + * } else { + * return Effect.succeed(age) + * } + * } + * + * const program = Effect.orElseFail(validate(-1), () => "invalid age") + * + * console.log(Effect.runSyncExit(program)) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'invalid age' } + * // } + * ``` + * + * @see {@link mapError} if you need to access the error to transform it. + * + * @since 2.0.0 + * @category Fallback + */ + (evaluate: LazyArg): (self: Effect) => Effect + /** + * Replaces the failure of an effect with a custom failure value. + * + * **Details** + * + * This function allows you to handle the failure of an effect by replacing it + * with a predefined failure value. If the effect fails, the new failure value + * provided by the `evaluate` function will be returned instead of the original + * failure. If the effect succeeds, the original success value is returned + * unchanged. + * + * **When to Use** + * + * This is particularly useful when you want to standardize error handling or + * provide a consistent failure value for specific operations. It simplifies + * error management by ensuring that all failures are replaced with a controlled + * alternative. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const validate = (age: number): Effect.Effect => { + * if (age < 0) { + * return Effect.fail("NegativeAgeError") + * } else if (age < 18) { + * return Effect.fail("IllegalAgeError") + * } else { + * return Effect.succeed(age) + * } + * } + * + * const program = Effect.orElseFail(validate(-1), () => "invalid age") + * + * console.log(Effect.runSyncExit(program)) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { _id: 'Cause', _tag: 'Fail', failure: 'invalid age' } + * // } + * ``` + * + * @see {@link mapError} if you need to access the error to transform it. + * + * @since 2.0.0 + * @category Fallback + */ + (self: Effect, evaluate: LazyArg): Effect +} = effect.orElseFail + +/** + * Ensures the effect always succeeds by replacing failures with a default + * success value. + * + * **Details** + * + * This function transforms an effect that may fail into one that cannot fail by + * replacing any failure with a provided success value. If the original effect + * fails, the failure is "swallowed," and the specified success value is + * returned instead. If the original effect succeeds, its value remains + * unchanged. + * + * **When to Use** + * + * This is especially useful for providing default values in case of failure, + * ensuring that an effect always completes successfully. By using this + * function, you can avoid the need for complex error handling and guarantee a + * fallback result. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const validate = (age: number): Effect.Effect => { + * if (age < 0) { + * return Effect.fail("NegativeAgeError") + * } else if (age < 18) { + * return Effect.fail("IllegalAgeError") + * } else { + * return Effect.succeed(age) + * } + * } + * + * const program = Effect.orElseSucceed(validate(-1), () => 18) + * + * console.log(Effect.runSyncExit(program)) + * // Output: + * // { _id: 'Exit', _tag: 'Success', value: 18 } + * ``` + * + * @since 2.0.0 + * @category Fallback + */ +export const orElseSucceed: { + /** + * Ensures the effect always succeeds by replacing failures with a default + * success value. + * + * **Details** + * + * This function transforms an effect that may fail into one that cannot fail by + * replacing any failure with a provided success value. If the original effect + * fails, the failure is "swallowed," and the specified success value is + * returned instead. If the original effect succeeds, its value remains + * unchanged. + * + * **When to Use** + * + * This is especially useful for providing default values in case of failure, + * ensuring that an effect always completes successfully. By using this + * function, you can avoid the need for complex error handling and guarantee a + * fallback result. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const validate = (age: number): Effect.Effect => { + * if (age < 0) { + * return Effect.fail("NegativeAgeError") + * } else if (age < 18) { + * return Effect.fail("IllegalAgeError") + * } else { + * return Effect.succeed(age) + * } + * } + * + * const program = Effect.orElseSucceed(validate(-1), () => 18) + * + * console.log(Effect.runSyncExit(program)) + * // Output: + * // { _id: 'Exit', _tag: 'Success', value: 18 } + * ``` + * + * @since 2.0.0 + * @category Fallback + */ + (evaluate: LazyArg): (self: Effect) => Effect + /** + * Ensures the effect always succeeds by replacing failures with a default + * success value. + * + * **Details** + * + * This function transforms an effect that may fail into one that cannot fail by + * replacing any failure with a provided success value. If the original effect + * fails, the failure is "swallowed," and the specified success value is + * returned instead. If the original effect succeeds, its value remains + * unchanged. + * + * **When to Use** + * + * This is especially useful for providing default values in case of failure, + * ensuring that an effect always completes successfully. By using this + * function, you can avoid the need for complex error handling and guarantee a + * fallback result. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const validate = (age: number): Effect.Effect => { + * if (age < 0) { + * return Effect.fail("NegativeAgeError") + * } else if (age < 18) { + * return Effect.fail("IllegalAgeError") + * } else { + * return Effect.succeed(age) + * } + * } + * + * const program = Effect.orElseSucceed(validate(-1), () => 18) + * + * console.log(Effect.runSyncExit(program)) + * // Output: + * // { _id: 'Exit', _tag: 'Success', value: 18 } + * ``` + * + * @since 2.0.0 + * @category Fallback + */ + (self: Effect, evaluate: LazyArg): Effect +} = effect.orElseSucceed + +/** + * Runs a sequence of effects and returns the result of the first successful + * one. + * + * **Details** + * + * This function allows you to execute a collection of effects in sequence, + * stopping at the first success. If an effect succeeds, its result is + * immediately returned, and no further effects in the sequence are executed. + * However, if all the effects fail, the function will return the error of the + * last effect. + * + * The execution is sequential, meaning that effects are evaluated one at a time + * in the order they are provided. This ensures predictable behavior and avoids + * unnecessary computations. + * + * If the collection of effects is empty, an `IllegalArgumentException` is + * thrown, indicating that the operation is invalid without any effects to try. + * + * **When to Use** + * + * This is particularly useful when you have multiple fallback strategies or + * alternative sources to obtain a result, such as attempting multiple APIs, + * retrieving configurations, or accessing resources in a prioritized manner. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * interface Config { + * host: string + * port: number + * apiKey: string + * } + * + * // Create a configuration object with sample values + * const makeConfig = (name: string): Config => ({ + * host: `${name}.example.com`, + * port: 8080, + * apiKey: "12345-abcde" + * }) + * + * // Simulate retrieving configuration from a remote node + * const remoteConfig = (name: string): Effect.Effect => + * Effect.gen(function* () { + * // Simulate node3 being the only one with available config + * if (name === "node3") { + * yield* Console.log(`Config for ${name} found`) + * return makeConfig(name) + * } else { + * yield* Console.log(`Unavailable config for ${name}`) + * return yield* Effect.fail(new Error(`Config not found for ${name}`)) + * } + * }) + * + * // Define the master configuration and potential fallback nodes + * const masterConfig = remoteConfig("master") + * const nodeConfigs = ["node1", "node2", "node3", "node4"].map(remoteConfig) + * + * // Attempt to find a working configuration, + * // starting with the master and then falling back to other nodes + * const config = Effect.firstSuccessOf([masterConfig, ...nodeConfigs]) + * + * // Run the effect to retrieve the configuration + * const result = Effect.runSync(config) + * + * console.log(result) + * // Output: + * // Unavailable config for master + * // Unavailable config for node1 + * // Unavailable config for node2 + * // Config for node3 found + * // { host: 'node3.example.com', port: 8080, apiKey: '12345-abcde' } + * ``` + * + * @since 2.0.0 + * @category Fallback + */ +export const firstSuccessOf: >( + effects: Iterable +) => Effect, Effect.Error, Effect.Context> = effect.firstSuccessOf + +/** + * Retrieves the `Random` service from the context. + * + * @since 2.0.0 + * @category Random + */ +export const random: Effect = effect.random + +/** + * Retrieves the `Random` service from the context and uses it to run the + * specified effect. + * + * @since 2.0.0 + * @category Random + */ +export const randomWith: (f: (random: Random.Random) => Effect) => Effect = + defaultServices.randomWith + +/** + * Executes the specified effect with the specified implementation of the + * `Random` service. + * + * @since 2.0.0 + * @category Random + */ +export const withRandom: { + /** + * Executes the specified effect with the specified implementation of the + * `Random` service. + * + * @since 2.0.0 + * @category Random + */ + (value: X): (effect: Effect) => Effect + /** + * Executes the specified effect with the specified implementation of the + * `Random` service. + * + * @since 2.0.0 + * @category Random + */ + (effect: Effect, value: X): Effect +} = defaultServices.withRandom + +/** + * Executes the specified effect with a `Random` service that cycles through + * a provided array of values. + * + * @example + * ```ts + * import { Effect, Random } from "effect" + * + * Effect.gen(function*() { + * console.log(yield* Random.next) // 0.2 + * console.log(yield* Random.next) // 0.5 + * console.log(yield* Random.next) // 0.8 + * }).pipe(Effect.withRandomFixed([0.2, 0.5, 0.8])) + * ``` + * + * @since 3.11.0 + * @category Random + */ +export const withRandomFixed: { + /** + * Executes the specified effect with a `Random` service that cycles through + * a provided array of values. + * + * @example + * ```ts + * import { Effect, Random } from "effect" + * + * Effect.gen(function*() { + * console.log(yield* Random.next) // 0.2 + * console.log(yield* Random.next) // 0.5 + * console.log(yield* Random.next) // 0.8 + * }).pipe(Effect.withRandomFixed([0.2, 0.5, 0.8])) + * ``` + * + * @since 3.11.0 + * @category Random + */ + >(values: T): (effect: Effect) => Effect + /** + * Executes the specified effect with a `Random` service that cycles through + * a provided array of values. + * + * @example + * ```ts + * import { Effect, Random } from "effect" + * + * Effect.gen(function*() { + * console.log(yield* Random.next) // 0.2 + * console.log(yield* Random.next) // 0.5 + * console.log(yield* Random.next) // 0.8 + * }).pipe(Effect.withRandomFixed([0.2, 0.5, 0.8])) + * ``` + * + * @since 3.11.0 + * @category Random + */ + , A, E, R>(effect: Effect, values: T): Effect +} = dual( + 2, + , A, E, R>(effect: Effect, values: T): Effect => + withRandom(effect, Random.fixed(values)) +) + +/** + * Sets the implementation of the `Random` service to the specified value and + * restores it to its original value when the scope is closed. + * + * @since 2.0.0 + * @category Random + */ +export const withRandomScoped: (value: A) => Effect = + fiberRuntime.withRandomScoped + +/** + * Returns an effect that accesses the runtime, which can be used to (unsafely) + * execute tasks. + * + * **When to Use** + * + * This is useful for integration with legacy code that must call back into + * Effect code. + * + * @since 2.0.0 + * @category Runtime + */ +export const runtime: () => Effect, never, R> = runtime_.runtime + +/** + * Retrieves an effect that succeeds with the current runtime flags, which + * govern behavior and features of the runtime system. + * + * @since 2.0.0 + * @category Runtime + */ +export const getRuntimeFlags: Effect = core.runtimeFlags + +/** + * @since 2.0.0 + * @category Runtime + */ +export const patchRuntimeFlags: (patch: RuntimeFlagsPatch.RuntimeFlagsPatch) => Effect = core.updateRuntimeFlags + +/** + * @since 2.0.0 + * @category Runtime + */ +export const withRuntimeFlagsPatch: { + /** + * @since 2.0.0 + * @category Runtime + */ + (update: RuntimeFlagsPatch.RuntimeFlagsPatch): (self: Effect) => Effect + /** + * @since 2.0.0 + * @category Runtime + */ + (self: Effect, update: RuntimeFlagsPatch.RuntimeFlagsPatch): Effect +} = core.withRuntimeFlags + +/** + * @since 2.0.0 + * @category Runtime + */ +export const withRuntimeFlagsPatchScoped: ( + update: RuntimeFlagsPatch.RuntimeFlagsPatch +) => Effect = fiberRuntime.withRuntimeFlagsScoped + +/** + * Tags each metric in an effect with specific key-value pairs. + * + * **Details** + * + * This function allows you to tag all metrics in an effect with a set of + * key-value pairs or a single key-value pair. Tags help you add metadata to + * metrics, making it easier to filter and categorize them in monitoring + * systems. The provided tags will apply to all metrics generated within the + * effect's scope. + * + * @since 2.0.0 + * @category Metrics + */ +export const tagMetrics: { + /** + * Tags each metric in an effect with specific key-value pairs. + * + * **Details** + * + * This function allows you to tag all metrics in an effect with a set of + * key-value pairs or a single key-value pair. Tags help you add metadata to + * metrics, making it easier to filter and categorize them in monitoring + * systems. The provided tags will apply to all metrics generated within the + * effect's scope. + * + * @since 2.0.0 + * @category Metrics + */ + (key: string, value: string): (effect: Effect) => Effect + /** + * Tags each metric in an effect with specific key-value pairs. + * + * **Details** + * + * This function allows you to tag all metrics in an effect with a set of + * key-value pairs or a single key-value pair. Tags help you add metadata to + * metrics, making it easier to filter and categorize them in monitoring + * systems. The provided tags will apply to all metrics generated within the + * effect's scope. + * + * @since 2.0.0 + * @category Metrics + */ + (values: Record): (effect: Effect) => Effect + /** + * Tags each metric in an effect with specific key-value pairs. + * + * **Details** + * + * This function allows you to tag all metrics in an effect with a set of + * key-value pairs or a single key-value pair. Tags help you add metadata to + * metrics, making it easier to filter and categorize them in monitoring + * systems. The provided tags will apply to all metrics generated within the + * effect's scope. + * + * @since 2.0.0 + * @category Metrics + */ + (effect: Effect, key: string, value: string): Effect + /** + * Tags each metric in an effect with specific key-value pairs. + * + * **Details** + * + * This function allows you to tag all metrics in an effect with a set of + * key-value pairs or a single key-value pair. Tags help you add metadata to + * metrics, making it easier to filter and categorize them in monitoring + * systems. The provided tags will apply to all metrics generated within the + * effect's scope. + * + * @since 2.0.0 + * @category Metrics + */ + (effect: Effect, values: Record): Effect +} = effect.tagMetrics + +/** + * Adds labels to metrics within an effect using `MetricLabel` objects. + * + * **Details** + * + * This function allows you to label metrics using `MetricLabel` objects. Labels + * help add structured metadata to metrics for categorization and filtering in + * monitoring systems. The provided labels will apply to all metrics within the + * effect's execution. + * + * @since 2.0.0 + * @category Metrics + */ +export const labelMetrics: { + /** + * Adds labels to metrics within an effect using `MetricLabel` objects. + * + * **Details** + * + * This function allows you to label metrics using `MetricLabel` objects. Labels + * help add structured metadata to metrics for categorization and filtering in + * monitoring systems. The provided labels will apply to all metrics within the + * effect's execution. + * + * @since 2.0.0 + * @category Metrics + */ + (labels: Iterable): (self: Effect) => Effect + /** + * Adds labels to metrics within an effect using `MetricLabel` objects. + * + * **Details** + * + * This function allows you to label metrics using `MetricLabel` objects. Labels + * help add structured metadata to metrics for categorization and filtering in + * monitoring systems. The provided labels will apply to all metrics within the + * effect's execution. + * + * @since 2.0.0 + * @category Metrics + */ + (self: Effect, labels: Iterable): Effect +} = effect.labelMetrics + +/** + * Tags metrics within a scope with a specific key-value pair. + * + * **Details** + * + * This function tags all metrics within a scope with the provided key-value + * pair. Once the scope is closed, the tag is automatically removed. This is + * useful for applying temporary context-specific tags to metrics during scoped + * operations. + * + * @since 2.0.0 + * @category Metrics + */ +export const tagMetricsScoped: (key: string, value: string) => Effect = + fiberRuntime.tagMetricsScoped + +/** + * Adds labels to metrics within a scope using `MetricLabel` objects. + * + * **Details** + * + * This function allows you to apply labels to all metrics generated within a + * specific scope using an array of `MetricLabel` objects. These labels provide + * additional metadata to metrics, which can be used for categorization, + * filtering, or monitoring purposes. The labels are scoped and will be removed + * automatically once the scope is closed, ensuring they are only applied + * temporarily within the defined context. + * + * @since 2.0.0 + * @category Metrics + */ +export const labelMetricsScoped: ( + labels: ReadonlyArray +) => Effect = fiberRuntime.labelMetricsScoped + +/** + * Retrieves the metric labels associated with the current scope. + * + * @since 2.0.0 + * @category Metrics + */ +export const metricLabels: Effect> = core.metricLabels + +/** + * Associates a metric with the current effect, updating it as the effect progresses. + * + * @since 2.0.0 + * @category Metrics + */ +export const withMetric: { + /** + * Associates a metric with the current effect, updating it as the effect progresses. + * + * @since 2.0.0 + * @category Metrics + */ + (metric: Metric.Metric): (self: Effect) => Effect + /** + * Associates a metric with the current effect, updating it as the effect progresses. + * + * @since 2.0.0 + * @category Metrics + */ + (self: Effect, metric: Metric.Metric): Effect +} = effect.withMetric + +/** + * @category Semaphore + * @since 2.0.0 + */ +export interface Permit { + readonly index: number +} + +/** + * A semaphore is a synchronization mechanism used to manage access to a shared + * resource. In Effect, semaphores help control resource access or coordinate + * tasks within asynchronous, concurrent operations. + * + * A semaphore acts as a generalized mutex, allowing a set number of permits to + * be held and released concurrently. Permits act like tickets, giving tasks or + * fibers controlled access to a shared resource. When no permits are available, + * tasks trying to acquire one will wait until a permit is released. + * + * @category Semaphore + * @since 2.0.0 + */ +export interface Semaphore { + /** + * Adjusts the number of permits available in the semaphore. + */ + resize(permits: number): Effect + + /** + * Runs an effect with the given number of permits and releases the permits + * when the effect completes. + * + * **Details** + * + * This function acquires the specified number of permits before executing + * the provided effect. Once the effect finishes, the permits are released. + * If insufficient permits are available, the function will wait until they + * are released by other tasks. + */ + withPermits(permits: number): (self: Effect) => Effect + + /** + * Runs an effect only if the specified number of permits are immediately + * available. + * + * **Details** + * + * This function attempts to acquire the specified number of permits. If they + * are available, it runs the effect and releases the permits after the effect + * completes. If permits are not available, the effect does not execute, and + * the result is `Option.none`. + */ + withPermitsIfAvailable(permits: number): (self: Effect) => Effect, E, R> + + /** + * Acquires the specified number of permits and returns the resulting + * available permits, suspending the task if they are not yet available. + * Concurrent pending `take` calls are processed in a first-in, first-out manner. + */ + take(permits: number): Effect + + /** + * Releases the specified number of permits and returns the resulting + * available permits. + */ + release(permits: number): Effect + + /** + * Releases all permits held by this semaphore and returns the resulting available permits. + */ + releaseAll: Effect +} + +/** + * Unsafely creates a new Semaphore. + * + * @since 2.0.0 + * @category Semaphore + */ +export const unsafeMakeSemaphore: (permits: number) => Semaphore = circular.unsafeMakeSemaphore + +/** + * Creates a new semaphore with the specified number of permits. + * + * **Details** + * + * This function initializes a semaphore that controls concurrent access to a + * shared resource. The number of permits determines how many tasks can access + * the resource concurrently. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // Create a semaphore with 3 permits + * const mutex = Effect.makeSemaphore(3) + * ``` + * + * @since 2.0.0 + * @category Semaphore + */ +export const makeSemaphore: (permits: number) => Effect = circular.makeSemaphore + +/** + * A `Latch` is a synchronization primitive that allows you to control the + * execution of fibers based on an open or closed state. It acts as a gate, + * where fibers can wait for the latch to open before proceeding. + * + * **Details** + * + * A `Latch` can be in one of two states: open or closed. Fibers can: + * - Wait for the latch to open using `await`. + * - Proceed only when the latch is open using `whenOpen`. + * - Open the latch to release all waiting fibers using `open`. + * - Close the latch to block fibers using `close`. + * + * Additionally, fibers can be released without changing the state of the latch + * using `release`. + * + * @category Latch + * @since 3.8.0 + */ +export interface Latch extends Effect { + /** + * Opens the latch, releasing all fibers waiting on it. + * + * **Details** + * + * Once the latch is opened, it remains open. Any fibers waiting on `await` + * will be released and can continue execution. + */ + readonly open: Effect + + /** + * Opens the latch, releasing all fibers waiting on it. + * + * **Details** + * + * Once the latch is opened, it remains open. Any fibers waiting on `await` + * will be released and can continue execution. + */ + readonly unsafeOpen: () => void + + /** + * Releases all fibers waiting on the latch without opening it. + * + * **Details** + * + * This function lets waiting fibers proceed without permanently changing the + * state of the latch. + */ + readonly release: Effect + + /** + * Waits for the latch to be opened. + * + * **Details** + * + * If the latch is already open, this effect completes immediately. Otherwise, + * it suspends the fiber until the latch is opened. + */ + readonly await: Effect + + /** + * Closes the latch, blocking fibers from proceeding. + * + * **Details** + * + * This operation puts the latch into a closed state, requiring it to be + * reopened before waiting fibers can proceed. + */ + readonly close: Effect + + /** + * Unsafely closes the latch, blocking fibers without effect guarantees. + * + * **Details** + * + * Use this operation cautiously, as it does not run within an effect context + * and bypasses runtime guarantees. + */ + readonly unsafeClose: () => void + + /** + * Runs the given effect only when the latch is open. + * + * **Details** + * + * This function ensures that the provided effect executes only if the latch + * is open. If the latch is closed, the fiber will wait until it opens. + */ + readonly whenOpen: (self: Effect) => Effect + + readonly [Unify.typeSymbol]?: unknown + readonly [Unify.unifySymbol]?: LatchUnify + readonly [Unify.ignoreSymbol]?: LatchUnifyIgnore +} + +/** + * @category Models + * @since 3.8.0 + */ +export interface LatchUnify extends EffectUnify { + Latch?: () => Latch +} + +/** + * @category Models + * @since 3.8.0 + */ +export interface LatchUnifyIgnore extends EffectUnifyIgnore { + Effect?: true +} + +/** + * @category Latch + * @since 3.8.0 + */ +export const unsafeMakeLatch: (open?: boolean | undefined) => Latch = circular.unsafeMakeLatch + +/** + * Creates a new `Latch`, starting in the specified state. + * + * **Details** + * + * This function initializes a `Latch` safely, ensuring proper runtime + * guarantees. By default, the latch starts in the closed state. + * + * **Example** + * + * ```ts + * import { Console, Effect } from "effect" + * + * const program = Effect.gen(function*() { + * // Create a latch, starting in the closed state + * const latch = yield* Effect.makeLatch(false) + * + * // Fork a fiber that logs "open sesame" when the latch is opened + * const fiber = yield* Console.log("open sesame").pipe( + * latch.whenOpen, + * Effect.fork + * ) + * + * yield* Effect.sleep("1 second") + * + * // Open the latch + * yield* latch.open + * yield* fiber.await + * }) + * + * Effect.runFork(program) + * // Output: open sesame (after 1 second) + * ``` + * + * @category Latch + * @since 3.8.0 + */ +export const makeLatch: (open?: boolean | undefined) => Effect = circular.makeLatch + +/** + * Runs an effect in the background, returning a fiber that can be observed or + * interrupted. + * + * Unless you specifically need a `Promise` or synchronous operation, `runFork` + * is a good default choice. + * + * **Details** + * + * This function is the foundational way to execute an effect in the background. + * It creates a "fiber," a lightweight, cooperative thread of execution that can + * be observed (to access its result), interrupted, or joined. Fibers are useful + * for concurrent programming and allow effects to run independently of the main + * program flow. + * + * Once the effect is running in a fiber, you can monitor its progress, cancel + * it if necessary, or retrieve its result when it completes. If the effect + * fails, the fiber will propagate the failure, which you can observe and + * handle. + * + * **When to Use** + * + * Use this function when you need to run an effect in the background, + * especially if the effect is long-running or performs periodic tasks. It's + * suitable for tasks that need to run independently but might still need + * observation or management, like logging, monitoring, or scheduled tasks. + * + * This function is ideal if you don't need the result immediately or if the + * effect is part of a larger concurrent workflow. + * + * **Example** (Running an Effect in the Background) + * + * ```ts + * import { Effect, Console, Schedule, Fiber } from "effect" + * + * // ┌─── Effect + * // ▼ + * const program = Effect.repeat( + * Console.log("running..."), + * Schedule.spaced("200 millis") + * ) + * + * // ┌─── RuntimeFiber + * // ▼ + * const fiber = Effect.runFork(program) + * + * setTimeout(() => { + * Effect.runFork(Fiber.interrupt(fiber)) + * }, 500) + * ``` + * + * @since 2.0.0 + * @category Running Effects + */ +export const runFork: ( + effect: Effect, + options?: Runtime.RunForkOptions +) => Fiber.RuntimeFiber = runtime_.unsafeForkEffect + +/** + * Executes an effect asynchronously and handles the result using a callback. + * + * **Details** + * + * This function runs an effect asynchronously and passes the result (`Exit`) to + * a specified callback. The callback is invoked with the outcome of the effect: + * - On success, the callback receives the successful result. + * - On failure, the callback receives the failure information. + * + * **When to Use** + * + * This function is effectful and should only be invoked at the edges of your + * program. + * + * @since 2.0.0 + * @category Running Effects + */ +export const runCallback: ( + effect: Effect, + options?: Runtime.RunCallbackOptions | undefined +) => Runtime.Cancel = runtime_.unsafeRunEffect + +/** + * Executes an effect and returns the result as a `Promise`. + * + * **Details** + * + * This function runs an effect and converts its result into a `Promise`. If the + * effect succeeds, the `Promise` will resolve with the successful result. If + * the effect fails, the `Promise` will reject with an error, which includes the + * failure details of the effect. + * + * The optional `options` parameter allows you to pass an `AbortSignal` for + * cancellation, enabling more fine-grained control over asynchronous tasks. + * + * **When to Use** + * + * Use this function when you need to execute an effect and work with its result + * in a promise-based system, such as when integrating with third-party + * libraries that expect `Promise` results. + * + * **Example** (Running a Successful Effect as a Promise) + * + * ```ts + * import { Effect } from "effect" + * + * Effect.runPromise(Effect.succeed(1)).then(console.log) + * // Output: 1 + * ``` + * + * **Example** (Handling a Failing Effect as a Rejected Promise) + * + * ```ts + * import { Effect } from "effect" + * + * Effect.runPromise(Effect.fail("my error")).catch(console.error) + * // Output: + * // (FiberFailure) Error: my error + * ``` + * + * @see {@link runPromiseExit} for a version that returns an `Exit` type instead + * of rejecting. + * + * @since 2.0.0 + * @category Running Effects + */ +export const runPromise: ( + effect: Effect, + options?: { readonly signal?: AbortSignal | undefined } | undefined +) => Promise = runtime_.unsafeRunPromiseEffect + +/** + * Runs an effect and returns a `Promise` that resolves to an `Exit`, + * representing the outcome. + * + * **Details** + * + * This function executes an effect and resolves to an `Exit` object. The `Exit` + * type provides detailed information about the result of the effect: + * - If the effect succeeds, the `Exit` will be of type `Success` and include + * the value produced by the effect. + * - If the effect fails, the `Exit` will be of type `Failure` and contain a + * `Cause` object, detailing the failure. + * + * Using this function allows you to examine both successful results and failure + * cases in a unified way, while still leveraging `Promise` for handling the + * asynchronous behavior of the effect. + * + * **When to Use** + * + * Use this function when you need to understand the outcome of an effect, + * whether it succeeded or failed, and want to work with this result using + * `Promise` syntax. This is particularly useful when integrating with systems + * that rely on promises but need more detailed error handling than a simple + * rejection. + * + * **Example** (Handling Results as Exit) + * + * ```ts + * import { Effect } from "effect" + * + * // Execute a successful effect and get the Exit result as a Promise + * Effect.runPromiseExit(Effect.succeed(1)).then(console.log) + * // Output: + * // { + * // _id: "Exit", + * // _tag: "Success", + * // value: 1 + * // } + * + * // Execute a failing effect and get the Exit result as a Promise + * Effect.runPromiseExit(Effect.fail("my error")).then(console.log) + * // Output: + * // { + * // _id: "Exit", + * // _tag: "Failure", + * // cause: { + * // _id: "Cause", + * // _tag: "Fail", + * // failure: "my error" + * // } + * // } + * ``` + * + * @since 2.0.0 + * @category Running Effects + */ +export const runPromiseExit: ( + effect: Effect, + options?: { readonly signal?: AbortSignal } | undefined +) => Promise> = runtime_.unsafeRunPromiseExitEffect + +/** + * Executes an effect synchronously, running it immediately and returning the + * result. + * + * **Details** + * + * This function evaluates the provided effect synchronously, returning its + * result directly. It is ideal for effects that do not fail or include + * asynchronous operations. If the effect does fail or involves async tasks, it + * will throw an error. Execution stops at the point of failure or asynchronous + * operation, making it unsuitable for effects that require asynchronous + * handling. + * + * **Important**: Attempting to run effects that involve asynchronous operations + * or failures will result in exceptions being thrown, so use this function with + * care for purely synchronous and error-free effects. + * + * **When to Use** + * + * Use this function when: + * - You are sure that the effect will not fail or involve asynchronous + * operations. + * - You need a direct, synchronous result from the effect. + * - You are working within a context where asynchronous effects are not + * allowed. + * + * Avoid using this function for effects that can fail or require asynchronous + * handling. For such cases, consider using {@link runPromise} or + * {@link runSyncExit}. + * + * **Example** (Synchronous Logging) + * + * ```ts + * import { Effect } from "effect" + * + * const program = Effect.sync(() => { + * console.log("Hello, World!") + * return 1 + * }) + * + * const result = Effect.runSync(program) + * // Output: Hello, World! + * + * console.log(result) + * // Output: 1 + * ``` + * + * **Example** (Incorrect Usage with Failing or Async Effects) + * + * ```ts + * import { Effect } from "effect" + * + * try { + * // Attempt to run an effect that fails + * Effect.runSync(Effect.fail("my error")) + * } catch (e) { + * console.error(e) + * } + * // Output: + * // (FiberFailure) Error: my error + * + * try { + * // Attempt to run an effect that involves async work + * Effect.runSync(Effect.promise(() => Promise.resolve(1))) + * } catch (e) { + * console.error(e) + * } + * // Output: + * // (FiberFailure) AsyncFiberException: Fiber #0 cannot be resolved synchronously. This is caused by using runSync on an effect that performs async work + * ``` + * + * @see {@link runSyncExit} for a version that returns an `Exit` type instead of + * throwing an error. + * + * @since 2.0.0 + * @category Running Effects + */ +export const runSync: (effect: Effect) => A = runtime_.unsafeRunSyncEffect + +/** + * Runs an effect synchronously and returns the result as an `Exit` type. + * + * **Details** + * + * This function executes the provided effect synchronously and returns an `Exit` + * type that encapsulates the outcome of the effect: + * - If the effect succeeds, the result is wrapped in a `Success`. + * - If the effect fails, it returns a `Failure` containing a `Cause` that explains + * the failure. + * + * If the effect involves asynchronous operations, this function will return a `Failure` + * with a `Die` cause, indicating that it cannot resolve the effect synchronously. + * This makes the function suitable for use only with effects that are synchronous + * in nature. + * + * **When to Use** + * + * Use this function when: + * - You want to handle both success and failure outcomes in a structured way using the `Exit` type. + * - You are working with effects that are purely synchronous and do not involve asynchronous operations. + * - You need to debug or inspect failures, including their causes, in a detailed manner. + * + * Avoid using this function for effects that involve asynchronous operations, as it will fail with a `Die` cause. + * + * **Example** (Handling Results as Exit) + * + * ```ts + * import { Effect } from "effect" + * + * console.log(Effect.runSyncExit(Effect.succeed(1))) + * // Output: + * // { + * // _id: "Exit", + * // _tag: "Success", + * // value: 1 + * // } + * + * console.log(Effect.runSyncExit(Effect.fail("my error"))) + * // Output: + * // { + * // _id: "Exit", + * // _tag: "Failure", + * // cause: { + * // _id: "Cause", + * // _tag: "Fail", + * // failure: "my error" + * // } + * // } + * ``` + * + * **Example** (Asynchronous Operation Resulting in Die) + * + * ```ts + * import { Effect } from "effect" + * + * console.log(Effect.runSyncExit(Effect.promise(() => Promise.resolve(1)))) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Die', + * // defect: [Fiber #0 cannot be resolved synchronously. This is caused by using runSync on an effect that performs async work] { + * // fiber: [FiberRuntime], + * // _tag: 'AsyncFiberException', + * // name: 'AsyncFiberException' + * // } + * // } + * // } + * ``` + * + * @since 2.0.0 + * @category Running Effects + */ +export const runSyncExit: (effect: Effect) => Exit.Exit = runtime_.unsafeRunSyncExitEffect + +/** + * Combines multiple effects and accumulates both successes and failures. + * + * **Details** + * + * This function allows you to combine multiple effects, continuing through all + * effects even if some of them fail. Unlike other functions that stop execution + * upon encountering an error, this function collects all errors into a `Cause`. + * The final result includes all successes and the accumulated failures. + * + * By default, effects are executed sequentially, but you can control + * concurrency and batching behavior using the `options` parameter. This + * provides flexibility in scenarios where you want to maximize performance or + * ensure specific ordering. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Console.log("task1").pipe(Effect.as(1)) + * const task2 = Effect.fail("Oh uh!").pipe(Effect.as(2)) + * const task3 = Console.log("task2").pipe(Effect.as(3)) + * const task4 = Effect.fail("Oh no!").pipe(Effect.as(4)) + * + * const program = task1.pipe( + * Effect.validate(task2), + * Effect.validate(task3), + * Effect.validate(task4) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // task1 + * // task2 + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Sequential', + * // left: { _id: 'Cause', _tag: 'Fail', failure: 'Oh uh!' }, + * // right: { _id: 'Cause', _tag: 'Fail', failure: 'Oh no!' } + * // } + * // } + * ``` + * + * @see {@link zip} for a version that stops at the first error. + * + * @since 2.0.0 + * @category Error Accumulation + */ +export const validate: { + /** + * Combines multiple effects and accumulates both successes and failures. + * + * **Details** + * + * This function allows you to combine multiple effects, continuing through all + * effects even if some of them fail. Unlike other functions that stop execution + * upon encountering an error, this function collects all errors into a `Cause`. + * The final result includes all successes and the accumulated failures. + * + * By default, effects are executed sequentially, but you can control + * concurrency and batching behavior using the `options` parameter. This + * provides flexibility in scenarios where you want to maximize performance or + * ensure specific ordering. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Console.log("task1").pipe(Effect.as(1)) + * const task2 = Effect.fail("Oh uh!").pipe(Effect.as(2)) + * const task3 = Console.log("task2").pipe(Effect.as(3)) + * const task4 = Effect.fail("Oh no!").pipe(Effect.as(4)) + * + * const program = task1.pipe( + * Effect.validate(task2), + * Effect.validate(task3), + * Effect.validate(task4) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // task1 + * // task2 + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Sequential', + * // left: { _id: 'Cause', _tag: 'Fail', failure: 'Oh uh!' }, + * // right: { _id: 'Cause', _tag: 'Fail', failure: 'Oh no!' } + * // } + * // } + * ``` + * + * @see {@link zip} for a version that stops at the first error. + * + * @since 2.0.0 + * @category Error Accumulation + */ + ( + that: Effect, + options?: { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } | undefined + ): (self: Effect) => Effect<[A, B], E1 | E, R1 | R> + /** + * Combines multiple effects and accumulates both successes and failures. + * + * **Details** + * + * This function allows you to combine multiple effects, continuing through all + * effects even if some of them fail. Unlike other functions that stop execution + * upon encountering an error, this function collects all errors into a `Cause`. + * The final result includes all successes and the accumulated failures. + * + * By default, effects are executed sequentially, but you can control + * concurrency and batching behavior using the `options` parameter. This + * provides flexibility in scenarios where you want to maximize performance or + * ensure specific ordering. + * + * **Example** + * + * ```ts + * import { Effect, Console } from "effect" + * + * const task1 = Console.log("task1").pipe(Effect.as(1)) + * const task2 = Effect.fail("Oh uh!").pipe(Effect.as(2)) + * const task3 = Console.log("task2").pipe(Effect.as(3)) + * const task4 = Effect.fail("Oh no!").pipe(Effect.as(4)) + * + * const program = task1.pipe( + * Effect.validate(task2), + * Effect.validate(task3), + * Effect.validate(task4) + * ) + * + * Effect.runPromiseExit(program).then(console.log) + * // Output: + * // task1 + * // task2 + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Sequential', + * // left: { _id: 'Cause', _tag: 'Fail', failure: 'Oh uh!' }, + * // right: { _id: 'Cause', _tag: 'Fail', failure: 'Oh no!' } + * // } + * // } + * ``` + * + * @see {@link zip} for a version that stops at the first error. + * + * @since 2.0.0 + * @category Error Accumulation + */ + ( + self: Effect, + that: Effect, + options?: + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): Effect<[A, B], E | E1, R | R1> +} = fiberRuntime.validate + +/** + * Sequentially combines two effects using a specified combiner function while + * accumulating errors. + * + * **Details** + * + * This function combines two effects, `self` and `that`, into a single effect + * by applying the provided combiner function to their results. If both effects + * succeed, the combiner function is applied to their results to produce the + * final value. If either effect fails, the failures are accumulated into a + * combined `Cause`. + * + * By default, effects are executed sequentially. However, the execution mode + * can be controlled using the `options` parameter to enable concurrency, + * batching, or customized finalizer behavior. + * + * @since 2.0.0 + * @category Error Accumulation + */ +export const validateWith: { + /** + * Sequentially combines two effects using a specified combiner function while + * accumulating errors. + * + * **Details** + * + * This function combines two effects, `self` and `that`, into a single effect + * by applying the provided combiner function to their results. If both effects + * succeed, the combiner function is applied to their results to produce the + * final value. If either effect fails, the failures are accumulated into a + * combined `Cause`. + * + * By default, effects are executed sequentially. However, the execution mode + * can be controlled using the `options` parameter to enable concurrency, + * batching, or customized finalizer behavior. + * + * @since 2.0.0 + * @category Error Accumulation + */ + ( + that: Effect, + f: (a: A, b: B) => C, + options?: + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): (self: Effect) => Effect + /** + * Sequentially combines two effects using a specified combiner function while + * accumulating errors. + * + * **Details** + * + * This function combines two effects, `self` and `that`, into a single effect + * by applying the provided combiner function to their results. If both effects + * succeed, the combiner function is applied to their results to produce the + * final value. If either effect fails, the failures are accumulated into a + * combined `Cause`. + * + * By default, effects are executed sequentially. However, the execution mode + * can be controlled using the `options` parameter to enable concurrency, + * batching, or customized finalizer behavior. + * + * @since 2.0.0 + * @category Error Accumulation + */ + ( + self: Effect, + that: Effect, + f: (a: A, b: B) => C, + options?: + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): Effect +} = fiberRuntime.validateWith + +/** + * Combines two effects into a single effect, producing a tuple of their + * results. + * + * **Details** + * + * This function combines two effects, `self` and `that`, into one. It executes + * the first effect (`self`) and then the second effect (`that`), collecting + * their results into a tuple. Both effects must succeed for the resulting + * effect to succeed. If either effect fails, the entire operation fails. + * + * By default, the effects are executed sequentially. If the `concurrent` option + * is set to `true`, the effects will run concurrently, potentially improving + * performance for independent operations. + * + * **Example** (Combining Two Effects Sequentially) + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * // Combine the two effects together + * // + * // ┌─── Effect<[number, string], never, never> + * // ▼ + * const program = Effect.zip(task1, task2) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="task1 done" + * // timestamp=... level=INFO fiber=#0 message="task2 done" + * // [ 1, 'hello' ] + * ``` + * + * **Example** (Combining Two Effects Concurrently) + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * // Run both effects concurrently using the concurrent option + * const program = Effect.zip(task1, task2, { concurrent: true }) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="task2 done" + * // timestamp=... level=INFO fiber=#0 message="task1 done" + * // [ 1, 'hello' ] + * ``` + * + * @see {@link zipWith} for a version that combines the results with a custom + * function. + * @see {@link validate} for a version that accumulates errors. + * + * @since 2.0.0 + * @category Zipping + */ +export const zip: { + /** + * Combines two effects into a single effect, producing a tuple of their + * results. + * + * **Details** + * + * This function combines two effects, `self` and `that`, into one. It executes + * the first effect (`self`) and then the second effect (`that`), collecting + * their results into a tuple. Both effects must succeed for the resulting + * effect to succeed. If either effect fails, the entire operation fails. + * + * By default, the effects are executed sequentially. If the `concurrent` option + * is set to `true`, the effects will run concurrently, potentially improving + * performance for independent operations. + * + * **Example** (Combining Two Effects Sequentially) + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * // Combine the two effects together + * // + * // ┌─── Effect<[number, string], never, never> + * // ▼ + * const program = Effect.zip(task1, task2) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="task1 done" + * // timestamp=... level=INFO fiber=#0 message="task2 done" + * // [ 1, 'hello' ] + * ``` + * + * **Example** (Combining Two Effects Concurrently) + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * // Run both effects concurrently using the concurrent option + * const program = Effect.zip(task1, task2, { concurrent: true }) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="task2 done" + * // timestamp=... level=INFO fiber=#0 message="task1 done" + * // [ 1, 'hello' ] + * ``` + * + * @see {@link zipWith} for a version that combines the results with a custom + * function. + * @see {@link validate} for a version that accumulates errors. + * + * @since 2.0.0 + * @category Zipping + */ + ( + that: Effect, + options?: + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): (self: Effect) => Effect<[A, A2], E2 | E, R2 | R> + /** + * Combines two effects into a single effect, producing a tuple of their + * results. + * + * **Details** + * + * This function combines two effects, `self` and `that`, into one. It executes + * the first effect (`self`) and then the second effect (`that`), collecting + * their results into a tuple. Both effects must succeed for the resulting + * effect to succeed. If either effect fails, the entire operation fails. + * + * By default, the effects are executed sequentially. If the `concurrent` option + * is set to `true`, the effects will run concurrently, potentially improving + * performance for independent operations. + * + * **Example** (Combining Two Effects Sequentially) + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * // Combine the two effects together + * // + * // ┌─── Effect<[number, string], never, never> + * // ▼ + * const program = Effect.zip(task1, task2) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="task1 done" + * // timestamp=... level=INFO fiber=#0 message="task2 done" + * // [ 1, 'hello' ] + * ``` + * + * **Example** (Combining Two Effects Concurrently) + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * // Run both effects concurrently using the concurrent option + * const program = Effect.zip(task1, task2, { concurrent: true }) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="task2 done" + * // timestamp=... level=INFO fiber=#0 message="task1 done" + * // [ 1, 'hello' ] + * ``` + * + * @see {@link zipWith} for a version that combines the results with a custom + * function. + * @see {@link validate} for a version that accumulates errors. + * + * @since 2.0.0 + * @category Zipping + */ + ( + self: Effect, + that: Effect, + options?: + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): Effect<[A, A2], E | E2, R | R2> +} = fiberRuntime.zipOptions + +/** + * Executes two effects sequentially, returning the result of the first effect + * and ignoring the result of the second. + * + * **Details** + * + * This function allows you to run two effects in sequence, where the result of + * the first effect is preserved, and the result of the second effect is + * discarded. By default, the two effects are executed sequentially. If you need + * them to run concurrently, you can pass the `{ concurrent: true }` option. + * + * The second effect will always be executed, even though its result is ignored. + * This makes it useful for cases where you want to execute an effect for its + * side effects while keeping the result of another effect. + * + * **When to Use** + * + * Use this function when you are only interested in the result of the first + * effect but still need to run the second effect for its side effects, such as + * logging or performing a cleanup action. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * const program = Effect.zipLeft(task1, task2) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="task1 done" + * // timestamp=... level=INFO fiber=#0 message="task2 done" + * // 1 + * ``` + * + * @see {@link zipRight} for a version that returns the result of the second + * effect. + * + * @since 2.0.0 + * @category Zipping + */ +export const zipLeft: { + /** + * Executes two effects sequentially, returning the result of the first effect + * and ignoring the result of the second. + * + * **Details** + * + * This function allows you to run two effects in sequence, where the result of + * the first effect is preserved, and the result of the second effect is + * discarded. By default, the two effects are executed sequentially. If you need + * them to run concurrently, you can pass the `{ concurrent: true }` option. + * + * The second effect will always be executed, even though its result is ignored. + * This makes it useful for cases where you want to execute an effect for its + * side effects while keeping the result of another effect. + * + * **When to Use** + * + * Use this function when you are only interested in the result of the first + * effect but still need to run the second effect for its side effects, such as + * logging or performing a cleanup action. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * const program = Effect.zipLeft(task1, task2) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="task1 done" + * // timestamp=... level=INFO fiber=#0 message="task2 done" + * // 1 + * ``` + * + * @see {@link zipRight} for a version that returns the result of the second + * effect. + * + * @since 2.0.0 + * @category Zipping + */ + ( + that: Effect, + options?: + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): (self: Effect) => Effect + /** + * Executes two effects sequentially, returning the result of the first effect + * and ignoring the result of the second. + * + * **Details** + * + * This function allows you to run two effects in sequence, where the result of + * the first effect is preserved, and the result of the second effect is + * discarded. By default, the two effects are executed sequentially. If you need + * them to run concurrently, you can pass the `{ concurrent: true }` option. + * + * The second effect will always be executed, even though its result is ignored. + * This makes it useful for cases where you want to execute an effect for its + * side effects while keeping the result of another effect. + * + * **When to Use** + * + * Use this function when you are only interested in the result of the first + * effect but still need to run the second effect for its side effects, such as + * logging or performing a cleanup action. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * const program = Effect.zipLeft(task1, task2) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="task1 done" + * // timestamp=... level=INFO fiber=#0 message="task2 done" + * // 1 + * ``` + * + * @see {@link zipRight} for a version that returns the result of the second + * effect. + * + * @since 2.0.0 + * @category Zipping + */ + ( + self: Effect, + that: Effect, + options?: + | { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + | undefined + ): Effect +} = fiberRuntime.zipLeftOptions + +/** + * Executes two effects sequentially, returning the result of the second effect + * while ignoring the result of the first. + * + * **Details** + * + * This function allows you to run two effects in sequence, keeping the result + * of the second effect and discarding the result of the first. By default, the + * two effects are executed sequentially. If you need them to run concurrently, + * you can pass the `{ concurrent: true }` option. + * + * The first effect will always be executed, even though its result is ignored. + * This makes it useful for scenarios where the first effect is needed for its + * side effects, but only the result of the second effect is important. + * + * **When to Use** + * + * Use this function when you are only interested in the result of the second + * effect but still need to run the first effect for its side effects, such as + * initialization or setup tasks. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * const program = Effect.zipRight(task1, task2) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="task1 done" + * // timestamp=... level=INFO fiber=#0 message="task2 done" + * // hello + * ``` + * + * @see {@link zipLeft} for a version that returns the result of the first + * effect. + * + * @since 2.0.0 + * @category Zipping + */ +export const zipRight: { + /** + * Executes two effects sequentially, returning the result of the second effect + * while ignoring the result of the first. + * + * **Details** + * + * This function allows you to run two effects in sequence, keeping the result + * of the second effect and discarding the result of the first. By default, the + * two effects are executed sequentially. If you need them to run concurrently, + * you can pass the `{ concurrent: true }` option. + * + * The first effect will always be executed, even though its result is ignored. + * This makes it useful for scenarios where the first effect is needed for its + * side effects, but only the result of the second effect is important. + * + * **When to Use** + * + * Use this function when you are only interested in the result of the second + * effect but still need to run the first effect for its side effects, such as + * initialization or setup tasks. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * const program = Effect.zipRight(task1, task2) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="task1 done" + * // timestamp=... level=INFO fiber=#0 message="task2 done" + * // hello + * ``` + * + * @see {@link zipLeft} for a version that returns the result of the first + * effect. + * + * @since 2.0.0 + * @category Zipping + */ + ( + that: Effect, + options?: { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + ): (self: Effect) => Effect + /** + * Executes two effects sequentially, returning the result of the second effect + * while ignoring the result of the first. + * + * **Details** + * + * This function allows you to run two effects in sequence, keeping the result + * of the second effect and discarding the result of the first. By default, the + * two effects are executed sequentially. If you need them to run concurrently, + * you can pass the `{ concurrent: true }` option. + * + * The first effect will always be executed, even though its result is ignored. + * This makes it useful for scenarios where the first effect is needed for its + * side effects, but only the result of the second effect is important. + * + * **When to Use** + * + * Use this function when you are only interested in the result of the second + * effect but still need to run the first effect for its side effects, such as + * initialization or setup tasks. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * const program = Effect.zipRight(task1, task2) + * + * Effect.runPromise(program).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#0 message="task1 done" + * // timestamp=... level=INFO fiber=#0 message="task2 done" + * // hello + * ``` + * + * @see {@link zipLeft} for a version that returns the result of the first + * effect. + * + * @since 2.0.0 + * @category Zipping + */ + ( + self: Effect, + that: Effect, + options?: { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + ): Effect +} = fiberRuntime.zipRightOptions + +/** + * Combines two effects sequentially and applies a function to their results to + * produce a single value. + * + * **Details** + * + * This function runs two effects in sequence (or concurrently, if the `{ + * concurrent: true }` option is provided) and combines their results using a + * provided function. Unlike {@link zip}, which returns a tuple of the results, + * this function processes the results with a custom function to produce a + * single output. + * + * **Example** (Combining Effects with a Custom Function) + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * const task3 = Effect.zipWith( + * task1, + * task2, + * // Combines results into a single value + * (number, string) => number + string.length + * ) + * + * Effect.runPromise(task3).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#3 message="task1 done" + * // timestamp=... level=INFO fiber=#2 message="task2 done" + * // 6 + * ``` + * + * @since 2.0.0 + * @category Zipping + */ +export const zipWith: { + /** + * Combines two effects sequentially and applies a function to their results to + * produce a single value. + * + * **Details** + * + * This function runs two effects in sequence (or concurrently, if the `{ + * concurrent: true }` option is provided) and combines their results using a + * provided function. Unlike {@link zip}, which returns a tuple of the results, + * this function processes the results with a custom function to produce a + * single output. + * + * **Example** (Combining Effects with a Custom Function) + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * const task3 = Effect.zipWith( + * task1, + * task2, + * // Combines results into a single value + * (number, string) => number + string.length + * ) + * + * Effect.runPromise(task3).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#3 message="task1 done" + * // timestamp=... level=INFO fiber=#2 message="task2 done" + * // 6 + * ``` + * + * @since 2.0.0 + * @category Zipping + */ + ( + that: Effect, + f: (a: A, b: A2) => B, + options?: { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + ): (self: Effect) => Effect + /** + * Combines two effects sequentially and applies a function to their results to + * produce a single value. + * + * **Details** + * + * This function runs two effects in sequence (or concurrently, if the `{ + * concurrent: true }` option is provided) and combines their results using a + * provided function. Unlike {@link zip}, which returns a tuple of the results, + * this function processes the results with a custom function to produce a + * single output. + * + * **Example** (Combining Effects with a Custom Function) + * + * ```ts + * import { Effect } from "effect" + * + * const task1 = Effect.succeed(1).pipe( + * Effect.delay("200 millis"), + * Effect.tap(Effect.log("task1 done")) + * ) + * const task2 = Effect.succeed("hello").pipe( + * Effect.delay("100 millis"), + * Effect.tap(Effect.log("task2 done")) + * ) + * + * const task3 = Effect.zipWith( + * task1, + * task2, + * // Combines results into a single value + * (number, string) => number + string.length + * ) + * + * Effect.runPromise(task3).then(console.log) + * // Output: + * // timestamp=... level=INFO fiber=#3 message="task1 done" + * // timestamp=... level=INFO fiber=#2 message="task2 done" + * // 6 + * ``` + * + * @since 2.0.0 + * @category Zipping + */ + ( + self: Effect, + that: Effect, + f: (a: A, b: A2) => B, + options?: { + readonly concurrent?: boolean | undefined + readonly batching?: boolean | "inherit" | undefined + readonly concurrentFinalizers?: boolean | undefined + } + ): Effect +} = fiberRuntime.zipWithOptions + +/** + * Applies the function produced by one effect to the value produced by another effect. + * + * **Details** + * + * This function combines two effects: + * - The first effect produces a function of type `(a: A) => B`. + * - The second effect produces a value of type `A`. + * + * Once both effects complete successfully, the function is applied to the value, resulting in an effect that produces a value of type `B`. + * + * @since 2.0.0 + */ +export const ap: { + /** + * Applies the function produced by one effect to the value produced by another effect. + * + * **Details** + * + * This function combines two effects: + * - The first effect produces a function of type `(a: A) => B`. + * - The second effect produces a value of type `A`. + * + * Once both effects complete successfully, the function is applied to the value, resulting in an effect that produces a value of type `B`. + * + * @since 2.0.0 + */ + (that: Effect): (self: Effect<(a: A) => B, E, R>) => Effect + /** + * Applies the function produced by one effect to the value produced by another effect. + * + * **Details** + * + * This function combines two effects: + * - The first effect produces a function of type `(a: A) => B`. + * - The second effect produces a value of type `A`. + * + * Once both effects complete successfully, the function is applied to the value, resulting in an effect that produces a value of type `B`. + * + * @since 2.0.0 + */ + (self: Effect<(a: A) => B, E, R>, that: Effect): Effect +} = dual( + 2, + (self: Effect<(a: A) => B, E, R>, that: Effect): Effect => + zipWith(self, that, (f, a) => f(a)) +) + +/** + * @category Requests & Batching + * @since 2.0.0 + */ +export const blocked: (blockedRequests: RequestBlock, _continue: Effect) => Blocked = core.blocked + +/** + * @category Requests & Batching + * @since 2.0.0 + */ +export const runRequestBlock: (blockedRequests: RequestBlock) => Effect = core.runRequestBlock + +/** + * @category Requests & Batching + * @since 2.0.0 + */ +export const step: (self: Effect) => Effect | Blocked, never, R> = core.step + +/** + * @since 2.0.0 + * @category Requests & Batching + */ +export const request: { + /** + * @since 2.0.0 + * @category Requests & Batching + */ + , Ds extends RequestResolver | Effect, any, any>>(dataSource: Ds): ( + self: A + ) => Effect< + Request.Request.Success, + Request.Request.Error, + [Ds] extends [Effect] ? Effect.Context : never + > + /** + * @since 2.0.0 + * @category Requests & Batching + */ + < + Ds extends RequestResolver | Effect, any, any>, + A extends Request.Request + >(self: A, dataSource: Ds): Effect< + Request.Request.Success, + Request.Request.Error, + [Ds] extends [Effect] ? Effect.Context : never + > +} = dual((args) => Request.isRequest(args[0]), query.fromRequest) + +/** + * @since 2.0.0 + * @category Requests & Batching + */ +export const cacheRequestResult: >( + request: A, + result: Request.Request.Result +) => Effect = query.cacheRequest + +/** + * @since 2.0.0 + * @category Requests & Batching + */ +export const withRequestBatching: { + /** + * @since 2.0.0 + * @category Requests & Batching + */ + (requestBatching: boolean): (self: Effect) => Effect + /** + * @since 2.0.0 + * @category Requests & Batching + */ + (self: Effect, requestBatching: boolean): Effect +} = core.withRequestBatching + +/** + * @since 2.0.0 + * @category Requests & Batching + */ +export const withRequestCaching: { + /** + * @since 2.0.0 + * @category Requests & Batching + */ + (strategy: boolean): (self: Effect) => Effect + /** + * @since 2.0.0 + * @category Requests & Batching + */ + (self: Effect, strategy: boolean): Effect +} = query.withRequestCaching + +/** + * @since 2.0.0 + * @category Requests & Batching + */ +export const withRequestCache: { + /** + * @since 2.0.0 + * @category Requests & Batching + */ + (cache: Request.Cache): (self: Effect) => Effect + /** + * @since 2.0.0 + * @category Requests & Batching + */ + (self: Effect, cache: Request.Cache): Effect +} = query.withRequestCache + +/** + * @since 2.0.0 + * @category Tracing + */ +export const tracer: Effect = effect.tracer + +/** + * @since 2.0.0 + * @category Tracing + */ +export const tracerWith: (f: (tracer: Tracer.Tracer) => Effect) => Effect = + defaultServices.tracerWith + +/** + * @since 2.0.0 + * @category Tracing + */ +export const withTracer: { + /** + * @since 2.0.0 + * @category Tracing + */ + (value: Tracer.Tracer): (effect: Effect) => Effect + /** + * @since 2.0.0 + * @category Tracing + */ + (effect: Effect, value: Tracer.Tracer): Effect +} = defaultServices.withTracer + +/** + * @since 2.0.0 + * @category Tracing + */ +export const withTracerScoped: (value: Tracer.Tracer) => Effect = + fiberRuntime.withTracerScoped + +/** + * Disable the tracer for the given Effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * Effect.succeed(42).pipe( + * Effect.withSpan("my-span"), + * // the span will not be registered with the tracer + * Effect.withTracerEnabled(false) + * ) + * ``` + * + * @since 2.0.0 + * @category Tracing + */ +export const withTracerEnabled: { + /** + * Disable the tracer for the given Effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * Effect.succeed(42).pipe( + * Effect.withSpan("my-span"), + * // the span will not be registered with the tracer + * Effect.withTracerEnabled(false) + * ) + * ``` + * + * @since 2.0.0 + * @category Tracing + */ + (enabled: boolean): (effect: Effect) => Effect + /** + * Disable the tracer for the given Effect. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * Effect.succeed(42).pipe( + * Effect.withSpan("my-span"), + * // the span will not be registered with the tracer + * Effect.withTracerEnabled(false) + * ) + * ``` + * + * @since 2.0.0 + * @category Tracing + */ + (effect: Effect, enabled: boolean): Effect +} = core.withTracerEnabled + +/** + * @since 2.0.0 + * @category Tracing + */ +export const withTracerTiming: { + /** + * @since 2.0.0 + * @category Tracing + */ + (enabled: boolean): (effect: Effect) => Effect + /** + * @since 2.0.0 + * @category Tracing + */ + (effect: Effect, enabled: boolean): Effect +} = core.withTracerTiming + +/** + * Adds annotations to each span in the effect for enhanced traceability. + * + * **Details** + * + * This function lets you attach key-value annotations to all spans generated + * during the execution of an effect. Annotations provide additional context, + * such as metadata or labels, which can help you understand and debug + * asynchronous workflows more effectively. + * + * You can either pass a single key-value pair or a record of key-value pairs to + * annotate the spans. These annotations can then be visualized in tracing tools + * that support span annotations. + * + * @since 2.0.0 + * @category Tracing + */ +export const annotateSpans: { + /** + * Adds annotations to each span in the effect for enhanced traceability. + * + * **Details** + * + * This function lets you attach key-value annotations to all spans generated + * during the execution of an effect. Annotations provide additional context, + * such as metadata or labels, which can help you understand and debug + * asynchronous workflows more effectively. + * + * You can either pass a single key-value pair or a record of key-value pairs to + * annotate the spans. These annotations can then be visualized in tracing tools + * that support span annotations. + * + * @since 2.0.0 + * @category Tracing + */ + (key: string, value: unknown): (effect: Effect) => Effect + /** + * Adds annotations to each span in the effect for enhanced traceability. + * + * **Details** + * + * This function lets you attach key-value annotations to all spans generated + * during the execution of an effect. Annotations provide additional context, + * such as metadata or labels, which can help you understand and debug + * asynchronous workflows more effectively. + * + * You can either pass a single key-value pair or a record of key-value pairs to + * annotate the spans. These annotations can then be visualized in tracing tools + * that support span annotations. + * + * @since 2.0.0 + * @category Tracing + */ + (values: Record): (effect: Effect) => Effect + /** + * Adds annotations to each span in the effect for enhanced traceability. + * + * **Details** + * + * This function lets you attach key-value annotations to all spans generated + * during the execution of an effect. Annotations provide additional context, + * such as metadata or labels, which can help you understand and debug + * asynchronous workflows more effectively. + * + * You can either pass a single key-value pair or a record of key-value pairs to + * annotate the spans. These annotations can then be visualized in tracing tools + * that support span annotations. + * + * @since 2.0.0 + * @category Tracing + */ + (effect: Effect, key: string, value: unknown): Effect + /** + * Adds annotations to each span in the effect for enhanced traceability. + * + * **Details** + * + * This function lets you attach key-value annotations to all spans generated + * during the execution of an effect. Annotations provide additional context, + * such as metadata or labels, which can help you understand and debug + * asynchronous workflows more effectively. + * + * You can either pass a single key-value pair or a record of key-value pairs to + * annotate the spans. These annotations can then be visualized in tracing tools + * that support span annotations. + * + * @since 2.0.0 + * @category Tracing + */ + (effect: Effect, values: Record): Effect +} = effect.annotateSpans + +/** + * Adds annotations to the currently active span for traceability. + * + * **Details** + * + * This function adds key-value annotations to the currently active span in the + * effect's trace. These annotations help provide more context about the + * operation being executed at a specific point in time. Unlike + * {@link annotateSpans}, which applies to all spans in an effect, this function + * focuses solely on the active span. + * + * You can either pass a single key-value pair or a record of key-value pairs to + * annotate the span. These annotations are useful for adding metadata to + * operations, especially in systems with detailed observability requirements. + * + * @since 2.0.0 + * @category Tracing + */ +export const annotateCurrentSpan: { + /** + * Adds annotations to the currently active span for traceability. + * + * **Details** + * + * This function adds key-value annotations to the currently active span in the + * effect's trace. These annotations help provide more context about the + * operation being executed at a specific point in time. Unlike + * {@link annotateSpans}, which applies to all spans in an effect, this function + * focuses solely on the active span. + * + * You can either pass a single key-value pair or a record of key-value pairs to + * annotate the span. These annotations are useful for adding metadata to + * operations, especially in systems with detailed observability requirements. + * + * @since 2.0.0 + * @category Tracing + */ + (key: string, value: unknown): Effect + /** + * Adds annotations to the currently active span for traceability. + * + * **Details** + * + * This function adds key-value annotations to the currently active span in the + * effect's trace. These annotations help provide more context about the + * operation being executed at a specific point in time. Unlike + * {@link annotateSpans}, which applies to all spans in an effect, this function + * focuses solely on the active span. + * + * You can either pass a single key-value pair or a record of key-value pairs to + * annotate the span. These annotations are useful for adding metadata to + * operations, especially in systems with detailed observability requirements. + * + * @since 2.0.0 + * @category Tracing + */ + (values: Record): Effect +} = effect.annotateCurrentSpan + +/** + * @since 2.0.0 + * @category Tracing + */ +export const currentSpan: Effect = effect.currentSpan + +/** + * @since 3.20.0 + * @category Tracing + */ +export const currentPropagatedSpan: Effect = effect.currentPropagatedSpan + +/** + * @since 2.0.0 + * @category Tracing + */ +export const currentParentSpan: Effect = effect.currentParentSpan + +/** + * @since 2.0.0 + * @category Tracing + */ +export const spanAnnotations: Effect> = effect.spanAnnotations + +/** + * @since 2.0.0 + * @category Tracing + */ +export const spanLinks: Effect> = effect.spanLinks + +/** + * For all spans in this effect, add a link with the provided span. + * + * @since 2.0.0 + * @category Tracing + */ +export const linkSpans: { + /** + * For all spans in this effect, add a link with the provided span. + * + * @since 2.0.0 + * @category Tracing + */ + (span: Tracer.AnySpan, attributes?: Record): (self: Effect) => Effect + /** + * For all spans in this effect, add a link with the provided span. + * + * @since 2.0.0 + * @category Tracing + */ + ( + self: Effect, + span: Tracer.AnySpan, + attributes?: Record + ): Effect +} = effect.linkSpans + +/** + * Add span links to the current span. + * + * @since 3.14.0 + * @category Tracing + */ +export const linkSpanCurrent: { + /** + * Add span links to the current span. + * + * @since 3.14.0 + * @category Tracing + */ + ( + span: Tracer.AnySpan, + attributes?: Readonly> | undefined + ): Effect + /** + * Add span links to the current span. + * + * @since 3.14.0 + * @category Tracing + */ + (links: ReadonlyArray): Effect +} = effect.linkSpanCurrent + +/** + * Create a new span for tracing. + * + * @since 2.0.0 + * @category Tracing + */ +export const makeSpan: ( + name: string, + options?: Tracer.SpanOptions +) => Effect = effect.makeSpan + +/** + * Create a new span for tracing, and automatically close it when the Scope + * finalizes. + * + * The span is not added to the current span stack, so no child spans will be + * created for it. + * + * @since 2.0.0 + * @category Tracing + */ +export const makeSpanScoped: ( + name: string, + options?: Tracer.SpanOptions | undefined +) => Effect = fiberRuntime.makeSpanScoped + +/** + * Create a new span for tracing, and automatically close it when the effect + * completes. + * + * The span is not added to the current span stack, so no child spans will be + * created for it. + * + * @since 2.0.0 + * @category Tracing + */ +export const useSpan: { + /** + * Create a new span for tracing, and automatically close it when the effect + * completes. + * + * The span is not added to the current span stack, so no child spans will be + * created for it. + * + * @since 2.0.0 + * @category Tracing + */ + (name: string, evaluate: (span: Tracer.Span) => Effect): Effect + /** + * Create a new span for tracing, and automatically close it when the effect + * completes. + * + * The span is not added to the current span stack, so no child spans will be + * created for it. + * + * @since 2.0.0 + * @category Tracing + */ + ( + name: string, + options: Tracer.SpanOptions, + evaluate: (span: Tracer.Span) => Effect + ): Effect +} = effect.useSpan + +/** + * Wraps the effect with a new span for tracing. + * + * @since 2.0.0 + * @category Tracing + */ +export const withSpan: { + /** + * Wraps the effect with a new span for tracing. + * + * @since 2.0.0 + * @category Tracing + */ + (name: string, options?: Tracer.SpanOptions | undefined): (self: Effect) => Effect> + /** + * Wraps the effect with a new span for tracing. + * + * @since 2.0.0 + * @category Tracing + */ + ( + self: Effect, + name: string, + options?: Tracer.SpanOptions | undefined + ): Effect> +} = effect.withSpan + +/** + * Wraps a function that returns an effect with a new span for tracing. + * + * @since 3.2.0 + * @category Models + */ +export interface FunctionWithSpanOptions { + readonly name: string + readonly attributes?: Record | undefined + readonly links?: ReadonlyArray | undefined + readonly parent?: Tracer.AnySpan | undefined + readonly root?: boolean | undefined + readonly context?: Context.Context | undefined + readonly kind?: Tracer.SpanKind | undefined +} + +/** + * Wraps a function that returns an effect with a new span for tracing. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * const getTodo = Effect.functionWithSpan({ + * body: (id: number) => Effect.succeed(`Got todo ${id}!`), + * options: (id) => ({ + * name: `getTodo-${id}`, + * attributes: { id } + * }) + * }) + * ``` + * + * @since 3.2.0 + * @category Tracing + */ +export const functionWithSpan: , Ret extends Effect>( + options: { + readonly body: (...args: Args) => Ret + readonly options: FunctionWithSpanOptions | ((...args: Args) => FunctionWithSpanOptions) + readonly captureStackTrace?: boolean | undefined + } +) => (...args: Args) => Unify.Unify = effect.functionWithSpan + +/** + * Wraps the effect with a new span for tracing. + * + * The span is ended when the Scope is finalized. + * + * @since 2.0.0 + * @category Tracing + */ +export const withSpanScoped: { + /** + * Wraps the effect with a new span for tracing. + * + * The span is ended when the Scope is finalized. + * + * @since 2.0.0 + * @category Tracing + */ + (name: string, options?: Tracer.SpanOptions): (self: Effect) => Effect | Scope.Scope> + /** + * Wraps the effect with a new span for tracing. + * + * The span is ended when the Scope is finalized. + * + * @since 2.0.0 + * @category Tracing + */ + (self: Effect, name: string, options?: Tracer.SpanOptions): Effect | Scope.Scope> +} = fiberRuntime.withSpanScoped + +/** + * Adds the provided span to the current span stack. + * + * @since 2.0.0 + * @category Tracing + */ +export const withParentSpan: { + /** + * Adds the provided span to the current span stack. + * + * @since 2.0.0 + * @category Tracing + */ + (span: Tracer.AnySpan): (self: Effect) => Effect> + /** + * Adds the provided span to the current span stack. + * + * @since 2.0.0 + * @category Tracing + */ + (self: Effect, span: Tracer.AnySpan): Effect> +} = effect.withParentSpan + +/** + * Safely handles nullable values by creating an effect that fails for `null` or + * `undefined`. + * + * **Details** + * + * This function ensures that an input value is non-null and non-undefined + * before processing it. If the value is valid, the effect succeeds with the + * value. If the value is `null` or `undefined`, the effect fails with a + * `NoSuchElementException`. This is particularly useful for avoiding + * null-related errors by clearly separating valid values from invalid ones in + * effectful computations. + * + * The failure with `NoSuchElementException` allows you to explicitly handle + * cases where a value is expected but not provided, leading to safer and more + * predictable code. + * + * **When to Use** + * + * Use this function when working with values that may be `null` or `undefined` + * and you want to ensure that only non-null values are processed. It helps + * enforce null-safety and makes error handling more explicit. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const maybe1 = Effect.fromNullable(1) + * + * Effect.runPromiseExit(maybe1).then(console.log) + * // Output: + * // { _id: 'Exit', _tag: 'Success', value: 1 } + * + * // ┌─── Effect + * // ▼ + * const maybe2 = Effect.fromNullable(null as number | null) + * + * Effect.runPromiseExit(maybe2).then(console.log) + * // Output: + * // { + * // _id: 'Exit', + * // _tag: 'Failure', + * // cause: { + * // _id: 'Cause', + * // _tag: 'Fail', + * // failure: { _tag: 'NoSuchElementException' } + * // } + * // } + * ``` + * + * @since 2.0.0 + * @category Optional Wrapping & Unwrapping + */ +export const fromNullable: (value: A) => Effect, Cause.NoSuchElementException> = effect.fromNullable + +/** + * Converts an effect that may fail with a `NoSuchElementException` into an + * effect that succeeds with an `Option`. + * + * **Details** + * + * This function transforms an effect that might fail with + * `Cause.NoSuchElementException` into an effect that succeeds with an `Option` + * type. If the original effect succeeds, its value is wrapped in `Option.some`. + * If it fails specifically due to a `NoSuchElementException`, the failure is + * mapped to `Option.none`. Other types of failures remain unchanged and are + * passed through as they are. + * + * This is useful when working with effects where you want to gracefully handle + * the absence of a value while preserving other potential failures. + * + * **When to Use** + * + * Use this function when you need to handle missing values as `Option.none` + * rather than throwing or propagating errors like `NoSuchElementException`. + * It’s ideal for scenarios where you want to explicitly represent optionality + * in a type-safe way while retaining other failure information. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * // ┌─── Effect + * // ▼ + * const maybe1 = Effect.fromNullable(1) + * + * // ┌─── Effect, never, never> + * // ▼ + * const option1 = Effect.optionFromOptional(maybe1) + * + * Effect.runPromise(option1).then(console.log) + * // Output: { _id: 'Option', _tag: 'Some', value: 1 } + * + * // ┌─── Effect + * // ▼ + * const maybe2 = Effect.fromNullable(null as number | null) + * + * // ┌─── Effect, never, never> + * // ▼ + * const option2 = Effect.optionFromOptional(maybe2) + * + * Effect.runPromise(option2).then(console.log) + * // Output: { _tag: 'None' } + * ``` + * + * @since 2.0.0 + * @category Optional Wrapping & Unwrapping + */ +export const optionFromOptional: ( + self: Effect +) => Effect, Exclude, R> = effect.optionFromOptional + +/** + * Converts an `Option` of an `Effect` into an `Effect` of an `Option`. + * + * **Details** + * + * This function transforms an `Option>` into an + * `Effect, E, R>`. If the `Option` is `None`, the resulting `Effect` + * will immediately succeed with a `None` value. If the `Option` is `Some`, the + * inner `Effect` will be executed, and its result wrapped in a `Some`. + * + * **Example** + * + * ```ts + * import { Effect, Option } from "effect" + * + * // ┌─── Option> + * // ▼ + * const maybe = Option.some(Effect.succeed(42)) + * + * // ┌─── Effect, never, never> + * // ▼ + * const result = Effect.transposeOption(maybe) + * + * console.log(Effect.runSync(result)) + * // Output: { _id: 'Option', _tag: 'Some', value: 42 } + * ``` + * + * @since 3.13.0 + * @category Optional Wrapping & Unwrapping + */ +export const transposeOption = ( + self: Option.Option> +): Effect, E, R> => { + return option_.isNone(self) ? succeedNone : map(self.value, option_.some) +} + +/** + * Applies an `Effect` on an `Option` and transposes the result. + * + * **Details** + * + * If the `Option` is `None`, the resulting `Effect` will immediately succeed with a `None` value. + * If the `Option` is `Some`, the effectful operation will be executed on the inner value, and its result wrapped in a `Some`. + * + * @example + * ```ts + * import { Effect, Option, pipe } from "effect" + * + * // ┌─── Effect, never, never>> + * // ▼ + * const noneResult = pipe( + * Option.none(), + * Effect.transposeMapOption(() => Effect.succeed(42)) // will not be executed + * ) + * console.log(Effect.runSync(noneResult)) + * // Output: { _id: 'Option', _tag: 'None' } + * + * // ┌─── Effect, never, never>> + * // ▼ + * const someSuccessResult = pipe( + * Option.some(42), + * Effect.transposeMapOption((value) => Effect.succeed(value * 2)) + * ) + * console.log(Effect.runSync(someSuccessResult)) + * // Output: { _id: 'Option', _tag: 'Some', value: 84 } + * ``` + * + * @since 3.14.0 + * @category Optional Wrapping & Unwrapping + */ +export const transposeMapOption = dual< + /** + * Applies an `Effect` on an `Option` and transposes the result. + * + * **Details** + * + * If the `Option` is `None`, the resulting `Effect` will immediately succeed with a `None` value. + * If the `Option` is `Some`, the effectful operation will be executed on the inner value, and its result wrapped in a `Some`. + * + * @example + * ```ts + * import { Effect, Option, pipe } from "effect" + * + * // ┌─── Effect, never, never>> + * // ▼ + * const noneResult = pipe( + * Option.none(), + * Effect.transposeMapOption(() => Effect.succeed(42)) // will not be executed + * ) + * console.log(Effect.runSync(noneResult)) + * // Output: { _id: 'Option', _tag: 'None' } + * + * // ┌─── Effect, never, never>> + * // ▼ + * const someSuccessResult = pipe( + * Option.some(42), + * Effect.transposeMapOption((value) => Effect.succeed(value * 2)) + * ) + * console.log(Effect.runSync(someSuccessResult)) + * // Output: { _id: 'Option', _tag: 'Some', value: 84 } + * ``` + * + * @since 3.14.0 + * @category Optional Wrapping & Unwrapping + */ + (f: (self: A) => Effect) => (self: Option.Option) => Effect, E, R>, + /** + * Applies an `Effect` on an `Option` and transposes the result. + * + * **Details** + * + * If the `Option` is `None`, the resulting `Effect` will immediately succeed with a `None` value. + * If the `Option` is `Some`, the effectful operation will be executed on the inner value, and its result wrapped in a `Some`. + * + * @example + * ```ts + * import { Effect, Option, pipe } from "effect" + * + * // ┌─── Effect, never, never>> + * // ▼ + * const noneResult = pipe( + * Option.none(), + * Effect.transposeMapOption(() => Effect.succeed(42)) // will not be executed + * ) + * console.log(Effect.runSync(noneResult)) + * // Output: { _id: 'Option', _tag: 'None' } + * + * // ┌─── Effect, never, never>> + * // ▼ + * const someSuccessResult = pipe( + * Option.some(42), + * Effect.transposeMapOption((value) => Effect.succeed(value * 2)) + * ) + * console.log(Effect.runSync(someSuccessResult)) + * // Output: { _id: 'Option', _tag: 'Some', value: 84 } + * ``` + * + * @since 3.14.0 + * @category Optional Wrapping & Unwrapping + */ + (self: Option.Option, f: (self: A) => Effect) => Effect, E, R> +>(2, (self, f) => option_.isNone(self) ? succeedNone : map(f(self.value), option_.some)) + +/** + * @since 2.0.0 + * @category Models + */ +export declare namespace Tag { + /** + * @since 2.0.0 + * @category Models + */ + export interface ProhibitedType { + Service?: `property "Service" is forbidden` + Identifier?: `property "Identifier" is forbidden` + _op?: `property "_op" is forbidden` + of?: `property "of" is forbidden` + context?: `property "context" is forbidden` + key?: `property "key" is forbidden` + stack?: `property "stack" is forbidden` + name?: `property "name" is forbidden` + pipe?: `property "pipe" is forbidden` + use?: `property "use" is forbidden` + } + + /** + * @since 2.0.0 + * @category Models + */ + export type AllowedType = (Record & ProhibitedType) | string | number | symbol + + /** + * @since 3.9.0 + * @category Models + */ + export type Proxy = { + [ + k in keyof Type as Type[k] extends ((...args: infer Args extends ReadonlyArray) => infer Ret) ? + ((...args: Readonly) => Ret) extends Type[k] ? k : never + : k + ]: Type[k] extends (...args: infer Args extends ReadonlyArray) => Effect ? + (...args: Readonly) => Effect + : Type[k] extends (...args: infer Args extends ReadonlyArray) => Promise ? + (...args: Readonly) => Effect + : Type[k] extends (...args: infer Args extends ReadonlyArray) => infer A ? + (...args: Readonly) => Effect + : Type[k] extends Effect ? Effect + : Effect + } +} + +const makeTagProxy = (TagClass: Context.Tag & Record) => { + const cache = new Map() + return new Proxy(TagClass, { + get(target: any, prop: any, receiver) { + if (prop in target) { + return Reflect.get(target, prop, receiver) + } + if (cache.has(prop)) { + return cache.get(prop) + } + const fn = (...args: Array) => + core.andThen(target, (s: any) => { + if (typeof s[prop] === "function") { + cache.set(prop, (...args: Array) => core.andThen(target, (s: any) => s[prop](...args))) + return s[prop](...args) + } + cache.set(prop, core.andThen(target, (s: any) => s[prop])) + return s[prop] + }) + const cn = core.andThen(target, (s: any) => s[prop]) + // @effect-diagnostics-next-line floatingEffect:off + Object.assign(fn, cn) + const apply = fn.apply + const bind = fn.bind + const call = fn.call + const proto = Object.setPrototypeOf({}, Object.getPrototypeOf(cn)) + proto.apply = apply + proto.bind = bind + proto.call = call + Object.setPrototypeOf(fn, proto) + cache.set(prop, fn) + return fn + } + }) +} + +/** + * Creates a unique tag for a dependency, embedding the service's methods as + * static properties. + * + * **Details** + * + * This function allows you to define a `Tag` for a service or dependency in + * your application. The `Tag` not only acts as an identifier but also provides + * direct access to the service's methods via static properties. This makes it + * easier to access and use the service in your code without manually managing + * contexts. + * + * In the example below, the fields of the service (in this case, the `notify` + * method) are turned into static properties of the Notifications class, making + * it easier to access them. + * + * **Example** + * + * ```ts + * import { Effect } from "effect" + * + * class Notifications extends Effect.Tag("Notifications")< + * Notifications, + * { readonly notify: (message: string) => Effect.Effect } + * >() {} + * + * // Create an effect that depends on the Notifications service + * const action = Notifications.notify("Hello, world!") + * ``` + * + * @since 2.0.0 + * @category Context + */ +export const Tag: (id: Id) => < + Self, + Type extends Tag.AllowedType +>() => + & Context.TagClass + & (Type extends Record ? Tag.Proxy : {}) + & { + use: ( + body: (_: Type) => X + ) => [X] extends [Effect] ? Effect + : [X] extends [PromiseLike] ? Effect + : Effect + } = (id) => () => { + const limit = Error.stackTraceLimit + Error.stackTraceLimit = 2 + const creationError = new Error() + Error.stackTraceLimit = limit + function TagClass() {} + Object.setPrototypeOf(TagClass, TagProto) + TagClass.key = id + Object.defineProperty(TagClass, "use", { + get() { + return (body: (_: any) => any) => core.andThen(this, body) + } + }) + Object.defineProperty(TagClass, "stack", { + get() { + return creationError.stack + } + }) + return makeTagProxy(TagClass as any) + } + +type MissingSelfGeneric = `Missing \`Self\` generic - use \`class Self extends Effect.Service()...\`` + +/** + * Simplifies the creation and management of services in Effect by defining both + * a `Tag` and a `Layer`. + * + * **Details** + * + * This function allows you to streamline the creation of services by combining + * the definition of a `Context.Tag` and a `Layer` in a single step. It supports + * various ways of providing the service implementation: + * - Using an `effect` to define the service dynamically. + * - Using `sync` or `succeed` to define the service statically. + * - Using `scoped` to create services with lifecycle management. + * + * It also allows you to specify dependencies for the service, which will be + * provided automatically when the service is used. Accessors can be optionally + * generated for the service, making it more convenient to use. + * + * **Example** + * + * ```ts + * import { Effect } from 'effect'; + * + * class Prefix extends Effect.Service()("Prefix", { + * sync: () => ({ prefix: "PRE" }) + * }) {} + * + * class Logger extends Effect.Service()("Logger", { + * accessors: true, + * effect: Effect.gen(function* () { + * const { prefix } = yield* Prefix + * return { + * info: (message: string) => + * Effect.sync(() => { + * console.log(`[${prefix}][${message}]`) + * }) + * } + * }), + * dependencies: [Prefix.Default] + * }) {} + * ``` + * + * @since 3.9.0 + * @category Context + * @experimental might be up for breaking changes + */ +export const Service: () => [Self] extends [never] ? MissingSelfGeneric : { + < + const Key extends string, + const Make extends + | { + readonly scoped: + | Effect, any, any> + | ((...args: any) => Effect, any, any>) + readonly dependencies?: ReadonlyArray + readonly accessors?: boolean + /** @deprecated */ + readonly ಠ_ಠ: never + } + | { + readonly effect: + | Effect, any, any> + | ((...args: any) => Effect, any, any>) + readonly dependencies?: ReadonlyArray + readonly accessors?: boolean + /** @deprecated */ + readonly ಠ_ಠ: never + } + | { + readonly sync: LazyArg> + readonly dependencies?: ReadonlyArray + readonly accessors?: boolean + /** @deprecated */ + readonly ಠ_ಠ: never + } + | { + readonly succeed: Service.AllowedType + readonly dependencies?: ReadonlyArray + readonly accessors?: boolean + /** @deprecated */ + readonly ಠ_ಠ: never + } + >( + key: Key, + make: Make + ): Service.Class + < + const Key extends string, + const Make extends NoExcessProperties<{ + readonly scoped: + | Effect, any, any> + | ((...args: any) => Effect, any, any>) + readonly dependencies?: ReadonlyArray + readonly accessors?: boolean + }, Make> + >( + key: Key, + make: Make + ): Service.Class + < + const Key extends string, + const Make extends NoExcessProperties<{ + readonly effect: + | Effect, any, any> + | ((...args: any) => Effect, any, any>) + readonly dependencies?: ReadonlyArray + readonly accessors?: boolean + }, Make> + >( + key: Key, + make: Make + ): Service.Class + < + const Key extends string, + const Make extends NoExcessProperties<{ + readonly sync: LazyArg> + readonly dependencies?: ReadonlyArray + readonly accessors?: boolean + }, Make> + >( + key: Key, + make: Make + ): Service.Class + < + const Key extends string, + const Make extends NoExcessProperties<{ + readonly succeed: Service.AllowedType + readonly dependencies?: ReadonlyArray + readonly accessors?: boolean + }, Make> + >( + key: Key, + make: Make + ): Service.Class +} = function() { + return function() { + const [id, maker] = arguments + const proxy = "accessors" in maker ? maker["accessors"] : false + const limit = Error.stackTraceLimit + Error.stackTraceLimit = 2 + const creationError = new Error() + Error.stackTraceLimit = limit + + let patchState: "unchecked" | "plain" | "patched" = "unchecked" + const TagClass: any = function(this: any, service: any) { + if (patchState === "unchecked") { + const proto = Object.getPrototypeOf(service) + if (proto === Object.prototype || proto === null) { + patchState = "plain" + } else { + const selfProto = Object.getPrototypeOf(this) + Object.setPrototypeOf(selfProto, proto) + patchState = "patched" + } + } + if (patchState === "plain") { + Object.assign(this, service) + } else if (patchState === "patched") { + Object.setPrototypeOf(service, Object.getPrototypeOf(this)) + return service + } + } + + TagClass.prototype._tag = id + Object.defineProperty(TagClass, "make", { + get() { + return (service: any) => new this(service) + } + }) + Object.defineProperty(TagClass, "use", { + get() { + return (body: any) => core.andThen(this, body) + } + }) + TagClass.key = id + + Object.assign(TagClass, TagProto) + + Object.defineProperty(TagClass, "stack", { + get() { + return creationError.stack + } + }) + + const hasDeps = "dependencies" in maker && maker.dependencies.length > 0 + const layerName = hasDeps ? "DefaultWithoutDependencies" : "Default" + let layerCache: Layer.Layer.Any | undefined + let isFunction = false + if ("effect" in maker) { + isFunction = typeof maker.effect === "function" + Object.defineProperty(TagClass, layerName, { + get(this: any) { + if (isFunction) { + return function(this: typeof TagClass) { + return layer.fromEffect(TagClass, map(maker.effect.apply(null, arguments), (_) => new this(_))) + }.bind(this) + } + return layerCache ??= layer.fromEffect(TagClass, map(maker.effect, (_) => new this(_))) + } + }) + } else if ("scoped" in maker) { + isFunction = typeof maker.scoped === "function" + Object.defineProperty(TagClass, layerName, { + get(this: any) { + if (isFunction) { + return function(this: typeof TagClass) { + return layer.scoped(TagClass, map(maker.scoped.apply(null, arguments), (_) => new this(_))) + }.bind(this) + } + return layerCache ??= layer.scoped(TagClass, map(maker.scoped, (_) => new this(_))) + } + }) + } else if ("sync" in maker) { + Object.defineProperty(TagClass, layerName, { + get(this: any) { + return layerCache ??= layer.sync(TagClass, () => new this(maker.sync())) + } + }) + } else { + Object.defineProperty(TagClass, layerName, { + get(this: any) { + return layerCache ??= layer.succeed(TagClass, new this(maker.succeed)) + } + }) + } + + if (hasDeps) { + let layerWithDepsCache: Layer.Layer.Any | undefined + Object.defineProperty(TagClass, "Default", { + get(this: any) { + if (isFunction) { + return function(this: typeof TagClass) { + return layer.provide( + this.DefaultWithoutDependencies.apply(null, arguments), + maker.dependencies + ) + } + } + return layerWithDepsCache ??= layer.provide( + this.DefaultWithoutDependencies, + maker.dependencies + ) + } + }) + } + + return proxy === true ? makeTagProxy(TagClass) : TagClass + } +} as any + +/** + * @since 3.9.0 + * @category Context + */ +export declare namespace Service { + /** + * @since 3.9.0 + */ + export interface ProhibitedType { + Service?: `property "Service" is forbidden` + Identifier?: `property "Identifier" is forbidden` + Default?: `property "Default" is forbidden` + DefaultWithoutDependencies?: `property "DefaultWithoutDependencies" is forbidden` + _op_layer?: `property "_op_layer" is forbidden` + _op?: `property "_op" is forbidden` + of?: `property "of" is forbidden` + make?: `property "make" is forbidden` + context?: `property "context" is forbidden` + key?: `property "key" is forbidden` + stack?: `property "stack" is forbidden` + name?: `property "name" is forbidden` + pipe?: `property "pipe" is forbidden` + use?: `property "use" is forbidden` + _tag?: `property "_tag" is forbidden` + } + + /** + * @since 3.9.0 + */ + export type AllowedType = MakeAccessors extends true ? + & Record + & { + readonly [K in Extract, keyof ProhibitedType>]: K extends "_tag" ? Key + : ProhibitedType[K] + } + : Record & { readonly _tag?: Key } + + /** + * @since 3.9.0 + */ + export type Class< + Self, + Key extends string, + Make + > = + & { + new(_: MakeService): MakeService & { + readonly _tag: Key + } + readonly use: ( + body: (_: Self) => X + ) => [X] extends [Effect] ? Effect + : [X] extends [PromiseLike] ? Effect + : Effect + readonly make: (_: MakeService) => Self + } + & Context.Tag + & { key: Key } + & (MakeAccessors extends true ? Tag.Proxy> : {}) + & (MakeDeps extends never ? { + readonly Default: HasArguments extends true ? + (...args: MakeArguments) => Layer.Layer, MakeContext> + : Layer.Layer, MakeContext> + } : + { + readonly DefaultWithoutDependencies: HasArguments extends true + ? (...args: MakeArguments) => Layer.Layer, MakeContext> + : Layer.Layer, MakeContext> + + readonly Default: HasArguments extends true ? (...args: MakeArguments) => Layer.Layer< + Self, + MakeError | MakeDepsE, + | Exclude, MakeDepsOut> + | MakeDepsIn + > : + Layer.Layer< + Self, + MakeError | MakeDepsE, + | Exclude, MakeDepsOut> + | MakeDepsIn + > + }) + + /** + * @since 3.9.0 + */ + export type MakeService = Make extends { readonly effect: Effect } ? _A + : Make extends { readonly scoped: Effect } ? _A + : Make extends { readonly effect: (...args: infer _Args) => Effect } ? _A + : Make extends { readonly scoped: (...args: infer _Args) => Effect } ? _A + : Make extends { readonly sync: LazyArg } ? A + : Make extends { readonly succeed: infer A } ? A + : never + + /** + * @since 3.9.0 + */ + export type MakeError = Make extends { readonly effect: Effect } ? _E + : Make extends { readonly scoped: Effect } ? _E + : Make extends { readonly effect: (...args: infer _Args) => Effect } ? _E + : Make extends { readonly scoped: (...args: infer _Args) => Effect } ? _E + : never + + /** + * @since 3.9.0 + */ + export type MakeContext = Make extends { readonly effect: Effect } ? _R + : Make extends { readonly scoped: Effect } ? Exclude<_R, Scope.Scope> + : Make extends { readonly effect: (...args: infer _Args) => Effect } ? _R + : Make extends { readonly scoped: (...args: infer _Args) => Effect } ? + Exclude<_R, Scope.Scope> + : never + + /** + * @since 3.9.0 + */ + export type MakeDeps = Make extends { readonly dependencies: ReadonlyArray } + ? Make["dependencies"][number] + : never + + /** + * @since 3.9.0 + */ + export type MakeDepsOut = Contravariant.Type[Layer.LayerTypeId]["_ROut"]> + + /** + * @since 3.9.0 + */ + export type MakeDepsE = Covariant.Type[Layer.LayerTypeId]["_E"]> + + /** + * @since 3.9.0 + */ + export type MakeDepsIn = Covariant.Type[Layer.LayerTypeId]["_RIn"]> + + /** + * @since 3.9.0 + */ + export type MakeAccessors = Make extends { readonly accessors: true } ? true + : false + + /** + * @since 3.16.0 + */ + export type MakeArguments = Make extends + { readonly effect: (...args: infer Args) => Effect } ? Args + : Make extends { readonly scoped: (...args: infer Args) => Effect } ? Args + : never + + /** + * @since 3.16.0 + */ + export type HasArguments = Make extends { + readonly scoped: (...args: ReadonlyArray) => Effect + } ? true : + Make extends { + readonly effect: (...args: ReadonlyArray) => Effect + } ? true : + false +} + +/** + * @since 3.11.0 + * @category Models + */ +export namespace fn { + /** + * @since 3.19.0 + * @category Models + */ + export type Return = Generator>, A, any> + /** + * @since 3.11.0 + * @category Models + */ + export type Gen = { + >, AEff, Args extends Array>( + body: (...args: Args) => Generator + ): (...args: Args) => Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + > + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A extends Effect + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A + ): (...args: Args) => Effect.AsEffect + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B extends Effect + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B + ): (...args: Args) => Effect.AsEffect + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C extends Effect + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C + ): (...args: Args) => Effect.AsEffect + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C, + D extends Effect + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C, + d: (_: C, ...args: NoInfer) => D + ): (...args: Args) => Effect.AsEffect + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C, + D, + E extends Effect + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C, + d: (_: C, ...args: NoInfer) => D, + e: (_: D, ...args: NoInfer) => E + ): (...args: Args) => Effect.AsEffect + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F extends Effect + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C, + d: (_: C, ...args: NoInfer) => D, + e: (_: D, ...args: NoInfer) => E, + f: (_: E, ...args: NoInfer) => F + ): (...args: Args) => Effect.AsEffect + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G extends Effect + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C, + d: (_: C, ...args: NoInfer) => D, + e: (_: D, ...args: NoInfer) => E, + f: (_: E, ...args: NoInfer) => F, + g: (_: F, ...args: NoInfer) => G + ): (...args: Args) => Effect.AsEffect + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H extends Effect + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C, + d: (_: C, ...args: NoInfer) => D, + e: (_: D, ...args: NoInfer) => E, + f: (_: E, ...args: NoInfer) => F, + g: (_: F, ...args: NoInfer) => G, + h: (_: G, ...args: NoInfer) => H + ): (...args: Args) => Effect.AsEffect + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I extends Effect + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C, + d: (_: C, ...args: NoInfer) => D, + e: (_: D, ...args: NoInfer) => E, + f: (_: E, ...args: NoInfer) => F, + g: (_: F, ...args: NoInfer) => G, + h: (_: G, ...args: NoInfer) => H, + i: (_: H, ...args: NoInfer) => I + ): (...args: Args) => Effect.AsEffect + } + + /** + * @since 3.11.0 + * @category Models + */ + export type NonGen = { + , Args extends Array>( + body: (...args: Args) => Eff + ): (...args: Args) => Effect.AsEffect + , A, Args extends Array>( + body: (...args: Args) => A, + a: (_: A, ...args: NoInfer) => Eff + ): (...args: Args) => Effect.AsEffect + , A, B, Args extends Array>( + body: (...args: Args) => A, + a: (_: A, ...args: NoInfer) => B, + b: (_: B, ...args: NoInfer) => Eff + ): (...args: Args) => Effect.AsEffect + , A, B, C, Args extends Array>( + body: (...args: Args) => A, + a: (_: A, ...args: NoInfer) => B, + b: (_: B, ...args: NoInfer) => C, + c: (_: C, ...args: NoInfer) => Eff + ): (...args: Args) => Effect.AsEffect + , A, B, C, D, Args extends Array>( + body: (...args: Args) => A, + a: (_: A, ...args: NoInfer) => B, + b: (_: B, ...args: NoInfer) => C, + c: (_: C, ...args: NoInfer) => D, + d: (_: D, ...args: NoInfer) => Eff + ): (...args: Args) => Effect.AsEffect + , A, B, C, D, E, Args extends Array>( + body: (...args: Args) => A, + a: (_: A, ...args: NoInfer) => B, + b: (_: B, ...args: NoInfer) => C, + c: (_: C, ...args: NoInfer) => D, + d: (_: D, ...args: NoInfer) => E, + e: (_: E, ...args: NoInfer) => Eff + ): (...args: Args) => Effect.AsEffect + , A, B, C, D, E, F, Args extends Array>( + body: (...args: Args) => A, + a: (_: A, ...args: NoInfer) => B, + b: (_: B, ...args: NoInfer) => C, + c: (_: C, ...args: NoInfer) => D, + d: (_: D, ...args: NoInfer) => E, + e: (_: E, ...args: NoInfer) => F, + f: (_: F, ...args: NoInfer) => Eff + ): (...args: Args) => Effect.AsEffect + , A, B, C, D, E, F, G, Args extends Array>( + body: (...args: Args) => A, + a: (_: A, ...args: NoInfer) => B, + b: (_: B, ...args: NoInfer) => C, + c: (_: C, ...args: NoInfer) => D, + d: (_: D, ...args: NoInfer) => E, + e: (_: E, ...args: NoInfer) => F, + f: (_: F, ...args: NoInfer) => G, + g: (_: G, ...args: NoInfer) => Eff + ): (...args: Args) => Effect.AsEffect + , A, B, C, D, E, F, G, H, Args extends Array>( + body: (...args: Args) => A, + a: (_: A, ...args: NoInfer) => B, + b: (_: B, ...args: NoInfer) => C, + c: (_: C, ...args: NoInfer) => D, + d: (_: D, ...args: NoInfer) => E, + e: (_: E, ...args: NoInfer) => F, + f: (_: F, ...args: NoInfer) => G, + g: (_: G, ...args: NoInfer) => H, + h: (_: H, ...args: NoInfer) => Eff + ): (...args: Args) => Effect.AsEffect + , A, B, C, D, E, F, G, H, I, Args extends Array>( + body: (...args: Args) => A, + a: (_: A, ...args: NoInfer) => B, + b: (_: B, ...args: NoInfer) => C, + c: (_: C, ...args: NoInfer) => D, + d: (_: D, ...args: NoInfer) => E, + e: (_: E, ...args: NoInfer) => F, + f: (_: F, ...args: NoInfer) => G, + g: (_: G, ...args: NoInfer) => H, + h: (_: H, ...args: NoInfer) => I, + i: (_: H, ...args: NoInfer) => Eff + ): (...args: Args) => Effect.AsEffect + } + + /** + * @since 3.11.0 + * @category Models + */ + export type Untraced = { + >, AEff, Args extends Array>( + body: (...args: Args) => Generator + ): (...args: Args) => Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + > + >, AEff, Args extends Array, A>( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A + ): (...args: Args) => A + >, AEff, Args extends Array, A, B>( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B + ): (...args: Args) => B + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C + ): (...args: Args) => C + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C, + D + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C, + d: (_: C, ...args: NoInfer) => D + ): (...args: Args) => D + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C, + D, + E + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C, + d: (_: C, ...args: NoInfer) => D, + e: (_: D, ...args: NoInfer) => E + ): (...args: Args) => E + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C, + d: (_: C, ...args: NoInfer) => D, + e: (_: D, ...args: NoInfer) => E, + f: (_: E, ...args: NoInfer) => F + ): (...args: Args) => F + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C, + d: (_: C, ...args: NoInfer) => D, + e: (_: D, ...args: NoInfer) => E, + f: (_: E, ...args: NoInfer) => F, + g: (_: F, ...args: NoInfer) => G + ): (...args: Args) => G + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C, + d: (_: C, ...args: NoInfer) => D, + e: (_: D, ...args: NoInfer) => E, + f: (_: E, ...args: NoInfer) => F, + g: (_: F, ...args: NoInfer) => G, + h: (_: G, ...args: NoInfer) => H + ): (...args: Args) => H + < + Eff extends YieldWrap>, + AEff, + Args extends Array, + A, + B, + C, + D, + E, + F, + G, + H, + I + >( + body: (...args: Args) => Generator, + a: ( + _: Effect< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never + >, + ...args: NoInfer + ) => A, + b: (_: A, ...args: NoInfer) => B, + c: (_: B, ...args: NoInfer) => C, + d: (_: C, ...args: NoInfer) => D, + e: (_: D, ...args: NoInfer) => E, + f: (_: E, ...args: NoInfer) => F, + g: (_: F, ...args: NoInfer) => G, + h: (_: G, ...args: NoInfer) => H, + i: (_: H, ...args: NoInfer) => I + ): (...args: Args) => I + } +} + +/** + * The `Effect.fn` function allows you to create traced functions that return an + * effect. It provides two key features: + * + * - **Stack traces with location details** if an error occurs. + * - **Automatic span creation** for tracing when a span name is provided. + * + * If a span name is passed as the first argument, the function's execution is + * tracked using that name. If no name is provided, stack tracing still works, + * but spans are not created. + * + * A function can be defined using either: + * + * - A generator function, allowing the use of `yield*` for effect composition. + * - A regular function that returns an `Effect`. + * + * **Example** (Creating a Traced Function with a Span Name) + * + * ```ts + * import { Effect } from "effect" + * + * const myfunc = Effect.fn("myspan")(function* (n: N) { + * yield* Effect.annotateCurrentSpan("n", n) // Attach metadata to the span + * console.log(`got: ${n}`) + * yield* Effect.fail(new Error("Boom!")) // Simulate failure + * }) + * + * Effect.runFork(myfunc(100).pipe(Effect.catchAllCause(Effect.logError))) + * // Output: + * // got: 100 + * // timestamp=... level=ERROR fiber=#0 cause="Error: Boom! + * // at (/.../index.ts:6:22) <= Raise location + * // at myspan (/.../index.ts:3:23) <= Definition location + * // at myspan (/.../index.ts:9:16)" <= Call location + * ``` + * + * `Effect.fn` automatically creates spans. The spans capture information about + * the function execution, including metadata and error details. + * + * **Example** (Exporting Spans to the Console) + * + * ```ts skip-type-checking + * import { Effect } from "effect" + * import { NodeSdk } from "@effect/opentelemetry" + * import { + * ConsoleSpanExporter, + * BatchSpanProcessor + * } from "@opentelemetry/sdk-trace-base" + * + * const myfunc = Effect.fn("myspan")(function* (n: N) { + * yield* Effect.annotateCurrentSpan("n", n) + * console.log(`got: ${n}`) + * yield* Effect.fail(new Error("Boom!")) + * }) + * + * const program = myfunc(100) + * + * const NodeSdkLive = NodeSdk.layer(() => ({ + * resource: { serviceName: "example" }, + * // Export span data to the console + * spanProcessor: new BatchSpanProcessor(new ConsoleSpanExporter()) + * })) + * + * Effect.runFork(program.pipe(Effect.provide(NodeSdkLive))) + * // Output: + * // got: 100 + * // { + * // resource: { + * // attributes: { + * // 'service.name': 'example', + * // 'telemetry.sdk.language': 'nodejs', + * // 'telemetry.sdk.name': '@effect/opentelemetry', + * // 'telemetry.sdk.version': '1.30.1' + * // } + * // }, + * // instrumentationScope: { name: 'example', version: undefined, schemaUrl: undefined }, + * // traceId: '22801570119e57a6e2aacda3dec9665b', + * // parentId: undefined, + * // traceState: undefined, + * // name: 'myspan', + * // id: '7af530c1e01bc0cb', + * // kind: 0, + * // timestamp: 1741182277518402.2, + * // duration: 4300.416, + * // attributes: { + * // n: 100, + * // 'code.stacktrace': 'at (/.../index.ts:8:23)\n' + + * // 'at (/.../index.ts:14:17)' + * // }, + * // status: { code: 2, message: 'Boom!' }, + * // events: [ + * // { + * // name: 'exception', + * // attributes: { + * // 'exception.type': 'Error', + * // 'exception.message': 'Boom!', + * // 'exception.stacktrace': 'Error: Boom!\n' + + * // ' at (/.../index.ts:11:22)\n' + + * // ' at myspan (/.../index.ts:8:23)\n' + + * // ' at myspan (/.../index.ts:14:17)' + * // }, + * // time: [ 1741182277, 522702583 ], + * // droppedAttributesCount: 0 + * // } + * // ], + * // links: [] + * // } + * ``` + * + * `Effect.fn` also acts as a pipe function, allowing you to create a pipeline + * after the function definition using the effect returned by the generator + * function as the starting value of the pipeline. + * + * **Example** (Creating a Traced Function with a Delay) + * + * ```ts + * import { Effect } from "effect" + * + * const myfunc = Effect.fn( + * function* (n: number) { + * console.log(`got: ${n}`) + * yield* Effect.fail(new Error("Boom!")) + * }, + * // You can access both the created effect and the original arguments + * (effect, n) => Effect.delay(effect, `${n / 100} seconds`) + * ) + * + * Effect.runFork(myfunc(100).pipe(Effect.catchAllCause(Effect.logError))) + * // Output: + * // got: 100 + * // timestamp=... level=ERROR fiber=#0 cause="Error: Boom! (<= after 1 second) + * ``` + * + * @see {@link fnUntraced} for a version of this function that doesn't add a span. + * + * @since 3.11.0 + * @category Tracing + */ +export const fn: + & fn.Gen + & fn.NonGen + & (( + name: string, + options?: Tracer.SpanOptions + ) => fn.Gen & fn.NonGen) = function(nameOrBody: Function | string, ...pipeables: Array) { + const limit = Error.stackTraceLimit + Error.stackTraceLimit = 2 + const errorDef = new Error() + Error.stackTraceLimit = limit + if (typeof nameOrBody !== "string") { + return defineLength(nameOrBody.length, function(this: any, ...args: Array) { + const limit = Error.stackTraceLimit + Error.stackTraceLimit = 2 + const errorCall = new Error() + Error.stackTraceLimit = limit + return fnApply({ + self: this, + body: nameOrBody, + args, + pipeables, + spanName: "", + spanOptions: { + context: internalTracer.DisablePropagation.context(true) + }, + errorDef, + errorCall + }) + }) as any + } + const name = nameOrBody + const options = pipeables[0] + return (body: Function, ...pipeables: Array) => + defineLength( + body.length, + ({ + [name](this: any, ...args: Array) { + const limit = Error.stackTraceLimit + Error.stackTraceLimit = 2 + const errorCall = new Error() + Error.stackTraceLimit = limit + return fnApply({ + self: this, + body, + args, + pipeables, + spanName: name, + spanOptions: options, + errorDef, + errorCall + }) + } + })[name] + ) + } + +function defineLength(length: number, fn: F) { + return Object.defineProperty(fn, "length", { + value: length, + configurable: true + }) +} + +function fnApply(options: { + readonly self: any + readonly body: Function + readonly args: Array + readonly pipeables: Array + readonly spanName: string + readonly spanOptions: Tracer.SpanOptions + readonly errorDef: Error + readonly errorCall: Error +}) { + let effect: Effect + let fnError: any = undefined + if (isGeneratorFunction(options.body)) { + effect = core.fromIterator(() => options.body.apply(options.self, options.args)) + } else { + try { + effect = options.body.apply(options.self, options.args) + } catch (error) { + fnError = error + effect = die(error) + } + } + if (options.pipeables.length > 0) { + try { + for (const x of options.pipeables) { + effect = x(effect, ...options.args) + } + } catch (error) { + effect = fnError + ? failCause(internalCause.sequential( + internalCause.die(fnError), + internalCause.die(error) + )) + : die(error) + } + } + + let cache: false | string = false + const captureStackTrace = () => { + if (cache !== false) { + return cache + } + if (options.errorCall.stack) { + const stackDef = options.errorDef.stack!.trim().split("\n") + const stackCall = options.errorCall.stack.trim().split("\n") + let endStackDef = stackDef.slice(2).join("\n").trim() + if (!endStackDef.includes(`(`)) { + endStackDef = endStackDef.replace(/at (.*)/, "at ($1)") + } + let endStackCall = stackCall.slice(2).join("\n").trim() + if (!endStackCall.includes(`(`)) { + endStackCall = endStackCall.replace(/at (.*)/, "at ($1)") + } + cache = `${endStackDef}\n${endStackCall}` + return cache + } + } + const opts: any = (options.spanOptions && "captureStackTrace" in options.spanOptions) + ? options.spanOptions + : { captureStackTrace, ...options.spanOptions } + return withSpan(effect, options.spanName, opts) +} + +/** + * Same as {@link fn}, but allows you to create a function that is not traced, for when performance is critical. + * + * @see {@link fn} for a version that includes tracing. + * + * @since 3.12.0 + * @category Tracing + */ +export const fnUntraced: fn.Untraced = core.fnUntraced + +// ----------------------------------------------------------------------------- +// Type constraints +// ----------------------------------------------------------------------------- + +/** + * A no-op type constraint that enforces the success channel of an Effect conforms to + * the specified success type `A`. + * + * @example + * import { Effect } from "effect" + * + * // Ensure that the program does not expose any unhandled errors. + * const program = Effect.succeed(42).pipe(Effect.ensureSuccessType()) + * + * @since 3.17.0 + * @category Type constraints + */ +export const ensureSuccessType = () => (effect: Effect): Effect => effect + +/** + * A no-op type constraint that enforces the error channel of an Effect conforms to + * the specified error type `E`. + * + * @example + * import { Effect } from "effect" + * + * // Ensure that the program does not expose any unhandled errors. + * const program = Effect.succeed(42).pipe(Effect.ensureErrorType()) + * + * @since 3.17.0 + * @category Type constraints + */ +export const ensureErrorType = () => (effect: Effect): Effect => effect + +/** + * A no-op type constraint that enforces the requirements channel of an Effect conforms to + * the specified requirements type `R`. + * + * @example + * import { Effect } from "effect" + * + * // Ensure that the program does not have any requirements. + * const program = Effect.succeed(42).pipe(Effect.ensureRequirementsType()) + * + * @since 3.17.0 + * @category Type constraints + */ +export const ensureRequirementsType = () => (effect: Effect): Effect => + effect diff --git a/backend/node_modules/effect/src/Either.ts b/backend/node_modules/effect/src/Either.ts new file mode 100644 index 0000000000000000000000000000000000000000..90066c96fbf048d78914cb269500173866fbd92d --- /dev/null +++ b/backend/node_modules/effect/src/Either.ts @@ -0,0 +1,1723 @@ +/** + * @since 2.0.0 + */ + +import * as Equivalence from "./Equivalence.js" +import type { LazyArg } from "./Function.js" +import { constNull, constUndefined, dual, identity } from "./Function.js" +import type { TypeLambda } from "./HKT.js" +import type { Inspectable } from "./Inspectable.js" +import * as doNotation from "./internal/doNotation.js" +import * as either from "./internal/either.js" +import * as option_ from "./internal/option.js" +import type { Option } from "./Option.js" +import type { Pipeable } from "./Pipeable.js" +import type { Predicate, Refinement } from "./Predicate.js" +import { isFunction } from "./Predicate.js" +import type { Covariant, NoInfer, NotFunction } from "./Types.js" +import type * as Unify from "./Unify.js" +import * as Gen from "./Utils.js" + +/** + * @category models + * @since 2.0.0 + */ +export type Either = Left | Right + +/** + * @category symbols + * @since 2.0.0 + */ +export const TypeId: unique symbol = either.TypeId + +/** + * @category symbols + * @since 2.0.0 + */ +export type TypeId = typeof TypeId + +// TODO(4.0): flip the order of the type parameters +/** + * @category models + * @since 2.0.0 + */ +export interface Left extends Pipeable, Inspectable { + readonly _tag: "Left" + readonly _op: "Left" + readonly left: E + readonly [TypeId]: { + readonly _R: Covariant + readonly _L: Covariant + } + [Unify.typeSymbol]?: unknown + [Unify.unifySymbol]?: EitherUnify + [Unify.ignoreSymbol]?: EitherUnifyIgnore +} + +// TODO(4.0): flip the order of the type parameters +/** + * @category models + * @since 2.0.0 + */ +export interface Right extends Pipeable, Inspectable { + readonly _tag: "Right" + readonly _op: "Right" + readonly right: A + readonly [TypeId]: { + readonly _R: Covariant + readonly _L: Covariant + } + [Unify.typeSymbol]?: unknown + [Unify.unifySymbol]?: EitherUnify + [Unify.ignoreSymbol]?: EitherUnifyIgnore +} + +/** + * @category models + * @since 2.0.0 + */ +export interface EitherUnify { + Either?: () => A[Unify.typeSymbol] extends Either | infer _ ? Either : never +} + +/** + * @category models + * @since 2.0.0 + */ +export interface EitherUnifyIgnore {} + +/** + * @category type lambdas + * @since 2.0.0 + */ +export interface EitherTypeLambda extends TypeLambda { + readonly type: Either +} + +/** + * @since 2.0.0 + */ +export declare namespace Either { + /** + * @since 2.0.0 + * @category type-level + */ + export type Left> = [T] extends [Either] ? _E : never + /** + * @since 2.0.0 + * @category type-level + */ + export type Right> = [T] extends [Either] ? _A : never +} + +/** + * Constructs a new `Either` holding a `Right` value. This usually represents a successful value due to the right bias + * of this structure. + * + * @category constructors + * @since 2.0.0 + */ +export const right: (a: A) => Either = either.right + +const void_: Either = right(void 0) +export { + /** + * @category constructors + * @since 3.13.0 + */ + void_ as void +} + +/** + * Constructs a new `Either` holding a `Left` value. This usually represents a failure, due to the right-bias of this + * structure. + * + * @category constructors + * @since 2.0.0 + */ +export const left: (e: E) => Either = either.left + +/** + * Takes a lazy default and a nullable value, if the value is not nully (`null` or `undefined`), turn it into a `Right`, if the value is nully use + * the provided default as a `Left`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual(Either.fromNullable(1, () => 'fallback'), Either.right(1)) + * assert.deepStrictEqual(Either.fromNullable(null, () => 'fallback'), Either.left('fallback')) + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const fromNullable: { + /** + * Takes a lazy default and a nullable value, if the value is not nully (`null` or `undefined`), turn it into a `Right`, if the value is nully use + * the provided default as a `Left`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual(Either.fromNullable(1, () => 'fallback'), Either.right(1)) + * assert.deepStrictEqual(Either.fromNullable(null, () => 'fallback'), Either.left('fallback')) + * ``` + * + * @category constructors + * @since 2.0.0 + */ + (onNullable: (right: A) => E): (self: A) => Either, E> + /** + * Takes a lazy default and a nullable value, if the value is not nully (`null` or `undefined`), turn it into a `Right`, if the value is nully use + * the provided default as a `Left`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual(Either.fromNullable(1, () => 'fallback'), Either.right(1)) + * assert.deepStrictEqual(Either.fromNullable(null, () => 'fallback'), Either.left('fallback')) + * ``` + * + * @category constructors + * @since 2.0.0 + */ + (self: A, onNullable: (right: A) => E): Either, E> +} = dual( + 2, + (self: A, onNullable: (right: A) => E): Either, E> => + self == null ? left(onNullable(self)) : right(self) +) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, Option } from "effect" + * + * assert.deepStrictEqual(Either.fromOption(Option.some(1), () => 'error'), Either.right(1)) + * assert.deepStrictEqual(Either.fromOption(Option.none(), () => 'error'), Either.left('error')) + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const fromOption: { + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, Option } from "effect" + * + * assert.deepStrictEqual(Either.fromOption(Option.some(1), () => 'error'), Either.right(1)) + * assert.deepStrictEqual(Either.fromOption(Option.none(), () => 'error'), Either.left('error')) + * ``` + * + * @category constructors + * @since 2.0.0 + */ + (onNone: () => E): (self: Option) => Either + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, Option } from "effect" + * + * assert.deepStrictEqual(Either.fromOption(Option.some(1), () => 'error'), Either.right(1)) + * assert.deepStrictEqual(Either.fromOption(Option.none(), () => 'error'), Either.left('error')) + * ``` + * + * @category constructors + * @since 2.0.0 + */ + (self: Option, onNone: () => E): Either +} = either.fromOption + +const try_: { + ( + options: { + readonly try: LazyArg + readonly catch: (error: unknown) => E + } + ): Either + (evaluate: LazyArg): Either +} = (( + evaluate: LazyArg | { + readonly try: LazyArg + readonly catch: (error: unknown) => E + } +) => { + if (isFunction(evaluate)) { + try { + return right(evaluate()) + } catch (e) { + return left(e) + } + } else { + try { + return right(evaluate.try()) + } catch (e) { + return left(evaluate.catch(e)) + } + } +}) as any + +export { + /** + * Imports a synchronous side-effect into a pure `Either` value, translating any + * thrown exceptions into typed failed eithers creating with `Either.left`. + * + * @category constructors + * @since 2.0.0 + */ + try_ as try +} + +/** + * Tests if a value is a `Either`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual(Either.isEither(Either.right(1)), true) + * assert.deepStrictEqual(Either.isEither(Either.left("a")), true) + * assert.deepStrictEqual(Either.isEither({ right: 1 }), false) + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isEither: (input: unknown) => input is Either = either.isEither + +/** + * Determine if a `Either` is a `Left`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual(Either.isLeft(Either.right(1)), false) + * assert.deepStrictEqual(Either.isLeft(Either.left("a")), true) + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isLeft: (self: Either) => self is Left = either.isLeft + +/** + * Determine if a `Either` is a `Right`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual(Either.isRight(Either.right(1)), true) + * assert.deepStrictEqual(Either.isRight(Either.left("a")), false) + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isRight: (self: Either) => self is Right = either.isRight + +/** + * Converts a `Either` to an `Option` discarding the `Left`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, Option } from "effect" + * + * assert.deepStrictEqual(Either.getRight(Either.right('ok')), Option.some('ok')) + * assert.deepStrictEqual(Either.getRight(Either.left('err')), Option.none()) + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const getRight: (self: Either) => Option = either.getRight + +/** + * Converts a `Either` to an `Option` discarding the value. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, Option } from "effect" + * + * assert.deepStrictEqual(Either.getLeft(Either.right('ok')), Option.none()) + * assert.deepStrictEqual(Either.getLeft(Either.left('err')), Option.some('err')) + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const getLeft: (self: Either) => Option = either.getLeft + +/** + * @category equivalence + * @since 2.0.0 + */ +export const getEquivalence = ({ left, right }: { + right: Equivalence.Equivalence + left: Equivalence.Equivalence +}): Equivalence.Equivalence> => + Equivalence.make((x, y) => + isLeft(x) ? + isLeft(y) && left(x.left, y.left) : + isRight(y) && right(x.right, y.right) + ) + +/** + * @category mapping + * @since 2.0.0 + */ +export const mapBoth: { + /** + * @category mapping + * @since 2.0.0 + */ + ( + options: { + readonly onLeft: (left: E) => E2 + readonly onRight: (right: A) => A2 + } + ): (self: Either) => Either + /** + * @category mapping + * @since 2.0.0 + */ + ( + self: Either, + options: { + readonly onLeft: (left: E) => E2 + readonly onRight: (right: A) => A2 + } + ): Either +} = dual( + 2, + (self: Either, { onLeft, onRight }: { + readonly onLeft: (left: E) => E2 + readonly onRight: (right: A) => A2 + }): Either => isLeft(self) ? left(onLeft(self.left)) : right(onRight(self.right)) +) + +/** + * Maps the `Left` side of an `Either` value to a new `Either` value. + * + * @category mapping + * @since 2.0.0 + */ +export const mapLeft: { + /** + * Maps the `Left` side of an `Either` value to a new `Either` value. + * + * @category mapping + * @since 2.0.0 + */ + (f: (left: E) => E2): (self: Either) => Either + /** + * Maps the `Left` side of an `Either` value to a new `Either` value. + * + * @category mapping + * @since 2.0.0 + */ + (self: Either, f: (left: E) => E2): Either +} = dual( + 2, + (self: Either, f: (left: E) => E2): Either => + isLeft(self) ? left(f(self.left)) : right(self.right) +) + +/** + * Maps the `Right` side of an `Either` value to a new `Either` value. + * + * @category mapping + * @since 2.0.0 + */ +export const map: { + /** + * Maps the `Right` side of an `Either` value to a new `Either` value. + * + * @category mapping + * @since 2.0.0 + */ + (f: (right: A) => A2): (self: Either) => Either + /** + * Maps the `Right` side of an `Either` value to a new `Either` value. + * + * @category mapping + * @since 2.0.0 + */ + (self: Either, f: (right: A) => A2): Either +} = dual( + 2, + (self: Either, f: (right: A) => A2): Either => + isRight(self) ? right(f(self.right)) : left(self.left) +) + +/** + * Takes two functions and an `Either` value, if the value is a `Left` the inner value is applied to the `onLeft function, + * if the value is a `Right` the inner value is applied to the `onRight` function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Either } from "effect" + * + * const onLeft = (strings: ReadonlyArray): string => `strings: ${strings.join(', ')}` + * + * const onRight = (value: number): string => `Ok: ${value}` + * + * assert.deepStrictEqual(pipe(Either.right(1), Either.match({ onLeft, onRight })), 'Ok: 1') + * assert.deepStrictEqual( + * pipe(Either.left(['string 1', 'string 2']), Either.match({ onLeft, onRight })), + * 'strings: string 1, string 2' + * ) + * ``` + * + * @category pattern matching + * @since 2.0.0 + */ +export const match: { + /** + * Takes two functions and an `Either` value, if the value is a `Left` the inner value is applied to the `onLeft function, + * if the value is a `Right` the inner value is applied to the `onRight` function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Either } from "effect" + * + * const onLeft = (strings: ReadonlyArray): string => `strings: ${strings.join(', ')}` + * + * const onRight = (value: number): string => `Ok: ${value}` + * + * assert.deepStrictEqual(pipe(Either.right(1), Either.match({ onLeft, onRight })), 'Ok: 1') + * assert.deepStrictEqual( + * pipe(Either.left(['string 1', 'string 2']), Either.match({ onLeft, onRight })), + * 'strings: string 1, string 2' + * ) + * ``` + * + * @category pattern matching + * @since 2.0.0 + */ + ( + options: { + readonly onLeft: (left: E) => B + readonly onRight: (right: A) => C + } + ): (self: Either) => B | C + /** + * Takes two functions and an `Either` value, if the value is a `Left` the inner value is applied to the `onLeft function, + * if the value is a `Right` the inner value is applied to the `onRight` function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Either } from "effect" + * + * const onLeft = (strings: ReadonlyArray): string => `strings: ${strings.join(', ')}` + * + * const onRight = (value: number): string => `Ok: ${value}` + * + * assert.deepStrictEqual(pipe(Either.right(1), Either.match({ onLeft, onRight })), 'Ok: 1') + * assert.deepStrictEqual( + * pipe(Either.left(['string 1', 'string 2']), Either.match({ onLeft, onRight })), + * 'strings: string 1, string 2' + * ) + * ``` + * + * @category pattern matching + * @since 2.0.0 + */ + ( + self: Either, + options: { + readonly onLeft: (left: E) => B + readonly onRight: (right: A) => C + } + ): B | C +} = dual( + 2, + (self: Either, { onLeft, onRight }: { + readonly onLeft: (left: E) => B + readonly onRight: (right: A) => C + }): B | C => isLeft(self) ? onLeft(self.left) : onRight(self.right) +) + +/** + * Transforms a `Predicate` function into a `Right` of the input value if the predicate returns `true` + * or `Left` of the result of the provided function if the predicate returns false + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Either } from "effect" + * + * const isPositive = (n: number): boolean => n > 0 + * const isPositiveEither = Either.liftPredicate(isPositive, n => `${n} is not positive`) + * + * assert.deepStrictEqual( + * isPositiveEither(1), + * Either.right(1) + * ) + * assert.deepStrictEqual( + * isPositiveEither(0), + * Either.left("0 is not positive") + * ) + * ``` + * + * @category lifting + * @since 3.4.0 + */ +export const liftPredicate: { + /** + * Transforms a `Predicate` function into a `Right` of the input value if the predicate returns `true` + * or `Left` of the result of the provided function if the predicate returns false + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Either } from "effect" + * + * const isPositive = (n: number): boolean => n > 0 + * const isPositiveEither = Either.liftPredicate(isPositive, n => `${n} is not positive`) + * + * assert.deepStrictEqual( + * isPositiveEither(1), + * Either.right(1) + * ) + * assert.deepStrictEqual( + * isPositiveEither(0), + * Either.left("0 is not positive") + * ) + * ``` + * + * @category lifting + * @since 3.4.0 + */ + (refinement: Refinement, orLeftWith: (a: A) => E): (a: A) => Either + /** + * Transforms a `Predicate` function into a `Right` of the input value if the predicate returns `true` + * or `Left` of the result of the provided function if the predicate returns false + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Either } from "effect" + * + * const isPositive = (n: number): boolean => n > 0 + * const isPositiveEither = Either.liftPredicate(isPositive, n => `${n} is not positive`) + * + * assert.deepStrictEqual( + * isPositiveEither(1), + * Either.right(1) + * ) + * assert.deepStrictEqual( + * isPositiveEither(0), + * Either.left("0 is not positive") + * ) + * ``` + * + * @category lifting + * @since 3.4.0 + */ + (predicate: Predicate, orLeftWith: (a: A) => E): (a: B) => Either + /** + * Transforms a `Predicate` function into a `Right` of the input value if the predicate returns `true` + * or `Left` of the result of the provided function if the predicate returns false + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Either } from "effect" + * + * const isPositive = (n: number): boolean => n > 0 + * const isPositiveEither = Either.liftPredicate(isPositive, n => `${n} is not positive`) + * + * assert.deepStrictEqual( + * isPositiveEither(1), + * Either.right(1) + * ) + * assert.deepStrictEqual( + * isPositiveEither(0), + * Either.left("0 is not positive") + * ) + * ``` + * + * @category lifting + * @since 3.4.0 + */ + (self: A, refinement: Refinement, orLeftWith: (a: A) => E): Either + /** + * Transforms a `Predicate` function into a `Right` of the input value if the predicate returns `true` + * or `Left` of the result of the provided function if the predicate returns false + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Either } from "effect" + * + * const isPositive = (n: number): boolean => n > 0 + * const isPositiveEither = Either.liftPredicate(isPositive, n => `${n} is not positive`) + * + * assert.deepStrictEqual( + * isPositiveEither(1), + * Either.right(1) + * ) + * assert.deepStrictEqual( + * isPositiveEither(0), + * Either.left("0 is not positive") + * ) + * ``` + * + * @category lifting + * @since 3.4.0 + */ + (self: B, predicate: Predicate, orLeftWith: (a: A) => E): Either +} = dual( + 3, + (a: A, predicate: Predicate, orLeftWith: (a: A) => E): Either => + predicate(a) ? right(a) : left(orLeftWith(a)) +) + +/** + * Filter the right value with the provided function. + * If the predicate fails, set the left value with the result of the provided function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Either } from "effect" + * + * const isPositive = (n: number): boolean => n > 0 + * + * assert.deepStrictEqual( + * pipe( + * Either.right(1), + * Either.filterOrLeft(isPositive, n => `${n} is not positive`) + * ), + * Either.right(1) + * ) + * assert.deepStrictEqual( + * pipe( + * Either.right(0), + * Either.filterOrLeft(isPositive, n => `${n} is not positive`) + * ), + * Either.left("0 is not positive") + * ) + * ``` + * + * @since 2.0.0 + * @category filtering & conditionals + */ +export const filterOrLeft: { + /** + * Filter the right value with the provided function. + * If the predicate fails, set the left value with the result of the provided function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Either } from "effect" + * + * const isPositive = (n: number): boolean => n > 0 + * + * assert.deepStrictEqual( + * pipe( + * Either.right(1), + * Either.filterOrLeft(isPositive, n => `${n} is not positive`) + * ), + * Either.right(1) + * ) + * assert.deepStrictEqual( + * pipe( + * Either.right(0), + * Either.filterOrLeft(isPositive, n => `${n} is not positive`) + * ), + * Either.left("0 is not positive") + * ) + * ``` + * + * @since 2.0.0 + * @category filtering & conditionals + */ + ( + refinement: Refinement, B>, + orLeftWith: (right: NoInfer) => E2 + ): (self: Either) => Either + /** + * Filter the right value with the provided function. + * If the predicate fails, set the left value with the result of the provided function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Either } from "effect" + * + * const isPositive = (n: number): boolean => n > 0 + * + * assert.deepStrictEqual( + * pipe( + * Either.right(1), + * Either.filterOrLeft(isPositive, n => `${n} is not positive`) + * ), + * Either.right(1) + * ) + * assert.deepStrictEqual( + * pipe( + * Either.right(0), + * Either.filterOrLeft(isPositive, n => `${n} is not positive`) + * ), + * Either.left("0 is not positive") + * ) + * ``` + * + * @since 2.0.0 + * @category filtering & conditionals + */ + (predicate: Predicate>, orLeftWith: (right: NoInfer) => E2): (self: Either) => Either + /** + * Filter the right value with the provided function. + * If the predicate fails, set the left value with the result of the provided function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Either } from "effect" + * + * const isPositive = (n: number): boolean => n > 0 + * + * assert.deepStrictEqual( + * pipe( + * Either.right(1), + * Either.filterOrLeft(isPositive, n => `${n} is not positive`) + * ), + * Either.right(1) + * ) + * assert.deepStrictEqual( + * pipe( + * Either.right(0), + * Either.filterOrLeft(isPositive, n => `${n} is not positive`) + * ), + * Either.left("0 is not positive") + * ) + * ``` + * + * @since 2.0.0 + * @category filtering & conditionals + */ + ( + self: Either, + refinement: Refinement, + orLeftWith: (right: A) => E2 + ): Either + /** + * Filter the right value with the provided function. + * If the predicate fails, set the left value with the result of the provided function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Either } from "effect" + * + * const isPositive = (n: number): boolean => n > 0 + * + * assert.deepStrictEqual( + * pipe( + * Either.right(1), + * Either.filterOrLeft(isPositive, n => `${n} is not positive`) + * ), + * Either.right(1) + * ) + * assert.deepStrictEqual( + * pipe( + * Either.right(0), + * Either.filterOrLeft(isPositive, n => `${n} is not positive`) + * ), + * Either.left("0 is not positive") + * ) + * ``` + * + * @since 2.0.0 + * @category filtering & conditionals + */ + (self: Either, predicate: Predicate, orLeftWith: (right: A) => E2): Either +} = dual(3, ( + self: Either, + predicate: Predicate, + orLeftWith: (right: A) => E2 +): Either => flatMap(self, (r) => predicate(r) ? right(r) : left(orLeftWith(r)))) + +/** + * @category getters + * @since 2.0.0 + */ +export const merge: (self: Either) => E | A = match({ + onLeft: identity, + onRight: identity +}) + +/** + * Returns the wrapped value if it's a `Right` or a default value if is a `Left`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual(Either.getOrElse(Either.right(1), (error) => error + "!"), 1) + * assert.deepStrictEqual(Either.getOrElse(Either.left("not a number"), (error) => error + "!"), "not a number!") + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const getOrElse: { + /** + * Returns the wrapped value if it's a `Right` or a default value if is a `Left`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual(Either.getOrElse(Either.right(1), (error) => error + "!"), 1) + * assert.deepStrictEqual(Either.getOrElse(Either.left("not a number"), (error) => error + "!"), "not a number!") + * ``` + * + * @category getters + * @since 2.0.0 + */ + (onLeft: (left: E) => A2): (self: Either) => A2 | A + /** + * Returns the wrapped value if it's a `Right` or a default value if is a `Left`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual(Either.getOrElse(Either.right(1), (error) => error + "!"), 1) + * assert.deepStrictEqual(Either.getOrElse(Either.left("not a number"), (error) => error + "!"), "not a number!") + * ``` + * + * @category getters + * @since 2.0.0 + */ + (self: Either, onLeft: (left: E) => A2): A | A2 +} = dual( + 2, + (self: Either, onLeft: (left: E) => A2): A | A2 => isLeft(self) ? onLeft(self.left) : self.right +) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual(Either.getOrNull(Either.right(1)), 1) + * assert.deepStrictEqual(Either.getOrNull(Either.left("a")), null) + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const getOrNull: (self: Either) => A | null = getOrElse(constNull) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual(Either.getOrUndefined(Either.right(1)), 1) + * assert.deepStrictEqual(Either.getOrUndefined(Either.left("a")), undefined) + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const getOrUndefined: (self: Either) => A | undefined = getOrElse(constUndefined) + +/** + * Extracts the value of an `Either` or throws if the `Either` is `Left`. + * + * If a default error is sufficient for your use case and you don't need to configure the thrown error, see {@link getOrThrow}. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual( + * Either.getOrThrowWith(Either.right(1), () => new Error('Unexpected Left')), + * 1 + * ) + * assert.throws(() => Either.getOrThrowWith(Either.left("error"), () => new Error('Unexpected Left'))) + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const getOrThrowWith: { + /** + * Extracts the value of an `Either` or throws if the `Either` is `Left`. + * + * If a default error is sufficient for your use case and you don't need to configure the thrown error, see {@link getOrThrow}. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual( + * Either.getOrThrowWith(Either.right(1), () => new Error('Unexpected Left')), + * 1 + * ) + * assert.throws(() => Either.getOrThrowWith(Either.left("error"), () => new Error('Unexpected Left'))) + * ``` + * + * @category getters + * @since 2.0.0 + */ + (onLeft: (left: E) => unknown): (self: Either) => A + /** + * Extracts the value of an `Either` or throws if the `Either` is `Left`. + * + * If a default error is sufficient for your use case and you don't need to configure the thrown error, see {@link getOrThrow}. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual( + * Either.getOrThrowWith(Either.right(1), () => new Error('Unexpected Left')), + * 1 + * ) + * assert.throws(() => Either.getOrThrowWith(Either.left("error"), () => new Error('Unexpected Left'))) + * ``` + * + * @category getters + * @since 2.0.0 + */ + (self: Either, onLeft: (left: E) => unknown): A +} = dual(2, (self: Either, onLeft: (left: E) => unknown): A => { + if (isRight(self)) { + return self.right + } + throw onLeft(self.left) +}) + +// TODO(4.0): by default should throw `L` (i.e getOrThrowWith with the identity function) +/** + * Extracts the value of an `Either` or throws if the `Either` is `Left`. + * + * The thrown error is a default error. To configure the error thrown, see {@link getOrThrowWith}. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual(Either.getOrThrow(Either.right(1)), 1) + * assert.throws(() => Either.getOrThrow(Either.left("error"))) + * ``` + * + * @throws `Error("getOrThrow called on a Left")` + * + * @category getters + * @since 2.0.0 + */ +export const getOrThrow: (self: Either) => A = getOrThrowWith(() => + new Error("getOrThrow called on a Left") +) + +/** + * Returns `self` if it is a `Right` or `that` otherwise. + * + * @category error handling + * @since 2.0.0 + */ +export const orElse: { + /** + * Returns `self` if it is a `Right` or `that` otherwise. + * + * @category error handling + * @since 2.0.0 + */ + (that: (left: E) => Either): (self: Either) => Either + /** + * Returns `self` if it is a `Right` or `that` otherwise. + * + * @category error handling + * @since 2.0.0 + */ + (self: Either, that: (left: E) => Either): Either +} = dual( + 2, + (self: Either, that: (left: E) => Either): Either => + isLeft(self) ? that(self.left) : right(self.right) +) + +/** + * @category sequencing + * @since 2.0.0 + */ +export const flatMap: { + /** + * @category sequencing + * @since 2.0.0 + */ + (f: (right: A) => Either): (self: Either) => Either + /** + * @category sequencing + * @since 2.0.0 + */ + (self: Either, f: (right: A) => Either): Either +} = dual( + 2, + (self: Either, f: (right: A) => Either): Either => + isLeft(self) ? left(self.left) : f(self.right) +) + +/** + * Executes a sequence of two `Either`s. The second `Either` can be dependent on the result of the first `Either`. + * + * @category sequencing + * @since 2.0.0 + */ +export const andThen: { + /** + * Executes a sequence of two `Either`s. The second `Either` can be dependent on the result of the first `Either`. + * + * @category sequencing + * @since 2.0.0 + */ + (f: (right: A) => Either): (self: Either) => Either + /** + * Executes a sequence of two `Either`s. The second `Either` can be dependent on the result of the first `Either`. + * + * @category sequencing + * @since 2.0.0 + */ + (f: Either): (self: Either) => Either + /** + * Executes a sequence of two `Either`s. The second `Either` can be dependent on the result of the first `Either`. + * + * @category sequencing + * @since 2.0.0 + */ + (f: (right: A) => A2): (self: Either) => Either + /** + * Executes a sequence of two `Either`s. The second `Either` can be dependent on the result of the first `Either`. + * + * @category sequencing + * @since 2.0.0 + */ + (right: NotFunction): (self: Either) => Either + /** + * Executes a sequence of two `Either`s. The second `Either` can be dependent on the result of the first `Either`. + * + * @category sequencing + * @since 2.0.0 + */ + (self: Either, f: (right: A) => Either): Either + /** + * Executes a sequence of two `Either`s. The second `Either` can be dependent on the result of the first `Either`. + * + * @category sequencing + * @since 2.0.0 + */ + (self: Either, f: Either): Either + /** + * Executes a sequence of two `Either`s. The second `Either` can be dependent on the result of the first `Either`. + * + * @category sequencing + * @since 2.0.0 + */ + (self: Either, f: (right: A) => A2): Either + /** + * Executes a sequence of two `Either`s. The second `Either` can be dependent on the result of the first `Either`. + * + * @category sequencing + * @since 2.0.0 + */ + (self: Either, f: NotFunction): Either +} = dual( + 2, + (self: Either, f: (right: A) => Either | Either): Either => + flatMap(self, (a) => { + const b = isFunction(f) ? f(a) : f + return isEither(b) ? b : right(b) + }) +) + +/** + * @category zipping + * @since 2.0.0 + */ +export const zipWith: { + /** + * @category zipping + * @since 2.0.0 + */ + (that: Either, f: (right: A, right2: A2) => B): (self: Either) => Either + /** + * @category zipping + * @since 2.0.0 + */ + (self: Either, that: Either, f: (right: A, right2: A2) => B): Either +} = dual( + 3, + (self: Either, that: Either, f: (right: A, right2: A2) => B): Either => + flatMap(self, (r) => map(that, (r2) => f(r, r2))) +) + +/** + * @category combining + * @since 2.0.0 + */ +export const ap: { + /** + * @category combining + * @since 2.0.0 + */ + (that: Either): (self: Either<(right: A) => A2, E>) => Either + /** + * @category combining + * @since 2.0.0 + */ + (self: Either<(right: A) => A2, E>, that: Either): Either +} = dual( + 2, + (self: Either<(right: A) => A2, E>, that: Either): Either => + zipWith(self, that, (f, a) => f(a)) +) + +/** + * Takes a structure of `Either`s and returns an `Either` of values with the same structure. + * + * - If a tuple is supplied, then the returned `Either` will contain a tuple with the same length. + * - If a struct is supplied, then the returned `Either` will contain a struct with the same keys. + * - If an iterable is supplied, then the returned `Either` will contain an array. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either } from "effect" + * + * assert.deepStrictEqual(Either.all([Either.right(1), Either.right(2)]), Either.right([1, 2])) + * assert.deepStrictEqual(Either.all({ right: Either.right(1), b: Either.right("hello") }), Either.right({ right: 1, b: "hello" })) + * assert.deepStrictEqual(Either.all({ right: Either.right(1), b: Either.left("error") }), Either.left("error")) + * ``` + * + * @category combining + * @since 2.0.0 + */ +// @ts-expect-error +export const all: > | Record>>( + input: I +) => [I] extends [ReadonlyArray>] ? Either< + { -readonly [K in keyof I]: [I[K]] extends [Either] ? A : never }, + I[number] extends never ? never : [I[number]] extends [Either] ? E : never + > + : [I] extends [Iterable>] ? Either, E> + : Either< + { -readonly [K in keyof I]: [I[K]] extends [Either] ? A : never }, + I[keyof I] extends never ? never : [I[keyof I]] extends [Either] ? E : never + > = ( + input: Iterable> | Record> + ): Either => { + if (Symbol.iterator in input) { + const out: Array> = [] + for (const e of input) { + if (isLeft(e)) { + return e + } + out.push(e.right) + } + return right(out) + } + + const out: Record = {} + for (const key of Object.keys(input)) { + const e = input[key] + if (isLeft(e)) { + return e + } + out[key] = e.right + } + return right(out) + } + +/** + * Returns an `Either` that swaps the error/success cases. This allows you to + * use all methods on the error channel, possibly before flipping back. + * + * @since 2.0.0 + * @category mapping + */ +export const flip = (self: Either): Either => isLeft(self) ? right(self.left) : left(self.right) + +const adapter = Gen.adapter() + +/** + * @category generators + * @since 2.0.0 + */ +export const gen: Gen.Gen> = (...args) => { + const f = args.length === 1 ? args[0] : args[1].bind(args[0]) + const iterator = f(adapter) + let state: IteratorResult = iterator.next() + while (!state.done) { + const current = Gen.isGenKind(state.value) + ? state.value.value + : Gen.yieldWrapGet(state.value) + if (isLeft(current)) { + return current + } + state = iterator.next(current.right as never) + } + return right(state.value) as any +} + +// ------------------------------------------------------------------------------------- +// do notation +// ------------------------------------------------------------------------------------- + +/** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Either` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, pipe } from "effect" + * + * const result = pipe( + * Either.Do, + * Either.bind("x", () => Either.right(2)), + * Either.bind("y", () => Either.right(3)), + * Either.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(result, Either.right({ x: 2, y: 3, sum: 5 })) + * ``` + * + * @see {@link bind} + * @see {@link bindTo} + * @see {@link let_ let} + * + * @category do notation + * @since 2.0.0 + */ +export const Do: Either<{}> = right({}) + +/** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Either` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, pipe } from "effect" + * + * const result = pipe( + * Either.Do, + * Either.bind("x", () => Either.right(2)), + * Either.bind("y", () => Either.right(3)), + * Either.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(result, Either.right({ x: 2, y: 3, sum: 5 })) + * ``` + * + * @see {@link Do} + * @see {@link bindTo} + * @see {@link let_ let} + * + * @category do notation + * @since 2.0.0 + */ +export const bind: { + /** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Either` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, pipe } from "effect" + * + * const result = pipe( + * Either.Do, + * Either.bind("x", () => Either.right(2)), + * Either.bind("y", () => Either.right(3)), + * Either.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(result, Either.right({ x: 2, y: 3, sum: 5 })) + * ``` + * + * @see {@link Do} + * @see {@link bindTo} + * @see {@link let_ let} + * + * @category do notation + * @since 2.0.0 + */ + (name: Exclude, f: (a: NoInfer) => Either): (self: Either) => Either<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, E | E2> + /** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Either` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, pipe } from "effect" + * + * const result = pipe( + * Either.Do, + * Either.bind("x", () => Either.right(2)), + * Either.bind("y", () => Either.right(3)), + * Either.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(result, Either.right({ x: 2, y: 3, sum: 5 })) + * ``` + * + * @see {@link Do} + * @see {@link bindTo} + * @see {@link let_ let} + * + * @category do notation + * @since 2.0.0 + */ + ( + self: Either, + name: Exclude, + f: (a: NoInfer) => Either + ): Either<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, E | E2> +} = doNotation.bind(map, flatMap) + +/** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Either` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, pipe } from "effect" + * + * const result = pipe( + * Either.Do, + * Either.bind("x", () => Either.right(2)), + * Either.bind("y", () => Either.right(3)), + * Either.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(result, Either.right({ x: 2, y: 3, sum: 5 })) + * ``` + * + * @see {@link Do} + * @see {@link bind} + * @see {@link let_ let} + * + * @category do notation + * @since 2.0.0 + */ +export const bindTo: { + /** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Either` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, pipe } from "effect" + * + * const result = pipe( + * Either.Do, + * Either.bind("x", () => Either.right(2)), + * Either.bind("y", () => Either.right(3)), + * Either.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(result, Either.right({ x: 2, y: 3, sum: 5 })) + * ``` + * + * @see {@link Do} + * @see {@link bind} + * @see {@link let_ let} + * + * @category do notation + * @since 2.0.0 + */ + (name: N): (self: Either) => Either<{ [K in N]: A }, E> + /** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Either` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, pipe } from "effect" + * + * const result = pipe( + * Either.Do, + * Either.bind("x", () => Either.right(2)), + * Either.bind("y", () => Either.right(3)), + * Either.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(result, Either.right({ x: 2, y: 3, sum: 5 })) + * ``` + * + * @see {@link Do} + * @see {@link bind} + * @see {@link let_ let} + * + * @category do notation + * @since 2.0.0 + */ + (self: Either, name: N): Either<{ [K in N]: A }, E> +} = doNotation.bindTo(map) + +const let_: { + ( + name: Exclude, + f: (r: NoInfer) => B + ): (self: Either) => Either<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, E> + ( + self: Either, + name: Exclude, + f: (r: NoInfer) => B + ): Either<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }, E> +} = doNotation.let_(map) + +export { + /** + * The "do simulation" in Effect allows you to write code in a more declarative style, similar to the "do notation" in other programming languages. It provides a way to define variables and perform operations on them using functions like `bind` and `let`. + * + * Here's how the do simulation works: + * + * 1. Start the do simulation using the `Do` value + * 2. Within the do simulation scope, you can use the `bind` function to define variables and bind them to `Either` values + * 3. You can accumulate multiple `bind` statements to define multiple variables within the scope + * 4. Inside the do simulation scope, you can also use the `let` function to define variables and bind them to simple values + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, pipe } from "effect" + * + * const result = pipe( + * Either.Do, + * Either.bind("x", () => Either.right(2)), + * Either.bind("y", () => Either.right(3)), + * Either.let("sum", ({ x, y }) => x + y) + * ) + * assert.deepStrictEqual(result, Either.right({ x: 2, y: 3, sum: 5 })) + * ``` + * + * @see {@link Do} + * @see {@link bindTo} + * @see {@link bind} + * + * @category do notation + * @since 2.0.0 + */ + let_ as let +} + +/** + * Converts an `Option` of an `Either` into an `Either` of an `Option`. + * + * **Details** + * + * This function transforms an `Option>` into an + * `Either, E>`. If the `Option` is `None`, the resulting `Either` + * will be a `Right` with a `None` value. If the `Option` is `Some`, the + * inner `Either` will be executed, and its result wrapped in a `Some`. + * + * @example + * ```ts + * import { Effect, Either, Option } from "effect" + * + * // ┌─── Option> + * // ▼ + * const maybe = Option.some(Either.right(42)) + * + * // ┌─── Either, never, never> + * // ▼ + * const result = Either.transposeOption(maybe) + * + * console.log(Effect.runSync(result)) + * // Output: { _id: 'Option', _tag: 'Some', value: 42 } + * ``` + * + * @since 3.14.0 + * @category Optional Wrapping & Unwrapping + */ +export const transposeOption = ( + self: Option> +): Either, E> => { + return option_.isNone(self) ? right(option_.none) : map(self.value, option_.some) +} + +/** + * Applies an `Either` on an `Option` and transposes the result. + * + * **Details** + * + * If the `Option` is `None`, the resulting `Either` will immediately succeed with a `Right` value of `None`. + * If the `Option` is `Some`, the transformation function will be applied to the inner value, and its result wrapped in a `Some`. + * + * @example + * ```ts + * import { Either, Option, pipe } from "effect" + * + * // ┌─── Either, never>> + * // ▼ + * const noneResult = pipe( + * Option.none(), + * Either.transposeMapOption(() => Either.right(42)) // will not be executed + * ) + * console.log(noneResult) + * // Output: { _id: 'Either', _tag: 'Right', right: { _id: 'Option', _tag: 'None' } } + * + * // ┌─── Either, never>> + * // ▼ + * const someRightResult = pipe( + * Option.some(42), + * Either.transposeMapOption((value) => Either.right(value * 2)) + * ) + * console.log(someRightResult) + * // Output: { _id: 'Either', _tag: 'Right', right: { _id: 'Option', _tag: 'Some', value: 84 } } + * ``` + * + * @since 3.15.0 + * @category Optional Wrapping & Unwrapping + */ +export const transposeMapOption = dual< + /** + * Applies an `Either` on an `Option` and transposes the result. + * + * **Details** + * + * If the `Option` is `None`, the resulting `Either` will immediately succeed with a `Right` value of `None`. + * If the `Option` is `Some`, the transformation function will be applied to the inner value, and its result wrapped in a `Some`. + * + * @example + * ```ts + * import { Either, Option, pipe } from "effect" + * + * // ┌─── Either, never>> + * // ▼ + * const noneResult = pipe( + * Option.none(), + * Either.transposeMapOption(() => Either.right(42)) // will not be executed + * ) + * console.log(noneResult) + * // Output: { _id: 'Either', _tag: 'Right', right: { _id: 'Option', _tag: 'None' } } + * + * // ┌─── Either, never>> + * // ▼ + * const someRightResult = pipe( + * Option.some(42), + * Either.transposeMapOption((value) => Either.right(value * 2)) + * ) + * console.log(someRightResult) + * // Output: { _id: 'Either', _tag: 'Right', right: { _id: 'Option', _tag: 'Some', value: 84 } } + * ``` + * + * @since 3.15.0 + * @category Optional Wrapping & Unwrapping + */ + (f: (self: A) => Either) => (self: Option) => Either, E>, + /** + * Applies an `Either` on an `Option` and transposes the result. + * + * **Details** + * + * If the `Option` is `None`, the resulting `Either` will immediately succeed with a `Right` value of `None`. + * If the `Option` is `Some`, the transformation function will be applied to the inner value, and its result wrapped in a `Some`. + * + * @example + * ```ts + * import { Either, Option, pipe } from "effect" + * + * // ┌─── Either, never>> + * // ▼ + * const noneResult = pipe( + * Option.none(), + * Either.transposeMapOption(() => Either.right(42)) // will not be executed + * ) + * console.log(noneResult) + * // Output: { _id: 'Either', _tag: 'Right', right: { _id: 'Option', _tag: 'None' } } + * + * // ┌─── Either, never>> + * // ▼ + * const someRightResult = pipe( + * Option.some(42), + * Either.transposeMapOption((value) => Either.right(value * 2)) + * ) + * console.log(someRightResult) + * // Output: { _id: 'Either', _tag: 'Right', right: { _id: 'Option', _tag: 'Some', value: 84 } } + * ``` + * + * @since 3.15.0 + * @category Optional Wrapping & Unwrapping + */ + (self: Option, f: (self: A) => Either) => Either, E> +>(2, (self, f) => option_.isNone(self) ? right(option_.none) : map(f(self.value), option_.some)) diff --git a/backend/node_modules/effect/src/Equivalence.ts b/backend/node_modules/effect/src/Equivalence.ts new file mode 100644 index 0000000000000000000000000000000000000000..f874355c725db85e33bbca08fc6100d0c5069c6a --- /dev/null +++ b/backend/node_modules/effect/src/Equivalence.ts @@ -0,0 +1,259 @@ +/** + * This module provides an implementation of the `Equivalence` type class, which defines a binary relation + * that is reflexive, symmetric, and transitive. In other words, it defines a notion of equivalence between values of a certain type. + * These properties are also known in mathematics as an "equivalence relation". + * + * @since 2.0.0 + */ +import { dual } from "./Function.js" +import type { TypeLambda } from "./HKT.js" + +/** + * @category type class + * @since 2.0.0 + */ +export interface Equivalence { + (self: A, that: A): boolean +} + +/** + * @category type lambdas + * @since 2.0.0 + */ +export interface EquivalenceTypeLambda extends TypeLambda { + readonly type: Equivalence +} + +/** + * @category constructors + * @since 2.0.0 + */ +export const make = (isEquivalent: (self: A, that: A) => boolean): Equivalence => (self: A, that: A): boolean => + self === that || isEquivalent(self, that) + +const isStrictEquivalent = (x: unknown, y: unknown) => x === y + +/** + * Return an `Equivalence` that uses strict equality (===) to compare values. + * + * @since 2.0.0 + * @category constructors + */ +export const strict: () => Equivalence = () => isStrictEquivalent + +/** + * @category instances + * @since 2.0.0 + */ +export const string: Equivalence = strict() + +/** + * @category instances + * @since 2.0.0 + */ +export const number: Equivalence = strict() + +/** + * @category instances + * @since 2.0.0 + */ +export const boolean: Equivalence = strict() + +/** + * @category instances + * @since 2.0.0 + */ +export const bigint: Equivalence = strict() + +/** + * @category instances + * @since 2.0.0 + */ +export const symbol: Equivalence = strict() + +/** + * @category combining + * @since 2.0.0 + */ +export const combine: { + /** + * @category combining + * @since 2.0.0 + */ + (that: Equivalence): (self: Equivalence) => Equivalence + /** + * @category combining + * @since 2.0.0 + */ + (self: Equivalence, that: Equivalence): Equivalence +} = dual(2, (self: Equivalence, that: Equivalence): Equivalence => make((x, y) => self(x, y) && that(x, y))) + +/** + * @category combining + * @since 2.0.0 + */ +export const combineMany: { + /** + * @category combining + * @since 2.0.0 + */ + (collection: Iterable>): (self: Equivalence) => Equivalence + /** + * @category combining + * @since 2.0.0 + */ + (self: Equivalence, collection: Iterable>): Equivalence +} = dual(2, (self: Equivalence, collection: Iterable>): Equivalence => + make((x, y) => { + if (!self(x, y)) { + return false + } + for (const equivalence of collection) { + if (!equivalence(x, y)) { + return false + } + } + return true + })) + +const isAlwaysEquivalent: Equivalence = (_x, _y) => true + +/** + * @category combining + * @since 2.0.0 + */ +export const combineAll = (collection: Iterable>): Equivalence => + combineMany(isAlwaysEquivalent, collection) + +/** + * @category mapping + * @since 2.0.0 + */ +export const mapInput: { + /** + * @category mapping + * @since 2.0.0 + */ + (f: (b: B) => A): (self: Equivalence) => Equivalence + /** + * @category mapping + * @since 2.0.0 + */ + (self: Equivalence, f: (b: B) => A): Equivalence +} = dual( + 2, + (self: Equivalence, f: (b: B) => A): Equivalence => make((x, y) => self(f(x), f(y))) +) + +/** + * @category instances + * @since 2.0.0 + */ +export const Date: Equivalence = mapInput(number, (date) => date.getTime()) + +/** + * @category combining + * @since 2.0.0 + */ +export const product: { + (that: Equivalence): (self: Equivalence) => Equivalence // readonly because invariant + (self: Equivalence, that: Equivalence): Equivalence // readonly because invariant +} = dual( + 2, + (self: Equivalence, that: Equivalence): Equivalence => + make(([xa, xb], [ya, yb]) => self(xa, ya) && that(xb, yb)) +) + +/** + * @category combining + * @since 2.0.0 + */ +export const all = (collection: Iterable>): Equivalence> => { + return make((x, y) => { + const len = Math.min(x.length, y.length) + + let collectionLength = 0 + for (const equivalence of collection) { + if (collectionLength >= len) { + break + } + if (!equivalence(x[collectionLength], y[collectionLength])) { + return false + } + collectionLength++ + } + return true + }) +} + +/** + * @category combining + * @since 2.0.0 + */ +export const productMany = ( + self: Equivalence, + collection: Iterable> +): Equivalence]> /* readonly because invariant */ => { + const equivalence = all(collection) + return make((x, y) => !self(x[0], y[0]) ? false : equivalence(x.slice(1), y.slice(1))) +} + +/** + * Similar to `Promise.all` but operates on `Equivalence`s. + * + * ```ts skip-type-checking + * [Equivalence, Equivalence, ...] -> Equivalence<[A, B, ...]> + * ``` + * + * Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple + * by applying each `Equivalence` to the corresponding element of the tuple. + * + * @category combinators + * @since 2.0.0 + */ +export const tuple = >>( + ...elements: T +): Equivalence] ? A : never }>> => all(elements) as any + +/** + * Creates a new `Equivalence` for an array of values based on a given `Equivalence` for the elements of the array. + * + * @category combinators + * @since 2.0.0 + */ +export const array = (item: Equivalence): Equivalence> => + make((self, that) => { + if (self.length !== that.length) { + return false + } + + for (let i = 0; i < self.length; i++) { + const isEq = item(self[i], that[i]) + if (!isEq) { + return false + } + } + + return true + }) + +/** + * Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct + * by applying each `Equivalence` to the corresponding property of the struct. + * + * @category combinators + * @since 2.0.0 + */ +export const struct = >>( + fields: R +): Equivalence<{ readonly [K in keyof R]: [R[K]] extends [Equivalence] ? A : never }> => { + const keys = Object.keys(fields) + return make((self, that) => { + for (const key of keys) { + if (!fields[key](self[key], that[key])) { + return false + } + } + return true + }) +} diff --git a/backend/node_modules/effect/src/Exit.ts b/backend/node_modules/effect/src/Exit.ts new file mode 100644 index 0000000000000000000000000000000000000000..ed37ef2bf351b82188a875b3fbbccc25a9256120 --- /dev/null +++ b/backend/node_modules/effect/src/Exit.ts @@ -0,0 +1,717 @@ +/** + * @since 2.0.0 + */ +import type * as Cause from "./Cause.js" +import type * as Effect from "./Effect.js" +import type * as Either from "./Either.js" +import type * as FiberId from "./FiberId.js" +import type { Inspectable } from "./Inspectable.js" +import * as core from "./internal/core.js" +import type * as Option from "./Option.js" +import type { Pipeable } from "./Pipeable.js" +import type { Predicate, Refinement } from "./Predicate.js" +import type { NoInfer } from "./Types.js" +import type * as Unify from "./Unify.js" + +/** + * An `Exit` describes the result of a executing an `Effect` workflow. + * + * There are two possible values for an `Exit`: + * - `Exit.Success` contain a success value of type `A` + * - `Exit.Failure` contains a failure `Cause` of type `E` + * + * @since 2.0.0 + * @category models + */ +export type Exit = Success | Failure + +/** + * Represents a failed `Effect` workflow containing the `Cause` of the failure + * of type `E`. + * + * @since 2.0.0 + * @category models + */ +export interface Failure extends Effect.Effect, Pipeable, Inspectable { + readonly _tag: "Failure" + readonly _op: "Failure" + readonly cause: Cause.Cause + [Unify.typeSymbol]?: unknown + [Unify.unifySymbol]?: ExitUnify + [Unify.ignoreSymbol]?: ExitUnifyIgnore + /** @internal */ + readonly effect_instruction_i0: Cause.Cause +} + +/** + * @category models + * @since 2.0.0 + */ +export interface ExitUnify extends Effect.EffectUnify { + Exit?: () => A[Unify.typeSymbol] extends Exit | infer _ ? Exit : never +} + +/** + * @category models + * @since 2.0.0 + */ +export interface ExitUnifyIgnore extends Effect.EffectUnifyIgnore { + Effect?: true +} + +/** + * Represents a successful `Effect` workflow and containing the returned value + * of type `A`. + * + * @since 2.0.0 + * @category models + */ +export interface Success extends Effect.Effect, Pipeable, Inspectable { + readonly _tag: "Success" + readonly _op: "Success" + readonly value: A + [Unify.typeSymbol]?: unknown + [Unify.unifySymbol]?: ExitUnify + [Unify.ignoreSymbol]?: ExitUnifyIgnore + /** @internal */ + readonly effect_instruction_i0: A +} + +/** + * Returns `true` if the specified value is an `Exit`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isExit: (u: unknown) => u is Exit = core.exitIsExit + +/** + * Returns `true` if the specified `Exit` is a `Failure`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isFailure: (self: Exit) => self is Failure = core.exitIsFailure + +/** + * Returns `true` if the specified `Exit` is a `Success`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isSuccess: (self: Exit) => self is Success = core.exitIsSuccess + +/** + * Returns `true` if the specified exit is a `Failure` **and** the `Cause` of + * the failure was due to interruption, `false` otherwise. + * + * @since 2.0.0 + * @category getters + */ +export const isInterrupted: (self: Exit) => boolean = core.exitIsInterrupted + +/** + * Maps the `Success` value of the specified exit to the provided constant + * value. + * + * @since 2.0.0 + * @category mapping + */ +export const as: { + /** + * Maps the `Success` value of the specified exit to the provided constant + * value. + * + * @since 2.0.0 + * @category mapping + */ + (value: A2): (self: Exit) => Exit + /** + * Maps the `Success` value of the specified exit to the provided constant + * value. + * + * @since 2.0.0 + * @category mapping + */ + (self: Exit, value: A2): Exit +} = core.exitAs + +/** + * Maps the `Success` value of the specified exit to a void. + * + * @since 2.0.0 + * @category mapping + */ +export const asVoid: (self: Exit) => Exit = core.exitAsVoid + +/** + * Returns a `Some>` if the specified exit is a `Failure`, `None` + * otherwise. + * + * @since 2.0.0 + * @category getters + */ +export const causeOption: (self: Exit) => Option.Option> = core.exitCauseOption + +/** + * Collects all of the specified exit values into a `Some, E>>`. If + * the provided iterable contains no elements, `None` will be returned. + * + * @since 2.0.0 + * @category constructors + */ +export const all: ( + exits: Iterable>, + options?: { readonly parallel?: boolean | undefined } | undefined +) => Option.Option, E>> = core.exitCollectAll + +/** + * Constructs a new `Exit.Failure` from the specified unrecoverable defect. + * + * @since 2.0.0 + * @category constructors + */ +export const die: (defect: unknown) => Exit = core.exitDie + +/** + * Executes the predicate on the value of the specified exit if it is a + * `Success`, otherwise returns `false`. + * + * @since 2.0.0 + * @category elements + */ +export const exists: { + /** + * Executes the predicate on the value of the specified exit if it is a + * `Success`, otherwise returns `false`. + * + * @since 2.0.0 + * @category elements + */ + (refinement: Refinement, B>): (self: Exit) => self is Exit + /** + * Executes the predicate on the value of the specified exit if it is a + * `Success`, otherwise returns `false`. + * + * @since 2.0.0 + * @category elements + */ + (predicate: Predicate>): (self: Exit) => boolean + /** + * Executes the predicate on the value of the specified exit if it is a + * `Success`, otherwise returns `false`. + * + * @since 2.0.0 + * @category elements + */ + (self: Exit, refinement: Refinement): self is Exit + /** + * Executes the predicate on the value of the specified exit if it is a + * `Success`, otherwise returns `false`. + * + * @since 2.0.0 + * @category elements + */ + (self: Exit, predicate: Predicate): boolean +} = core.exitExists + +/** + * Constructs a new `Exit.Failure` from the specified recoverable error of type + * `E`. + * + * @since 2.0.0 + * @category constructors + */ +export const fail: (error: E) => Exit = core.exitFail + +/** + * Constructs a new `Exit.Failure` from the specified `Cause` of type `E`. + * + * @since 2.0.0 + * @category constructors + */ +export const failCause: (cause: Cause.Cause) => Exit = core.exitFailCause + +/** + * @since 2.0.0 + * @category sequencing + */ +export const flatMap: { + /** + * @since 2.0.0 + * @category sequencing + */ + (f: (a: A) => Exit): (self: Exit) => Exit + /** + * @since 2.0.0 + * @category sequencing + */ + (self: Exit, f: (a: A) => Exit): Exit +} = core.exitFlatMap + +/** + * @since 2.0.0 + * @category sequencing + */ +export const flatMapEffect: { + /** + * @since 2.0.0 + * @category sequencing + */ + (f: (a: A) => Effect.Effect, E2, R>): (self: Exit) => Effect.Effect, E2, R> + /** + * @since 2.0.0 + * @category sequencing + */ + (self: Exit, f: (a: A) => Effect.Effect, E2, R>): Effect.Effect, E2, R> +} = core.exitFlatMapEffect + +/** + * @since 2.0.0 + * @category sequencing + */ +export const flatten: (self: Exit, E2>) => Exit = core.exitFlatten + +/** + * @since 2.0.0 + * @category traversing + */ +export const forEachEffect: { + /** + * @since 2.0.0 + * @category traversing + */ + (f: (a: A) => Effect.Effect): (self: Exit) => Effect.Effect, never, R> + /** + * @since 2.0.0 + * @category traversing + */ + (self: Exit, f: (a: A) => Effect.Effect): Effect.Effect, never, R> +} = core.exitForEachEffect + +/** + * Converts an `Either` into an `Exit`. + * + * @since 2.0.0 + * @category conversions + */ +export const fromEither: (either: Either.Either) => Exit = core.exitFromEither + +/** + * Converts an `Option` into an `Exit`. + * + * @since 2.0.0 + * @category conversions + */ +export const fromOption: (option: Option.Option) => Exit = core.exitFromOption + +/** + * Returns the `A` if specified exit is a `Success`, otherwise returns the + * alternate `A` value computed from the specified function which receives the + * `Cause` of the exit `Failure`. + * + * @since 2.0.0 + * @category getters + */ +export const getOrElse: { + /** + * Returns the `A` if specified exit is a `Success`, otherwise returns the + * alternate `A` value computed from the specified function which receives the + * `Cause` of the exit `Failure`. + * + * @since 2.0.0 + * @category getters + */ + (orElse: (cause: Cause.Cause) => A2): (self: Exit) => A2 | A + /** + * Returns the `A` if specified exit is a `Success`, otherwise returns the + * alternate `A` value computed from the specified function which receives the + * `Cause` of the exit `Failure`. + * + * @since 2.0.0 + * @category getters + */ + (self: Exit, orElse: (cause: Cause.Cause) => A2): A | A2 +} = core.exitGetOrElse + +/** + * Constructs a new `Exit.Failure` from the specified `FiberId` indicating that + * the `Fiber` running an `Effect` workflow was terminated due to interruption. + * + * @since 2.0.0 + * @category constructors + */ +export const interrupt: (fiberId: FiberId.FiberId) => Exit = core.exitInterrupt + +/** + * Maps over the `Success` value of the specified exit using the provided + * function. + * + * @since 2.0.0 + * @category mapping + */ +export const map: { + /** + * Maps over the `Success` value of the specified exit using the provided + * function. + * + * @since 2.0.0 + * @category mapping + */ + (f: (a: A) => B): (self: Exit) => Exit + /** + * Maps over the `Success` value of the specified exit using the provided + * function. + * + * @since 2.0.0 + * @category mapping + */ + (self: Exit, f: (a: A) => B): Exit +} = core.exitMap + +/** + * Maps over the `Success` and `Failure` cases of the specified exit using the + * provided functions. + * + * @since 2.0.0 + * @category mapping + */ +export const mapBoth: { + /** + * Maps over the `Success` and `Failure` cases of the specified exit using the + * provided functions. + * + * @since 2.0.0 + * @category mapping + */ + ( + options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } + ): (self: Exit) => Exit + /** + * Maps over the `Success` and `Failure` cases of the specified exit using the + * provided functions. + * + * @since 2.0.0 + * @category mapping + */ + ( + self: Exit, + options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } + ): Exit +} = core.exitMapBoth + +/** + * Maps over the error contained in the `Failure` of the specified exit using + * the provided function. + * + * @since 2.0.0 + * @category mapping + */ +export const mapError: { + /** + * Maps over the error contained in the `Failure` of the specified exit using + * the provided function. + * + * @since 2.0.0 + * @category mapping + */ + (f: (e: E) => E2): (self: Exit) => Exit + /** + * Maps over the error contained in the `Failure` of the specified exit using + * the provided function. + * + * @since 2.0.0 + * @category mapping + */ + (self: Exit, f: (e: E) => E2): Exit +} = core.exitMapError + +/** + * Maps over the `Cause` contained in the `Failure` of the specified exit using + * the provided function. + * + * @since 2.0.0 + * @category mapping + */ +export const mapErrorCause: { + /** + * Maps over the `Cause` contained in the `Failure` of the specified exit using + * the provided function. + * + * @since 2.0.0 + * @category mapping + */ + (f: (cause: Cause.Cause) => Cause.Cause): (self: Exit) => Exit + /** + * Maps over the `Cause` contained in the `Failure` of the specified exit using + * the provided function. + * + * @since 2.0.0 + * @category mapping + */ + (self: Exit, f: (cause: Cause.Cause) => Cause.Cause): Exit +} = core.exitMapErrorCause + +/** + * @since 2.0.0 + * @category folding + */ +export const match: { + /** + * @since 2.0.0 + * @category folding + */ + ( + options: { readonly onFailure: (cause: Cause.Cause) => Z1; readonly onSuccess: (a: A) => Z2 } + ): (self: Exit) => Z1 | Z2 + /** + * @since 2.0.0 + * @category folding + */ + ( + self: Exit, + options: { readonly onFailure: (cause: Cause.Cause) => Z1; readonly onSuccess: (a: A) => Z2 } + ): Z1 | Z2 +} = core.exitMatch + +/** + * @since 2.0.0 + * @category folding + */ +export const matchEffect: { + /** + * @since 2.0.0 + * @category folding + */ + ( + options: { + readonly onFailure: (cause: Cause.Cause) => Effect.Effect + readonly onSuccess: (a: A) => Effect.Effect + } + ): (self: Exit) => Effect.Effect + /** + * @since 2.0.0 + * @category folding + */ + ( + self: Exit, + options: { + readonly onFailure: (cause: Cause.Cause) => Effect.Effect + readonly onSuccess: (a: A) => Effect.Effect + } + ): Effect.Effect +} = core.exitMatchEffect + +/** + * Constructs a new `Exit.Success` containing the specified value of type `A`. + * + * @since 2.0.0 + * @category constructors + */ +export const succeed: (value: A) => Exit = core.exitSucceed + +const void_: Exit = core.exitVoid +export { + /** + * Represents an `Exit` which succeeds with `undefined`. + * + * @since 2.0.0 + * @category constructors + */ + void_ as void +} + +/** + * Sequentially zips the this result with the specified result or else returns + * the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ +export const zip: { + /** + * Sequentially zips the this result with the specified result or else returns + * the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ + (that: Exit): (self: Exit) => Exit<[A, A2], E2 | E> + /** + * Sequentially zips the this result with the specified result or else returns + * the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ + (self: Exit, that: Exit): Exit<[A, A2], E | E2> +} = core.exitZip + +/** + * Sequentially zips the this result with the specified result discarding the + * second element of the tuple or else returns the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ +export const zipLeft: { + /** + * Sequentially zips the this result with the specified result discarding the + * second element of the tuple or else returns the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ + (that: Exit): (self: Exit) => Exit + /** + * Sequentially zips the this result with the specified result discarding the + * second element of the tuple or else returns the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ + (self: Exit, that: Exit): Exit +} = core.exitZipLeft + +/** + * Sequentially zips the this result with the specified result discarding the + * first element of the tuple or else returns the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ +export const zipRight: { + /** + * Sequentially zips the this result with the specified result discarding the + * first element of the tuple or else returns the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ + (that: Exit): (self: Exit) => Exit + /** + * Sequentially zips the this result with the specified result discarding the + * first element of the tuple or else returns the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ + (self: Exit, that: Exit): Exit +} = core.exitZipRight + +/** + * Parallelly zips the this result with the specified result or else returns + * the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ +export const zipPar: { + /** + * Parallelly zips the this result with the specified result or else returns + * the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ + (that: Exit): (self: Exit) => Exit<[A, A2], E2 | E> + /** + * Parallelly zips the this result with the specified result or else returns + * the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ + (self: Exit, that: Exit): Exit<[A, A2], E | E2> +} = core.exitZipPar + +/** + * Parallelly zips the this result with the specified result discarding the + * second element of the tuple or else returns the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ +export const zipParLeft: { + /** + * Parallelly zips the this result with the specified result discarding the + * second element of the tuple or else returns the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ + (that: Exit): (self: Exit) => Exit + /** + * Parallelly zips the this result with the specified result discarding the + * second element of the tuple or else returns the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ + (self: Exit, that: Exit): Exit +} = core.exitZipParLeft + +/** + * Parallelly zips the this result with the specified result discarding the + * first element of the tuple or else returns the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ +export const zipParRight: { + /** + * Parallelly zips the this result with the specified result discarding the + * first element of the tuple or else returns the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ + (that: Exit): (self: Exit) => Exit + /** + * Parallelly zips the this result with the specified result discarding the + * first element of the tuple or else returns the failed `Cause`. + * + * @since 2.0.0 + * @category zipping + */ + (self: Exit, that: Exit): Exit +} = core.exitZipParRight + +/** + * Zips this exit together with that exit using the specified combination + * functions. + * + * @since 2.0.0 + * @category zipping + */ +export const zipWith: { + /** + * Zips this exit together with that exit using the specified combination + * functions. + * + * @since 2.0.0 + * @category zipping + */ + ( + that: Exit, + options: { + readonly onSuccess: (a: A, b: B) => C + readonly onFailure: (cause: Cause.Cause, cause2: Cause.Cause) => Cause.Cause + } + ): (self: Exit) => Exit + /** + * Zips this exit together with that exit using the specified combination + * functions. + * + * @since 2.0.0 + * @category zipping + */ + ( + self: Exit, + that: Exit, + options: { + readonly onSuccess: (a: A, b: B) => C + readonly onFailure: (cause: Cause.Cause, cause2: Cause.Cause) => Cause.Cause + } + ): Exit +} = core.exitZipWith diff --git a/backend/node_modules/effect/src/FastCheck.ts b/backend/node_modules/effect/src/FastCheck.ts new file mode 100644 index 0000000000000000000000000000000000000000..b5a3803d1544c6e4e7eeedf37b7c4b453ccddc57 --- /dev/null +++ b/backend/node_modules/effect/src/FastCheck.ts @@ -0,0 +1,9 @@ +/** + * @since 3.10.0 + */ + +/** + * @category re-exports + * @since 3.10.0 + */ +export * from "fast-check" diff --git a/backend/node_modules/effect/src/Fiber.ts b/backend/node_modules/effect/src/Fiber.ts new file mode 100644 index 0000000000000000000000000000000000000000..65d32cfc6c12f984b39b2e13877e2d95642b8fc6 --- /dev/null +++ b/backend/node_modules/effect/src/Fiber.ts @@ -0,0 +1,926 @@ +/** + * @since 2.0.0 + */ +import type * as Cause from "./Cause.js" +import type { Context } from "./Context.js" +import type { DefaultServices } from "./DefaultServices.js" +import type * as Effect from "./Effect.js" +import type * as Either from "./Either.js" +import type * as Exit from "./Exit.js" +import type * as FiberId from "./FiberId.js" +import type { FiberRef } from "./FiberRef.js" +import type * as FiberRefs from "./FiberRefs.js" +import type * as FiberStatus from "./FiberStatus.js" +import type * as HashSet from "./HashSet.js" +import * as core from "./internal/core.js" +import * as circular from "./internal/effect/circular.js" +import * as internal from "./internal/fiber.js" +import * as fiberRuntime from "./internal/fiberRuntime.js" +import type * as Option from "./Option.js" +import type * as order from "./Order.js" +import type * as RuntimeFlags from "./RuntimeFlags.js" +import type { Scheduler } from "./Scheduler.js" +import type * as Scope from "./Scope.js" +import type { Supervisor } from "./Supervisor.js" +import type { AnySpan, Tracer } from "./Tracer.js" +import type * as Types from "./Types.js" +import type * as Unify from "./Unify.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const FiberTypeId: unique symbol = internal.FiberTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type FiberTypeId = typeof FiberTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export const RuntimeFiberTypeId: unique symbol = internal.RuntimeFiberTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type RuntimeFiberTypeId = typeof RuntimeFiberTypeId + +/** + * A fiber is a lightweight thread of execution that never consumes more than a + * whole thread (but may consume much less, depending on contention and + * asynchronicity). Fibers are spawned by forking effects, which run + * concurrently with the parent effect. + * + * Fibers can be joined, yielding their result to other fibers, or interrupted, + * which terminates the fiber, safely releasing all resources. + * + * @since 2.0.0 + * @category models + */ +export interface Fiber extends Effect.Effect, Fiber.Variance { + /** + * The identity of the fiber. + */ + id(): FiberId.FiberId + + /** + * Awaits the fiber, which suspends the awaiting fiber until the result of the + * fiber has been determined. + */ + readonly await: Effect.Effect> + + /** + * Retrieves the immediate children of the fiber. + */ + readonly children: Effect.Effect>> + + /** + * Inherits values from all `FiberRef` instances into current fiber. This + * will resume immediately. + */ + readonly inheritAll: Effect.Effect + + /** + * Tentatively observes the fiber, but returns immediately if it is not + * already done. + */ + readonly poll: Effect.Effect>> + + /** + * In the background, interrupts the fiber as if interrupted from the + * specified fiber. If the fiber has already exited, the returned effect will + * resume immediately. Otherwise, the effect will resume when the fiber exits. + */ + interruptAsFork(fiberId: FiberId.FiberId): Effect.Effect + + readonly [Unify.typeSymbol]?: unknown + readonly [Unify.unifySymbol]?: FiberUnify + readonly [Unify.ignoreSymbol]?: FiberUnifyIgnore +} + +/** + * @category models + * @since 3.8.0 + */ +export interface FiberUnify extends Effect.EffectUnify { + Fiber?: () => A[Unify.typeSymbol] extends Fiber | infer _ ? Fiber : never +} + +/** + * @category models + * @since 3.8.0 + */ +export interface FiberUnifyIgnore extends Effect.EffectUnifyIgnore { + Effect?: true +} + +/** + * A runtime fiber that is executing an effect. Runtime fibers have an + * identity and a trace. + * + * @since 2.0.0 + * @category models + */ +export interface RuntimeFiber extends Fiber, Fiber.RuntimeVariance { + /** + * Reads the current number of ops that have occurred since the last yield + */ + get currentOpCount(): number + + /** + * Reads the current value of a fiber ref + */ + getFiberRef(fiberRef: FiberRef): X + + /** + * The identity of the fiber. + */ + id(): FiberId.Runtime + + /** + * The status of the fiber. + */ + readonly status: Effect.Effect + + /** + * Returns the current `RuntimeFlags` the fiber is running with. + */ + readonly runtimeFlags: Effect.Effect + + /** + * Adds an observer to the list of observers. + */ + addObserver(observer: (exit: Exit.Exit) => void): void + + /** + * Removes the specified observer from the list of observers that will be + * notified when the fiber exits. + */ + removeObserver(observer: (exit: Exit.Exit) => void): void + + /** + * Retrieves all fiber refs of the fiber. + */ + getFiberRefs(): FiberRefs.FiberRefs + + /** + * Unsafely observes the fiber, but returns immediately if it is not + * already done. + */ + unsafePoll(): Exit.Exit | null + + /** + * In the background, interrupts the fiber as if interrupted from the + * specified fiber. If the fiber has already exited, the returned effect will + * resume immediately. Otherwise, the effect will resume when the fiber exits. + */ + unsafeInterruptAsFork(fiberId: FiberId.FiberId): void + + /** + * Gets the current context + */ + get currentContext(): Context + + /** + * Gets the current context + */ + get currentDefaultServices(): Context + + /** + * Gets the current scheduler + */ + get currentScheduler(): Scheduler + + /** + * Gets the current tracer + */ + get currentTracer(): Tracer + + /** + * Gets the current span + */ + get currentSpan(): AnySpan | undefined + + /** + * Gets the current supervisor + */ + get currentSupervisor(): Supervisor + + readonly [Unify.typeSymbol]?: unknown + readonly [Unify.unifySymbol]?: RuntimeFiberUnify + readonly [Unify.ignoreSymbol]?: RuntimeFiberUnifyIgnore +} + +/** + * @category models + * @since 3.8.0 + */ +export interface RuntimeFiberUnify extends FiberUnify { + RuntimeFiber?: () => A[Unify.typeSymbol] extends RuntimeFiber | infer _ ? RuntimeFiber + : never +} + +/** + * @category models + * @since 3.8.0 + */ +export interface RuntimeFiberUnifyIgnore extends FiberUnifyIgnore { + Fiber?: true +} + +/** + * @since 2.0.0 + */ +export declare namespace Fiber { + /** + * @since 2.0.0 + * @category models + */ + export type Runtime = RuntimeFiber + + /** + * @since 2.0.0 + * @category models + */ + export interface Variance { + readonly [FiberTypeId]: { + readonly _A: Types.Covariant + readonly _E: Types.Covariant + } + } + + /** + * @since 2.0.0 + */ + export interface RuntimeVariance { + readonly [RuntimeFiberTypeId]: { + readonly _A: Types.Covariant + readonly _E: Types.Covariant + } + } + + /** + * @since 2.0.0 + * @category models + */ + export interface Dump { + /** + * The fiber's unique identifier. + */ + readonly id: FiberId.Runtime + /** + * The status of the fiber. + */ + readonly status: FiberStatus.FiberStatus + } + + /** + * A record containing information about a `Fiber`. + * + * @since 2.0.0 + * @category models + */ + export interface Descriptor { + /** + * The fiber's unique identifier. + */ + readonly id: FiberId.FiberId + /** + * The status of the fiber. + */ + readonly status: FiberStatus.FiberStatus + /** + * The set of fibers attempting to interrupt the fiber or its ancestors. + */ + readonly interruptors: HashSet.HashSet + } +} + +/** + * @since 2.0.0 + * @category instances + */ +export const Order: order.Order> = internal.Order + +/** + * Returns `true` if the specified value is a `Fiber`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isFiber: (u: unknown) => u is Fiber = internal.isFiber + +/** + * Returns `true` if the specified `Fiber` is a `RuntimeFiber`, `false` + * otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isRuntimeFiber: (self: Fiber) => self is RuntimeFiber = internal.isRuntimeFiber + +/** + * The identity of the fiber. + * + * @since 2.0.0 + * @category getters + */ +export const id: (self: Fiber) => FiberId.FiberId = internal.id + +const _await: (self: Fiber) => Effect.Effect> = internal._await + +export { + /** + * Awaits the fiber, which suspends the awaiting fiber until the result of the + * fiber has been determined. + * + * @since 2.0.0 + * @category getters + */ + _await as await +} + +/** + * Awaits on all fibers to be completed, successfully or not. + * + * @since 2.0.0 + * @category destructors + */ +export const awaitAll: >>( + fibers: T +) => Effect.Effect< + [T] extends [ReadonlyArray] + ? number extends T["length"] ? Array ? Exit.Exit : never> + : { -readonly [K in keyof T]: T[K] extends Fiber ? Exit.Exit : never } + : Array ? U extends Fiber ? Exit.Exit : never : never> +> = fiberRuntime.fiberAwaitAll + +/** + * Retrieves the immediate children of the fiber. + * + * @since 2.0.0 + * @category getters + */ +export const children: (self: Fiber) => Effect.Effect>> = internal.children + +/** + * Collects all fibers into a single fiber producing an in-order list of the + * results. + * + * @since 2.0.0 + * @category constructors + */ +export const all: (fibers: Iterable>) => Fiber, E> = fiberRuntime.fiberAll + +/** + * A fiber that is done with the specified `Exit` value. + * + * @since 2.0.0 + * @category constructors + */ +export const done: (exit: Exit.Exit) => Fiber = internal.done + +/** + * @since 2.0.0 + * @category destructors + */ +export const dump: (self: RuntimeFiber) => Effect.Effect = internal.dump + +/** + * @since 2.0.0 + * @category destructors + */ +export const dumpAll: ( + fibers: Iterable> +) => Effect.Effect> = internal.dumpAll + +/** + * A fiber that has already failed with the specified value. + * + * @since 2.0.0 + * @category constructors + */ +export const fail: (error: E) => Fiber = internal.fail + +/** + * Creates a `Fiber` that has already failed with the specified cause. + * + * @since 2.0.0 + * @category constructors + */ +export const failCause: (cause: Cause.Cause) => Fiber = internal.failCause + +/** + * Lifts an `Effect` into a `Fiber`. + * + * @since 2.0.0 + * @category conversions + */ +export const fromEffect: (effect: Effect.Effect) => Effect.Effect> = internal.fromEffect + +/** + * Gets the current fiber if one is running. + * + * @since 2.0.0 + * @category utilities + */ +export const getCurrentFiber: () => Option.Option> = internal.getCurrentFiber + +/** + * Inherits values from all `FiberRef` instances into current fiber. This + * will resume immediately. + * + * @since 2.0.0 + * @category destructors + */ +export const inheritAll: (self: Fiber) => Effect.Effect = internal.inheritAll + +/** + * Interrupts the fiber from whichever fiber is calling this method. If the + * fiber has already exited, the returned effect will resume immediately. + * Otherwise, the effect will resume when the fiber exits. + * + * @since 2.0.0 + * @category interruption + */ +export const interrupt: (self: Fiber) => Effect.Effect> = core.interruptFiber + +/** + * Constructrs a `Fiber` that is already interrupted. + * + * @since 2.0.0 + * @category constructors + */ +export const interrupted: (fiberId: FiberId.FiberId) => Fiber = internal.interrupted + +/** + * Interrupts the fiber as if interrupted from the specified fiber. If the + * fiber has already exited, the returned effect will resume immediately. + * Otherwise, the effect will resume when the fiber exits. + * + * @since 2.0.0 + * @category interruption + */ +export const interruptAs: { + /** + * Interrupts the fiber as if interrupted from the specified fiber. If the + * fiber has already exited, the returned effect will resume immediately. + * Otherwise, the effect will resume when the fiber exits. + * + * @since 2.0.0 + * @category interruption + */ + (fiberId: FiberId.FiberId): (self: Fiber) => Effect.Effect> + /** + * Interrupts the fiber as if interrupted from the specified fiber. If the + * fiber has already exited, the returned effect will resume immediately. + * Otherwise, the effect will resume when the fiber exits. + * + * @since 2.0.0 + * @category interruption + */ + (self: Fiber, fiberId: FiberId.FiberId): Effect.Effect> +} = core.interruptAsFiber + +/** + * Interrupts the fiber as if interrupted from the specified fiber. If the + * fiber has already exited, the returned effect will resume immediately. + * Otherwise, the effect will resume when the fiber exits. + * + * @since 2.0.0 + * @category interruption + */ +export const interruptAsFork: { + /** + * Interrupts the fiber as if interrupted from the specified fiber. If the + * fiber has already exited, the returned effect will resume immediately. + * Otherwise, the effect will resume when the fiber exits. + * + * @since 2.0.0 + * @category interruption + */ + (fiberId: FiberId.FiberId): (self: Fiber) => Effect.Effect + /** + * Interrupts the fiber as if interrupted from the specified fiber. If the + * fiber has already exited, the returned effect will resume immediately. + * Otherwise, the effect will resume when the fiber exits. + * + * @since 2.0.0 + * @category interruption + */ + (self: Fiber, fiberId: FiberId.FiberId): Effect.Effect +} = internal.interruptAsFork + +/** + * Interrupts all fibers, awaiting their interruption. + * + * @since 2.0.0 + * @category interruption + */ +export const interruptAll: (fibers: Iterable>) => Effect.Effect = internal.interruptAll + +/** + * Interrupts all fibers as by the specified fiber, awaiting their + * interruption. + * + * @since 2.0.0 + * @category interruption + */ +export const interruptAllAs: { + /** + * Interrupts all fibers as by the specified fiber, awaiting their + * interruption. + * + * @since 2.0.0 + * @category interruption + */ + (fiberId: FiberId.FiberId): (fibers: Iterable>) => Effect.Effect + /** + * Interrupts all fibers as by the specified fiber, awaiting their + * interruption. + * + * @since 2.0.0 + * @category interruption + */ + (fibers: Iterable>, fiberId: FiberId.FiberId): Effect.Effect +} = internal.interruptAllAs + +/** + * Interrupts the fiber from whichever fiber is calling this method. The + * interruption will happen in a separate daemon fiber, and the returned + * effect will always resume immediately without waiting. + * + * @since 2.0.0 + * @category interruption + */ +export const interruptFork: (self: Fiber) => Effect.Effect = fiberRuntime.fiberInterruptFork + +/** + * Joins the fiber, which suspends the joining fiber until the result of the + * fiber has been determined. Attempting to join a fiber that has erred will + * result in a catchable error. Joining an interrupted fiber will result in an + * "inner interruption" of this fiber, unlike interruption triggered by + * another fiber, "inner interruption" can be caught and recovered. + * + * @since 2.0.0 + * @category destructors + */ +export const join: (self: Fiber) => Effect.Effect = internal.join + +/** + * Joins all fibers, awaiting their _successful_ completion. Attempting to + * join a fiber that has erred will result in a catchable error, _if_ that + * error does not result from interruption. + * + * @since 2.0.0 + * @category destructors + */ +export const joinAll: (fibers: Iterable>) => Effect.Effect, E> = fiberRuntime.fiberJoinAll + +/** + * Maps over the value the Fiber computes. + * + * @since 2.0.0 + * @category mapping + */ +export const map: { + /** + * Maps over the value the Fiber computes. + * + * @since 2.0.0 + * @category mapping + */ + (f: (a: A) => B): (self: Fiber) => Fiber + /** + * Maps over the value the Fiber computes. + * + * @since 2.0.0 + * @category mapping + */ + (self: Fiber, f: (a: A) => B): Fiber +} = internal.map + +/** + * Effectually maps over the value the fiber computes. + * + * @since 2.0.0 + * @category mapping + */ +export const mapEffect: { + /** + * Effectually maps over the value the fiber computes. + * + * @since 2.0.0 + * @category mapping + */ + (f: (a: A) => Effect.Effect): (self: Fiber) => Fiber + /** + * Effectually maps over the value the fiber computes. + * + * @since 2.0.0 + * @category mapping + */ + (self: Fiber, f: (a: A) => Effect.Effect): Fiber +} = internal.mapEffect + +/** + * Passes the success of this fiber to the specified callback, and continues + * with the fiber that it returns. + * + * @since 2.0.0 + * @category mapping + */ +export const mapFiber: { + /** + * Passes the success of this fiber to the specified callback, and continues + * with the fiber that it returns. + * + * @since 2.0.0 + * @category mapping + */ + (f: (a: A) => Fiber): (self: Fiber) => Effect.Effect> + /** + * Passes the success of this fiber to the specified callback, and continues + * with the fiber that it returns. + * + * @since 2.0.0 + * @category mapping + */ + (self: Fiber, f: (a: A) => Fiber): Effect.Effect> +} = internal.mapFiber + +/** + * Folds over the `Fiber` or `RuntimeFiber`. + * + * @since 2.0.0 + * @category folding + */ +export const match: { + /** + * Folds over the `Fiber` or `RuntimeFiber`. + * + * @since 2.0.0 + * @category folding + */ + ( + options: { + readonly onFiber: (fiber: Fiber) => Z + readonly onRuntimeFiber: (fiber: RuntimeFiber) => Z + } + ): (self: Fiber) => Z + /** + * Folds over the `Fiber` or `RuntimeFiber`. + * + * @since 2.0.0 + * @category folding + */ + ( + self: Fiber, + options: { + readonly onFiber: (fiber: Fiber) => Z + readonly onRuntimeFiber: (fiber: RuntimeFiber) => Z + } + ): Z +} = internal.match + +/** + * A fiber that never fails or succeeds. + * + * @since 2.0.0 + * @category constructors + */ +export const never: Fiber = internal.never + +/** + * Returns a fiber that prefers `this` fiber, but falls back to the `that` one + * when `this` one fails. Interrupting the returned fiber will interrupt both + * fibers, sequentially, from left to right. + * + * @since 2.0.0 + * @category alternatives + */ +export const orElse: { + /** + * Returns a fiber that prefers `this` fiber, but falls back to the `that` one + * when `this` one fails. Interrupting the returned fiber will interrupt both + * fibers, sequentially, from left to right. + * + * @since 2.0.0 + * @category alternatives + */ + (that: Fiber): (self: Fiber) => Fiber + /** + * Returns a fiber that prefers `this` fiber, but falls back to the `that` one + * when `this` one fails. Interrupting the returned fiber will interrupt both + * fibers, sequentially, from left to right. + * + * @since 2.0.0 + * @category alternatives + */ + (self: Fiber, that: Fiber): Fiber +} = internal.orElse + +/** + * Returns a fiber that prefers `this` fiber, but falls back to the `that` one + * when `this` one fails. Interrupting the returned fiber will interrupt both + * fibers, sequentially, from left to right. + * + * @since 2.0.0 + * @category alternatives + */ +export const orElseEither: { + /** + * Returns a fiber that prefers `this` fiber, but falls back to the `that` one + * when `this` one fails. Interrupting the returned fiber will interrupt both + * fibers, sequentially, from left to right. + * + * @since 2.0.0 + * @category alternatives + */ + (that: Fiber): (self: Fiber) => Fiber, E2 | E> + /** + * Returns a fiber that prefers `this` fiber, but falls back to the `that` one + * when `this` one fails. Interrupting the returned fiber will interrupt both + * fibers, sequentially, from left to right. + * + * @since 2.0.0 + * @category alternatives + */ + (self: Fiber, that: Fiber): Fiber, E | E2> +} = internal.orElseEither + +/** + * Tentatively observes the fiber, but returns immediately if it is not + * already done. + * + * @since 2.0.0 + * @category getters + */ +export const poll: (self: Fiber) => Effect.Effect>> = internal.poll + +/** + * Pretty-prints a `RuntimeFiber`. + * + * @since 2.0.0 + * @category destructors + */ +export const pretty: (self: RuntimeFiber) => Effect.Effect = internal.pretty + +/** + * Returns a chunk containing all root fibers. + * + * @since 2.0.0 + * @category constructors + */ +export const roots: Effect.Effect>> = internal.roots + +/** + * Returns a chunk containing all root fibers. + * + * @since 2.0.0 + * @category constructors + */ +export const unsafeRoots: (_: void) => Array> = internal.unsafeRoots + +/** + * Converts this fiber into a scoped effect. The fiber is interrupted when the + * scope is closed. + * + * @since 2.0.0 + * @category destructors + */ +export const scoped: (self: Fiber) => Effect.Effect, never, Scope.Scope> = + fiberRuntime.fiberScoped + +/** + * Returns the `FiberStatus` of a `RuntimeFiber`. + * + * @since 2.0.0 + * @category getters + */ +export const status: (self: RuntimeFiber) => Effect.Effect = internal.status + +/** + * Returns a fiber that has already succeeded with the specified value. + * + * @since 2.0.0 + * @category constructors + */ +export const succeed: (value: A) => Fiber = internal.succeed + +const void_: Fiber = internal.void +export { + /** + * A fiber that has already succeeded with unit. + * + * @since 2.0.0 + * @category constructors + */ + void_ as void +} + +/** + * Zips this fiber and the specified fiber together, producing a tuple of + * their output. + * + * @since 2.0.0 + * @category zipping + */ +export const zip: { + /** + * Zips this fiber and the specified fiber together, producing a tuple of + * their output. + * + * @since 2.0.0 + * @category zipping + */ + (that: Fiber): (self: Fiber) => Fiber<[A, A2], E2 | E> + /** + * Zips this fiber and the specified fiber together, producing a tuple of + * their output. + * + * @since 2.0.0 + * @category zipping + */ + (self: Fiber, that: Fiber): Fiber<[A, A2], E | E2> +} = circular.zipFiber + +/** + * Same as `zip` but discards the output of that `Fiber`. + * + * @since 2.0.0 + * @category zipping + */ +export const zipLeft: { + /** + * Same as `zip` but discards the output of that `Fiber`. + * + * @since 2.0.0 + * @category zipping + */ + (that: Fiber): (self: Fiber) => Fiber + /** + * Same as `zip` but discards the output of that `Fiber`. + * + * @since 2.0.0 + * @category zipping + */ + (self: Fiber, that: Fiber): Fiber +} = circular.zipLeftFiber + +/** + * Same as `zip` but discards the output of this `Fiber`. + * + * @since 2.0.0 + * @category zipping + */ +export const zipRight: { + /** + * Same as `zip` but discards the output of this `Fiber`. + * + * @since 2.0.0 + * @category zipping + */ + (that: Fiber): (self: Fiber) => Fiber + /** + * Same as `zip` but discards the output of this `Fiber`. + * + * @since 2.0.0 + * @category zipping + */ + (self: Fiber, that: Fiber): Fiber +} = circular.zipRightFiber + +/** + * Zips this fiber with the specified fiber, combining their results using the + * specified combiner function. Both joins and interruptions are performed in + * sequential order from left to right. + * + * @since 2.0.0 + * @category zipping + */ +export const zipWith: { + /** + * Zips this fiber with the specified fiber, combining their results using the + * specified combiner function. Both joins and interruptions are performed in + * sequential order from left to right. + * + * @since 2.0.0 + * @category zipping + */ + (that: Fiber, f: (a: A, b: B) => C): (self: Fiber) => Fiber + /** + * Zips this fiber with the specified fiber, combining their results using the + * specified combiner function. Both joins and interruptions are performed in + * sequential order from left to right. + * + * @since 2.0.0 + * @category zipping + */ + (self: Fiber, that: Fiber, f: (a: A, b: B) => C): Fiber +} = circular.zipWithFiber diff --git a/backend/node_modules/effect/src/FiberRefs.ts b/backend/node_modules/effect/src/FiberRefs.ts new file mode 100644 index 0000000000000000000000000000000000000000..b151f54281575db5217d4f4df7151f6917988201 --- /dev/null +++ b/backend/node_modules/effect/src/FiberRefs.ts @@ -0,0 +1,288 @@ +/** + * @since 2.0.0 + */ +import type * as Arr from "./Array.js" +import type * as Effect from "./Effect.js" +import type * as FiberId from "./FiberId.js" +import type * as FiberRef from "./FiberRef.js" +import type * as HashSet from "./HashSet.js" +import * as internal from "./internal/fiberRefs.js" +import type * as Option from "./Option.js" +import type { Pipeable } from "./Pipeable.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const FiberRefsSym: unique symbol = internal.FiberRefsSym + +/** + * @since 2.0.0 + * @category symbols + */ +export type FiberRefsSym = typeof FiberRefsSym + +/** + * `FiberRefs` is a data type that represents a collection of `FiberRef` values. + * + * This allows safely propagating `FiberRef` values across fiber boundaries, for + * example between an asynchronous producer and consumer. + * + * @since 2.0.0 + * @category models + */ +export interface FiberRefs extends Pipeable { + readonly [FiberRefsSym]: FiberRefsSym + readonly locals: Map, Arr.NonEmptyReadonlyArray> +} + +const delete_: { + (fiberRef: FiberRef.FiberRef): (self: FiberRefs) => FiberRefs + (self: FiberRefs, fiberRef: FiberRef.FiberRef): FiberRefs +} = internal.delete_ + +export { + /** + * Deletes the specified `FiberRef` from the `FibterRefs`. + * + * @since 2.0.0 + * @category utils + */ + delete_ as delete +} + +/** + * Returns a set of each `FiberRef` in this collection. + * + * @since 2.0.0 + * @category getters + */ +export const fiberRefs: (self: FiberRefs) => HashSet.HashSet> = internal.fiberRefs + +/** + * Forks this collection of fiber refs as the specified child fiber id. This + * will potentially modify the value of the fiber refs, as determined by the + * individual fiber refs that make up the collection. + * + * @since 2.0.0 + * @category utils + */ +export const forkAs: { + /** + * Forks this collection of fiber refs as the specified child fiber id. This + * will potentially modify the value of the fiber refs, as determined by the + * individual fiber refs that make up the collection. + * + * @since 2.0.0 + * @category utils + */ + (childId: FiberId.Single): (self: FiberRefs) => FiberRefs + /** + * Forks this collection of fiber refs as the specified child fiber id. This + * will potentially modify the value of the fiber refs, as determined by the + * individual fiber refs that make up the collection. + * + * @since 2.0.0 + * @category utils + */ + (self: FiberRefs, childId: FiberId.Single): FiberRefs +} = internal.forkAs + +/** + * Gets the value of the specified `FiberRef` in this collection of `FiberRef` + * values if it exists or `None` otherwise. + * + * @since 2.0.0 + * @category getters + */ +export const get: { + /** + * Gets the value of the specified `FiberRef` in this collection of `FiberRef` + * values if it exists or `None` otherwise. + * + * @since 2.0.0 + * @category getters + */ + (fiberRef: FiberRef.FiberRef): (self: FiberRefs) => Option.Option + /** + * Gets the value of the specified `FiberRef` in this collection of `FiberRef` + * values if it exists or `None` otherwise. + * + * @since 2.0.0 + * @category getters + */ + (self: FiberRefs, fiberRef: FiberRef.FiberRef): Option.Option +} = internal.get + +/** + * Gets the value of the specified `FiberRef` in this collection of `FiberRef` + * values if it exists or the `initial` value of the `FiberRef` otherwise. + * + * @since 2.0.0 + * @category getters + */ +export const getOrDefault: { + /** + * Gets the value of the specified `FiberRef` in this collection of `FiberRef` + * values if it exists or the `initial` value of the `FiberRef` otherwise. + * + * @since 2.0.0 + * @category getters + */ + (fiberRef: FiberRef.FiberRef): (self: FiberRefs) => A + /** + * Gets the value of the specified `FiberRef` in this collection of `FiberRef` + * values if it exists or the `initial` value of the `FiberRef` otherwise. + * + * @since 2.0.0 + * @category getters + */ + (self: FiberRefs, fiberRef: FiberRef.FiberRef): A +} = internal.getOrDefault + +/** + * Joins this collection of fiber refs to the specified collection, as the + * specified fiber id. This will perform diffing and merging to ensure + * preservation of maximum information from both child and parent refs. + * + * @since 2.0.0 + * @category utils + */ +export const joinAs: { + /** + * Joins this collection of fiber refs to the specified collection, as the + * specified fiber id. This will perform diffing and merging to ensure + * preservation of maximum information from both child and parent refs. + * + * @since 2.0.0 + * @category utils + */ + (fiberId: FiberId.Single, that: FiberRefs): (self: FiberRefs) => FiberRefs + /** + * Joins this collection of fiber refs to the specified collection, as the + * specified fiber id. This will perform diffing and merging to ensure + * preservation of maximum information from both child and parent refs. + * + * @since 2.0.0 + * @category utils + */ + (self: FiberRefs, fiberId: FiberId.Single, that: FiberRefs): FiberRefs +} = internal.joinAs + +/** + * Set each ref to either its value or its default. + * + * @since 2.0.0 + * @category utils + */ +export const setAll: (self: FiberRefs) => Effect.Effect = internal.setAll + +/** + * Updates the value of the specified `FiberRef` using the provided `FiberId` + * + * @since 2.0.0 + * @category utils + */ +export const updateAs: { + /** + * Updates the value of the specified `FiberRef` using the provided `FiberId` + * + * @since 2.0.0 + * @category utils + */ + ( + options: { + readonly fiberId: FiberId.Single + readonly fiberRef: FiberRef.FiberRef + readonly value: A + } + ): (self: FiberRefs) => FiberRefs + /** + * Updates the value of the specified `FiberRef` using the provided `FiberId` + * + * @since 2.0.0 + * @category utils + */ + ( + self: FiberRefs, + options: { + readonly fiberId: FiberId.Single + readonly fiberRef: FiberRef.FiberRef + readonly value: A + } + ): FiberRefs +} = internal.updateAs + +/** + * Updates the values of the specified `FiberRef` & value pairs using the provided `FiberId` + * + * @since 2.0.0 + * @category utils + */ +export const updateManyAs: { + /** + * Updates the values of the specified `FiberRef` & value pairs using the provided `FiberId` + * + * @since 2.0.0 + * @category utils + */ + ( + options: { + readonly forkAs?: FiberId.Single | undefined + readonly entries: readonly [ + readonly [ + FiberRef.FiberRef, + readonly [readonly [FiberId.Single, any], ...Array] + ], + ...Array< + readonly [ + FiberRef.FiberRef, + readonly [readonly [FiberId.Single, any], ...Array] + ] + > + ] + } + ): (self: FiberRefs) => FiberRefs + /** + * Updates the values of the specified `FiberRef` & value pairs using the provided `FiberId` + * + * @since 2.0.0 + * @category utils + */ + ( + self: FiberRefs, + options: { + readonly forkAs?: FiberId.Single | undefined + readonly entries: readonly [ + readonly [ + FiberRef.FiberRef, + readonly [readonly [FiberId.Single, any], ...Array] + ], + ...Array< + readonly [ + FiberRef.FiberRef, + readonly [readonly [FiberId.Single, any], ...Array] + ] + > + ] + } + ): FiberRefs +} = internal.updateManyAs + +/** + * Note: it will not copy the provided Map, make sure to provide a fresh one. + * + * @since 2.0.0 + * @category unsafe + */ +export const unsafeMake: ( + fiberRefLocals: Map, Arr.NonEmptyReadonlyArray> +) => FiberRefs = internal.unsafeMake + +/** + * The empty collection of `FiberRef` values. + * + * @category constructors + * @since 2.0.0 + */ +export const empty: () => FiberRefs = internal.empty diff --git a/backend/node_modules/effect/src/FiberRefsPatch.ts b/backend/node_modules/effect/src/FiberRefsPatch.ts new file mode 100644 index 0000000000000000000000000000000000000000..9024c227175d59cd4598ddaaa8b36f5a92bbc9c4 --- /dev/null +++ b/backend/node_modules/effect/src/FiberRefsPatch.ts @@ -0,0 +1,139 @@ +/** + * @since 2.0.0 + */ +import type * as FiberId from "./FiberId.js" +import type * as FiberRef from "./FiberRef.js" +import type * as FiberRefs from "./FiberRefs.js" +import * as internal from "./internal/fiberRefs/patch.js" + +/** + * A `FiberRefsPatch` captures the changes in `FiberRef` values made by a single + * fiber as a value. This allows fibers to apply the changes made by a workflow + * without inheriting all the `FiberRef` values of the fiber that executed the + * workflow. + * + * @since 2.0.0 + * @category models + */ +export type FiberRefsPatch = Empty | Add | Remove | Update | AndThen + +/** + * @since 2.0.0 + * @category models + */ +export interface Empty { + readonly _tag: "Empty" +} + +/** + * @since 2.0.0 + * @category models + */ +export interface Add { + readonly _tag: "Add" + readonly fiberRef: FiberRef.FiberRef + readonly value: unknown +} + +/** + * @since 2.0.0 + * @category models + */ +export interface Remove { + readonly _tag: "Remove" + readonly fiberRef: FiberRef.FiberRef +} + +/** + * @since 2.0.0 + * @category models + */ +export interface Update { + readonly _tag: "Update" + readonly fiberRef: FiberRef.FiberRef + readonly patch: unknown +} + +/** + * @since 2.0.0 + * @category models + */ +export interface AndThen { + readonly _tag: "AndThen" + readonly first: FiberRefsPatch + readonly second: FiberRefsPatch +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const empty: FiberRefsPatch = internal.empty + +/** + * Constructs a patch that describes the changes between the specified + * collections of `FiberRef` + * + * @since 2.0.0 + * @category constructors + */ +export const diff: (oldValue: FiberRefs.FiberRefs, newValue: FiberRefs.FiberRefs) => FiberRefsPatch = internal.diff + +/** + * Combines this patch and the specified patch to create a new patch that + * describes applying the changes from this patch and the specified patch + * sequentially. + * + * @since 2.0.0 + * @category constructors + */ +export const combine: { + /** + * Combines this patch and the specified patch to create a new patch that + * describes applying the changes from this patch and the specified patch + * sequentially. + * + * @since 2.0.0 + * @category constructors + */ + (that: FiberRefsPatch): (self: FiberRefsPatch) => FiberRefsPatch + /** + * Combines this patch and the specified patch to create a new patch that + * describes applying the changes from this patch and the specified patch + * sequentially. + * + * @since 2.0.0 + * @category constructors + */ + (self: FiberRefsPatch, that: FiberRefsPatch): FiberRefsPatch +} = internal.combine + +/** + * Applies the changes described by this patch to the specified collection + * of `FiberRef` values. + * + * @since 2.0.0 + * @category destructors + */ +export const patch: { + /** + * Applies the changes described by this patch to the specified collection + * of `FiberRef` values. + * + * @since 2.0.0 + * @category destructors + */ + (fiberId: FiberId.Runtime, oldValue: FiberRefs.FiberRefs): (self: FiberRefsPatch) => FiberRefs.FiberRefs + /** + * Applies the changes described by this patch to the specified collection + * of `FiberRef` values. + * + * @since 2.0.0 + * @category destructors + */ + ( + self: FiberRefsPatch, + fiberId: FiberId.Runtime, + oldValue: FiberRefs.FiberRefs + ): FiberRefs.FiberRefs +} = internal.patch diff --git a/backend/node_modules/effect/src/FiberSet.ts b/backend/node_modules/effect/src/FiberSet.ts new file mode 100644 index 0000000000000000000000000000000000000000..790756392ce069af30c36c2e668c74fead9f6253 --- /dev/null +++ b/backend/node_modules/effect/src/FiberSet.ts @@ -0,0 +1,529 @@ +/** + * @since 2.0.0 + */ +import * as Cause from "./Cause.js" +import * as Deferred from "./Deferred.js" +import * as Effect from "./Effect.js" +import * as Exit from "./Exit.js" +import * as Fiber from "./Fiber.js" +import * as FiberId from "./FiberId.js" +import { constFalse, constVoid, dual } from "./Function.js" +import * as HashSet from "./HashSet.js" +import * as Inspectable from "./Inspectable.js" +import * as Iterable from "./Iterable.js" +import { type Pipeable, pipeArguments } from "./Pipeable.js" +import * as Predicate from "./Predicate.js" +import * as Runtime from "./Runtime.js" +import type * as Scope from "./Scope.js" + +/** + * @since 2.0.0 + * @categories type ids + */ +export const TypeId: unique symbol = Symbol.for("effect/FiberSet") + +/** + * @since 2.0.0 + * @categories type ids + */ +export type TypeId = typeof TypeId + +/** + * @since 2.0.0 + * @categories models + */ +export interface FiberSet + extends Pipeable, Inspectable.Inspectable, Iterable> +{ + readonly [TypeId]: TypeId + readonly deferred: Deferred.Deferred + /** @internal */ + state: { + readonly _tag: "Open" + readonly backing: Set> + } | { + readonly _tag: "Closed" + } +} + +/** + * @since 2.0.0 + * @categories refinements + */ +export const isFiberSet = (u: unknown): u is FiberSet => Predicate.hasProperty(u, TypeId) + +const Proto = { + [TypeId]: TypeId, + [Symbol.iterator](this: FiberSet) { + if (this.state._tag === "Closed") { + return Iterable.empty() + } + return this.state.backing[Symbol.iterator]() + }, + toString(this: FiberSet) { + return Inspectable.format(this.toJSON()) + }, + toJSON(this: FiberSet) { + return { + _id: "FiberMap", + state: this.state + } + }, + [Inspectable.NodeInspectSymbol](this: FiberSet) { + return this.toJSON() + }, + pipe() { + return pipeArguments(this, arguments) + } +} + +const unsafeMake = ( + backing: Set>, + deferred: Deferred.Deferred +): FiberSet => { + const self = Object.create(Proto) + self.state = { _tag: "Open", backing } + self.deferred = deferred + return self +} + +/** + * A FiberSet can be used to store a collection of fibers. + * When the associated Scope is closed, all fibers in the set will be interrupted. + * + * You can add fibers to the set using `FiberSet.add` or `FiberSet.run`, and the fibers will + * be automatically removed from the FiberSet when they complete. + * + * @example + * ```ts + * import { Effect, FiberSet } from "effect" + * + * Effect.gen(function*() { + * const set = yield* FiberSet.make() + * + * // run some effects and add the fibers to the set + * yield* FiberSet.run(set, Effect.never) + * yield* FiberSet.run(set, Effect.never) + * + * yield* Effect.sleep(1000) + * }).pipe( + * Effect.scoped // The fibers will be interrupted when the scope is closed + * ) + * ``` + * + * @since 2.0.0 + * @categories constructors + */ +export const make = (): Effect.Effect, never, Scope.Scope> => + Effect.acquireRelease( + Effect.map(Deferred.make(), (deferred) => unsafeMake(new Set(), deferred)), + (set) => + Effect.withFiberRuntime((parent) => { + const state = set.state + if (state._tag === "Closed") return Effect.void + set.state = { _tag: "Closed" } + const fibers = state.backing + return Fiber.interruptAllAs(fibers, FiberId.combine(parent.id(), internalFiberId)).pipe( + Effect.intoDeferred(set.deferred) + ) + }) + ) + +/** + * Create an Effect run function that is backed by a FiberSet. + * + * @since 2.0.0 + * @categories constructors + */ +export const makeRuntime = (): Effect.Effect< + ( + effect: Effect.Effect, + options?: Runtime.RunForkOptions | undefined + ) => Fiber.RuntimeFiber, + never, + Scope.Scope | R +> => + Effect.flatMap( + make(), + (self) => runtime(self)() + ) + +/** + * Create an Effect run function that is backed by a FiberSet. + * + * @since 3.13.0 + * @categories constructors + */ +export const makeRuntimePromise = (): Effect.Effect< + ( + effect: Effect.Effect, + options?: Runtime.RunForkOptions | undefined + ) => Promise, + never, + Scope.Scope | R +> => + Effect.flatMap( + make(), + (self) => runtimePromise(self)() + ) + +const internalFiberIdId = -1 +const internalFiberId = FiberId.make(internalFiberIdId, 0) +const isInternalInterruption = Cause.reduceWithContext(undefined, { + emptyCase: constFalse, + failCase: constFalse, + dieCase: constFalse, + interruptCase: (_, fiberId) => HashSet.has(FiberId.ids(fiberId), internalFiberIdId), + sequentialCase: (_, left, right) => left || right, + parallelCase: (_, left, right) => left || right +}) + +/** + * Add a fiber to the FiberSet. When the fiber completes, it will be removed. + * + * @since 2.0.0 + * @categories combinators + */ +export const unsafeAdd: { + /** + * Add a fiber to the FiberSet. When the fiber completes, it will be removed. + * + * @since 2.0.0 + * @categories combinators + */ + ( + fiber: Fiber.RuntimeFiber, + options?: { + readonly interruptAs?: FiberId.FiberId | undefined + readonly propagateInterruption?: boolean | undefined + } | undefined + ): (self: FiberSet) => void + /** + * Add a fiber to the FiberSet. When the fiber completes, it will be removed. + * + * @since 2.0.0 + * @categories combinators + */ + ( + self: FiberSet, + fiber: Fiber.RuntimeFiber, + options?: { + readonly interruptAs?: FiberId.FiberId | undefined + readonly propagateInterruption?: boolean | undefined + } | undefined + ): void +} = dual((args) => isFiberSet(args[0]), ( + self: FiberSet, + fiber: Fiber.RuntimeFiber, + options?: { + readonly interruptAs?: FiberId.FiberId | undefined + readonly propagateInterruption?: boolean | undefined + } | undefined +): void => { + if (self.state._tag === "Closed") { + fiber.unsafeInterruptAsFork(FiberId.combine(options?.interruptAs ?? FiberId.none, internalFiberId)) + return + } else if (self.state.backing.has(fiber)) { + return + } + self.state.backing.add(fiber) + fiber.addObserver((exit) => { + if (self.state._tag === "Closed") { + return + } + self.state.backing.delete(fiber) + if ( + Exit.isFailure(exit) && + ( + options?.propagateInterruption === true ? + !isInternalInterruption(exit.cause) : + !Cause.isInterruptedOnly(exit.cause) + ) + ) { + Deferred.unsafeDone(self.deferred, exit as any) + } + }) +}) + +/** + * Add a fiber to the FiberSet. When the fiber completes, it will be removed. + * + * @since 2.0.0 + * @categories combinators + */ +export const add: { + /** + * Add a fiber to the FiberSet. When the fiber completes, it will be removed. + * + * @since 2.0.0 + * @categories combinators + */ + ( + fiber: Fiber.RuntimeFiber, + options?: { + readonly propagateInterruption?: boolean | undefined + } | undefined + ): (self: FiberSet) => Effect.Effect + /** + * Add a fiber to the FiberSet. When the fiber completes, it will be removed. + * + * @since 2.0.0 + * @categories combinators + */ + ( + self: FiberSet, + fiber: Fiber.RuntimeFiber, + options?: { + readonly propagateInterruption?: boolean | undefined + } | undefined + ): Effect.Effect +} = dual( + (args) => isFiberSet(args[0]), + ( + self: FiberSet, + fiber: Fiber.RuntimeFiber, + options?: { + readonly propagateInterruption?: boolean | undefined + } | undefined + ): Effect.Effect => + Effect.fiberIdWith((fiberId) => + Effect.sync(() => + unsafeAdd(self, fiber, { + ...options, + interruptAs: fiberId + }) + ) + ) +) + +/** + * @since 2.0.0 + * @categories combinators + */ +export const clear = (self: FiberSet): Effect.Effect => + Effect.withFiberRuntime((clearFiber) => { + if (self.state._tag === "Closed") { + return Effect.void + } + return Effect.forEach(self.state.backing, (fiber) => + // will be removed by the observer + Fiber.interruptAs(fiber, FiberId.combine(clearFiber.id(), internalFiberId))) + }) + +const constInterruptedFiber = (function() { + let fiber: Fiber.RuntimeFiber | undefined = undefined + return () => { + if (fiber === undefined) { + fiber = Effect.runFork(Effect.interrupt) + } + return fiber + } +})() + +/** + * Fork an Effect and add the forked fiber to the FiberSet. + * When the fiber completes, it will be removed from the FiberSet. + * + * @since 2.0.0 + * @categories combinators + */ +export const run: { + /** + * Fork an Effect and add the forked fiber to the FiberSet. + * When the fiber completes, it will be removed from the FiberSet. + * + * @since 2.0.0 + * @categories combinators + */ + ( + self: FiberSet, + options?: { + readonly propagateInterruption?: boolean | undefined + } | undefined + ): ( + effect: Effect.Effect + ) => Effect.Effect, never, R> + /** + * Fork an Effect and add the forked fiber to the FiberSet. + * When the fiber completes, it will be removed from the FiberSet. + * + * @since 2.0.0 + * @categories combinators + */ + ( + self: FiberSet, + effect: Effect.Effect, + options?: { + readonly propagateInterruption?: boolean | undefined + } | undefined + ): Effect.Effect, never, R> +} = function() { + const self = arguments[0] as FiberSet + if (!Effect.isEffect(arguments[1])) { + const options = arguments[1] + return (effect: Effect.Effect) => runImpl(self, effect, options) + } + return runImpl(self, arguments[1], arguments[2]) as any +} + +const runImpl = ( + self: FiberSet, + effect: Effect.Effect, + options?: { + readonly propagateInterruption?: boolean | undefined + } +): Effect.Effect, never, R> => + Effect.fiberIdWith((fiberId) => { + if (self.state._tag === "Closed") { + return Effect.sync(constInterruptedFiber) + } + return Effect.tap( + Effect.forkDaemon(effect), + (fiber) => + unsafeAdd(self, fiber, { + ...options, + interruptAs: fiberId + }) + ) + }) + +/** + * Capture a Runtime and use it to fork Effect's, adding the forked fibers to the FiberSet. + * + * @example + * ```ts + * import { Context, Effect, FiberSet } from "effect" + * + * interface Users { + * readonly _: unique symbol + * } + * const Users = Context.GenericTag> + * }>("Users") + * + * Effect.gen(function*() { + * const set = yield* FiberSet.make() + * const run = yield* FiberSet.runtime(set)() + * + * // run some effects and add the fibers to the set + * run(Effect.andThen(Users, _ => _.getAll)) + * }).pipe( + * Effect.scoped // The fibers will be interrupted when the scope is closed + * ) + * ``` + * + * @since 2.0.0 + * @categories combinators + */ +export const runtime: ( + self: FiberSet +) => () => Effect.Effect< + ( + effect: Effect.Effect, + options?: + | Runtime.RunForkOptions & { readonly propagateInterruption?: boolean | undefined } + | undefined + ) => Fiber.RuntimeFiber, + never, + R +> = (self: FiberSet) => () => + Effect.map( + Effect.runtime(), + (runtime) => { + const runFork = Runtime.runFork(runtime) + return ( + effect: Effect.Effect, + options?: + | Runtime.RunForkOptions & { readonly propagateInterruption?: boolean | undefined } + | undefined + ) => { + if (self.state._tag === "Closed") { + return constInterruptedFiber() + } + const fiber = runFork(effect, options) + unsafeAdd(self, fiber) + return fiber + } + } + ) + +/** + * Capture a Runtime and use it to fork Effect's, adding the forked fibers to the FiberSet. + * + * The returned run function will return Promise's. + * + * @since 3.13.0 + * @categories combinators + */ +export const runtimePromise = (self: FiberSet): () => Effect.Effect< + ( + effect: Effect.Effect, + options?: + | Runtime.RunForkOptions & { readonly propagateInterruption?: boolean | undefined } + | undefined + ) => Promise, + never, + R +> => +() => + Effect.map( + runtime(self)(), + (runFork) => + ( + effect: Effect.Effect, + options?: + | Runtime.RunForkOptions & { readonly propagateInterruption?: boolean | undefined } + | undefined + ): Promise => + new Promise((resolve, reject) => + runFork(effect, options).addObserver((exit) => { + if (Exit.isSuccess(exit)) { + resolve(exit.value) + } else { + reject(Cause.squash(exit.cause)) + } + }) + ) + ) + +/** + * @since 2.0.0 + * @categories combinators + */ +export const size = (self: FiberSet): Effect.Effect => + Effect.sync(() => self.state._tag === "Closed" ? 0 : self.state.backing.size) + +/** + * Join all fibers in the FiberSet. If any of the Fiber's in the set terminate with a failure, + * the returned Effect will terminate with the first failure that occurred. + * + * @since 2.0.0 + * @categories combinators + * @example + * ```ts + * import { Effect, FiberSet } from "effect"; + * + * Effect.gen(function* (_) { + * const set = yield* _(FiberSet.make()); + * yield* _(FiberSet.add(set, Effect.runFork(Effect.fail("error")))); + * + * // parent fiber will fail with "error" + * yield* _(FiberSet.join(set)); + * }); + * ``` + */ +export const join = (self: FiberSet): Effect.Effect => + Deferred.await(self.deferred as Deferred.Deferred) + +/** + * Wait until the fiber set is empty. + * + * @since 3.13.0 + * @categories combinators + */ +export const awaitEmpty = (self: FiberSet): Effect.Effect => + Effect.whileLoop({ + while: () => self.state._tag === "Open" && self.state.backing.size > 0, + body: () => Fiber.await(Iterable.unsafeHead(self)), + step: constVoid + }) diff --git a/backend/node_modules/effect/src/FiberStatus.ts b/backend/node_modules/effect/src/FiberStatus.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c08a7fa39f0395b2ae0468c43fe66b336611db5 --- /dev/null +++ b/backend/node_modules/effect/src/FiberStatus.ts @@ -0,0 +1,108 @@ +/** + * @since 2.0.0 + */ +import type * as Equal from "./Equal.js" +import type * as FiberId from "./FiberId.js" +import * as internal from "./internal/fiberStatus.js" +import type * as RuntimeFlags from "./RuntimeFlags.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const FiberStatusTypeId: unique symbol = internal.FiberStatusTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type FiberStatusTypeId = typeof FiberStatusTypeId + +/** + * @since 2.0.0 + * @category models + */ +export type FiberStatus = Done | Running | Suspended + +/** + * @since 2.0.0 + * @category models + */ +export interface Done extends Equal.Equal { + readonly _tag: "Done" + readonly [FiberStatusTypeId]: FiberStatusTypeId +} + +/** + * @since 2.0.0 + * @category models + */ +export interface Running extends Equal.Equal { + readonly _tag: "Running" + readonly [FiberStatusTypeId]: FiberStatusTypeId + readonly runtimeFlags: RuntimeFlags.RuntimeFlags +} + +/** + * @since 2.0.0 + * @category models + */ +export interface Suspended extends Equal.Equal { + readonly _tag: "Suspended" + readonly [FiberStatusTypeId]: FiberStatusTypeId + readonly runtimeFlags: RuntimeFlags.RuntimeFlags + readonly blockingOn: FiberId.FiberId +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const done: FiberStatus = internal.done + +/** + * @since 2.0.0 + * @category constructors + */ +export const running: (runtimeFlags: RuntimeFlags.RuntimeFlags) => FiberStatus = internal.running + +/** + * @since 2.0.0 + * @category constructors + */ +export const suspended: (runtimeFlags: RuntimeFlags.RuntimeFlags, blockingOn: FiberId.FiberId) => FiberStatus = + internal.suspended + +/** + * Returns `true` if the specified value is a `FiberStatus`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isFiberStatus: (u: unknown) => u is FiberStatus = internal.isFiberStatus + +/** + * Returns `true` if the specified `FiberStatus` is `Done`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isDone: (self: FiberStatus) => self is Done = internal.isDone + +/** + * Returns `true` if the specified `FiberStatus` is `Running`, `false` + * otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isRunning: (self: FiberStatus) => self is Running = internal.isRunning + +/** + * Returns `true` if the specified `FiberStatus` is `Suspended`, `false` + * otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isSuspended: (self: FiberStatus) => self is Suspended = internal.isSuspended diff --git a/backend/node_modules/effect/src/Function.ts b/backend/node_modules/effect/src/Function.ts new file mode 100644 index 0000000000000000000000000000000000000000..b2abab6dee6221f129baa611f03692abdf5d8a33 --- /dev/null +++ b/backend/node_modules/effect/src/Function.ts @@ -0,0 +1,1378 @@ +/** + * @since 2.0.0 + */ +import type { TypeLambda } from "./HKT.js" + +/** + * @category type lambdas + * @since 2.0.0 + */ +export interface FunctionTypeLambda extends TypeLambda { + readonly type: (a: this["In"]) => this["Target"] +} + +/** + * Tests if a value is a `function`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { isFunction } from "effect/Predicate" + * + * assert.deepStrictEqual(isFunction(isFunction), true) + * assert.deepStrictEqual(isFunction("function"), false) + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isFunction = (input: unknown): input is Function => typeof input === "function" + +/** + * Creates a function that can be used in a data-last (aka `pipe`able) or + * data-first style. + * + * The first parameter to `dual` is either the arity of the uncurried function + * or a predicate that determines if the function is being used in a data-first + * or data-last style. + * + * Using the arity is the most common use case, but there are some cases where + * you may want to use a predicate. For example, if you have a function that + * takes an optional argument, you can use a predicate to determine if the + * function is being used in a data-first or data-last style. + * + * You can pass either the arity of the uncurried function or a predicate + * which determines if the function is being used in a data-first or + * data-last style. + * + * **Example** (Using arity to determine data-first or data-last style) + * + * ```ts + * import { dual, pipe } from "effect/Function" + * + * const sum = dual< + * (that: number) => (self: number) => number, + * (self: number, that: number) => number + * >(2, (self, that) => self + that) + * + * console.log(sum(2, 3)) // 5 + * console.log(pipe(2, sum(3))) // 5 + * ``` + * + * **Example** (Using call signatures to define the overloads) + * + * ```ts + * import { dual, pipe } from "effect/Function" + * + * const sum: { + * (that: number): (self: number) => number + * (self: number, that: number): number + * } = dual(2, (self: number, that: number): number => self + that) + * + * console.log(sum(2, 3)) // 5 + * console.log(pipe(2, sum(3))) // 5 + * ``` + * + * **Example** (Using a predicate to determine data-first or data-last style) + * + * ```ts + * import { dual, pipe } from "effect/Function" + * + * const sum = dual< + * (that: number) => (self: number) => number, + * (self: number, that: number) => number + * >( + * (args) => args.length === 2, + * (self, that) => self + that + * ) + * + * console.log(sum(2, 3)) // 5 + * console.log(pipe(2, sum(3))) // 5 + * ``` + * + * @since 2.0.0 + */ +export const dual: { + /** + * Creates a function that can be used in a data-last (aka `pipe`able) or + * data-first style. + * + * The first parameter to `dual` is either the arity of the uncurried function + * or a predicate that determines if the function is being used in a data-first + * or data-last style. + * + * Using the arity is the most common use case, but there are some cases where + * you may want to use a predicate. For example, if you have a function that + * takes an optional argument, you can use a predicate to determine if the + * function is being used in a data-first or data-last style. + * + * You can pass either the arity of the uncurried function or a predicate + * which determines if the function is being used in a data-first or + * data-last style. + * + * **Example** (Using arity to determine data-first or data-last style) + * + * ```ts + * import { dual, pipe } from "effect/Function" + * + * const sum = dual< + * (that: number) => (self: number) => number, + * (self: number, that: number) => number + * >(2, (self, that) => self + that) + * + * console.log(sum(2, 3)) // 5 + * console.log(pipe(2, sum(3))) // 5 + * ``` + * + * **Example** (Using call signatures to define the overloads) + * + * ```ts + * import { dual, pipe } from "effect/Function" + * + * const sum: { + * (that: number): (self: number) => number + * (self: number, that: number): number + * } = dual(2, (self: number, that: number): number => self + that) + * + * console.log(sum(2, 3)) // 5 + * console.log(pipe(2, sum(3))) // 5 + * ``` + * + * **Example** (Using a predicate to determine data-first or data-last style) + * + * ```ts + * import { dual, pipe } from "effect/Function" + * + * const sum = dual< + * (that: number) => (self: number) => number, + * (self: number, that: number) => number + * >( + * (args) => args.length === 2, + * (self, that) => self + that + * ) + * + * console.log(sum(2, 3)) // 5 + * console.log(pipe(2, sum(3))) // 5 + * ``` + * + * @since 2.0.0 + */ + ) => any, DataFirst extends (...args: Array) => any>(arity: Parameters["length"], body: DataFirst): DataLast & DataFirst + /** + * Creates a function that can be used in a data-last (aka `pipe`able) or + * data-first style. + * + * The first parameter to `dual` is either the arity of the uncurried function + * or a predicate that determines if the function is being used in a data-first + * or data-last style. + * + * Using the arity is the most common use case, but there are some cases where + * you may want to use a predicate. For example, if you have a function that + * takes an optional argument, you can use a predicate to determine if the + * function is being used in a data-first or data-last style. + * + * You can pass either the arity of the uncurried function or a predicate + * which determines if the function is being used in a data-first or + * data-last style. + * + * **Example** (Using arity to determine data-first or data-last style) + * + * ```ts + * import { dual, pipe } from "effect/Function" + * + * const sum = dual< + * (that: number) => (self: number) => number, + * (self: number, that: number) => number + * >(2, (self, that) => self + that) + * + * console.log(sum(2, 3)) // 5 + * console.log(pipe(2, sum(3))) // 5 + * ``` + * + * **Example** (Using call signatures to define the overloads) + * + * ```ts + * import { dual, pipe } from "effect/Function" + * + * const sum: { + * (that: number): (self: number) => number + * (self: number, that: number): number + * } = dual(2, (self: number, that: number): number => self + that) + * + * console.log(sum(2, 3)) // 5 + * console.log(pipe(2, sum(3))) // 5 + * ``` + * + * **Example** (Using a predicate to determine data-first or data-last style) + * + * ```ts + * import { dual, pipe } from "effect/Function" + * + * const sum = dual< + * (that: number) => (self: number) => number, + * (self: number, that: number) => number + * >( + * (args) => args.length === 2, + * (self, that) => self + that + * ) + * + * console.log(sum(2, 3)) // 5 + * console.log(pipe(2, sum(3))) // 5 + * ``` + * + * @since 2.0.0 + */ + ) => any, DataFirst extends (...args: Array) => any>(isDataFirst: (args: IArguments) => boolean, body: DataFirst): DataLast & DataFirst +} = function(arity, body) { + if (typeof arity === "function") { + return function() { + if (arity(arguments)) { + // @ts-expect-error + return body.apply(this, arguments) + } + return ((self: any) => body(self, ...arguments)) as any + } + } + + switch (arity) { + case 0: + case 1: + throw new RangeError(`Invalid arity ${arity}`) + + case 2: + return function(a, b) { + if (arguments.length >= 2) { + return body(a, b) + } + return function(self: any) { + return body(self, a) + } + } + + case 3: + return function(a, b, c) { + if (arguments.length >= 3) { + return body(a, b, c) + } + return function(self: any) { + return body(self, a, b) + } + } + + case 4: + return function(a, b, c, d) { + if (arguments.length >= 4) { + return body(a, b, c, d) + } + return function(self: any) { + return body(self, a, b, c) + } + } + + case 5: + return function(a, b, c, d, e) { + if (arguments.length >= 5) { + return body(a, b, c, d, e) + } + return function(self: any) { + return body(self, a, b, c, d) + } + } + + default: + return function() { + if (arguments.length >= arity) { + // @ts-expect-error + return body.apply(this, arguments) + } + const args = arguments + return function(self: any) { + return body(self, ...args) + } + } + } +} +/** + * Apply a function to given values. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, apply } from "effect/Function" + * import { length } from "effect/String" + * + * assert.deepStrictEqual(pipe(length, apply("hello")), 5) + * ``` + * + * @since 2.0.0 + */ +export const apply = >(...a: A) => (self: (...a: A) => B): B => self(...a) + +/** + * A lazy argument. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { LazyArg, constant } from "effect/Function" + * + * const constNull: LazyArg = constant(null) + * ``` + * + * @since 2.0.0 + */ +export interface LazyArg { + (): A +} + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { FunctionN } from "effect/Function" + * + * const sum: FunctionN<[number, number], number> = (a, b) => a + b + * ``` + * + * @since 2.0.0 + */ +export interface FunctionN, B> { + (...args: A): B +} + +/** + * The identity function, i.e. A function that returns its input argument. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { identity } from "effect/Function" + * + * assert.deepStrictEqual(identity(5), 5) + * ``` + * + * @since 2.0.0 + */ +export const identity = (a: A): A => a + +/** + * A function that ensures that the type of an expression matches some type, + * without changing the resulting type of that expression. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { satisfies } from "effect/Function" + * + * const test1 = satisfies()(5 as const) + * //^? const test: 5 + * // @ts-expect-error + * const test2 = satisfies()(5) + * //^? Argument of type 'number' is not assignable to parameter of type 'string' + * + * assert.deepStrictEqual(satisfies()(5), 5) + * ``` + * + * @since 2.0.0 + */ +export const satisfies = () => (b: B) => b + +/** + * Casts the result to the specified type. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { unsafeCoerce, identity } from "effect/Function" + * + * assert.deepStrictEqual(unsafeCoerce, identity) + * ``` + * + * @since 2.0.0 + */ +export const unsafeCoerce: (a: A) => B = identity as any + +/** + * Creates a constant value that never changes. + * + * This is useful when you want to pass a value to a higher-order function (a function that takes another function as its argument) + * and want that inner function to always use the same value, no matter how many times it is called. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { constant } from "effect/Function" + * + * const constNull = constant(null) + * + * assert.deepStrictEqual(constNull(), null) + * assert.deepStrictEqual(constNull(), null) + * ``` + * + * @since 2.0.0 + */ +export const constant = (value: A): LazyArg => () => value + +/** + * A thunk that returns always `true`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { constTrue } from "effect/Function" + * + * assert.deepStrictEqual(constTrue(), true) + * ``` + * + * @since 2.0.0 + */ +export const constTrue: LazyArg = constant(true) + +/** + * A thunk that returns always `false`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { constFalse } from "effect/Function" + * + * assert.deepStrictEqual(constFalse(), false) + * ``` + * + * @since 2.0.0 + */ +export const constFalse: LazyArg = constant(false) + +/** + * A thunk that returns always `null`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { constNull } from "effect/Function" + * + * assert.deepStrictEqual(constNull(), null) + * ``` + * + * @since 2.0.0 + */ +export const constNull: LazyArg = constant(null) + +/** + * A thunk that returns always `undefined`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { constUndefined } from "effect/Function" + * + * assert.deepStrictEqual(constUndefined(), undefined) + * ``` + * + * @since 2.0.0 + */ +export const constUndefined: LazyArg = constant(undefined) + +/** + * A thunk that returns always `void`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { constVoid } from "effect/Function" + * + * assert.deepStrictEqual(constVoid(), undefined) + * ``` + * + * @since 2.0.0 + */ +export const constVoid: LazyArg = constUndefined + +/** + * Reverses the order of arguments for a curried function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { flip } from "effect/Function" + * + * const f = (a: number) => (b: string) => a - b.length + * + * assert.deepStrictEqual(flip(f)('aaa')(2), -1) + * ``` + * + * @since 2.0.0 + */ +export const flip = , B extends Array, C>( + f: (...a: A) => (...b: B) => C +): (...b: B) => (...a: A) => C => +(...b) => +(...a) => f(...a)(...b) + +/** + * Composes two functions, `ab` and `bc` into a single function that takes in an argument `a` of type `A` and returns a result of type `C`. + * The result is obtained by first applying the `ab` function to `a` and then applying the `bc` function to the result of `ab`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { compose } from "effect/Function" + * + * const increment = (n: number) => n + 1; + * const square = (n: number) => n * n; + * + * assert.strictEqual(compose(increment, square)(2), 9); + * ``` + * + * @since 2.0.0 + */ +export const compose: { + /** + * Composes two functions, `ab` and `bc` into a single function that takes in an argument `a` of type `A` and returns a result of type `C`. + * The result is obtained by first applying the `ab` function to `a` and then applying the `bc` function to the result of `ab`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { compose } from "effect/Function" + * + * const increment = (n: number) => n + 1; + * const square = (n: number) => n * n; + * + * assert.strictEqual(compose(increment, square)(2), 9); + * ``` + * + * @since 2.0.0 + */ + (bc: (b: B) => C): (self: (a: A) => B) => (a: A) => C + /** + * Composes two functions, `ab` and `bc` into a single function that takes in an argument `a` of type `A` and returns a result of type `C`. + * The result is obtained by first applying the `ab` function to `a` and then applying the `bc` function to the result of `ab`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { compose } from "effect/Function" + * + * const increment = (n: number) => n + 1; + * const square = (n: number) => n * n; + * + * assert.strictEqual(compose(increment, square)(2), 9); + * ``` + * + * @since 2.0.0 + */ + (self: (a: A) => B, bc: (b: B) => C): (a: A) => C +} = dual(2, (ab: (a: A) => B, bc: (b: B) => C): (a: A) => C => (a) => bc(ab(a))) + +/** + * The `absurd` function is a stub for cases where a value of type `never` is encountered in your code, + * meaning that it should be impossible for this code to be executed. + * + * This function is particularly useful when it's necessary to specify that certain cases are impossible. + * + * @since 2.0.0 + */ +export const absurd = (_: never): A => { + throw new Error("Called `absurd` function which should be uncallable") +} + +/** + * Creates a version of this function: instead of `n` arguments, it accepts a single tuple argument. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { tupled } from "effect/Function" + * + * const sumTupled = tupled((x: number, y: number): number => x + y) + * + * assert.deepStrictEqual(sumTupled([1, 2]), 3) + * ``` + * + * @since 2.0.0 + */ +export const tupled = , B>(f: (...a: A) => B): (a: A) => B => (a) => f(...a) + +/** + * Inverse function of `tupled` + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { untupled } from "effect/Function" + * + * const getFirst = untupled((tuple: [A, B]): A => tuple[0]) + * + * assert.deepStrictEqual(getFirst(1, 2), 1) + * ``` + * + * @since 2.0.0 + */ +export const untupled = , B>(f: (a: A) => B): (...a: A) => B => (...a) => f(a) + +/** + * Pipes the value of an expression into a pipeline of functions. + * + * **Details** + * + * The `pipe` function is a utility that allows us to compose functions in a + * readable and sequential manner. It takes the output of one function and + * passes it as the input to the next function in the pipeline. This enables us + * to build complex transformations by chaining multiple functions together. + * + * ```ts skip-type-checking + * import { pipe } from "effect" + * + * const result = pipe(input, func1, func2, ..., funcN) + * ``` + * + * In this syntax, `input` is the initial value, and `func1`, `func2`, ..., + * `funcN` are the functions to be applied in sequence. The result of each + * function becomes the input for the next function, and the final result is + * returned. + * + * Here's an illustration of how `pipe` works: + * + * ``` + * ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌────────┐ + * │ input │───►│ func1 │───►│ func2 │───►│ ... │───►│ funcN │───►│ result │ + * └───────┘ └───────┘ └───────┘ └───────┘ └───────┘ └────────┘ + * ``` + * + * It's important to note that functions passed to `pipe` must have a **single + * argument** because they are only called with a single argument. + * + * **When to Use** + * + * This is useful in combination with data-last functions as a simulation of + * methods: + * + * ```ts skip-type-checking + * as.map(f).filter(g) + * ``` + * + * becomes: + * + * ```ts skip-type-checking + * import { pipe, Array } from "effect" + * + * pipe(as, Array.map(f), Array.filter(g)) + * ``` + * + * **Example** (Chaining Arithmetic Operations) + * + * ```ts + * import { pipe } from "effect" + * + * // Define simple arithmetic operations + * const increment = (x: number) => x + 1 + * const double = (x: number) => x * 2 + * const subtractTen = (x: number) => x - 10 + * + * // Sequentially apply these operations using `pipe` + * const result = pipe(5, increment, double, subtractTen) + * + * console.log(result) + * // Output: 2 + * ``` + * + * @since 2.0.0 + */ +export function pipe(a: A): A +export function pipe(a: A, ab: (a: A) => B): B +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C +): C +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D +): D +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E +): E +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F +): F +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G +): G +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H +): H +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I +): I +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J +): J +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K +): K +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L +): L +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M +): M +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N +): N +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never, + O = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O +): O +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never, + O = never, + P = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P +): P +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never, + O = never, + P = never, + Q = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q +): Q +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never, + O = never, + P = never, + Q = never, + R = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R +): R +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never, + O = never, + P = never, + Q = never, + R = never, + S = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => S +): S +export function pipe< + A, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never, + K = never, + L = never, + M = never, + N = never, + O = never, + P = never, + Q = never, + R = never, + S = never, + T = never +>( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => S, + st: (s: S) => T +): T +export function pipe( + a: unknown, + ab?: Function, + bc?: Function, + cd?: Function, + de?: Function, + ef?: Function, + fg?: Function, + gh?: Function, + hi?: Function +): unknown { + switch (arguments.length) { + case 1: + return a + case 2: + return ab!(a) + case 3: + return bc!(ab!(a)) + case 4: + return cd!(bc!(ab!(a))) + case 5: + return de!(cd!(bc!(ab!(a)))) + case 6: + return ef!(de!(cd!(bc!(ab!(a))))) + case 7: + return fg!(ef!(de!(cd!(bc!(ab!(a)))))) + case 8: + return gh!(fg!(ef!(de!(cd!(bc!(ab!(a))))))) + case 9: + return hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(a)))))))) + default: { + let ret = arguments[0] + for (let i = 1; i < arguments.length; i++) { + ret = arguments[i](ret) + } + return ret + } + } +} + +/** + * Performs left-to-right function composition. The first argument may have any arity, the remaining arguments must be unary. + * + * See also [`pipe`](#pipe). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { flow } from "effect/Function" + * + * const len = (s: string): number => s.length + * const double = (n: number): number => n * 2 + * + * const f = flow(len, double) + * + * assert.strictEqual(f('aaa'), 6) + * ``` + * + * @since 2.0.0 + */ +export function flow, B = never>( + ab: (...a: A) => B +): (...a: A) => B +export function flow, B = never, C = never>( + ab: (...a: A) => B, + bc: (b: B) => C +): (...a: A) => C +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never +>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...a: A) => D +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never, + E = never +>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E +): (...a: A) => E +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never, + E = never, + F = never +>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F +): (...a: A) => F +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never +>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G +): (...a: A) => G +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never +>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H +): (...a: A) => H +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never +>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I +): (...a: A) => I +export function flow< + A extends ReadonlyArray, + B = never, + C = never, + D = never, + E = never, + F = never, + G = never, + H = never, + I = never, + J = never +>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J +): (...a: A) => J +export function flow( + ab: Function, + bc?: Function, + cd?: Function, + de?: Function, + ef?: Function, + fg?: Function, + gh?: Function, + hi?: Function, + ij?: Function +): unknown { + switch (arguments.length) { + case 1: + return ab + case 2: + return function(this: unknown) { + return bc!(ab.apply(this, arguments)) + } + case 3: + return function(this: unknown) { + return cd!(bc!(ab.apply(this, arguments))) + } + case 4: + return function(this: unknown) { + return de!(cd!(bc!(ab.apply(this, arguments)))) + } + case 5: + return function(this: unknown) { + return ef!(de!(cd!(bc!(ab.apply(this, arguments))))) + } + case 6: + return function(this: unknown) { + return fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments)))))) + } + case 7: + return function(this: unknown) { + return gh!(fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments))))))) + } + case 8: + return function(this: unknown) { + return hi!(gh!(fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments)))))))) + } + case 9: + return function(this: unknown) { + return ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments))))))))) + } + } + return +} + +/** + * Type hole simulation. + * + * @since 2.0.0 + */ +export const hole: () => T = unsafeCoerce(absurd) + +/** + * The SK combinator, also known as the "S-K combinator" or "S-combinator", is a fundamental combinator in the + * lambda calculus and the SKI combinator calculus. + * + * This function is useful for discarding the first argument passed to it and returning the second argument. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { SK } from "effect/Function"; + * + * assert.deepStrictEqual(SK(0, "hello"), "hello") + * ``` + * + * @since 2.0.0 + */ +export const SK = (_: A, b: B): B => b diff --git a/backend/node_modules/effect/src/GlobalValue.ts b/backend/node_modules/effect/src/GlobalValue.ts new file mode 100644 index 0000000000000000000000000000000000000000..5b5fe0c414a9ef072cdf3477c27d58e5a45fddb9 --- /dev/null +++ b/backend/node_modules/effect/src/GlobalValue.ts @@ -0,0 +1,53 @@ +/** + * The `GlobalValue` module ensures that a single instance of a value is created globally, + * even when modules are imported multiple times (e.g., due to mixing CommonJS and ESM builds) + * or during hot-reloading in development environments like Next.js or Remix. + * + * It achieves this by using a versioned global store, identified by a unique `Symbol` tied to + * the current version of the `effect` library. The store holds values that are keyed by an identifier, + * allowing the reuse of previously computed instances across imports or reloads. + * + * This pattern is particularly useful in scenarios where frequent reloading can cause services or + * single-instance objects to be recreated unnecessarily, such as in development environments with hot-reloading. + * + * @since 2.0.0 + */ +const globalStoreId = `effect/GlobalValue` + +let globalStore: Map + +/** + * Retrieves or computes a global value associated with the given `id`. If the value for this `id` + * has already been computed, it will be returned from the global store. If it does not exist yet, + * the provided `compute` function will be executed to compute the value, store it, and then return it. + * + * This ensures that even in cases where the module is imported multiple times (e.g., in mixed environments + * like CommonJS and ESM, or during hot-reloading in development), the value is computed only once and reused + * thereafter. + * + * @example + * ```ts + * import { globalValue } from "effect/GlobalValue" + * + * // This cache will persist as long as the module is running, + * // even if reloaded or imported elsewhere + * const myCache = globalValue( + * Symbol.for("myCache"), + * () => new WeakMap() + * ) + * ``` + * + * @since 2.0.0 + */ +export const globalValue = (id: unknown, compute: () => A): A => { + if (!globalStore) { + // @ts-expect-error + globalThis[globalStoreId] ??= new Map() + // @ts-expect-error + globalStore = globalThis[globalStoreId] as Map + } + if (!globalStore.has(id)) { + globalStore.set(id, compute()) + } + return globalStore.get(id)! +} diff --git a/backend/node_modules/effect/src/GroupBy.ts b/backend/node_modules/effect/src/GroupBy.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ff11b2c91b8a56ab1290c678cd10767562d3358 --- /dev/null +++ b/backend/node_modules/effect/src/GroupBy.ts @@ -0,0 +1,141 @@ +/** + * @since 2.0.0 + */ +import * as internal from "./internal/groupBy.js" +import type { Pipeable } from "./Pipeable.js" +import type { Predicate } from "./Predicate.js" +import type * as Queue from "./Queue.js" +import type * as Stream from "./Stream.js" +import type * as Take from "./Take.js" +import type { Covariant, NoInfer } from "./Types.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const GroupByTypeId: unique symbol = internal.GroupByTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type GroupByTypeId = typeof GroupByTypeId + +/** + * Representation of a grouped stream. This allows to filter which groups will + * be processed. Once this is applied all groups will be processed in parallel + * and the results will be merged in arbitrary order. + * + * @since 2.0.0 + * @category models + */ +export interface GroupBy extends GroupBy.Variance, Pipeable { + readonly grouped: Stream.Stream>], E, R> +} + +/** + * @since 2.0.0 + */ +export declare namespace GroupBy { + /** + * @since 2.0.0 + * @category models + */ + export interface Variance { + readonly [GroupByTypeId]: { + readonly _K: Covariant + readonly _V: Covariant + readonly _E: Covariant + readonly _R: Covariant + } + } +} + +/** + * Run the function across all groups, collecting the results in an + * arbitrary order. + * + * @since 2.0.0 + * @category destructors + */ +export const evaluate: { + /** + * Run the function across all groups, collecting the results in an + * arbitrary order. + * + * @since 2.0.0 + * @category destructors + */ + ( + f: (key: K, stream: Stream.Stream) => Stream.Stream, + options?: { readonly bufferSize?: number | undefined } | undefined + ): (self: GroupBy) => Stream.Stream + /** + * Run the function across all groups, collecting the results in an + * arbitrary order. + * + * @since 2.0.0 + * @category destructors + */ + ( + self: GroupBy, + f: (key: K, stream: Stream.Stream) => Stream.Stream, + options?: { readonly bufferSize?: number | undefined } | undefined + ): Stream.Stream +} = internal.evaluate + +/** + * Filter the groups to be processed. + * + * @since 2.0.0 + * @category utils + */ +export const filter: { + /** + * Filter the groups to be processed. + * + * @since 2.0.0 + * @category utils + */ + (predicate: Predicate>): (self: GroupBy) => GroupBy + /** + * Filter the groups to be processed. + * + * @since 2.0.0 + * @category utils + */ + (self: GroupBy, predicate: Predicate): GroupBy +} = internal.filter + +/** + * Only consider the first `n` groups found in the `Stream`. + * + * @since 2.0.0 + * @category utils + */ +export const first: { + /** + * Only consider the first `n` groups found in the `Stream`. + * + * @since 2.0.0 + * @category utils + */ + (n: number): (self: GroupBy) => GroupBy + /** + * Only consider the first `n` groups found in the `Stream`. + * + * @since 2.0.0 + * @category utils + */ + (self: GroupBy, n: number): GroupBy +} = internal.first + +/** + * Constructs a `GroupBy` from a `Stream`. + * + * @since 2.0.0 + * @category constructors + */ +export const make: ( + grouped: Stream.Stream>], E, R> +) => GroupBy = internal.make diff --git a/backend/node_modules/effect/src/HKT.ts b/backend/node_modules/effect/src/HKT.ts new file mode 100644 index 0000000000000000000000000000000000000000..c013c6476b16e2930da72c6add38ebd382a2d31d --- /dev/null +++ b/backend/node_modules/effect/src/HKT.ts @@ -0,0 +1,45 @@ +/** + * @since 2.0.0 + */ +import type * as Types from "./Types.js" + +/** + * @since 2.0.0 + */ +export declare const URI: unique symbol + +/** + * @since 2.0.0 + */ +export interface TypeClass { + readonly [URI]?: F +} + +/** + * @since 2.0.0 + */ +export interface TypeLambda { + readonly In: unknown + readonly Out2: unknown + readonly Out1: unknown + readonly Target: unknown +} + +/** + * @since 2.0.0 + */ +export type Kind = F extends { + readonly type: unknown +} ? (F & { + readonly In: In + readonly Out2: Out2 + readonly Out1: Out1 + readonly Target: Target + })["type"] + : { + readonly F: F + readonly In: Types.Contravariant + readonly Out2: Types.Covariant + readonly Out1: Types.Covariant + readonly Target: Types.Invariant + } diff --git a/backend/node_modules/effect/src/HashMap.ts b/backend/node_modules/effect/src/HashMap.ts new file mode 100644 index 0000000000000000000000000000000000000000..695bfa92afbaff147d1f9e9f99b04ecaa2861459 --- /dev/null +++ b/backend/node_modules/effect/src/HashMap.ts @@ -0,0 +1,919 @@ +/** + * @since 2.0.0 + */ + +import type { Equal } from "./Equal.js" +import type { HashSet } from "./HashSet.js" +import type { Inspectable } from "./Inspectable.js" +import * as HM from "./internal/hashMap.js" +import * as keySet_ from "./internal/hashMap/keySet.js" +import type { Option } from "./Option.js" +import type { Pipeable } from "./Pipeable.js" +import type { NoInfer } from "./Types.js" + +const TypeId: unique symbol = HM.HashMapTypeId as TypeId + +/** + * @since 2.0.0 + * @category symbol + */ +export type TypeId = typeof TypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface HashMap extends Iterable<[Key, Value]>, Equal, Pipeable, Inspectable { + readonly [TypeId]: TypeId +} + +/** + * @since 2.0.0 + */ +export declare namespace HashMap { + /** + * @since 2.0.0 + * @category models + */ + export type UpdateFn = (option: Option) => Option + /** + * This type-level utility extracts the key type `K` from a `HashMap` type. + * + * @example + * ```ts + * import { HashMap } from "effect" + * + * declare const hm: HashMap.HashMap + * + * // $ExpectType string + * type K = HashMap.HashMap.Key + * + * ``` + * @since 2.0.0 + * @category type-level + */ + export type Key> = [T] extends [HashMap] ? _K : never + /** + * This type-level utility extracts the value type `V` from a `HashMap` type. + * + * @example + * ```ts + * import { HashMap } from "effect" + * + * declare const hm: HashMap.HashMap + * + * // $ExpectType number + * type V = HashMap.HashMap.Value + * + * ``` + * @since 2.0.0 + * @category type-level + */ + export type Value> = [T] extends [HashMap] ? _V : never + + /** + * This type-level utility extracts the entry type `[K, V]` from a `HashMap` type. + * + * @example + * ```ts + * import { HashMap } from "effect" + * + * declare const hm: HashMap.HashMap + * + * // $ExpectType [string, number] + * type V = HashMap.HashMap.Entry + * + * ``` + * @since 3.9.0 + * @category type-level + */ + export type Entry> = [Key, Value] +} + +/** + * @since 2.0.0 + * @category refinements + */ +export const isHashMap: { + /** + * @since 2.0.0 + * @category refinements + */ + (u: Iterable): u is HashMap + /** + * @since 2.0.0 + * @category refinements + */ + (u: unknown): u is HashMap +} = HM.isHashMap + +/** + * Creates a new `HashMap`. + * + * @since 2.0.0 + * @category constructors + */ +export const empty: () => HashMap = HM.empty + +/** + * Constructs a new `HashMap` from an array of key/value pairs. + * + * @since 2.0.0 + * @category constructors + */ +export const make: >( + ...entries: Entries +) => HashMap< + Entries[number] extends readonly [infer K, any] ? K : never, + Entries[number] extends readonly [any, infer V] ? V : never +> = HM.make + +/** + * Creates a new `HashMap` from an iterable collection of key/value pairs. + * + * @since 2.0.0 + * @category constructors + */ +export const fromIterable: (entries: Iterable) => HashMap = HM.fromIterable + +/** + * Checks if the `HashMap` contains any entries. + * + * @since 2.0.0 + * @category elements + */ +export const isEmpty: (self: HashMap) => boolean = HM.isEmpty + +/** + * Safely lookup the value for the specified key in the `HashMap` using the + * internal hashing function. + * + * @since 2.0.0 + * @category elements + */ +export const get: { + /** + * Safely lookup the value for the specified key in the `HashMap` using the + * internal hashing function. + * + * @since 2.0.0 + * @category elements + */ + (key: K1): (self: HashMap) => Option + /** + * Safely lookup the value for the specified key in the `HashMap` using the + * internal hashing function. + * + * @since 2.0.0 + * @category elements + */ + (self: HashMap, key: K1): Option +} = HM.get + +/** + * Lookup the value for the specified key in the `HashMap` using a custom hash. + * + * @since 2.0.0 + * @category elements + */ +export const getHash: { + /** + * Lookup the value for the specified key in the `HashMap` using a custom hash. + * + * @since 2.0.0 + * @category elements + */ + (key: K1, hash: number): (self: HashMap) => Option + /** + * Lookup the value for the specified key in the `HashMap` using a custom hash. + * + * @since 2.0.0 + * @category elements + */ + (self: HashMap, key: K1, hash: number): Option +} = HM.getHash + +/** + * Unsafely lookup the value for the specified key in the `HashMap` using the + * internal hashing function. + * + * @since 2.0.0 + * @category unsafe + */ +export const unsafeGet: { + /** + * Unsafely lookup the value for the specified key in the `HashMap` using the + * internal hashing function. + * + * @since 2.0.0 + * @category unsafe + */ + (key: K1): (self: HashMap) => V + /** + * Unsafely lookup the value for the specified key in the `HashMap` using the + * internal hashing function. + * + * @since 2.0.0 + * @category unsafe + */ + (self: HashMap, key: K1): V +} = HM.unsafeGet + +/** + * Checks if the specified key has an entry in the `HashMap`. + * + * @since 2.0.0 + * @category elements + */ +export const has: { + /** + * Checks if the specified key has an entry in the `HashMap`. + * + * @since 2.0.0 + * @category elements + */ + (key: K1): (self: HashMap) => boolean + /** + * Checks if the specified key has an entry in the `HashMap`. + * + * @since 2.0.0 + * @category elements + */ + (self: HashMap, key: K1): boolean +} = HM.has + +/** + * Checks if the specified key has an entry in the `HashMap` using a custom + * hash. + * + * @since 2.0.0 + * @category elements + */ +export const hasHash: { + /** + * Checks if the specified key has an entry in the `HashMap` using a custom + * hash. + * + * @since 2.0.0 + * @category elements + */ + (key: K1, hash: number): (self: HashMap) => boolean + /** + * Checks if the specified key has an entry in the `HashMap` using a custom + * hash. + * + * @since 2.0.0 + * @category elements + */ + (self: HashMap, key: K1, hash: number): boolean +} = HM.hasHash + +/** + * Checks if an element matching the given predicate exists in the given `HashMap`. + * + * @example + * ```ts + * import { HashMap } from "effect" + * + * const hm = HashMap.make([1, 'a']) + * HashMap.hasBy(hm, (value, key) => value === 'a' && key === 1); // -> true + * HashMap.hasBy(hm, (value) => value === 'b'); // -> false + * + * ``` + * + * @since 3.16.0 + * @category elements + */ +export const hasBy: { + /** + * Checks if an element matching the given predicate exists in the given `HashMap`. + * + * @example + * ```ts + * import { HashMap } from "effect" + * + * const hm = HashMap.make([1, 'a']) + * HashMap.hasBy(hm, (value, key) => value === 'a' && key === 1); // -> true + * HashMap.hasBy(hm, (value) => value === 'b'); // -> false + * + * ``` + * + * @since 3.16.0 + * @category elements + */ + (predicate: (value: NoInfer, key: NoInfer) => boolean): (self: HashMap) => boolean + /** + * Checks if an element matching the given predicate exists in the given `HashMap`. + * + * @example + * ```ts + * import { HashMap } from "effect" + * + * const hm = HashMap.make([1, 'a']) + * HashMap.hasBy(hm, (value, key) => value === 'a' && key === 1); // -> true + * HashMap.hasBy(hm, (value) => value === 'b'); // -> false + * + * ``` + * + * @since 3.16.0 + * @category elements + */ + ( + self: HashMap, + predicate: (value: NoInfer, key: NoInfer) => boolean + ): boolean +} = HM.hasBy + +/** + * Sets the specified key to the specified value using the internal hashing + * function. + * + * @since 2.0.0 + */ +export const set: { + /** + * Sets the specified key to the specified value using the internal hashing + * function. + * + * @since 2.0.0 + */ + (key: K, value: V): (self: HashMap) => HashMap + /** + * Sets the specified key to the specified value using the internal hashing + * function. + * + * @since 2.0.0 + */ + (self: HashMap, key: K, value: V): HashMap +} = HM.set + +/** + * Returns an `IterableIterator` of the keys within the `HashMap`. + * + * @since 2.0.0 + * @category getters + */ +export const keys: (self: HashMap) => IterableIterator = HM.keys + +/** + * Returns a `HashSet` of keys within the `HashMap`. + * + * @since 2.0.0 + * @category getter + */ +export const keySet: (self: HashMap) => HashSet = keySet_.keySet + +/** + * Returns an `IterableIterator` of the values within the `HashMap`. + * + * @since 2.0.0 + * @category getters + */ +export const values: (self: HashMap) => IterableIterator = HM.values + +/** + * Returns an `Array` of the values within the `HashMap`. + * + * @since 3.13.0 + * @category getters + */ +export const toValues = (self: HashMap): Array => Array.from(values(self)) + +/** + * Returns an `IterableIterator` of the entries within the `HashMap`. + * + * @since 2.0.0 + * @category getters + */ +export const entries: (self: HashMap) => IterableIterator<[K, V]> = HM.entries + +/** + * Returns an `Array<[K, V]>` of the entries within the `HashMap`. + * + * @since 2.0.0 + * @category getters + */ +export const toEntries = (self: HashMap): Array<[K, V]> => Array.from(entries(self)) + +/** + * Returns the number of entries within the `HashMap`. + * + * @since 2.0.0 + * @category getters + */ +export const size: (self: HashMap) => number = HM.size + +/** + * Counts all the element of the given HashMap that pass the given predicate + * + * **Example** + * + * ```ts + * import { HashMap } from "effect" + * + * const map = HashMap.make([1, "a"], [2, "b"], [3, "c"]) + * const result = HashMap.countBy(map, (_v, key) => key % 2 === 1) + * console.log(result) // 2 + * ``` + * + * @since 3.17.0 + * @category folding + */ +export const countBy: { + /** + * Counts all the element of the given HashMap that pass the given predicate + * + * **Example** + * + * ```ts + * import { HashMap } from "effect" + * + * const map = HashMap.make([1, "a"], [2, "b"], [3, "c"]) + * const result = HashMap.countBy(map, (_v, key) => key % 2 === 1) + * console.log(result) // 2 + * ``` + * + * @since 3.17.0 + * @category folding + */ + (predicate: (value: NoInfer, key: NoInfer) => boolean): (self: HashMap) => number + /** + * Counts all the element of the given HashMap that pass the given predicate + * + * **Example** + * + * ```ts + * import { HashMap } from "effect" + * + * const map = HashMap.make([1, "a"], [2, "b"], [3, "c"]) + * const result = HashMap.countBy(map, (_v, key) => key % 2 === 1) + * console.log(result) // 2 + * ``` + * + * @since 3.17.0 + * @category folding + */ + ( + self: HashMap, + predicate: (value: NoInfer, key: NoInfer) => boolean + ): number +} = HM.countBy + +/** + * Marks the `HashMap` as mutable. + * + * @since 2.0.0 + */ +export const beginMutation: (self: HashMap) => HashMap = HM.beginMutation + +/** + * Marks the `HashMap` as immutable. + * + * @since 2.0.0 + */ +export const endMutation: (self: HashMap) => HashMap = HM.endMutation + +/** + * Mutates the `HashMap` within the context of the provided function. + * + * @since 2.0.0 + */ +export const mutate: { + /** + * Mutates the `HashMap` within the context of the provided function. + * + * @since 2.0.0 + */ + (f: (self: HashMap) => void): (self: HashMap) => HashMap + /** + * Mutates the `HashMap` within the context of the provided function. + * + * @since 2.0.0 + */ + (self: HashMap, f: (self: HashMap) => void): HashMap +} = HM.mutate + +/** + * Set or remove the specified key in the `HashMap` using the specified + * update function. The value of the specified key will be computed using the + * provided hash. + * + * The update function will be invoked with the current value of the key if it + * exists, or `None` if no such value exists. + * + * @since 2.0.0 + */ +export const modifyAt: { + /** + * Set or remove the specified key in the `HashMap` using the specified + * update function. The value of the specified key will be computed using the + * provided hash. + * + * The update function will be invoked with the current value of the key if it + * exists, or `None` if no such value exists. + * + * @since 2.0.0 + */ + (key: K, f: HashMap.UpdateFn): (self: HashMap) => HashMap + /** + * Set or remove the specified key in the `HashMap` using the specified + * update function. The value of the specified key will be computed using the + * provided hash. + * + * The update function will be invoked with the current value of the key if it + * exists, or `None` if no such value exists. + * + * @since 2.0.0 + */ + (self: HashMap, key: K, f: HashMap.UpdateFn): HashMap +} = HM.modifyAt + +/** + * Alter the value of the specified key in the `HashMap` using the specified + * update function. The value of the specified key will be computed using the + * provided hash. + * + * The update function will be invoked with the current value of the key if it + * exists, or `None` if no such value exists. + * + * This function will always either update or insert a value into the `HashMap`. + * + * @since 2.0.0 + */ +export const modifyHash: { + /** + * Alter the value of the specified key in the `HashMap` using the specified + * update function. The value of the specified key will be computed using the + * provided hash. + * + * The update function will be invoked with the current value of the key if it + * exists, or `None` if no such value exists. + * + * This function will always either update or insert a value into the `HashMap`. + * + * @since 2.0.0 + */ + (key: K, hash: number, f: HashMap.UpdateFn): (self: HashMap) => HashMap + /** + * Alter the value of the specified key in the `HashMap` using the specified + * update function. The value of the specified key will be computed using the + * provided hash. + * + * The update function will be invoked with the current value of the key if it + * exists, or `None` if no such value exists. + * + * This function will always either update or insert a value into the `HashMap`. + * + * @since 2.0.0 + */ + (self: HashMap, key: K, hash: number, f: HashMap.UpdateFn): HashMap +} = HM.modifyHash + +/** + * Updates the value of the specified key within the `HashMap` if it exists. + * + * @since 2.0.0 + */ +export const modify: { + /** + * Updates the value of the specified key within the `HashMap` if it exists. + * + * @since 2.0.0 + */ + (key: K, f: (v: V) => V): (self: HashMap) => HashMap + /** + * Updates the value of the specified key within the `HashMap` if it exists. + * + * @since 2.0.0 + */ + (self: HashMap, key: K, f: (v: V) => V): HashMap +} = HM.modify + +/** + * Performs a union of this `HashMap` and that `HashMap`. + * + * @since 2.0.0 + */ +export const union: { + /** + * Performs a union of this `HashMap` and that `HashMap`. + * + * @since 2.0.0 + */ + (that: HashMap): (self: HashMap) => HashMap + /** + * Performs a union of this `HashMap` and that `HashMap`. + * + * @since 2.0.0 + */ + (self: HashMap, that: HashMap): HashMap +} = HM.union + +/** + * Remove the entry for the specified key in the `HashMap` using the internal + * hashing function. + * + * @since 2.0.0 + */ +export const remove: { + /** + * Remove the entry for the specified key in the `HashMap` using the internal + * hashing function. + * + * @since 2.0.0 + */ + (key: K): (self: HashMap) => HashMap + /** + * Remove the entry for the specified key in the `HashMap` using the internal + * hashing function. + * + * @since 2.0.0 + */ + (self: HashMap, key: K): HashMap +} = HM.remove + +/** + * Removes all entries in the `HashMap` which have the specified keys. + * + * @since 2.0.0 + */ +export const removeMany: { + /** + * Removes all entries in the `HashMap` which have the specified keys. + * + * @since 2.0.0 + */ + (keys: Iterable): (self: HashMap) => HashMap + /** + * Removes all entries in the `HashMap` which have the specified keys. + * + * @since 2.0.0 + */ + (self: HashMap, keys: Iterable): HashMap +} = HM.removeMany + +/** + * Maps over the entries of the `HashMap` using the specified function. + * + * @since 2.0.0 + * @category mapping + */ +export const map: { + /** + * Maps over the entries of the `HashMap` using the specified function. + * + * @since 2.0.0 + * @category mapping + */ + (f: (value: V, key: K) => A): (self: HashMap) => HashMap + /** + * Maps over the entries of the `HashMap` using the specified function. + * + * @since 2.0.0 + * @category mapping + */ + (self: HashMap, f: (value: V, key: K) => A): HashMap +} = HM.map + +/** + * Chains over the entries of the `HashMap` using the specified function. + * + * **NOTE**: the hash and equal of both maps have to be the same. + * + * @since 2.0.0 + * @category sequencing + */ +export const flatMap: { + /** + * Chains over the entries of the `HashMap` using the specified function. + * + * **NOTE**: the hash and equal of both maps have to be the same. + * + * @since 2.0.0 + * @category sequencing + */ + (f: (value: A, key: K) => HashMap): (self: HashMap) => HashMap + /** + * Chains over the entries of the `HashMap` using the specified function. + * + * **NOTE**: the hash and equal of both maps have to be the same. + * + * @since 2.0.0 + * @category sequencing + */ + (self: HashMap, f: (value: A, key: K) => HashMap): HashMap +} = HM.flatMap + +/** + * Applies the specified function to the entries of the `HashMap`. + * + * @since 2.0.0 + * @category traversing + */ +export const forEach: { + /** + * Applies the specified function to the entries of the `HashMap`. + * + * @since 2.0.0 + * @category traversing + */ + (f: (value: V, key: K) => void): (self: HashMap) => void + /** + * Applies the specified function to the entries of the `HashMap`. + * + * @since 2.0.0 + * @category traversing + */ + (self: HashMap, f: (value: V, key: K) => void): void +} = HM.forEach + +/** + * Reduces the specified state over the entries of the `HashMap`. + * + * @since 2.0.0 + * @category folding + */ +export const reduce: { + /** + * Reduces the specified state over the entries of the `HashMap`. + * + * @since 2.0.0 + * @category folding + */ + (zero: Z, f: (accumulator: Z, value: V, key: K) => Z): (self: HashMap) => Z + /** + * Reduces the specified state over the entries of the `HashMap`. + * + * @since 2.0.0 + * @category folding + */ + (self: HashMap, zero: Z, f: (accumulator: Z, value: V, key: K) => Z): Z +} = HM.reduce + +/** + * Filters entries out of a `HashMap` using the specified predicate. + * + * @since 2.0.0 + * @category filtering + */ +export const filter: { + /** + * Filters entries out of a `HashMap` using the specified predicate. + * + * @since 2.0.0 + * @category filtering + */ + (f: (a: NoInfer, k: K) => a is B): (self: HashMap) => HashMap + /** + * Filters entries out of a `HashMap` using the specified predicate. + * + * @since 2.0.0 + * @category filtering + */ + (f: (a: NoInfer, k: K) => boolean): (self: HashMap) => HashMap + /** + * Filters entries out of a `HashMap` using the specified predicate. + * + * @since 2.0.0 + * @category filtering + */ + (self: HashMap, f: (a: A, k: K) => a is B): HashMap + /** + * Filters entries out of a `HashMap` using the specified predicate. + * + * @since 2.0.0 + * @category filtering + */ + (self: HashMap, f: (a: A, k: K) => boolean): HashMap +} = HM.filter + +/** + * Filters out `None` values from a `HashMap` of `Options`s. + * + * @since 2.0.0 + * @category filtering + */ +export const compact: (self: HashMap>) => HashMap = HM.compact + +/** + * Maps over the entries of the `HashMap` using the specified partial function + * and filters out `None` values. + * + * @since 2.0.0 + * @category filtering + */ +export const filterMap: { + /** + * Maps over the entries of the `HashMap` using the specified partial function + * and filters out `None` values. + * + * @since 2.0.0 + * @category filtering + */ + (f: (value: A, key: K) => Option): (self: HashMap) => HashMap + /** + * Maps over the entries of the `HashMap` using the specified partial function + * and filters out `None` values. + * + * @since 2.0.0 + * @category filtering + */ + (self: HashMap, f: (value: A, key: K) => Option): HashMap +} = HM.filterMap + +/** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * @category elements + * @since 2.0.0 + */ +export const findFirst: { + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * @category elements + * @since 2.0.0 + */ + (predicate: (a: NoInfer, k: K) => a is B): (self: HashMap) => Option<[K, B]> + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * @category elements + * @since 2.0.0 + */ + (predicate: (a: NoInfer, k: K) => boolean): (self: HashMap) => Option<[K, A]> + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * @category elements + * @since 2.0.0 + */ + (self: HashMap, predicate: (a: A, k: K) => a is B): Option<[K, B]> + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * @category elements + * @since 2.0.0 + */ + (self: HashMap, predicate: (a: A, k: K) => boolean): Option<[K, A]> +} = HM.findFirst + +/** + * Checks if any entry in a hashmap meets a specific condition. + * + * @since 3.13.0 + * @category elements + */ +export const some: { + /** + * Checks if any entry in a hashmap meets a specific condition. + * + * @since 3.13.0 + * @category elements + */ + (predicate: (a: NoInfer, k: K) => boolean): (self: HashMap) => boolean + /** + * Checks if any entry in a hashmap meets a specific condition. + * + * @since 3.13.0 + * @category elements + */ + (self: HashMap, predicate: (a: A, k: K) => boolean): boolean +} = HM.some + +/** + * Checks if all entries in a hashmap meets a specific condition. + * + * @param self - The hashmap to check. + * @param predicate - The condition to test entries (value, key). + * + * @since 3.14.0 + * @category elements + */ +export const every: { + /** + * Checks if all entries in a hashmap meets a specific condition. + * + * @param self - The hashmap to check. + * @param predicate - The condition to test entries (value, key). + * + * @since 3.14.0 + * @category elements + */ + (predicate: (a: NoInfer, k: K) => boolean): (self: HashMap) => boolean + /** + * Checks if all entries in a hashmap meets a specific condition. + * + * @param self - The hashmap to check. + * @param predicate - The condition to test entries (value, key). + * + * @since 3.14.0 + * @category elements + */ + (self: HashMap, predicate: (a: A, k: K) => boolean): boolean +} = HM.every diff --git a/backend/node_modules/effect/src/Inspectable.ts b/backend/node_modules/effect/src/Inspectable.ts new file mode 100644 index 0000000000000000000000000000000000000000..9bab2d1e9c4d22a19321584aa57deb9f4c876342 --- /dev/null +++ b/backend/node_modules/effect/src/Inspectable.ts @@ -0,0 +1,287 @@ +/** + * @since 2.0.0 + */ +import type * as FiberRefs from "./FiberRefs.js" +import { globalValue } from "./GlobalValue.js" +import * as Predicate from "./Predicate.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const NodeInspectSymbol = Symbol.for("nodejs.util.inspect.custom") + +/** + * @since 2.0.0 + * @category symbols + */ +export type NodeInspectSymbol = typeof NodeInspectSymbol + +/** + * @since 2.0.0 + * @category models + */ +export interface Inspectable { + toString(): string + toJSON(): unknown + [NodeInspectSymbol](): unknown +} + +/** + * @since 2.0.0 + */ +export const toJSON = (x: unknown): unknown => { + try { + if ( + Predicate.hasProperty(x, "toJSON") && Predicate.isFunction(x["toJSON"]) && + x["toJSON"].length === 0 + ) { + return x.toJSON() + } else if (Array.isArray(x)) { + return x.map(toJSON) + } + } catch { + return {} + } + return redact(x) +} + +const CIRCULAR = "[Circular]" + +/** @internal */ +export function formatDate(date: Date): string { + try { + return date.toISOString() + } catch { + return "Invalid Date" + } +} + +function safeToString(input: any): string { + try { + const s = input.toString() + return typeof s === "string" ? s : String(s) + } catch { + return "[toString threw]" + } +} + +/** @internal */ +export function formatPropertyKey(name: PropertyKey): string { + return Predicate.isString(name) ? JSON.stringify(name) : String(name) +} + +/** @internal */ +export function formatUnknown( + input: unknown, + options?: { + readonly space?: number | string | undefined + readonly ignoreToString?: boolean | undefined + } +): string { + const space = options?.space ?? 0 + const seen = new WeakSet() + const gap = !space ? "" : (Predicate.isNumber(space) ? " ".repeat(space) : space) + const ind = (d: number) => gap.repeat(d) + + const wrap = (v: unknown, body: string): string => { + const ctor = (v as any)?.constructor + return ctor && ctor !== Object.prototype.constructor && ctor.name ? `${ctor.name}(${body})` : body + } + + const ownKeys = (o: object): Array => { + try { + return Reflect.ownKeys(o) + } catch { + return ["[ownKeys threw]"] + } + } + + function go(v: unknown, d = 0): string { + if (Array.isArray(v)) { + if (seen.has(v)) return CIRCULAR + seen.add(v) + if (!gap || v.length <= 1) return `[${v.map((x) => go(x, d)).join(",")}]` + const inner = v.map((x) => go(x, d + 1)).join(",\n" + ind(d + 1)) + return `[\n${ind(d + 1)}${inner}\n${ind(d)}]` + } + + if (Predicate.isDate(v)) return formatDate(v) + + if ( + !options?.ignoreToString && + Predicate.hasProperty(v, "toString") && + Predicate.isFunction(v["toString"]) && + v["toString"] !== Object.prototype.toString && + v["toString"] !== Array.prototype.toString + ) { + const s = safeToString(v) + if (v instanceof Error && v.cause) { + return `${s} (cause: ${go(v.cause, d)})` + } + return s + } + + if (Predicate.isString(v)) return JSON.stringify(v) + + if ( + Predicate.isNumber(v) || + v == null || + Predicate.isBoolean(v) || + Predicate.isSymbol(v) + ) return String(v) + + if (Predicate.isBigInt(v)) return String(v) + "n" + + if (v instanceof Set || v instanceof Map) { + if (seen.has(v)) return CIRCULAR + seen.add(v) + return `${v.constructor.name}(${go(Array.from(v), d)})` + } + + if (Predicate.isObject(v)) { + if (seen.has(v)) return CIRCULAR + seen.add(v) + const keys = ownKeys(v) + if (!gap || keys.length <= 1) { + const body = `{${keys.map((k) => `${formatPropertyKey(k)}:${go((v as any)[k], d)}`).join(",")}}` + return wrap(v, body) + } + const body = `{\n${ + keys.map((k) => `${ind(d + 1)}${formatPropertyKey(k)}: ${go((v as any)[k], d + 1)}`).join(",\n") + }\n${ind(d)}}` + return wrap(v, body) + } + + return String(v) + } + + return go(input, 0) +} + +/** + * @since 2.0.0 + */ +export const format = (x: unknown): string => JSON.stringify(x, null, 2) + +/** + * @since 2.0.0 + */ +export const BaseProto: Inspectable = { + toJSON() { + return toJSON(this) + }, + [NodeInspectSymbol]() { + return this.toJSON() + }, + toString() { + return format(this.toJSON()) + } +} + +/** + * @since 2.0.0 + */ +export abstract class Class { + /** + * @since 2.0.0 + */ + abstract toJSON(): unknown + /** + * @since 2.0.0 + */ + [NodeInspectSymbol]() { + return this.toJSON() + } + /** + * @since 2.0.0 + */ + toString() { + return format(this.toJSON()) + } +} + +/** + * @since 2.0.0 + */ +export const toStringUnknown = (u: unknown, whitespace: number | string | undefined = 2): string => { + if (typeof u === "string") { + return u + } + try { + return typeof u === "object" ? stringifyCircular(u, whitespace) : String(u) + } catch { + return String(u) + } +} + +/** + * @since 2.0.0 + */ +export const stringifyCircular = (obj: unknown, whitespace?: number | string | undefined): string => { + let cache: Array = [] + const retVal = JSON.stringify( + obj, + (_key, value) => + typeof value === "object" && value !== null + ? cache.includes(value) + ? undefined // circular reference + : cache.push(value) && (redactableState.fiberRefs !== undefined && isRedactable(value) + ? value[symbolRedactable](redactableState.fiberRefs) + : value) + : value, + whitespace + ) + ;(cache as any) = undefined + return retVal +} + +/** + * @since 3.10.0 + * @category redactable + */ +export interface Redactable { + readonly [symbolRedactable]: (fiberRefs: FiberRefs.FiberRefs) => unknown +} + +/** + * @since 3.10.0 + * @category redactable + */ +export const symbolRedactable: unique symbol = Symbol.for("effect/Inspectable/Redactable") + +/** + * @since 3.10.0 + * @category redactable + */ +export const isRedactable = (u: unknown): u is Redactable => + typeof u === "object" && u !== null && symbolRedactable in u + +const redactableState = globalValue("effect/Inspectable/redactableState", () => ({ + fiberRefs: undefined as FiberRefs.FiberRefs | undefined +})) + +/** + * @since 3.10.0 + * @category redactable + */ +export const withRedactableContext = (context: FiberRefs.FiberRefs, f: () => A): A => { + const prev = redactableState.fiberRefs + redactableState.fiberRefs = context + try { + return f() + } finally { + redactableState.fiberRefs = prev + } +} + +/** + * @since 3.10.0 + * @category redactable + */ +export const redact = (u: unknown): unknown => { + if (isRedactable(u) && redactableState.fiberRefs !== undefined) { + return u[symbolRedactable](redactableState.fiberRefs) + } + return u +} diff --git a/backend/node_modules/effect/src/Iterable.ts b/backend/node_modules/effect/src/Iterable.ts new file mode 100644 index 0000000000000000000000000000000000000000..ac25fd34695b3376a0b7104356ff0c97da05c7c7 --- /dev/null +++ b/backend/node_modules/effect/src/Iterable.ts @@ -0,0 +1,1606 @@ +/** + * This module provides utility functions for working with Iterables in TypeScript. + * + * @since 2.0.0 + */ + +import type { NonEmptyArray } from "./Array.js" +import type { Either } from "./Either.js" +import * as E from "./Either.js" +import * as Equal from "./Equal.js" +import { dual, identity } from "./Function.js" +import type { Option } from "./Option.js" +import * as O from "./Option.js" +import { isBoolean } from "./Predicate.js" +import type * as Record from "./Record.js" +import * as Tuple from "./Tuple.js" +import type { NoInfer } from "./Types.js" + +/** + * Return a `Iterable` with element `i` initialized with `f(i)`. + * + * If the `length` is not specified, the `Iterable` will be infinite. + * + * **Note**. `length` is normalized to an integer >= 1. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { makeBy } from "effect/Iterable" + * + * assert.deepStrictEqual(Array.from(makeBy(n => n * 2, { length: 5 })), [0, 2, 4, 6, 8]) + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const makeBy = (f: (i: number) => A, options?: { + readonly length?: number +}): Iterable => { + const max = options?.length !== undefined ? Math.max(1, Math.floor(options.length)) : Infinity + return { + [Symbol.iterator]() { + let i = 0 + return { + next(): IteratorResult { + if (i < max) { + return { value: f(i++), done: false } + } + return { done: true, value: undefined } + } + } + } + } +} + +/** + * Return a `Iterable` containing a range of integers, including both endpoints. + * + * If `end` is omitted, the range will not have an upper bound. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { range } from "effect/Iterable" + * + * assert.deepStrictEqual(Array.from(range(1, 3)), [1, 2, 3]) + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const range = (start: number, end?: number): Iterable => { + if (end === undefined) { + return makeBy((i) => start + i) + } + return makeBy((i) => start + i, { + length: start <= end ? end - start + 1 : 1 + }) +} + +/** + * Return a `Iterable` containing a value repeated the specified number of times. + * + * **Note**. `n` is normalized to an integer >= 1. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { replicate } from "effect/Iterable" + * + * assert.deepStrictEqual(Array.from(replicate("a", 3)), ["a", "a", "a"]) + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const replicate: { + /** + * Return a `Iterable` containing a value repeated the specified number of times. + * + * **Note**. `n` is normalized to an integer >= 1. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { replicate } from "effect/Iterable" + * + * assert.deepStrictEqual(Array.from(replicate("a", 3)), ["a", "a", "a"]) + * ``` + * + * @category constructors + * @since 2.0.0 + */ + (n: number): (a: A) => Iterable + /** + * Return a `Iterable` containing a value repeated the specified number of times. + * + * **Note**. `n` is normalized to an integer >= 1. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { replicate } from "effect/Iterable" + * + * assert.deepStrictEqual(Array.from(replicate("a", 3)), ["a", "a", "a"]) + * ``` + * + * @category constructors + * @since 2.0.0 + */ + (a: A, n: number): Iterable +} = dual(2, (a: A, n: number): Iterable => makeBy(() => a, { length: n })) + +/** + * Takes a record and returns an Iterable of tuples containing its keys and values. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { fromRecord } from "effect/Iterable" + * + * const x = { a: 1, b: 2, c: 3 } + * assert.deepStrictEqual(Array.from(fromRecord(x)), [["a", 1], ["b", 2], ["c", 3]]) + * ``` + * + * @category conversions + * @since 2.0.0 + */ +export const fromRecord = (self: Readonly>): Iterable<[K, A]> => ({ + *[Symbol.iterator]() { + for (const key in self) { + if (Object.prototype.hasOwnProperty.call(self, key)) { + yield [key, self[key]] + } + } + } +}) + +/** + * Prepend an element to the front of an `Iterable`, creating a new `Iterable`. + * + * @category concatenating + * @since 2.0.0 + */ +export const prepend: { + /** + * Prepend an element to the front of an `Iterable`, creating a new `Iterable`. + * + * @category concatenating + * @since 2.0.0 + */ + (head: B): (self: Iterable) => Iterable + /** + * Prepend an element to the front of an `Iterable`, creating a new `Iterable`. + * + * @category concatenating + * @since 2.0.0 + */ + (self: Iterable, head: B): Iterable +} = dual(2, (self: Iterable, head: B): Iterable => prependAll(self, [head])) + +/** + * Prepends the specified prefix iterable to the beginning of the specified iterable. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Iterable } from "effect" + * + * assert.deepStrictEqual( + * Array.from(Iterable.prependAll([1, 2], ["a", "b"])), + * ["a", "b", 1, 2] + * ) + * ``` + * + * @category concatenating + * @since 2.0.0 + */ +export const prependAll: { + /** + * Prepends the specified prefix iterable to the beginning of the specified iterable. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Iterable } from "effect" + * + * assert.deepStrictEqual( + * Array.from(Iterable.prependAll([1, 2], ["a", "b"])), + * ["a", "b", 1, 2] + * ) + * ``` + * + * @category concatenating + * @since 2.0.0 + */ + (that: Iterable): (self: Iterable) => Iterable + /** + * Prepends the specified prefix iterable to the beginning of the specified iterable. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Iterable } from "effect" + * + * assert.deepStrictEqual( + * Array.from(Iterable.prependAll([1, 2], ["a", "b"])), + * ["a", "b", 1, 2] + * ) + * ``` + * + * @category concatenating + * @since 2.0.0 + */ + (self: Iterable, that: Iterable): Iterable +} = dual( + 2, + (self: Iterable, that: Iterable): Iterable => appendAll(that, self) +) + +/** + * Append an element to the end of an `Iterable`, creating a new `Iterable`. + * + * @category concatenating + * @since 2.0.0 + */ +export const append: { + /** + * Append an element to the end of an `Iterable`, creating a new `Iterable`. + * + * @category concatenating + * @since 2.0.0 + */ + (last: B): (self: Iterable) => Iterable + /** + * Append an element to the end of an `Iterable`, creating a new `Iterable`. + * + * @category concatenating + * @since 2.0.0 + */ + (self: Iterable, last: B): Iterable +} = dual(2, (self: Iterable, last: B): Iterable => appendAll(self, [last])) + +/** + * Concatenates two iterables, combining their elements. + * + * @category concatenating + * @since 2.0.0 + */ +export const appendAll: { + /** + * Concatenates two iterables, combining their elements. + * + * @category concatenating + * @since 2.0.0 + */ + (that: Iterable): (self: Iterable) => Iterable + /** + * Concatenates two iterables, combining their elements. + * + * @category concatenating + * @since 2.0.0 + */ + (self: Iterable, that: Iterable): Iterable +} = dual( + 2, + (self: Iterable, that: Iterable): Iterable => ({ + [Symbol.iterator]() { + const iterA = self[Symbol.iterator]() + let doneA = false + let iterB: Iterator + return { + next() { + if (!doneA) { + const r = iterA.next() + if (r.done) { + doneA = true + iterB = that[Symbol.iterator]() + return iterB.next() + } + return r + } + return iterB.next() + } + } + } + }) +) + +/** + * Reduce an `Iterable` from the left, keeping all intermediate results instead of only the final result. + * + * @category folding + * @since 2.0.0 + */ +export const scan: { + /** + * Reduce an `Iterable` from the left, keeping all intermediate results instead of only the final result. + * + * @category folding + * @since 2.0.0 + */ + (b: B, f: (b: B, a: A) => B): (self: Iterable) => Iterable + /** + * Reduce an `Iterable` from the left, keeping all intermediate results instead of only the final result. + * + * @category folding + * @since 2.0.0 + */ + (self: Iterable, b: B, f: (b: B, a: A) => B): Iterable +} = dual(3, (self: Iterable, b: B, f: (b: B, a: A) => B): Iterable => ({ + [Symbol.iterator]() { + let acc = b + let iterator: Iterator | undefined + function next() { + if (iterator === undefined) { + iterator = self[Symbol.iterator]() + return { done: false, value: acc } + } + const result = iterator.next() + if (result.done) { + return result + } + acc = f(acc, result.value) + return { done: false, value: acc } + } + return { next } + } +})) + +/** + * Determine if an `Iterable` is empty + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { isEmpty } from "effect/Iterable" + * + * assert.deepStrictEqual(isEmpty([]), true); + * assert.deepStrictEqual(isEmpty([1, 2, 3]), false); + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isEmpty = (self: Iterable): self is Iterable => { + const iterator = self[Symbol.iterator]() + return iterator.next().done === true +} + +/** + * Return the number of elements in a `Iterable`. + * + * @category getters + * @since 2.0.0 + */ +export const size = (self: Iterable): number => { + const iterator = self[Symbol.iterator]() + let count = 0 + while (!iterator.next().done) { + count++ + } + return count +} + +/** + * Get the first element of a `Iterable`, or `None` if the `Iterable` is empty. + * + * @category getters + * @since 2.0.0 + */ +export const head = (self: Iterable): Option => { + const iterator = self[Symbol.iterator]() + const result = iterator.next() + return result.done ? O.none() : O.some(result.value) +} + +/** + * Get the first element of a `Iterable`, or throw an error if the `Iterable` is empty. + * + * @category getters + * @since 3.3.0 + */ +export const unsafeHead = (self: Iterable): A => { + const iterator = self[Symbol.iterator]() + const result = iterator.next() + if (result.done) throw new Error("unsafeHead: empty iterable") + return result.value +} + +/** + * Keep only a max number of elements from the start of an `Iterable`, creating a new `Iterable`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * @category getters + * @since 2.0.0 + */ +export const take: { + /** + * Keep only a max number of elements from the start of an `Iterable`, creating a new `Iterable`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * @category getters + * @since 2.0.0 + */ + (n: number): (self: Iterable) => Iterable + /** + * Keep only a max number of elements from the start of an `Iterable`, creating a new `Iterable`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * @category getters + * @since 2.0.0 + */ + (self: Iterable, n: number): Iterable +} = dual(2, (self: Iterable, n: number): Iterable => ({ + [Symbol.iterator]() { + let i = 0 + const iterator = self[Symbol.iterator]() + return { + next() { + if (i < n) { + i++ + return iterator.next() + } + return { done: true, value: undefined } + } + } + } +})) + +/** + * Calculate the longest initial Iterable for which all element satisfy the specified predicate, creating a new `Iterable`. + * + * @category getters + * @since 2.0.0 + */ +export const takeWhile: { + /** + * Calculate the longest initial Iterable for which all element satisfy the specified predicate, creating a new `Iterable`. + * + * @category getters + * @since 2.0.0 + */ + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Iterable + /** + * Calculate the longest initial Iterable for which all element satisfy the specified predicate, creating a new `Iterable`. + * + * @category getters + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Iterable + /** + * Calculate the longest initial Iterable for which all element satisfy the specified predicate, creating a new `Iterable`. + * + * @category getters + * @since 2.0.0 + */ + (self: Iterable, refinement: (a: A, i: number) => a is B): Iterable + /** + * Calculate the longest initial Iterable for which all element satisfy the specified predicate, creating a new `Iterable`. + * + * @category getters + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): Iterable +} = dual(2, (self: Iterable, predicate: (a: A, i: number) => boolean): Iterable => ({ + [Symbol.iterator]() { + const iterator = self[Symbol.iterator]() + let i = 0 + return { + next() { + const result = iterator.next() + if (result.done || !predicate(result.value, i++)) { + return { done: true, value: undefined } + } + return result + } + } + } +})) + +/** + * Drop a max number of elements from the start of an `Iterable` + * + * **Note**. `n` is normalized to a non negative integer. + * + * @category getters + * @since 2.0.0 + */ +export const drop: { + /** + * Drop a max number of elements from the start of an `Iterable` + * + * **Note**. `n` is normalized to a non negative integer. + * + * @category getters + * @since 2.0.0 + */ + (n: number): (self: Iterable) => Iterable + /** + * Drop a max number of elements from the start of an `Iterable` + * + * **Note**. `n` is normalized to a non negative integer. + * + * @category getters + * @since 2.0.0 + */ + (self: Iterable, n: number): Iterable +} = dual(2, (self: Iterable, n: number): Iterable => ({ + [Symbol.iterator]() { + const iterator = self[Symbol.iterator]() + let i = 0 + return { + next() { + while (i < n) { + const result = iterator.next() + if (result.done) { + return { done: true, value: undefined } + } + i++ + } + return iterator.next() + } + } + } +})) + +/** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * @category elements + * @since 2.0.0 + */ +export const findFirst: { + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * @category elements + * @since 2.0.0 + */ + (f: (a: NoInfer, i: number) => Option): (self: Iterable) => Option + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * @category elements + * @since 2.0.0 + */ + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Option + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * @category elements + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, f: (a: A, i: number) => Option): Option + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, refinement: (a: A, i: number) => a is B): Option + /** + * Returns the first element that satisfies the specified + * predicate, or `None` if no such element exists. + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): Option +} = dual( + 2, + (self: Iterable, f: ((a: A, i: number) => boolean) | ((a: A, i: number) => Option)): Option => { + let i = 0 + for (const a of self) { + const o = f(a, i) + if (isBoolean(o)) { + if (o) { + return O.some(a) + } + } else { + if (O.isSome(o)) { + return o + } + } + i++ + } + return O.none() + } +) + +/** + * Find the last element for which a predicate holds. + * + * @category elements + * @since 2.0.0 + */ +export const findLast: { + /** + * Find the last element for which a predicate holds. + * + * @category elements + * @since 2.0.0 + */ + (f: (a: NoInfer, i: number) => Option): (self: Iterable) => Option + /** + * Find the last element for which a predicate holds. + * + * @category elements + * @since 2.0.0 + */ + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Option + /** + * Find the last element for which a predicate holds. + * + * @category elements + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Option + /** + * Find the last element for which a predicate holds. + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, f: (a: A, i: number) => Option): Option + /** + * Find the last element for which a predicate holds. + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, refinement: (a: A, i: number) => a is B): Option + /** + * Find the last element for which a predicate holds. + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): Option +} = dual( + 2, + (self: Iterable, f: ((a: A, i: number) => boolean) | ((a: A, i: number) => Option)): Option => { + let i = 0 + let last: Option = O.none() + for (const a of self) { + const o = f(a, i) + if (isBoolean(o)) { + if (o) { + last = O.some(a) + } + } else { + if (O.isSome(o)) { + last = o + } + } + i++ + } + return last + } +) + +/** + * Takes two `Iterable`s and returns an `Iterable` of corresponding pairs. + * + * @category zipping + * @since 2.0.0 + */ +export const zip: { + /** + * Takes two `Iterable`s and returns an `Iterable` of corresponding pairs. + * + * @category zipping + * @since 2.0.0 + */ + (that: Iterable): (self: Iterable) => Iterable<[A, B]> + /** + * Takes two `Iterable`s and returns an `Iterable` of corresponding pairs. + * + * @category zipping + * @since 2.0.0 + */ + (self: Iterable, that: Iterable): Iterable<[A, B]> +} = dual( + 2, + (self: Iterable, that: Iterable): Iterable<[A, B]> => zipWith(self, that, Tuple.make) +) + +/** + * Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results. If one + * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. + * + * @category zipping + * @since 2.0.0 + */ +export const zipWith: { + /** + * Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results. If one + * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. + * + * @category zipping + * @since 2.0.0 + */ + (that: Iterable, f: (a: A, b: B) => C): (self: Iterable) => Iterable + /** + * Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results. If one + * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. + * + * @category zipping + * @since 2.0.0 + */ + (self: Iterable, that: Iterable, f: (a: A, b: B) => C): Iterable +} = dual(3, (self: Iterable, that: Iterable, f: (a: A, b: B) => C): Iterable => ({ + [Symbol.iterator]() { + const selfIterator = self[Symbol.iterator]() + const thatIterator = that[Symbol.iterator]() + return { + next() { + const selfResult = selfIterator.next() + const thatResult = thatIterator.next() + if (selfResult.done || thatResult.done) { + return { done: true, value: undefined } + } + return { done: false, value: f(selfResult.value, thatResult.value) } + } + } + } +})) + +/** + * Places an element in between members of an `Iterable`. + * If the input is a non-empty array, the result is also a non-empty array. + * + * @since 2.0.0 + */ +export const intersperse: { + /** + * Places an element in between members of an `Iterable`. + * If the input is a non-empty array, the result is also a non-empty array. + * + * @since 2.0.0 + */ + (middle: B): (self: Iterable) => Iterable + /** + * Places an element in between members of an `Iterable`. + * If the input is a non-empty array, the result is also a non-empty array. + * + * @since 2.0.0 + */ + (self: Iterable, middle: B): Iterable +} = dual(2, (self: Iterable, middle: B): Iterable => ({ + [Symbol.iterator]() { + const iterator = self[Symbol.iterator]() + let next = iterator.next() + let emitted = false + return { + next() { + if (next.done) { + return next + } else if (emitted) { + emitted = false + return { done: false, value: middle } + } + emitted = true + const result = next + next = iterator.next() + return result + } + } + } +})) + +/** + * Returns a function that checks if an `Iterable` contains a given value using a provided `isEquivalent` function. + * + * @category elements + * @since 2.0.0 + */ +export const containsWith = (isEquivalent: (self: A, that: A) => boolean): { + (a: A): (self: Iterable) => boolean + (self: Iterable, a: A): boolean +} => + dual(2, (self: Iterable, a: A): boolean => { + for (const i of self) { + if (isEquivalent(a, i)) { + return true + } + } + return false + }) + +const _equivalence = Equal.equivalence() + +/** + * Returns a function that checks if a `Iterable` contains a given value using the default `Equivalence`. + * + * @category elements + * @since 2.0.0 + */ +export const contains: { + /** + * Returns a function that checks if a `Iterable` contains a given value using the default `Equivalence`. + * + * @category elements + * @since 2.0.0 + */ + (a: A): (self: Iterable) => boolean + /** + * Returns a function that checks if a `Iterable` contains a given value using the default `Equivalence`. + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, a: A): boolean +} = containsWith(_equivalence) + +/** + * Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of + * the `Iterable`. + * + * @category splitting + * @since 2.0.0 + */ +export const chunksOf: { + /** + * Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of + * the `Iterable`. + * + * @category splitting + * @since 2.0.0 + */ + (n: number): (self: Iterable) => Iterable> + /** + * Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of + * the `Iterable`. + * + * @category splitting + * @since 2.0.0 + */ + (self: Iterable, n: number): Iterable> +} = dual(2, (self: Iterable, n: number): Iterable> => { + const safeN = Math.max(1, Math.floor(n)) + return ({ + [Symbol.iterator]() { + let iterator: Iterator | undefined = self[Symbol.iterator]() + return { + next() { + if (iterator === undefined) { + return { done: true, value: undefined } + } + + const chunk: Array = [] + for (let i = 0; i < safeN; i++) { + const result = iterator.next() + if (result.done) { + iterator = undefined + return chunk.length === 0 ? { done: true, value: undefined } : { done: false, value: chunk } + } + chunk.push(result.value) + } + + return { done: false, value: chunk } + } + } + } + }) +}) + +/** + * Group equal, consecutive elements of an `Iterable` into `NonEmptyArray`s using the provided `isEquivalent` function. + * + * @category grouping + * @since 2.0.0 + */ +export const groupWith: { + /** + * Group equal, consecutive elements of an `Iterable` into `NonEmptyArray`s using the provided `isEquivalent` function. + * + * @category grouping + * @since 2.0.0 + */ + (isEquivalent: (self: A, that: A) => boolean): (self: Iterable) => Iterable> + /** + * Group equal, consecutive elements of an `Iterable` into `NonEmptyArray`s using the provided `isEquivalent` function. + * + * @category grouping + * @since 2.0.0 + */ + (self: Iterable, isEquivalent: (self: A, that: A) => boolean): Iterable> +} = dual( + 2, + (self: Iterable, isEquivalent: (self: A, that: A) => boolean): Iterable> => ({ + [Symbol.iterator]() { + const iterator = self[Symbol.iterator]() + let nextResult: IteratorResult | undefined + return { + next() { + let result: IteratorResult + if (nextResult !== undefined) { + if (nextResult.done) { + return { done: true, value: undefined } + } + result = nextResult + nextResult = undefined + } else { + result = iterator.next() + if (result.done) { + return { done: true, value: undefined } + } + } + const chunk: NonEmptyArray = [result.value] + + while (true) { + const next = iterator.next() + if (next.done || !isEquivalent(result.value, next.value)) { + nextResult = next + return { done: false, value: chunk } + } + chunk.push(next.value) + } + } + } + } + }) +) + +/** + * Group equal, consecutive elements of an `Iterable` into `NonEmptyArray`s. + * + * @category grouping + * @since 2.0.0 + */ +export const group: (self: Iterable) => Iterable> = groupWith( + Equal.equivalence() +) + +/** + * Splits an `Iterable` into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning + * function on each element, and grouping the results according to values returned + * + * @category grouping + * @since 2.0.0 + */ +export const groupBy: { + /** + * Splits an `Iterable` into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning + * function on each element, and grouping the results according to values returned + * + * @category grouping + * @since 2.0.0 + */ + (f: (a: A) => K): (self: Iterable) => Record, NonEmptyArray> + /** + * Splits an `Iterable` into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning + * function on each element, and grouping the results according to values returned + * + * @category grouping + * @since 2.0.0 + */ + (self: Iterable, f: (a: A) => K): Record, NonEmptyArray> +} = dual(2, ( + self: Iterable, + f: (a: A) => K +): Record, NonEmptyArray> => { + const out: Record> = {} + for (const a of self) { + const k = f(a) + if (Object.prototype.hasOwnProperty.call(out, k)) { + out[k].push(a) + } else { + out[k] = [a] + } + } + return out +}) + +const constEmpty: Iterable = { + [Symbol.iterator]() { + return constEmptyIterator + } +} +const constEmptyIterator: Iterator = { + next() { + return { done: true, value: undefined } + } +} + +/** + * @category constructors + * @since 2.0.0 + */ +export const empty = (): Iterable => constEmpty + +/** + * Constructs a new `Iterable` from the specified value. + * + * @category constructors + * @since 2.0.0 + */ +export const of = (a: A): Iterable => [a] + +/** + * @category mapping + * @since 2.0.0 + */ +export const map: { + /** + * @category mapping + * @since 2.0.0 + */ + (f: (a: NoInfer, i: number) => B): (self: Iterable) => Iterable + /** + * @category mapping + * @since 2.0.0 + */ + (self: Iterable, f: (a: NoInfer, i: number) => B): Iterable +} = dual(2, (self: Iterable, f: (a: A, i: number) => B): Iterable => ({ + [Symbol.iterator]() { + const iterator = self[Symbol.iterator]() + let i = 0 + return { + next() { + const result = iterator.next() + if (result.done) { + return { done: true, value: undefined } + } + return { done: false, value: f(result.value, i++) } + } + } + } +})) + +/** + * Applies a function to each element in an Iterable and returns a new Iterable containing the concatenated mapped elements. + * + * @category sequencing + * @since 2.0.0 + */ +export const flatMap: { + /** + * Applies a function to each element in an Iterable and returns a new Iterable containing the concatenated mapped elements. + * + * @category sequencing + * @since 2.0.0 + */ + (f: (a: NoInfer, i: number) => Iterable): (self: Iterable) => Iterable + /** + * Applies a function to each element in an Iterable and returns a new Iterable containing the concatenated mapped elements. + * + * @category sequencing + * @since 2.0.0 + */ + (self: Iterable, f: (a: NoInfer, i: number) => Iterable): Iterable +} = dual( + 2, + (self: Iterable, f: (a: A, i: number) => Iterable): Iterable => flatten(map(self, f)) +) + +/** + * Flattens an Iterable of Iterables into a single Iterable + * + * @category sequencing + * @since 2.0.0 + */ +export const flatten = (self: Iterable>): Iterable => ({ + [Symbol.iterator]() { + const outerIterator = self[Symbol.iterator]() + let innerIterator: Iterator | undefined + function next() { + if (innerIterator === undefined) { + const next = outerIterator.next() + if (next.done) { + return next + } + innerIterator = next.value[Symbol.iterator]() + } + const result = innerIterator.next() + if (result.done) { + innerIterator = undefined + return next() + } + return result + } + return { next } + } +}) + +/** + * @category filtering + * @since 2.0.0 + */ +export const filterMap: { + /** + * @category filtering + * @since 2.0.0 + */ + (f: (a: A, i: number) => Option): (self: Iterable) => Iterable + /** + * @category filtering + * @since 2.0.0 + */ + (self: Iterable, f: (a: A, i: number) => Option): Iterable +} = dual( + 2, + (self: Iterable, f: (a: A, i: number) => Option): Iterable => ({ + [Symbol.iterator]() { + const iterator = self[Symbol.iterator]() + let i = 0 + return { + next() { + let result = iterator.next() + while (!result.done) { + const b = f(result.value, i++) + if (O.isSome(b)) { + return { done: false, value: b.value } + } + result = iterator.next() + } + return { done: true, value: undefined } + } + } + } + }) +) + +/** + * Transforms all elements of the `Iterable` for as long as the specified function returns some value + * + * @category filtering + * @since 2.0.0 + */ +export const filterMapWhile: { + /** + * Transforms all elements of the `Iterable` for as long as the specified function returns some value + * + * @category filtering + * @since 2.0.0 + */ + (f: (a: A, i: number) => Option): (self: Iterable) => Iterable + /** + * Transforms all elements of the `Iterable` for as long as the specified function returns some value + * + * @category filtering + * @since 2.0.0 + */ + (self: Iterable, f: (a: A, i: number) => Option): Iterable +} = dual(2, (self: Iterable, f: (a: A, i: number) => Option) => ({ + [Symbol.iterator]() { + const iterator = self[Symbol.iterator]() + let i = 0 + return { + next() { + const result = iterator.next() + if (result.done) { + return { done: true, value: undefined } + } + const b = f(result.value, i++) + if (O.isSome(b)) { + return { done: false, value: b.value } + } + return { done: true, value: undefined } + } + } + } +})) + +/** + * Retrieves the `Some` values from an `Iterable` of `Option`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Iterable, Option } from "effect" + * + * assert.deepStrictEqual( + * Array.from(Iterable.getSomes([Option.some(1), Option.none(), Option.some(2)])), + * [1, 2] + * ) + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const getSomes: (self: Iterable>) => Iterable = filterMap(identity) + +/** + * Retrieves the `Left` values from an `Iterable` of `Either`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Iterable, Either } from "effect" + * + * assert.deepStrictEqual( + * Array.from(Iterable.getLefts([Either.right(1), Either.left("err"), Either.right(2)])), + * ["err"] + * ) + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const getLefts = (self: Iterable>): Iterable => filterMap(self, E.getLeft) + +/** + * Retrieves the `Right` values from an `Iterable` of `Either`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Iterable, Either } from "effect" + * + * assert.deepStrictEqual( + * Array.from(Iterable.getRights([Either.right(1), Either.left("err"), Either.right(2)])), + * [1, 2] + * ) + * ``` + * + * @category filtering + * @since 2.0.0 + */ +export const getRights = (self: Iterable>): Iterable => filterMap(self, E.getRight) + +/** + * @category filtering + * @since 2.0.0 + */ +export const filter: { + /** + * @category filtering + * @since 2.0.0 + */ + (refinement: (a: NoInfer, i: number) => a is B): (self: Iterable) => Iterable + /** + * @category filtering + * @since 2.0.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => Iterable + /** + * @category filtering + * @since 2.0.0 + */ + (self: Iterable, refinement: (a: A, i: number) => a is B): Iterable + /** + * @category filtering + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): Iterable +} = dual( + 2, + (self: Iterable, predicate: (a: A, i: number) => boolean): Iterable => ({ + [Symbol.iterator]() { + const iterator = self[Symbol.iterator]() + let i = 0 + return { + next() { + let result = iterator.next() + while (!result.done) { + if (predicate(result.value, i++)) { + return { done: false, value: result.value } + } + result = iterator.next() + } + return { done: true, value: undefined } + } + } + } + }) +) + +/** + * @category sequencing + * @since 2.0.0 + */ +export const flatMapNullable: { + /** + * @category sequencing + * @since 2.0.0 + */ + (f: (a: A) => B | null | undefined): (self: Iterable) => Iterable> + /** + * @category sequencing + * @since 2.0.0 + */ + (self: Iterable, f: (a: A) => B | null | undefined): Iterable> +} = dual( + 2, + (self: Iterable, f: (a: A) => B | null | undefined): Iterable> => + filterMap(self, (a) => { + const b = f(a) + return b == null ? O.none() : O.some(b) + }) +) + +/** + * Check if a predicate holds true for some `Iterable` element. + * + * @category elements + * @since 2.0.0 + */ +export const some: { + /** + * Check if a predicate holds true for some `Iterable` element. + * + * @category elements + * @since 2.0.0 + */ + (predicate: (a: A, i: number) => boolean): (self: Iterable) => boolean + /** + * Check if a predicate holds true for some `Iterable` element. + * + * @category elements + * @since 2.0.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): boolean +} = dual( + 2, + (self: Iterable, predicate: (a: A, i: number) => boolean): boolean => { + let i = 0 + for (const a of self) { + if (predicate(a, i++)) { + return true + } + } + return false + } +) + +/** + * @category constructors + * @since 2.0.0 + */ +export const unfold = (b: B, f: (b: B) => Option): Iterable => ({ + [Symbol.iterator]() { + let next = b + return { + next() { + const o = f(next) + if (O.isNone(o)) { + return { done: true, value: undefined } + } + const [a, b] = o.value + next = b + return { done: false, value: a } + } + } + } +}) + +/** + * Iterate over the `Iterable` applying `f`. + * + * @since 2.0.0 + */ +export const forEach: { + /** + * Iterate over the `Iterable` applying `f`. + * + * @since 2.0.0 + */ + (f: (a: A, i: number) => void): (self: Iterable) => void + /** + * Iterate over the `Iterable` applying `f`. + * + * @since 2.0.0 + */ + (self: Iterable, f: (a: A, i: number) => void): void +} = dual(2, (self: Iterable, f: (a: A, i: number) => void): void => { + let i = 0 + for (const a of self) { + f(a, i++) + } +}) + +/** + * @category folding + * @since 2.0.0 + */ +export const reduce: { + /** + * @category folding + * @since 2.0.0 + */ + (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B + /** + * @category folding + * @since 2.0.0 + */ + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B +} = dual(3, (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B => { + if (Array.isArray(self)) { + return self.reduce(f, b) + } + let i = 0 + let result = b + for (const n of self) { + result = f(result, n, i++) + } + return result +}) + +/** + * Deduplicates adjacent elements that are identical using the provided `isEquivalent` function. + * + * @since 2.0.0 + */ +export const dedupeAdjacentWith: { + /** + * Deduplicates adjacent elements that are identical using the provided `isEquivalent` function. + * + * @since 2.0.0 + */ + (isEquivalent: (self: A, that: A) => boolean): (self: Iterable) => Iterable + /** + * Deduplicates adjacent elements that are identical using the provided `isEquivalent` function. + * + * @since 2.0.0 + */ + (self: Iterable, isEquivalent: (self: A, that: A) => boolean): Iterable +} = dual(2, (self: Iterable, isEquivalent: (self: A, that: A) => boolean): Iterable => ({ + [Symbol.iterator]() { + const iterator = self[Symbol.iterator]() + let first = true + let last: A + function next(): IteratorResult { + const result = iterator.next() + if (result.done) { + return { done: true, value: undefined } + } + if (first) { + first = false + last = result.value + return result + } + const current = result.value + if (isEquivalent(last, current)) { + return next() + } + last = current + return result + } + return { next } + } +})) + +/** + * Deduplicates adjacent elements that are identical. + * + * @since 2.0.0 + */ +export const dedupeAdjacent: (self: Iterable) => Iterable = dedupeAdjacentWith(Equal.equivalence()) + +/** + * Zips this Iterable crosswise with the specified Iterable using the specified combiner. + * + * @since 2.0.0 + * @category elements + */ +export const cartesianWith: { + /** + * Zips this Iterable crosswise with the specified Iterable using the specified combiner. + * + * @since 2.0.0 + * @category elements + */ + (that: Iterable, f: (a: A, b: B) => C): (self: Iterable) => Iterable + /** + * Zips this Iterable crosswise with the specified Iterable using the specified combiner. + * + * @since 2.0.0 + * @category elements + */ + (self: Iterable, that: Iterable, f: (a: A, b: B) => C): Iterable +} = dual( + 3, + (self: Iterable, that: Iterable, f: (a: A, b: B) => C): Iterable => + flatMap(self, (a) => map(that, (b) => f(a, b))) +) + +/** + * Zips this Iterable crosswise with the specified Iterable. + * + * @since 2.0.0 + * @category elements + */ +export const cartesian: { + /** + * Zips this Iterable crosswise with the specified Iterable. + * + * @since 2.0.0 + * @category elements + */ + (that: Iterable): (self: Iterable) => Iterable<[A, B]> + /** + * Zips this Iterable crosswise with the specified Iterable. + * + * @since 2.0.0 + * @category elements + */ + (self: Iterable, that: Iterable): Iterable<[A, B]> +} = dual( + 2, + (self: Iterable, that: Iterable): Iterable<[A, B]> => cartesianWith(self, that, (a, b) => [a, b]) +) + +/** + * Counts all the element of the given iterable that pass the given predicate + * + * **Example** + * + * ```ts + * import { Iterable } from "effect" + * + * const result = Iterable.countBy([1, 2, 3, 4, 5], n => n % 2 === 0) + * console.log(result) // 2 + * ``` + * + * @category folding + * @since 3.16.0 + */ +export const countBy: { + /** + * Counts all the element of the given iterable that pass the given predicate + * + * **Example** + * + * ```ts + * import { Iterable } from "effect" + * + * const result = Iterable.countBy([1, 2, 3, 4, 5], n => n % 2 === 0) + * console.log(result) // 2 + * ``` + * + * @category folding + * @since 3.16.0 + */ + (predicate: (a: NoInfer, i: number) => boolean): (self: Iterable) => number + /** + * Counts all the element of the given iterable that pass the given predicate + * + * **Example** + * + * ```ts + * import { Iterable } from "effect" + * + * const result = Iterable.countBy([1, 2, 3, 4, 5], n => n % 2 === 0) + * console.log(result) // 2 + * ``` + * + * @category folding + * @since 3.16.0 + */ + (self: Iterable, predicate: (a: A, i: number) => boolean): number +} = dual( + 2, + ( + self: Iterable, + f: (a: A, i: number) => boolean + ): number => { + let count = 0 + let i = 0 + for (const a of self) { + if (f(a, i)) { + count++ + } + i++ + } + return count + } +) diff --git a/backend/node_modules/effect/src/JSONSchema.ts b/backend/node_modules/effect/src/JSONSchema.ts new file mode 100644 index 0000000000000000000000000000000000000000..4b5220eb434a98e7210a37256a2b3ce72f4651f3 --- /dev/null +++ b/backend/node_modules/effect/src/JSONSchema.ts @@ -0,0 +1,1044 @@ +/** + * @since 3.10.0 + */ + +import * as Arr from "./Array.js" +import * as errors_ from "./internal/schema/errors.js" +import * as schemaId_ from "./internal/schema/schemaId.js" +import * as Option from "./Option.js" +import * as ParseResult from "./ParseResult.js" +import * as Predicate from "./Predicate.js" +import * as Record from "./Record.js" +import type * as Schema from "./Schema.js" +import * as AST from "./SchemaAST.js" + +type JsonValue = string | number | boolean | null | Array | { [key: string]: JsonValue } + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchemaAnnotations { + title?: string + description?: string + default?: JsonValue + examples?: Array +} + +/** + * @category model + * @since 3.11.5 + */ +export interface JsonSchema7Never extends JsonSchemaAnnotations { + $id: "/schemas/never" + not: {} +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7Any extends JsonSchemaAnnotations { + $id: "/schemas/any" +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7Unknown extends JsonSchemaAnnotations { + $id: "/schemas/unknown" +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7Void extends JsonSchemaAnnotations { + $id: "/schemas/void" +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7object extends JsonSchemaAnnotations { + $id: "/schemas/object" + anyOf: [ + { type: "object" }, + { type: "array" } + ] +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7empty extends JsonSchemaAnnotations { + $id: "/schemas/%7B%7D" + anyOf: [ + { type: "object" }, + { type: "array" } + ] +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7Ref extends JsonSchemaAnnotations { + $ref: string +} + +/** + * @category model + * @since 3.11.7 + */ +export interface JsonSchema7Null extends JsonSchemaAnnotations { + type: "null" +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7String extends JsonSchemaAnnotations { + type: "string" + minLength?: number + maxLength?: number + pattern?: string + format?: string + contentMediaType?: string + allOf?: Array<{ + minLength?: number + maxLength?: number + pattern?: string + }> +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7Numeric extends JsonSchemaAnnotations { + minimum?: number + exclusiveMinimum?: number + maximum?: number + exclusiveMaximum?: number + multipleOf?: number + allOf?: Array<{ + minimum?: number + exclusiveMinimum?: number + maximum?: number + exclusiveMaximum?: number + multipleOf?: number + }> +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7Number extends JsonSchema7Numeric { + type: "number" +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7Integer extends JsonSchema7Numeric { + type: "integer" +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7Boolean extends JsonSchemaAnnotations { + type: "boolean" +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7Array extends JsonSchemaAnnotations { + type: "array" + items?: JsonSchema7 | Array | false + prefixItems?: Array + minItems?: number + maxItems?: number + additionalItems?: JsonSchema7 | boolean +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7Enum extends JsonSchemaAnnotations { + type?: "string" | "number" | "boolean" + enum: Array +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7Enums extends JsonSchemaAnnotations { + $comment: "/schemas/enums" + anyOf: Array<{ + type: "string" | "number" + title: string + enum: [string | number] + }> +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7AnyOf extends JsonSchemaAnnotations { + anyOf: Array +} + +/** + * @category model + * @since 3.10.0 + */ +export interface JsonSchema7Object extends JsonSchemaAnnotations { + type: "object" + required: Array + properties: Record + additionalProperties?: boolean | JsonSchema7 + patternProperties?: Record + propertyNames?: JsonSchema7 +} + +/** + * @category model + * @since 3.10.0 + */ +export type JsonSchema7 = + | JsonSchema7Never + | JsonSchema7Any + | JsonSchema7Unknown + | JsonSchema7Void + | JsonSchema7object + | JsonSchema7empty + | JsonSchema7Ref + | JsonSchema7Null + | JsonSchema7String + | JsonSchema7Number + | JsonSchema7Integer + | JsonSchema7Boolean + | JsonSchema7Array + | JsonSchema7Enum + | JsonSchema7Enums + | JsonSchema7AnyOf + | JsonSchema7Object + +/** + * @category model + * @since 3.10.0 + */ +export type JsonSchema7Root = JsonSchema7 & { + $schema?: string + $defs?: Record +} + +/** + * Generates a JSON Schema from a schema. + * + * **Options** + * + * - `target`: The target JSON Schema version. Possible values are: + * - `"jsonSchema7"`: JSON Schema draft-07 (default behavior). + * - `"jsonSchema2019-09"`: JSON Schema draft-2019-09. + * - `"jsonSchema2020-12"`: JSON Schema draft-2020-12. + * - `"openApi3.1"`: OpenAPI 3.1. + * + * @category encoding + * @since 3.10.0 + */ +export const make = (schema: Schema.Schema, options?: { + readonly target?: Target | undefined +}): JsonSchema7Root => { + const definitions: Record = {} + const target = options?.target ?? "jsonSchema7" + const ast = AST.isTransformation(schema.ast) && isParseJsonTransformation(schema.ast.from) + // Special case top level `parseJson` transformations + ? schema.ast.to + : schema.ast + const jsonSchema = fromAST(ast, { + definitions, + target + }) + const out: JsonSchema7Root = { + $schema: getMetaSchemaUri(target), + $defs: {}, + ...jsonSchema + } + if (Record.isEmptyRecord(definitions)) { + delete out.$defs + } else { + out.$defs = definitions + } + return out +} + +type Target = "jsonSchema7" | "jsonSchema2019-09" | "openApi3.1" | "jsonSchema2020-12" + +type TopLevelReferenceStrategy = "skip" | "keep" + +type AdditionalPropertiesStrategy = "allow" | "strict" + +/** @internal */ +export function getMetaSchemaUri(target: Target) { + switch (target) { + case "jsonSchema7": + return "http://json-schema.org/draft-07/schema#" + case "jsonSchema2019-09": + return "https://json-schema.org/draft/2019-09/schema" + case "jsonSchema2020-12": + case "openApi3.1": + return "https://json-schema.org/draft/2020-12/schema" + } +} + +/** + * Returns a JSON Schema with additional options and definitions. + * + * **Warning** + * + * This function is experimental and subject to change. + * + * **Options** + * + * - `definitions`: A record of definitions that are included in the schema. + * - `definitionPath`: The path to the definitions within the schema (defaults + * to "#/$defs/"). + * - `target`: Which spec to target. Possible values are: + * - `'jsonSchema7'`: JSON Schema draft-07 (default behavior). + * - `'jsonSchema2019-09'`: JSON Schema draft-2019-09. + * - `'openApi3.1'`: OpenAPI 3.1. + * - `topLevelReferenceStrategy`: Controls the handling of the top-level + * reference. Possible values are: + * - `"keep"`: Keep the top-level reference (default behavior). + * - `"skip"`: Skip the top-level reference. + * - `additionalPropertiesStrategy`: Controls the handling of additional properties. Possible values are: + * - `"strict"`: Disallow additional properties (default behavior). + * - `"allow"`: Allow additional properties. + * + * @category encoding + * @since 3.11.5 + * @experimental + */ +export const fromAST = (ast: AST.AST, options: { + readonly definitions: Record + readonly definitionPath?: string | undefined + readonly target?: Target | undefined + readonly topLevelReferenceStrategy?: TopLevelReferenceStrategy | undefined + readonly additionalPropertiesStrategy?: AdditionalPropertiesStrategy | undefined +}): JsonSchema7 => { + const definitionPath = options.definitionPath ?? "#/$defs/" + const getRef = (id: string) => definitionPath + id + const target = options.target ?? "jsonSchema7" + const topLevelReferenceStrategy = options.topLevelReferenceStrategy ?? "keep" + const additionalPropertiesStrategy = options.additionalPropertiesStrategy ?? "strict" + return go( + ast, + options.definitions, + "handle-identifier", + [], + { + getRef, + target, + topLevelReferenceStrategy, + additionalPropertiesStrategy + }, + "handle-annotation", + "handle-errors" + ) +} + +const constNever: JsonSchema7Never = { + $id: "/schemas/never", + not: {} +} + +const constAny: JsonSchema7Any = { + $id: "/schemas/any" +} + +const constUnknown: JsonSchema7Unknown = { + $id: "/schemas/unknown" +} + +const constVoid: JsonSchema7Void = { + $id: "/schemas/void" +} + +const constObject: JsonSchema7object = { + $id: "/schemas/object", + "anyOf": [ + { "type": "object" }, + { "type": "array" } + ] +} + +const constEmptyStruct: JsonSchema7empty = { + $id: "/schemas/%7B%7D", + "anyOf": [ + { "type": "object" }, + { "type": "array" } + ] +} + +function getRawDescription(annotated: AST.Annotated | undefined): string | undefined { + if (annotated !== undefined) return Option.getOrUndefined(AST.getDescriptionAnnotation(annotated)) +} + +function getRawTitle(annotated: AST.Annotated | undefined): string | undefined { + if (annotated !== undefined) return Option.getOrUndefined(AST.getTitleAnnotation(annotated)) +} + +function getRawDefault(annotated: AST.Annotated | undefined): Option.Option { + if (annotated !== undefined) return AST.getDefaultAnnotation(annotated) + return Option.none() +} + +function encodeDefault(ast: AST.AST, def: unknown): Option.Option { + const getOption = ParseResult.getOption(ast, false) + return getOption(def) +} + +function getRawExamples(annotated: AST.Annotated | undefined): ReadonlyArray | undefined { + if (annotated !== undefined) return Option.getOrUndefined(AST.getExamplesAnnotation(annotated)) +} + +function encodeExamples(ast: AST.AST, examples: ReadonlyArray): Array | undefined { + const getOption = ParseResult.getOption(ast, false) + const out = Arr.filterMap(examples, (e) => getOption(e).pipe(Option.filter(isJsonValue))) + return out.length > 0 ? out : undefined +} + +function filterBuiltIn(ast: AST.AST, annotation: string | undefined, key: symbol): string | undefined { + if (annotation !== undefined) { + switch (ast._tag) { + case "StringKeyword": + return annotation !== AST.stringKeyword.annotations[key] ? annotation : undefined + case "NumberKeyword": + return annotation !== AST.numberKeyword.annotations[key] ? annotation : undefined + case "BooleanKeyword": + return annotation !== AST.booleanKeyword.annotations[key] ? annotation : undefined + } + } + return annotation +} + +function isJsonValue(value: unknown, visited: Set = new Set()): value is JsonValue { + if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") { + return true + } + if (Array.isArray(value) || typeof value === "object") { + // Check for cyclic references + if (visited.has(value)) { + return false + } + visited.add(value) + try { + if (Array.isArray(value)) { + return value.every((item) => isJsonValue(item, visited)) + } + // Exclude non-plain objects (Date, RegExp, etc.) by checking constructor + const proto = Object.getPrototypeOf(value) + if (proto !== null && proto !== Object.prototype) { + return false + } + // JSON only allows string keys, so exclude objects with Symbol keys + if (Object.getOwnPropertySymbols(value).length > 0) { + return false + } + // Check all values are JSON values + return Object.values(value).every((v) => isJsonValue(v, visited)) + } finally { + visited.delete(value) + } + } + return false +} + +function pruneJsonSchemaAnnotations( + ast: AST.AST, + description: string | undefined, + title: string | undefined, + def: Option.Option, + examples: ReadonlyArray | undefined +): JsonSchemaAnnotations | undefined { + const out: JsonSchemaAnnotations = {} + if (description !== undefined) out.description = description + if (title !== undefined) out.title = title + if (Option.isSome(def)) { + const o = encodeDefault(ast, def.value) + if (Option.isSome(o) && isJsonValue(o.value)) { + out.default = o.value + } + } + if (examples !== undefined) { + const encodedExamples = encodeExamples(ast, examples) + if (encodedExamples !== undefined) { + out.examples = encodedExamples + } + } + if (Object.keys(out).length === 0) { + return undefined + } + return out +} + +function getContextJsonSchemaAnnotations(ast: AST.AST, annotated: AST.Annotated): JsonSchemaAnnotations | undefined { + return pruneJsonSchemaAnnotations( + ast, + getRawDescription(annotated), + getRawTitle(annotated), + getRawDefault(annotated), + getRawExamples(annotated) + ) +} + +function getJsonSchemaAnnotations(ast: AST.AST): JsonSchemaAnnotations | undefined { + return pruneJsonSchemaAnnotations( + ast, + filterBuiltIn(ast, getRawDescription(ast), AST.DescriptionAnnotationId), + filterBuiltIn(ast, getRawTitle(ast), AST.TitleAnnotationId), + getRawDefault(ast), + getRawExamples(ast) + ) +} + +function mergeJsonSchemaAnnotations( + jsonSchema: JsonSchema7, + jsonSchemaAnnotations: JsonSchemaAnnotations | undefined +): JsonSchema7 { + if (jsonSchemaAnnotations) { + if ("$ref" in jsonSchema) { + return { allOf: [jsonSchema], ...jsonSchemaAnnotations } as any + } + return { ...jsonSchema, ...jsonSchemaAnnotations } + } + return jsonSchema +} + +const pruneUndefined = (ast: AST.AST): AST.AST | undefined => { + if (Option.isNone(AST.getJSONSchemaAnnotation(ast))) { + return AST.pruneUndefined(ast, pruneUndefined, (ast) => pruneUndefined(ast.from)) + } +} + +const isParseJsonTransformation = (ast: AST.AST): boolean => + ast.annotations[AST.SchemaIdAnnotationId] === AST.ParseJsonSchemaId + +const isOverrideAnnotation = (ast: AST.AST, jsonSchema: JsonSchema7): boolean => { + if (AST.isRefinement(ast)) { + const schemaId = ast.annotations[AST.SchemaIdAnnotationId] + if (schemaId === schemaId_.IntSchemaId) { + return "type" in jsonSchema && jsonSchema.type !== "integer" + } + } + return ("type" in jsonSchema) || ("oneOf" in jsonSchema) || ("anyOf" in jsonSchema) || ("$ref" in jsonSchema) +} + +const mergeRefinements = (from: any, jsonSchema: any, ast: AST.AST): any => { + const out: any = { ...from, ...getJsonSchemaAnnotations(ast), ...jsonSchema } + out.allOf ??= [] + + const handle = (name: string, filter: (i: any) => boolean) => { + if (name in jsonSchema && name in from) { + out.allOf.unshift({ [name]: from[name] }) + out.allOf = out.allOf.filter(filter) + } + } + + handle("minLength", (i) => i.minLength > jsonSchema.minLength) + handle("maxLength", (i) => i.maxLength < jsonSchema.maxLength) + handle("pattern", (i) => i.pattern !== jsonSchema.pattern) + handle("minItems", (i) => i.minItems > jsonSchema.minItems) + handle("maxItems", (i) => i.maxItems < jsonSchema.maxItems) + handle("minimum", (i) => i.minimum > jsonSchema.minimum) + handle("maximum", (i) => i.maximum < jsonSchema.maximum) + handle("exclusiveMinimum", (i) => i.exclusiveMinimum > jsonSchema.exclusiveMinimum) + handle("exclusiveMaximum", (i) => i.exclusiveMaximum < jsonSchema.exclusiveMaximum) + handle("multipleOf", (i) => i.multipleOf !== jsonSchema.multipleOf) + + if (out.allOf.length === 0) { + delete out.allOf + } + return out +} + +type GoOptions = { + readonly getRef: (id: string) => string + readonly target: Target + readonly topLevelReferenceStrategy: TopLevelReferenceStrategy + readonly additionalPropertiesStrategy: AdditionalPropertiesStrategy +} + +function isContentSchemaSupported(options: GoOptions): boolean { + switch (options.target) { + case "jsonSchema7": + return false + case "jsonSchema2019-09": + case "jsonSchema2020-12": + case "openApi3.1": + return true + } +} + +function getAdditionalProperties(options: GoOptions): boolean { + switch (options.additionalPropertiesStrategy) { + case "allow": + return true + case "strict": + return false + } +} + +function addASTAnnotations(jsonSchema: JsonSchema7, ast: AST.AST): JsonSchema7 { + return addAnnotations(jsonSchema, getJsonSchemaAnnotations(ast)) +} + +function addAnnotations(jsonSchema: JsonSchema7, annotations: JsonSchemaAnnotations | undefined): JsonSchema7 { + if (annotations === undefined || Object.keys(annotations).length === 0) { + return jsonSchema + } + if ("$ref" in jsonSchema) { + return { allOf: [jsonSchema], ...annotations } as any + } + return { ...jsonSchema, ...annotations } +} + +function getIdentifierAnnotation(ast: AST.AST): string | undefined { + const identifier = Option.getOrUndefined(AST.getJSONIdentifier(ast)) + if (identifier === undefined) { + if (AST.isSuspend(ast)) { + return getIdentifierAnnotation(ast.f()) + } + if (AST.isTransformation(ast) && AST.isTypeLiteral(ast.from) && AST.isDeclaration(ast.to)) { + const to = ast.to + const surrogate = AST.getSurrogateAnnotation(to) + if (Option.isSome(surrogate)) { + return getIdentifierAnnotation(to) + } + } + } + return identifier +} + +function go( + ast: AST.AST, + $defs: Record, + identifier: "handle-identifier" | "ignore-identifier", + path: ReadonlyArray, + options: GoOptions, + annotation: "handle-annotation" | "ignore-annotation", + errors: "handle-errors" | "ignore-errors" +): JsonSchema7 { + if ( + identifier === "handle-identifier" && + (options.topLevelReferenceStrategy !== "skip" || AST.isSuspend(ast)) + ) { + const id = getIdentifierAnnotation(ast) + if (id !== undefined) { + const escapedId = id.replace(/~/ig, "~0").replace(/\//ig, "~1") + const out = { $ref: options.getRef(escapedId) } + if (!Record.has($defs, id)) { + $defs[id] = out + $defs[id] = go(ast, $defs, "ignore-identifier", path, options, "handle-annotation", errors) + } + return out + } + } + if (annotation === "handle-annotation") { + const hook = AST.getJSONSchemaAnnotation(ast) + if (Option.isSome(hook)) { + const handler = hook.value as JsonSchema7 + if (isOverrideAnnotation(ast, handler)) { + switch (ast._tag) { + case "Declaration": + return addASTAnnotations(handler, ast) + default: + return handler + } + } else { + switch (ast._tag) { + case "Refinement": { + const t = AST.getTransformationFrom(ast) + if (t === undefined) { + return mergeRefinements( + go(ast.from, $defs, identifier, path, options, "handle-annotation", errors), + handler, + ast + ) + } else { + return go(t, $defs, identifier, path, options, "handle-annotation", errors) + } + } + default: + return { + ...go(ast, $defs, identifier, path, options, "ignore-annotation", errors), + ...handler + } as any + } + } + } + } + const surrogate = AST.getSurrogateAnnotation(ast) + if (Option.isSome(surrogate)) { + return go(surrogate.value, $defs, identifier, path, options, "handle-annotation", errors) + } + switch (ast._tag) { + // Unsupported + case "Declaration": + case "UndefinedKeyword": + case "BigIntKeyword": + case "UniqueSymbol": + case "SymbolKeyword": { + if (errors === "ignore-errors") return addASTAnnotations(constAny, ast) + throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)) + } + case "Suspend": { + if (identifier === "handle-identifier") { + if (errors === "ignore-errors") return addASTAnnotations(constAny, ast) + throw new Error(errors_.getJSONSchemaMissingIdentifierAnnotationErrorMessage(path, ast)) + } + return go(ast.f(), $defs, "ignore-identifier", path, options, "handle-annotation", errors) + } + // Primitives + case "NeverKeyword": + return addASTAnnotations(constNever, ast) + case "VoidKeyword": + return addASTAnnotations(constVoid, ast) + case "UnknownKeyword": + return addASTAnnotations(constUnknown, ast) + case "AnyKeyword": + return addASTAnnotations(constAny, ast) + case "ObjectKeyword": + return addASTAnnotations(constObject, ast) + case "StringKeyword": + return addASTAnnotations({ type: "string" }, ast) + case "NumberKeyword": + return addASTAnnotations({ type: "number" }, ast) + case "BooleanKeyword": + return addASTAnnotations({ type: "boolean" }, ast) + case "Literal": { + const literal = ast.literal + if (literal === null) { + return addASTAnnotations({ type: "null" }, ast) + } else if (Predicate.isString(literal)) { + return addASTAnnotations({ type: "string", enum: [literal] }, ast) + } else if (Predicate.isNumber(literal)) { + return addASTAnnotations({ type: "number", enum: [literal] }, ast) + } else if (Predicate.isBoolean(literal)) { + return addASTAnnotations({ type: "boolean", enum: [literal] }, ast) + } + if (errors === "ignore-errors") return addASTAnnotations(constAny, ast) + throw new Error(errors_.getJSONSchemaMissingAnnotationErrorMessage(path, ast)) + } + case "Enums": { + const anyOf = ast.enums.map((e) => { + const type: "string" | "number" = Predicate.isNumber(e[1]) ? "number" : "string" + return { type, title: e[0], enum: [e[1]] } + }) + return anyOf.length >= 1 ? + addASTAnnotations({ + $comment: "/schemas/enums", + anyOf + }, ast) : + addASTAnnotations(constNever, ast) + } + case "TupleType": { + const elements = ast.elements.map((e, i) => + mergeJsonSchemaAnnotations( + go(e.type, $defs, "handle-identifier", path.concat(i), options, "handle-annotation", errors), + getContextJsonSchemaAnnotations(e.type, e) + ) + ) + const rest = ast.rest.map((type) => + mergeJsonSchemaAnnotations( + go(type.type, $defs, "handle-identifier", path, options, "handle-annotation", errors), + getContextJsonSchemaAnnotations(type.type, type) + ) + ) + const output: JsonSchema7Array = { type: "array" } + // --------------------------------------------- + // handle elements + // --------------------------------------------- + const len = ast.elements.length + if (len > 0) { + output.minItems = len - ast.elements.filter((element) => element.isOptional).length + if (options.target === "jsonSchema7") { + output.items = elements + } else { + output.prefixItems = elements + } + } + // --------------------------------------------- + // handle rest element + // --------------------------------------------- + const restLength = rest.length + if (restLength > 0) { + const head = rest[0] + const isHomogeneous = restLength === 1 && ast.elements.every((e) => e.type === ast.rest[0].type) + if (isHomogeneous) { + if (options.target === "jsonSchema7") { + output.items = head + } else { + output.items = head + delete output.prefixItems + } + } else { + if (options.target === "jsonSchema7") { + output.additionalItems = head + } else { + output.items = head + } + } + + // --------------------------------------------- + // handle post rest elements + // --------------------------------------------- + if (restLength > 1) { + if (errors === "ignore-errors") return addASTAnnotations(constAny, ast) + throw new Error(errors_.getJSONSchemaUnsupportedPostRestElementsErrorMessage(path)) + } + } else { + if (len > 0) { + if (options.target === "jsonSchema7") { + output.additionalItems = false + } else { + output.items = false + } + } else { + output.maxItems = 0 + } + } + + return addASTAnnotations(output, ast) + } + case "TypeLiteral": { + if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) { + return addASTAnnotations(constEmptyStruct, ast) + } + const output: JsonSchema7Object = { + type: "object", + required: [], + properties: {}, + additionalProperties: getAdditionalProperties(options) + } + let patternProperties: JsonSchema7 | undefined = undefined + let propertyNames: JsonSchema7 | undefined = undefined + for (const is of ast.indexSignatures) { + const pruned = pruneUndefined(is.type) ?? is.type + const parameter = is.parameter + switch (parameter._tag) { + case "StringKeyword": { + output.additionalProperties = go( + pruned, + $defs, + "handle-identifier", + path, + options, + "handle-annotation", + errors + ) + break + } + case "TemplateLiteral": { + patternProperties = go(pruned, $defs, "handle-identifier", path, options, "handle-annotation", errors) + propertyNames = { + type: "string", + pattern: AST.getTemplateLiteralRegExp(parameter).source + } + break + } + case "Refinement": { + patternProperties = go(pruned, $defs, "handle-identifier", path, options, "handle-annotation", errors) + propertyNames = go(parameter, $defs, "handle-identifier", path, options, "handle-annotation", errors) + break + } + case "SymbolKeyword": { + const indexSignaturePath = path.concat("[symbol]") + output.additionalProperties = go( + pruned, + $defs, + "handle-identifier", + indexSignaturePath, + options, + "handle-annotation", + errors + ) + propertyNames = go( + parameter, + $defs, + "handle-identifier", + indexSignaturePath, + options, + "handle-annotation", + errors + ) + break + } + } + } + // --------------------------------------------- + // handle property signatures + // --------------------------------------------- + for (let i = 0; i < ast.propertySignatures.length; i++) { + const ps = ast.propertySignatures[i] + const name = ps.name + if (Predicate.isString(name)) { + const pruned = pruneUndefined(ps.type) + const type = pruned ?? ps.type + output.properties[name] = mergeJsonSchemaAnnotations( + go(type, $defs, "handle-identifier", path.concat(ps.name), options, "handle-annotation", errors), + getContextJsonSchemaAnnotations(type, ps) + ) + // --------------------------------------------- + // handle optional property signatures + // --------------------------------------------- + if (!ps.isOptional && pruned === undefined) { + output.required.push(name) + } + } else { + if (errors === "ignore-errors") return addASTAnnotations(constAny, ast) + throw new Error(errors_.getJSONSchemaUnsupportedKeyErrorMessage(name, path)) + } + } + // --------------------------------------------- + // handle index signatures + // --------------------------------------------- + if (patternProperties !== undefined) { + delete output.additionalProperties + output.patternProperties = { "": patternProperties } + } + if (propertyNames !== undefined) { + output.propertyNames = propertyNames + } + + return addASTAnnotations(output, ast) + } + case "Union": { + const members: Array = ast.types.map((t) => + go(t, $defs, "handle-identifier", path, options, "handle-annotation", errors) + ) + const anyOf = compactUnion(members) + switch (anyOf.length) { + case 0: + return constNever + case 1: + return addASTAnnotations(anyOf[0], ast) + default: + return addASTAnnotations({ anyOf }, ast) + } + } + case "Refinement": + return go(ast.from, $defs, identifier, path, options, "handle-annotation", errors) + case "TemplateLiteral": { + const regex = AST.getTemplateLiteralRegExp(ast) + return addASTAnnotations({ + type: "string", + title: String(ast), + description: "a template literal", + pattern: regex.source + }, ast) + } + case "Transformation": { + if (isParseJsonTransformation(ast.from)) { + const out: JsonSchema7String & { contentSchema?: JsonSchema7 } = { + "type": "string", + "contentMediaType": "application/json" + } + if (isContentSchemaSupported(options)) { + out["contentSchema"] = go(ast.to, $defs, identifier, path, options, "handle-annotation", errors) + } + return out + } + const from = go(ast.from, $defs, identifier, path, options, "handle-annotation", errors) + if ( + ast.transformation._tag === "TypeLiteralTransformation" && + isJsonSchema7Object(from) + ) { + const to = go(ast.to, {}, "ignore-identifier", path, options, "handle-annotation", "ignore-errors") + if (isJsonSchema7Object(to)) { + for (const t of ast.transformation.propertySignatureTransformations) { + const toKey = t.to + const fromKey = t.from + if (Predicate.isString(toKey) && Predicate.isString(fromKey)) { + const toProperty = to.properties[toKey] + if (Predicate.isRecord(toProperty)) { + const fromProperty = from.properties[fromKey] + if (Predicate.isRecord(fromProperty)) { + const annotations: JsonSchemaAnnotations = {} + if (Predicate.isString(toProperty.title)) annotations.title = toProperty.title + if (Predicate.isString(toProperty.description)) annotations.description = toProperty.description + if (Array.isArray(toProperty.examples)) annotations.examples = toProperty.examples + if (Object.hasOwn(toProperty, "default") && toProperty.default !== undefined) { + annotations.default = toProperty.default + } + from.properties[fromKey] = addAnnotations(fromProperty, annotations) + } + } + } + } + } + } + return addASTAnnotations(from, ast) + } + } +} + +function isJsonSchema7Object(jsonSchema: unknown): jsonSchema is JsonSchema7Object { + return Predicate.isRecord(jsonSchema) && jsonSchema.type === "object" && Predicate.isRecord(jsonSchema.properties) +} + +function isNeverWithoutCustomAnnotations(jsonSchema: JsonSchema7): boolean { + return jsonSchema === constNever || (Predicate.hasProperty(jsonSchema, "$id") && jsonSchema.$id === constNever.$id && + Object.keys(jsonSchema).length === 3 && jsonSchema.title === AST.neverKeyword.annotations[AST.TitleAnnotationId]) +} + +function isAny(jsonSchema: JsonSchema7): jsonSchema is JsonSchema7Any { + return "$id" in jsonSchema && jsonSchema.$id === constAny.$id +} + +function isUnknown(jsonSchema: JsonSchema7): jsonSchema is JsonSchema7Unknown { + return "$id" in jsonSchema && jsonSchema.$id === constUnknown.$id +} + +function isVoid(jsonSchema: JsonSchema7): jsonSchema is JsonSchema7Void { + return "$id" in jsonSchema && jsonSchema.$id === constVoid.$id +} + +function isCompactableLiteral(jsonSchema: JsonSchema7 | undefined): jsonSchema is JsonSchema7Enum { + return Predicate.hasProperty(jsonSchema, "enum") && "type" in jsonSchema && Object.keys(jsonSchema).length === 2 +} + +function compactUnion(members: Array): Array { + const out: Array = [] + for (const m of members) { + if (isNeverWithoutCustomAnnotations(m)) continue + if (isAny(m) || isUnknown(m) || isVoid(m)) return [m] + if (isCompactableLiteral(m) && out.length > 0) { + const last = out[out.length - 1] + if (isCompactableLiteral(last) && last.type === m.type) { + out[out.length - 1] = { + type: last.type, + enum: [...last.enum, ...m.enum] + } as JsonSchema7Enum + continue + } + } + out.push(m) + } + return out +} diff --git a/backend/node_modules/effect/src/LayerMap.ts b/backend/node_modules/effect/src/LayerMap.ts new file mode 100644 index 0000000000000000000000000000000000000000..15deb394ae58b37a705c1c9d5b7b715bfa53a899 --- /dev/null +++ b/backend/node_modules/effect/src/LayerMap.ts @@ -0,0 +1,436 @@ +/** + * @since 3.14.0 + * @experimental + */ +import * as Context from "./Context.js" +import type * as Duration from "./Duration.js" +import * as Effect from "./Effect.js" +import * as FiberRefsPatch from "./FiberRefsPatch.js" +import { identity } from "./Function.js" +import * as core from "./internal/core.js" +import * as Layer from "./Layer.js" +import * as RcMap from "./RcMap.js" +import * as Runtime from "./Runtime.js" +import * as Scope from "./Scope.js" +import type { Mutable, NoExcessProperties } from "./Types.js" + +/** + * @since 3.14.0 + * @category Symbols + */ +export const TypeId: unique symbol = Symbol.for("effect/LayerMap") + +/** + * @since 3.14.0 + * @category Symbols + */ +export type TypeId = typeof TypeId + +/** + * @since 3.14.0 + * @category Models + * @experimental + */ +export interface LayerMap { + readonly [TypeId]: TypeId + + /** + * The internal RcMap that stores the resources. + */ + readonly rcMap: RcMap.RcMap + readonly runtimeEffect: Effect.Effect, E, Scope.Scope> + }, E> + + /** + * Retrieves a Layer for the resources associated with the key. + */ + get(key: K): Layer.Layer + + /** + * Retrieves a Runtime for the resources associated with the key. + */ + runtime(key: K): Effect.Effect, E, Scope.Scope> + + /** + * Invalidates the resource associated with the key. + */ + invalidate(key: K): Effect.Effect +} + +/** + * @since 3.14.0 + * @category Constructors + * @experimental + * + * A `LayerMap` allows you to create a map of Layer's that can be used to + * dynamically access resources based on a key. + * + * ```ts + * import { NodeRuntime } from "@effect/platform-node" + * import { Context, Effect, FiberRef, Layer, LayerMap } from "effect" + * + * class Greeter extends Context.Tag("Greeter") + * }>() {} + * + * // create a service that wraps a LayerMap + * class GreeterMap extends LayerMap.Service()("GreeterMap", { + * // define the lookup function for the layer map + * // + * // The returned Layer will be used to provide the Greeter service for the + * // given name. + * lookup: (name: string) => + * Layer.succeed(Greeter, { + * greet: Effect.succeed(`Hello, ${name}!`) + * }).pipe( + * Layer.merge(Layer.locallyScoped(FiberRef.currentConcurrency, 123)) + * ), + * + * // If a layer is not used for a certain amount of time, it can be removed + * idleTimeToLive: "5 seconds", + * + * // Supply the dependencies for the layers in the LayerMap + * dependencies: [] + * }) {} + * + * // usage + * const program: Effect.Effect = Effect.gen(function*() { + * // access and use the Greeter service + * const greeter = yield* Greeter + * yield* Effect.log(yield* greeter.greet) + * }).pipe( + * // use the GreeterMap service to provide a variant of the Greeter service + * Effect.provide(GreeterMap.get("John")) + * ) + * + * // run the program + * program.pipe( + * Effect.provide(GreeterMap.Default), + * NodeRuntime.runMain + * ) + * ``` + */ +export const make: < + K, + L extends Layer.Layer, + PreloadKeys extends Iterable | undefined = undefined +>( + lookup: (key: K) => L, + options?: { + readonly idleTimeToLive?: Duration.DurationInput | undefined + readonly preloadKeys?: PreloadKeys + } | undefined +) => Effect.Effect< + LayerMap< + K, + L extends Layer.Layer ? _A : never, + L extends Layer.Layer ? _E : never + >, + PreloadKeys extends undefined ? never : L extends Layer.Layer ? _E : never, + Scope.Scope | (L extends Layer.Layer ? _R : never) +> = Effect.fnUntraced(function*( + lookup: (key: K) => Layer.Layer, + options?: { + readonly idleTimeToLive?: Duration.DurationInput | undefined + readonly preloadKeys?: Iterable | undefined + } | undefined +) { + const context = yield* Effect.context() + + // If we are inside another layer build, use the current memo map, + // otherwise create a new one. + const memoMap = context.unsafeMap.has(Layer.CurrentMemoMap.key) + ? Context.get(context, Layer.CurrentMemoMap) + : yield* Layer.makeMemoMap + + const rcMap = yield* RcMap.make({ + lookup: (key: K) => + Effect.scopeWith((scope) => Effect.diffFiberRefs(Layer.buildWithMemoMap(lookup(key), memoMap, scope))).pipe( + Effect.map(([patch, context]) => ({ + layer: Layer.scopedContext( + core.withFiberRuntime, any, Scope.Scope>((fiber) => { + const scope = Context.unsafeGet(fiber.currentContext, Scope.Scope) + const oldRefs = fiber.getFiberRefs() + const newRefs = FiberRefsPatch.patch(patch, fiber.id(), oldRefs) + const revert = FiberRefsPatch.diff(newRefs, oldRefs) + fiber.setFiberRefs(newRefs) + return Effect.as( + Scope.addFinalizerExit(scope, () => { + fiber.setFiberRefs(FiberRefsPatch.patch(revert, fiber.id(), fiber.getFiberRefs())) + return Effect.void + }), + context + ) + }) + ), + runtimeEffect: Effect.withFiberRuntime, any, Scope.Scope>((fiber) => { + const fiberRefs = FiberRefsPatch.patch(patch, fiber.id(), fiber.getFiberRefs()) + return Effect.succeed(Runtime.make({ + context, + fiberRefs, + runtimeFlags: Runtime.defaultRuntime.runtimeFlags + })) + }) + } as const)) + ), + idleTimeToLive: options?.idleTimeToLive + }) + + if (options?.preloadKeys) { + for (const key of options.preloadKeys) { + yield* (RcMap.get(rcMap, key) as Effect.Effect) + } + } + + return identity, any>>({ + [TypeId]: TypeId, + rcMap, + get: (key) => Layer.unwrapScoped(Effect.map(RcMap.get(rcMap, key), ({ layer }) => layer)), + runtime: (key) => Effect.flatMap(RcMap.get(rcMap, key), ({ runtimeEffect }) => runtimeEffect), + invalidate: (key) => RcMap.invalidate(rcMap, key) + }) +}) + +/** + * @since 3.14.0 + * @category Constructors + * @experimental + */ +export const fromRecord = < + const Layers extends Record>, + const Preload extends boolean = false +>( + layers: Layers, + options?: { + readonly idleTimeToLive?: Duration.DurationInput | undefined + readonly preload?: Preload | undefined + } | undefined +): Effect.Effect< + LayerMap< + keyof Layers, + Layers[keyof Layers] extends Layer.Layer ? _A : never, + Preload extends true ? never : Layers[keyof Layers] extends Layer.Layer ? _E : never + >, + Preload extends true ? never : Layers[keyof Layers] extends Layer.Layer ? _E : never, + Scope.Scope | (Layers[keyof Layers] extends Layer.Layer ? _R : never) +> => + make((key: keyof Layers) => layers[key], { + ...options, + preloadKeys: options?.preload ? Object.keys(layers) : undefined + }) as any + +/** + * @since 3.14.0 + * @category Service + */ +export interface TagClass< + in out Self, + in out Id extends string, + in out K, + in out I, + in out E, + in out R, + in out LE, + in out Deps extends Layer.Layer +> extends Context.TagClass> { + /** + * A default layer for the `LayerMap` service. + */ + readonly Default: Layer.Layer< + Self, + (Deps extends Layer.Layer ? _E : never) | LE, + | Exclude ? _A : never)> + | (Deps extends Layer.Layer ? _R : never) + > + + /** + * A default layer for the `LayerMap` service without the dependencies provided. + */ + readonly DefaultWithoutDependencies: Layer.Layer + + /** + * Retrieves a Layer for the resources associated with the key. + */ + readonly get: (key: K) => Layer.Layer + + /** + * Retrieves a Runtime for the resources associated with the key. + */ + readonly runtime: (key: K) => Effect.Effect, E, Scope.Scope | Self> + + /** + * Invalidates the resource associated with the key. + */ + readonly invalidate: (key: K) => Effect.Effect +} + +/** + * @since 3.14.0 + * @category Service + * @experimental + * + * Create a `LayerMap` service that provides a dynamic set of resources based on + * a key. + * + * ```ts + * import { NodeRuntime } from "@effect/platform-node" + * import { Context, Effect, FiberRef, Layer, LayerMap } from "effect" + * + * class Greeter extends Context.Tag("Greeter") + * }>() {} + * + * // create a service that wraps a LayerMap + * class GreeterMap extends LayerMap.Service()("GreeterMap", { + * // define the lookup function for the layer map + * // + * // The returned Layer will be used to provide the Greeter service for the + * // given name. + * lookup: (name: string) => + * Layer.succeed(Greeter, { + * greet: Effect.succeed(`Hello, ${name}!`) + * }).pipe( + * Layer.merge(Layer.locallyScoped(FiberRef.currentConcurrency, 123)) + * ), + * + * // If a layer is not used for a certain amount of time, it can be removed + * idleTimeToLive: "5 seconds", + * + * // Supply the dependencies for the layers in the LayerMap + * dependencies: [] + * }) {} + * + * // usage + * const program: Effect.Effect = Effect.gen(function*() { + * // access and use the Greeter service + * const greeter = yield* Greeter + * yield* Effect.log(yield* greeter.greet) + * }).pipe( + * // use the GreeterMap service to provide a variant of the Greeter service + * Effect.provide(GreeterMap.get("John")) + * ) + * + * // run the program + * program.pipe( + * Effect.provide(GreeterMap.Default), + * NodeRuntime.runMain + * ) + * ``` + */ +export const Service = () => +< + const Id extends string, + Options extends + | NoExcessProperties< + { + readonly lookup: (key: any) => Layer.Layer + readonly dependencies?: ReadonlyArray> + readonly idleTimeToLive?: Duration.DurationInput | undefined + readonly preloadKeys?: + | Iterable any } ? K : never> + | undefined + }, + Options + > + | NoExcessProperties<{ + readonly layers: Record> + readonly dependencies?: ReadonlyArray> + readonly idleTimeToLive?: Duration.DurationInput | undefined + readonly preload?: boolean + }, Options> +>( + id: Id, + options: Options +): TagClass< + Self, + Id, + Options extends { readonly lookup: (key: infer K) => any } ? K + : Options extends { readonly layers: infer Layers } ? keyof Layers + : never, + Service.Success, + Options extends { readonly preload: true } ? never : Service.Error, + Service.Context, + Options extends { readonly preload: true } ? Service.Error + : Options extends { readonly preloadKey: Iterable } ? Service.Error + : never, + Options extends { readonly dependencies: ReadonlyArray } ? Options["dependencies"][number] : never +> => { + const Err = globalThis.Error as any + const limit = Err.stackTraceLimit + Err.stackTraceLimit = 2 + const creationError = new Err() + Err.stackTraceLimit = limit + + function TagClass() {} + const TagClass_ = TagClass as any as Mutable> + Object.setPrototypeOf(TagClass, Object.getPrototypeOf(Context.GenericTag(id))) + TagClass.key = id + Object.defineProperty(TagClass, "stack", { + get() { + return creationError.stack + } + }) + + TagClass_.DefaultWithoutDependencies = Layer.scoped( + TagClass_, + "lookup" in options + ? make(options.lookup, options) + : fromRecord(options.layers as any, options) + ) + TagClass_.Default = options.dependencies && options.dependencies.length > 0 ? + Layer.provide(TagClass_.DefaultWithoutDependencies, options.dependencies as any) : + TagClass_.DefaultWithoutDependencies + + TagClass_.get = (key: string) => Layer.unwrapScoped(Effect.map(TagClass_, (layerMap) => layerMap.get(key))) + TagClass_.runtime = (key: string) => Effect.flatMap(TagClass_, (layerMap) => layerMap.runtime(key)) + TagClass_.invalidate = (key: string) => Effect.flatMap(TagClass_, (layerMap) => layerMap.invalidate(key)) + + return TagClass as any +} + +/** + * @since 3.14.0 + * @category Service + * @experimental + */ +export declare namespace Service { + /** + * @since 3.14.0 + * @category Service + * @experimental + */ + export type Key = Options extends { readonly lookup: (key: infer K) => any } ? K + : Options extends { readonly layers: infer Layers } ? keyof Layers + : never + + /** + * @since 3.14.0 + * @category Service + * @experimental + */ + export type Layers = Options extends { readonly lookup: (key: infer _K) => infer Layers } ? Layers + : Options extends { readonly layers: infer Layers } ? Layers[keyof Layers] + : never + + /** + * @since 3.14.0 + * @category Service + * @experimental + */ + export type Success = Layers extends Layer.Layer ? _A : never + + /** + * @since 3.14.0 + * @category Service + * @experimental + */ + export type Error = Layers extends Layer.Layer ? _E : never + + /** + * @since 3.14.0 + * @category Service + * @experimental + */ + export type Context = Layers extends Layer.Layer ? _R : never +} diff --git a/backend/node_modules/effect/src/LogSpan.ts b/backend/node_modules/effect/src/LogSpan.ts new file mode 100644 index 0000000000000000000000000000000000000000..6c898befde25ac8c68362a47c8063deb090f9cd9 --- /dev/null +++ b/backend/node_modules/effect/src/LogSpan.ts @@ -0,0 +1,25 @@ +/** + * @since 2.0.0 + */ +import * as internal from "./internal/logSpan.js" + +/** + * @since 2.0.0 + * @category models + */ +export interface LogSpan { + readonly label: string + readonly startTime: number +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const make: (label: string, startTime: number) => LogSpan = internal.make + +/** + * @since 2.0.0 + * @category destructors + */ +export const render: (now: number) => (self: LogSpan) => string = internal.render diff --git a/backend/node_modules/effect/src/Match.ts b/backend/node_modules/effect/src/Match.ts new file mode 100644 index 0000000000000000000000000000000000000000..28f12fa538300e38ddd28d2a31586a96e4ba9d05 --- /dev/null +++ b/backend/node_modules/effect/src/Match.ts @@ -0,0 +1,1493 @@ +/** + * The `effect/match` module provides a type-safe pattern matching system for + * TypeScript. Inspired by functional programming, it simplifies conditional + * logic by replacing verbose if/else or switch statements with a structured and + * expressive API. + * + * This module supports matching against types, values, and discriminated unions + * while enforcing exhaustiveness checking to ensure all cases are handled. + * + * Although pattern matching is not yet a native JavaScript feature, + * `effect/match` offers a reliable implementation that is available today. + * + * **How Pattern Matching Works** + * + * Pattern matching follows a structured process: + * + * - **Creating a matcher**: Define a `Matcher` that operates on either a + * specific `Match.type` or `Match.value`. + * + * - **Defining patterns**: Use combinators such as `Match.when`, `Match.not`, + * and `Match.tag` to specify matching conditions. + * + * - **Completing the match**: Apply a finalizer such as `Match.exhaustive`, + * `Match.orElse`, or `Match.option` to determine how unmatched cases should + * be handled. + * + * @since 1.0.0 + */ +import type * as Either from "./Either.js" +import * as internal from "./internal/matcher.js" +import type * as Option from "./Option.js" +import type { Pipeable } from "./Pipeable.js" +import * as Predicate from "./Predicate.js" +import type * as T from "./Types.js" +import type { Unify } from "./Unify.js" + +/** + * @category Symbols + * @since 1.0.0 + */ +export const MatcherTypeId: unique symbol = internal.TypeId + +/** + * @category Symbols + * @since 1.0.0 + */ +export type MatcherTypeId = typeof MatcherTypeId + +/** + * Pattern matching follows a structured process: + * + * - **Creating a matcher**: Define a `Matcher` that operates on either a + * specific `Match.type` or `Match.value`. + * + * - **Defining patterns**: Use combinators such as `Match.when`, `Match.not`, + * and `Match.tag` to specify matching conditions. + * + * - **Completing the match**: Apply a finalizer such as `Match.exhaustive`, + * `Match.orElse`, or `Match.option` to determine how unmatched cases should + * be handled. + * + * @example + * ```ts + * import { Match } from "effect" + * + * // Simulated dynamic input that can be a string or a number + * const input: string | number = "some input" + * + * // ┌─── string + * // ▼ + * const result = Match.value(input).pipe( + * // Match if the value is a number + * Match.when(Match.number, (n) => `number: ${n}`), + * // Match if the value is a string + * Match.when(Match.string, (s) => `string: ${s}`), + * // Ensure all possible cases are covered + * Match.exhaustive + * ) + * + * console.log(result) + * // Output: "string: some input" + * ``` + * + * @category Model + * @since 1.0.0 + */ +export type Matcher = + | TypeMatcher + | ValueMatcher + +/** + * @category Model + * @since 1.0.0 + */ +export interface TypeMatcher extends Pipeable { + readonly _tag: "TypeMatcher" + readonly [MatcherTypeId]: { + readonly _input: T.Contravariant + readonly _filters: T.Covariant + readonly _remaining: T.Covariant + readonly _result: T.Covariant + readonly _return: T.Covariant + } + readonly cases: ReadonlyArray + add(_case: Case): TypeMatcher +} + +/** + * @category Model + * @since 1.0.0 + */ +export interface ValueMatcher + extends Pipeable +{ + readonly _tag: "ValueMatcher" + readonly [MatcherTypeId]: { + readonly _input: T.Contravariant + readonly _filters: T.Covariant + readonly _remaining: T.Covariant + readonly _result: T.Covariant + readonly _provided: T.Covariant + readonly _return: T.Covariant + } + readonly provided: Provided + readonly value: Either.Either + add(_case: Case): ValueMatcher +} + +/** + * @category Model + * @since 1.0.0 + */ +export type Case = When | Not + +/** + * @category Model + * @since 1.0.0 + */ +export interface When { + readonly _tag: "When" + guard(u: unknown): boolean + evaluate(input: unknown): any +} + +/** + * @category Model + * @since 1.0.0 + */ +export interface Not { + readonly _tag: "Not" + guard(u: unknown): boolean + evaluate(input: unknown): any +} + +/** + * Creates a matcher for a specific type. + * + * **Details** + * + * This function defines a `Matcher` that operates on a given type, allowing you + * to specify conditions for handling different cases. Once the matcher is + * created, you can use pattern-matching functions like {@link when} to define + * how different values should be processed. + * + * **Example** (Matching Numbers and Strings) + * + * ```ts + * import { Match } from "effect" + * + * // Create a matcher for values that are either strings or numbers + * // + * // ┌─── (u: string | number) => string + * // ▼ + * const match = Match.type().pipe( + * // Match when the value is a number + * Match.when(Match.number, (n) => `number: ${n}`), + * // Match when the value is a string + * Match.when(Match.string, (s) => `string: ${s}`), + * // Ensure all possible cases are handled + * Match.exhaustive + * ) + * + * console.log(match(0)) + * // Output: "number: 0" + * + * console.log(match("hello")) + * // Output: "string: hello" + * ``` + * + * @see {@link value} for creating a matcher from a specific value. + * + * @category Creating a matcher + * @since 1.0.0 + */ +export const type: () => Matcher, I, never, never> = internal.type + +/** + * Creates a matcher from a specific value. + * + * **Details** + * + * This function allows you to define a `Matcher` directly from a given value, + * rather than from a type. This is useful when working with known values, + * enabling structured pattern matching on objects, primitives, or any data + * structure. + * + * Once the matcher is created, you can use pattern-matching functions like + * {@link when} to define how different cases should be handled. + * + * **Example** (Matching an Object by Property) + * + * ```ts + * import { Match } from "effect" + * + * const input = { name: "John", age: 30 } + * + * // Create a matcher for the specific object + * const result = Match.value(input).pipe( + * // Match when the 'name' property is "John" + * Match.when( + * { name: "John" }, + * (user) => `${user.name} is ${user.age} years old` + * ), + * // Provide a fallback if no match is found + * Match.orElse(() => "Oh, not John") + * ) + * + * console.log(result) + * // Output: "John is 30 years old" + * ``` + * + * @see {@link type} for creating a matcher from a specific type. + * + * @category Creating a matcher + * @since 1.0.0 + */ +export const value: ( + i: I +) => Matcher, I, never, I> = internal.value + +/** + * @category Creating a matcher + * @since 1.0.0 + */ +export const valueTags: { + /** + * @category Creating a matcher + * @since 1.0.0 + */ + < + const I, + P extends + & { readonly [Tag in Types.Tags<"_tag", I> & string]: (_: Extract) => any } + & { readonly [Tag in Exclude>]: never } + >(fields: P): (input: I) => Unify> + /** + * @category Creating a matcher + * @since 1.0.0 + */ + < + const I, + P extends + & { readonly [Tag in Types.Tags<"_tag", I> & string]: (_: Extract) => any } + & { readonly [Tag in Exclude>]: never } + >(input: I, fields: P): Unify> +} = internal.valueTags + +/** + * @category Creating a matcher + * @since 1.0.0 + */ +export const typeTags: { + /** + * @category Creating a matcher + * @since 1.0.0 + */ + (): < + P extends + & { + readonly [Tag in Types.Tags<"_tag", I> & string]: ( + _: Extract + ) => Ret + } + & { readonly [Tag in Exclude>]: never } + >(fields: P) => (input: I) => Ret + /** + * @category Creating a matcher + * @since 1.0.0 + */ + (): < + P extends + & { + readonly [Tag in Types.Tags<"_tag", I> & string]: ( + _: Extract + ) => any + } + & { readonly [Tag in Exclude>]: never } + >(fields: P) => (input: I) => Unify> +} = internal.typeTags + +/** + * Ensures that all branches of a matcher return a specific type. + * + * **Details** + * + * This function enforces a consistent return type across all pattern-matching + * branches. By specifying a return type, TypeScript will check that every + * matching condition produces a value of the expected type. + * + * **Important:** This function must be the first step in the matcher pipeline. + * If used later, TypeScript will not enforce type consistency correctly. + * + * **Example** (Validating Return Type Consistency) + * + * ```ts + * import { Match } from "effect" + * + * const match = Match.type<{ a: number } | { b: string }>().pipe( + * // Ensure all branches return a string + * Match.withReturnType(), + * // ❌ Type error: 'number' is not assignable to type 'string' + * // @ts-expect-error + * Match.when({ a: Match.number }, (_) => _.a), + * // ✅ Correct: returns a string + * Match.when({ b: Match.string }, (_) => _.b), + * Match.exhaustive + * ) + * ``` + * + * @since 1.0.0 + */ +export const withReturnType: () => ( + self: Matcher +) => [Ret] extends [[A] extends [never] ? any : A] ? Matcher + : "withReturnType constraint does not extend Result type" = internal.withReturnType + +/** + * Defines a condition for matching values. + * + * **Details** + * + * This function enables pattern matching by checking whether a given value + * satisfies a condition. It supports both direct value comparisons and + * predicate functions. If the condition is met, the associated function is + * executed. + * + * This function is useful when defining matchers that need to check for + * specific values or apply logical conditions to determine a match. It works + * well with structured objects and primitive types. + * + * **Example** (Matching with Values and Predicates) + * + * ```ts + * import { Match } from "effect" + * + * // Create a matcher for objects with an "age" property + * const match = Match.type<{ age: number }>().pipe( + * // Match when age is greater than 18 + * Match.when({ age: (age) => age > 18 }, (user) => `Age: ${user.age}`), + * // Match when age is exactly 18 + * Match.when({ age: 18 }, () => "You can vote"), + * // Fallback case for all other ages + * Match.orElse((user) => `${user.age} is too young`) + * ) + * + * console.log(match({ age: 20 })) + * // Output: "Age: 20" + * + * console.log(match({ age: 18 })) + * // Output: "You can vote" + * + * console.log(match({ age: 4 })) + * // Output: "4 is too young" + * ``` + * + * @see {@link whenOr} Use this when multiple patterns should match in a single + * condition. + * @see {@link whenAnd} Use this when a value must match all provided patterns. + * @see {@link orElse} Provides a fallback when no patterns match. + * + * @category Defining patterns + * @since 1.0.0 + */ +export const when: < + R, + const P extends Types.PatternPrimitive | Types.PatternBase, + Ret, + Fn extends (_: Types.WhenMatch) => Ret +>( + pattern: P, + f: Fn +) => ( + self: Matcher +) => Matcher< + I, + Types.AddWithout>, + Types.ApplyFilters>>, + A | ReturnType, + Pr, + Ret +> = internal.when + +/** + * Matches one of multiple patterns in a single condition. + * + * **Details** + * + * This function allows defining a condition where a value matches any of the + * provided patterns. If a match is found, the associated function is executed. + * It simplifies cases where multiple patterns share the same handling logic. + * + * Unlike {@link when}, which requires separate conditions for each pattern, + * this function enables combining them into a single statement, making the + * matcher more concise. + * + * @example + * ```ts + * import { Match } from "effect" + * + * type ErrorType = + * | { readonly _tag: "NetworkError"; readonly message: string } + * | { readonly _tag: "TimeoutError"; readonly duration: number } + * | { readonly _tag: "ValidationError"; readonly field: string } + * + * const handleError = Match.type().pipe( + * Match.whenOr( + * { _tag: "NetworkError" }, + * { _tag: "TimeoutError" }, + * () => "Retry the request" + * ), + * Match.when({ _tag: "ValidationError" }, (_) => `Invalid field: ${_.field}`), + * Match.exhaustive + * ) + * + * console.log(handleError({ _tag: "NetworkError", message: "No connection" })) + * // Output: "Retry the request" + * + * console.log(handleError({ _tag: "ValidationError", field: "email" })) + * // Output: "Invalid field: email" + * ``` + * + * @category Defining patterns + * @since 1.0.0 + */ +export const whenOr: < + R, + const P extends ReadonlyArray | Types.PatternBase>, + Ret, + Fn extends (_: Types.WhenMatch) => Ret +>( + ...args: [...patterns: P, f: Fn] +) => ( + self: Matcher +) => Matcher< + I, + Types.AddWithout>, + Types.ApplyFilters>>, + A | ReturnType, + Pr, + Ret +> = internal.whenOr + +/** + * Matches a value that satisfies all provided patterns. + * + * **Details** + * + * This function allows defining a condition where a value must match all the + * given patterns simultaneously. If the value satisfies every pattern, the + * associated function is executed. + * + * Unlike {@link when}, which matches a single pattern at a time, this function + * ensures that multiple conditions are met before executing the callback. It is + * useful when checking for values that need to fulfill multiple criteria at + * once. + * + * @example + * ```ts + * import { Match } from "effect" + * + * type User = { readonly age: number; readonly role: "admin" | "user" } + * + * const checkUser = Match.type().pipe( + * Match.whenAnd( + * { age: (n) => n >= 18 }, + * { role: "admin" }, + * () => "Admin access granted" + * ), + * Match.orElse(() => "Access denied") + * ) + * + * console.log(checkUser({ age: 20, role: "admin" })) + * // Output: "Admin access granted" + * + * console.log(checkUser({ age: 20, role: "user" })) + * // Output: "Access denied" + * ``` + * + * @category Defining patterns + * @since 1.0.0 + */ +export const whenAnd: < + R, + const P extends ReadonlyArray | Types.PatternBase>, + Ret, + Fn extends (_: Types.WhenMatch>) => Ret +>( + ...args: [...patterns: P, f: Fn] +) => ( + self: Matcher +) => Matcher< + I, + Types.AddWithout>>, + Types.ApplyFilters>>>, + A | ReturnType, + Pr +> = internal.whenAnd + +/** + * Matches values based on a specified discriminant field. + * + * **Details** + * + * This function is used to define pattern matching on objects that follow a + * **discriminated union** structure, where a specific field (e.g., `type`, + * `kind`, `_tag`) determines the variant of the object. It allows matching + * multiple values of the discriminant and provides a function to handle the + * matched cases. + * + * @example + * ```ts + * import { Match, pipe } from "effect" + * + * const match = pipe( + * Match.type<{ type: "A"; a: string } | { type: "B"; b: number } | { type: "C"; c: boolean }>(), + * Match.discriminator("type")("A", "B", (_) => `A or B: ${_.type}`), + * Match.discriminator("type")("C", (_) => `C(${_.c})`), + * Match.exhaustive + * ) + * ``` + * + * @category Defining patterns + * @since 1.0.0 + */ +export const discriminator: ( + field: D +) => & string, Ret, Fn extends (_: Extract>) => Ret>( + ...pattern: [first: P, ...values: Array

, f: Fn] +) => ( + self: Matcher +) => Matcher< + I, + Types.AddWithout>>, + Types.ApplyFilters>>>, + ReturnType | A, + Pr, + Ret +> = internal.tag + +/** + * Matches values where the `_tag` field starts with a given prefix. + * + * **Details** + * + * This function allows you to match on values in a **discriminated union** + * based on whether the `_tag` field starts with a specified prefix. It is + * useful for handling hierarchical or namespaced tags, where multiple related + * cases share a common prefix. + * + * @example + * ```ts + * import { Match, pipe } from "effect" + * + * const match = pipe( + * Match.type<{ _tag: "A" } | { _tag: "B" } | { _tag: "A.A" } | {}>(), + * Match.tagStartsWith("A", (_) => 1 as const), + * Match.tagStartsWith("B", (_) => 2 as const), + * Match.orElse((_) => 3 as const) + * ) + * + * console.log(match({ _tag: "A" })) // 1 + * console.log(match({ _tag: "B" })) // 2 + * console.log(match({ _tag: "A.A" })) // 1 + * ``` + * + * @category Defining patterns + * @since 1.0.0 + */ +export const tagStartsWith: < + R, + P extends string, + Ret, + Fn extends (_: Extract>) => Ret +>( + pattern: P, + f: Fn +) => ( + self: Matcher +) => Matcher< + I, + Types.AddWithout>>, + Types.ApplyFilters>>>, + ReturnType | A, + Pr, + Ret +> = internal.tagStartsWith + +/** + * Matches values based on their `_tag` field, mapping each tag to a + * corresponding handler. + * + * **Details** + * + * This function provides a way to handle discriminated unions by mapping `_tag` + * values to specific functions. Each handler receives the matched value and + * returns a transformed result. If all possible tags are handled, you can + * enforce exhaustiveness using `Match.exhaustive` to ensure no case is missed. + * + * @example + * ```ts + * import { Match, pipe } from "effect" + * + * const match = pipe( + * Match.type<{ _tag: "A"; a: string } | { _tag: "B"; b: number } | { _tag: "C"; c: boolean }>(), + * Match.tags({ + * A: (a) => a.a, + * B: (b) => b.b, + * C: (c) => c.c + * }), + * Match.exhaustive + * ) + * ``` + * + * @category Defining patterns + * @since 1.0.0 + */ +export const tags: < + R, + Ret, + P extends + & { readonly [Tag in Types.Tags<"_tag", R> & string]?: ((_: Extract>) => Ret) | undefined } + & { readonly [Tag in Exclude>]: never } +>( + fields: P +) => ( + self: Matcher +) => Matcher< + I, + Types.AddWithout>>, + Types.ApplyFilters>>>, + A | ReturnType, + Pr, + Ret +> = internal.tags + +/** + * Matches values based on their `_tag` field and requires handling of all + * possible cases. + * + * **Details** + * + * This function is designed for **discriminated unions** where every possible + * `_tag` value must have a corresponding handler. Unlike {@link tags}, this + * function ensures **exhaustiveness**, meaning all cases must be explicitly + * handled. If a `_tag` value is missing from the mapping, TypeScript will + * report an error. + * + * @example + * ```ts + * import { Match, pipe } from "effect" + * + * const match = pipe( + * Match.type<{ _tag: "A"; a: string } | { _tag: "B"; b: number } | { _tag: "C"; c: boolean }>(), + * Match.tagsExhaustive({ + * A: (a) => a.a, + * B: (b) => b.b, + * C: (c) => c.c + * }) + * ) + * ``` + * + * @category Defining patterns + * @since 1.0.0 + */ +export const tagsExhaustive: < + R, + Ret, + P extends + & { readonly [Tag in Types.Tags<"_tag", R> & string]: (_: Extract>) => Ret } + & { readonly [Tag in Exclude>]: never } +>( + fields: P +) => ( + self: Matcher +) => [Pr] extends [never] ? (u: I) => Unify> : Unify> = + internal.tagsExhaustive + +/** + * Excludes a specific value from matching while allowing all others. + * + * **Details** + * + * This function is useful when you need to **handle all values except one or + * more specific cases**. Instead of listing all possible matches manually, this + * function simplifies the logic by allowing you to specify values to exclude. + * Any excluded value will bypass the provided function and continue matching + * through other cases. + * + * **Example** (Ignoring a Specific Value) + * + * ```ts + * import { Match } from "effect" + * + * // Create a matcher for string or number values + * const match = Match.type().pipe( + * // Match any value except "hi", returning "ok" + * Match.not("hi", () => "ok"), + * // Fallback case for when the value is "hi" + * Match.orElse(() => "fallback") + * ) + * + * console.log(match("hello")) + * // Output: "ok" + * + * console.log(match("hi")) + * // Output: "fallback" + * ``` + * + * @category Defining patterns + * @since 1.0.0 + */ +export const not: < + R, + const P extends Types.PatternPrimitive | Types.PatternBase, + Ret, + Fn extends (_: Types.NotMatch) => Ret +>( + pattern: P, + f: Fn +) => ( + self: Matcher +) => Matcher< + I, + Types.AddOnly>, + Types.ApplyFilters>>, + A | ReturnType, + Pr, + Ret +> = internal.not + +/** + * Matches non-empty strings. + * + * @category Predicates + * @since 1.0.0 + */ +export const nonEmptyString: SafeRefinement = internal.nonEmptyString + +/** + * Matches a specific set of literal values (e.g., `Match.is("a", 42, true)`). + * + * @category Predicates + * @since 1.0.0 + */ +export const is: < + Literals extends ReadonlyArray +>(...literals: Literals) => SafeRefinement = internal.is + +/** + * Matches values of type `string`. + * + * @category Predicates + * @since 1.0.0 + */ +export const string: Predicate.Refinement = Predicate.isString + +/** + * Matches values of type `number`. + * + * @category Predicates + * @since 1.0.0 + */ +export const number: Predicate.Refinement = Predicate.isNumber + +/** + * Matches any value without restrictions. + * + * @category Predicates + * @since 1.0.0 + */ +export const any: SafeRefinement = internal.any + +/** + * Matches any defined (non-null and non-undefined) value. + * + * @category Predicates + * @since 1.0.0 + */ +export const defined: (u: A) => u is A & {} = internal.defined + +/** + * Matches values of type `boolean`. + * + * @category Predicates + * @since 1.0.0 + */ +export const boolean: Predicate.Refinement = Predicate.isBoolean + +const _undefined: Predicate.Refinement = Predicate.isUndefined +export { + /** + * Matches the value `undefined`. + * + * @category Predicates + * @since 1.0.0 + */ + _undefined as undefined +} + +const _null: Predicate.Refinement = Predicate.isNull +export { + /** + * Matches the value `null`. + * + * @category Predicates + * @since 1.0.0 + */ + _null as null +} + +/** + * Matches values of type `bigint`. + * + * @category Predicates + * @since 1.0.0 + */ +export const bigint: Predicate.Refinement = Predicate.isBigInt + +/** + * Matches values of type `symbol`. + * + * @category Predicates + * @since 1.0.0 + */ +export const symbol: Predicate.Refinement = Predicate.isSymbol + +/** + * Matches values that are instances of `Date`. + * + * @category Predicates + * @since 1.0.0 + */ +export const date: Predicate.Refinement = Predicate.isDate + +/** + * Matches objects where keys are `string` or `symbol` and values are `unknown`. + * + * @category Predicates + * @since 1.0.0 + */ +export const record: Predicate.Refinement = Predicate.isRecord + +/** + * Matches instances of a given class. + * + * @category Predicates + * @since 1.0.0 + */ +export const instanceOf: any>( + constructor: A +) => SafeRefinement, never> = internal.instanceOf + +/** + * @category Predicates + * @since 1.0.0 + */ +export const instanceOfUnsafe: any>( + constructor: A +) => SafeRefinement, InstanceType> = internal.instanceOf + +/** + * Provides a fallback value when no patterns match. + * + * **Details** + * + * This function ensures that a matcher always returns a valid result, even if + * no defined patterns match. It acts as a default case, similar to the + * `default` clause in a `switch` statement or the final `else` in an `if-else` + * chain. + * + * **Example** (Providing a Default Value When No Patterns Match) + * + * ```ts + * import { Match } from "effect" + * + * // Create a matcher for string or number values + * const match = Match.type().pipe( + * // Match when the value is "a" + * Match.when("a", () => "ok"), + * // Fallback when no patterns match + * Match.orElse(() => "fallback") + * ) + * + * console.log(match("a")) + * // Output: "ok" + * + * console.log(match("b")) + * // Output: "fallback" + * ``` + * + * @category Completion + * @since 1.0.0 + */ +export const orElse: Ret>( + f: F +) => ( + self: Matcher +) => [Pr] extends [never] ? (input: I) => Unify | A> : Unify | A> = internal.orElse + +// TODO(4.0): Rename to "orThrow"? Like Either.getOrThrow +/** + * Throws an error if no pattern matches. + * + * **Details** + * + * This function finalizes a matcher by ensuring that if no patterns match, an + * error is thrown. It is useful when all cases should be covered, and any + * unexpected input should trigger an error instead of returning a default + * value. + * + * When used, this function removes the need for an explicit fallback case and + * ensures that an unmatched value is never silently ignored. + * + * @category Completion + * @since 1.0.0 + */ +export const orElseAbsurd: ( + self: Matcher +) => [Pr] extends [never] ? (input: I) => Unify : Unify = internal.orElseAbsurd + +/** + * Wraps the match result in an `Either`, distinguishing matched and unmatched + * cases. + * + * **Details** + * + * This function ensures that the result of a matcher is always wrapped in an + * `Either`, allowing clear differentiation between successful matches + * (`Right(value)`) and cases where no pattern matched (`Left(unmatched + * value)`). + * + * This approach is particularly useful when handling optional values or when an + * unmatched case should be explicitly handled rather than returning a default + * value or throwing an error. + * + * **Example** (Extracting a User Role with `Match.either`) + * + * ```ts + * import { Match } from "effect" + * + * type User = { readonly role: "admin" | "editor" | "viewer" } + * + * // Create a matcher to extract user roles + * const getRole = Match.type().pipe( + * Match.when({ role: "admin" }, () => "Has full access"), + * Match.when({ role: "editor" }, () => "Can edit content"), + * Match.either // Wrap the result in an Either + * ) + * + * console.log(getRole({ role: "admin" })) + * // Output: { _id: 'Either', _tag: 'Right', right: 'Has full access' } + * + * console.log(getRole({ role: "viewer" })) + * // Output: { _id: 'Either', _tag: 'Left', left: { role: 'viewer' } } + * ``` + * + * @category Completion + * @since 1.0.0 + */ +export const either: ( + self: Matcher +) => [Pr] extends [never] ? (input: I) => Either.Either, R> : Either.Either, R> = internal.either + +/** + * Wraps the match result in an `Option`, representing an optional match. + * + * **Details** + * + * This function ensures that the result of a matcher is wrapped in an `Option`, + * making it easy to handle cases where no pattern matches. If a match is found, + * it returns `Some(value)`, otherwise, it returns `None`. + * + * This is useful in cases where a missing match is expected and should be + * handled explicitly rather than throwing an error or returning a default + * value. + * + * **Example** (Extracting a User Role with `Match.option`) + * + * ```ts + * import { Match } from "effect" + * + * type User = { readonly role: "admin" | "editor" | "viewer" } + * + * // Create a matcher to extract user roles + * const getRole = Match.type().pipe( + * Match.when({ role: "admin" }, () => "Has full access"), + * Match.when({ role: "editor" }, () => "Can edit content"), + * Match.option // Wrap the result in an Option + * ) + * + * console.log(getRole({ role: "admin" })) + * // Output: { _id: 'Option', _tag: 'Some', value: 'Has full access' } + * + * console.log(getRole({ role: "viewer" })) + * // Output: { _id: 'Option', _tag: 'None' } + * ``` + * + * @category Completion + * @since 1.0.0 + */ +export const option: ( + self: Matcher +) => [Pr] extends [never] ? (input: I) => Option.Option> : Option.Option> = internal.option + +/** + * The `Match.exhaustive` method finalizes the pattern matching process by + * ensuring that all possible cases are accounted for. If any case is missing, + * TypeScript will produce a type error. This is particularly useful when + * working with unions, as it helps prevent unintended gaps in pattern matching. + * + * **Example** (Ensuring All Cases Are Covered) + * + * ```ts + * import { Match } from "effect" + * + * // Create a matcher for string or number values + * const match = Match.type().pipe( + * // Match when the value is a number + * Match.when(Match.number, (n) => `number: ${n}`), + * // Mark the match as exhaustive, ensuring all cases are handled + * // TypeScript will throw an error if any case is missing + * // @ts-expect-error Type 'string' is not assignable to type 'never' + * Match.exhaustive + * ) + * ``` + * + * @category Completion + * @since 1.0.0 + */ +export const exhaustive: ( + self: Matcher +) => [Pr] extends [never] ? (u: I) => Unify : Unify = internal.exhaustive + +/** + * @since 1.0.0 + * @category Symbols + */ +export const SafeRefinementId = Symbol.for("effect/SafeRefinement") + +/** + * @since 1.0.0 + * @category Symbols + */ +export type SafeRefinementId = typeof SafeRefinementId + +/** + * @category Model + * @since 1.0.0 + */ +export interface SafeRefinement { + readonly [SafeRefinementId]: (a: A) => R +} + +const Fail = Symbol.for("effect/Fail") +type Fail = typeof Fail + +/** + * @since 1.0.0 + */ +export declare namespace Types { + /** + * @since 1.0.0 + */ + export type WhenMatch = + // check for any + [0] extends [1 & R] ? ResolvePred

: + P extends SafeRefinement ? SP + : P extends Predicate.Refinement + // try to narrow refinement + ? [Extract] extends [infer X] ? [X] extends [never] + // fallback to original refinement + ? RP + : X + : never + : P extends PredicateA ? PP + : ExtractMatch + + /** + * @since 1.0.0 + */ + export type NotMatch = Exclude>> + + type PForNotMatch

= [ToInvertedRefinement

] extends [infer X] ? X + : never + + /** + * @since 1.0.0 + */ + export type PForMatch

= [ResolvePred

] extends [infer X] ? X + : never + + /** + * @since 1.0.0 + */ + export type PForExclude

= [SafeRefinementR>] extends [infer X] ? X + : never + + // utilities + type PredicateA = Predicate.Predicate | Predicate.Refinement + + type SafeRefinementR = A extends never ? never + : A extends SafeRefinement ? R + : A extends Function ? A + : A extends Record ? { [K in keyof A]: SafeRefinementR } + : A + + type ResolvePred = A extends never ? never + : A extends SafeRefinement ? _A + : A extends Predicate.Refinement ? P + : A extends Predicate.Predicate ? P + : A extends Record ? { [K in keyof A]: ResolvePred } + : A + + type ToSafeRefinement = A extends never ? never + : A extends Predicate.Refinement ? SafeRefinement + : A extends Predicate.Predicate ? SafeRefinement + : A extends SafeRefinement ? A + : A extends Record ? { [K in keyof A]: ToSafeRefinement } + : NonLiteralsTo + + type ToInvertedRefinement = A extends never ? never + : A extends Predicate.Refinement ? SafeRefinement

+ : A extends Predicate.Predicate ? SafeRefinement + : A extends SafeRefinement ? SafeRefinement<_R> + : A extends Record ? { [K in keyof A]: ToInvertedRefinement } + : NonLiteralsTo + + type NonLiteralsTo = [A] extends [string | number | boolean | bigint] ? [string] extends [A] ? T + : [number] extends [A] ? T + : [boolean] extends [A] ? T + : [bigint] extends [A] ? T + : A + : A + + /** + * @since 1.0.0 + */ + export type PatternBase = A extends ReadonlyArray ? ReadonlyArray | PatternPrimitive + : A extends Record ? Partial< + { [K in keyof A]: PatternPrimitive | PatternBase } + > + : never + + /** + * @since 1.0.0 + */ + export type PatternPrimitive = PredicateA | A | SafeRefinement + + /** + * @since 1.0.0 + */ + export interface Without { + readonly _tag: "Without" + readonly _X: X + } + + /** + * @since 1.0.0 + */ + export interface Only { + readonly _tag: "Only" + readonly _X: X + } + + /** + * @since 1.0.0 + */ + export type AddWithout = [A] extends [Without] ? Without + : [A] extends [Only] ? Only> + : never + + /** + * @since 1.0.0 + */ + export type AddOnly = [A] extends [Without] ? [X] extends [WX] ? never + : Only + : [A] extends [Only] ? [X] extends [OX] ? Only + : never + : never + + /** + * @since 1.0.0 + */ + export type ApplyFilters = A extends Only ? X + : A extends Without ? Exclude + : never + + /** + * @since 1.0.0 + */ + export type Tags = P extends Record ? X : never + + /** + * @since 1.0.0 + */ + export type ArrayToIntersection> = T.UnionToIntersection< + A[number] + > + + /** + * @since 1.0.0 + */ + export type ExtractMatch = [ExtractAndNarrow] extends [infer EI] ? EI + : never + + type Replace = A extends Function ? A + : A extends Record ? { [K in keyof A]: K extends keyof B ? Replace : A[K] } + : [B] extends [A] ? B + : A + + type MaybeReplace = [P] extends [I] ? P + : [I] extends [P] ? Replace + : Fail + + type BuiltInObjects = + | Function + | Date + | RegExp + | Generator + | { readonly [Symbol.toStringTag]: string } + + type IsPlainObject = T extends BuiltInObjects ? false + : T extends Record ? true + : false + + type Simplify = { [K in keyof A]: A[K] } & {} + + type ExtractAndNarrow = P extends Predicate.Refinement ? + _Out extends Input ? Extract<_Out, Input> + : Extract : + P extends SafeRefinement ? [0] extends [1 & _R] ? Input + : _In extends Input ? Extract<_In, Input> + : Extract + : P extends Predicate.Predicate ? Extract + : Input extends infer I ? Exclude< + I extends ReadonlyArray ? P extends ReadonlyArray ? { + readonly [K in keyof I]: K extends keyof P ? ExtractAndNarrow + : I[K] + } extends infer R ? Fail extends R[keyof R] ? never + : R + : never + : never + : IsPlainObject extends true ? string extends keyof I ? I extends P ? I + : never + : symbol extends keyof I ? I extends P ? I + : never + : Simplify< + & { [RK in Extract]-?: ExtractAndNarrow } + & Omit + > extends infer R ? keyof P extends NonFailKeys ? R + : never + : never + : MaybeReplace extends infer R ? [I] extends [R] ? I + : R + : never, + Fail + > : + never + + type NonFailKeys = keyof A & {} extends infer K ? K extends keyof A ? A[K] extends Fail ? never : K + : never : + never +} diff --git a/backend/node_modules/effect/src/MetricBoundaries.ts b/backend/node_modules/effect/src/MetricBoundaries.ts new file mode 100644 index 0000000000000000000000000000000000000000..a4cb78a0e78ab743f2fb81cdf368b66fa97c68ee --- /dev/null +++ b/backend/node_modules/effect/src/MetricBoundaries.ts @@ -0,0 +1,69 @@ +/** + * @since 2.0.0 + */ +import type * as Equal from "./Equal.js" +import * as internal from "./internal/metric/boundaries.js" +import type { Pipeable } from "./Pipeable.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const MetricBoundariesTypeId: unique symbol = internal.MetricBoundariesTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type MetricBoundariesTypeId = typeof MetricBoundariesTypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface MetricBoundaries extends Equal.Equal, Pipeable { + readonly [MetricBoundariesTypeId]: MetricBoundariesTypeId + readonly values: ReadonlyArray +} + +/** + * @since 2.0.0 + * @category refinements + */ +export const isMetricBoundaries: (u: unknown) => u is MetricBoundaries = internal.isMetricBoundaries + +/** + * @since 2.0.0 + * @category constructors + */ +export const fromIterable: (iterable: Iterable) => MetricBoundaries = internal.fromIterable + +/** + * A helper method to create histogram bucket boundaries for a histogram + * with linear increasing values. + * + * @since 2.0.0 + * @category constructors + */ +export const linear: ( + options: { + readonly start: number + readonly width: number + readonly count: number + } +) => MetricBoundaries = internal.linear + +/** + * A helper method to create histogram bucket boundaries for a histogram + * with exponentially increasing values. + * + * @since 2.0.0 + * @category constructors + */ +export const exponential: ( + options: { + readonly start: number + readonly factor: number + readonly count: number + } +) => MetricBoundaries = internal.exponential diff --git a/backend/node_modules/effect/src/MetricHook.ts b/backend/node_modules/effect/src/MetricHook.ts new file mode 100644 index 0000000000000000000000000000000000000000..b6997e3c2986ce032aa648e72e442fdc388ccc22 --- /dev/null +++ b/backend/node_modules/effect/src/MetricHook.ts @@ -0,0 +1,175 @@ +/** + * @since 2.0.0 + */ +import type { LazyArg } from "./Function.js" +import * as internal from "./internal/metric/hook.js" +import type * as MetricKey from "./MetricKey.js" +import type * as MetricState from "./MetricState.js" +import type { Pipeable } from "./Pipeable.js" +import type * as Types from "./Types.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const MetricHookTypeId: unique symbol = internal.MetricHookTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type MetricHookTypeId = typeof MetricHookTypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface MetricHook extends MetricHook.Variance, Pipeable { + get(): Out + update(input: In): void + modify(input: In): void +} + +/** + * @since 2.0.0 + */ +export declare namespace MetricHook { + /** + * @since 2.0.0 + * @category models + */ + export type Root = MetricHook + + /** + * @since 2.0.0 + * @category models + */ + export type Untyped = MetricHook + + /** + * @since 2.0.0 + * @category models + */ + export type Counter = MetricHook> + + /** + * @since 2.0.0 + * @category models + */ + export type Gauge = MetricHook> + + /** + * @since 2.0.0 + * @category models + */ + export type Frequency = MetricHook + + /** + * @since 2.0.0 + * @category models + */ + export type Histogram = MetricHook + + /** + * @since 2.0.0 + * @category models + */ + export type Summary = MetricHook + + /** + * @since 2.0.0 + * @category models + */ + export interface Variance { + readonly [MetricHookTypeId]: { + readonly _In: Types.Contravariant + readonly _Out: Types.Covariant + } + } +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const make: (options: { + readonly get: LazyArg + readonly update: (input: In) => void + readonly modify: (input: In) => void +}) => MetricHook = internal.make + +/** + * @since 2.0.0 + * @category constructors + */ +export const counter: (key: MetricKey.MetricKey.Counter) => MetricHook.Counter = + internal.counter + +/** + * @since 2.0.0 + * @category constructors + */ +export const frequency: (_key: MetricKey.MetricKey.Frequency) => MetricHook.Frequency = internal.frequency + +/** + * @since 2.0.0 + * @category constructors + */ +export const gauge: { + /** + * @since 2.0.0 + * @category constructors + */ + (key: MetricKey.MetricKey.Gauge, startAt: number): MetricHook.Gauge + /** + * @since 2.0.0 + * @category constructors + */ + (key: MetricKey.MetricKey.Gauge, startAt: bigint): MetricHook.Gauge +} = internal.gauge + +/** + * @since 2.0.0 + * @category constructors + */ +export const histogram: (key: MetricKey.MetricKey.Histogram) => MetricHook.Histogram = internal.histogram + +/** + * @since 2.0.0 + * @category constructors + */ +export const summary: (key: MetricKey.MetricKey.Summary) => MetricHook.Summary = internal.summary + +/** + * @since 2.0.0 + * @category utils + */ +export const onUpdate: { + /** + * @since 2.0.0 + * @category utils + */ + (f: (input: In) => void): (self: MetricHook) => MetricHook + /** + * @since 2.0.0 + * @category utils + */ + (self: MetricHook, f: (input: In) => void): MetricHook +} = internal.onUpdate + +/** + * @since 3.6.5 + * @category utils + */ +export const onModify: { + /** + * @since 3.6.5 + * @category utils + */ + (f: (input: In) => void): (self: MetricHook) => MetricHook + /** + * @since 3.6.5 + * @category utils + */ + (self: MetricHook, f: (input: In) => void): MetricHook +} = internal.onModify diff --git a/backend/node_modules/effect/src/MetricKey.ts b/backend/node_modules/effect/src/MetricKey.ts new file mode 100644 index 0000000000000000000000000000000000000000..d923837e455e72a87b2c5a5022e90969507f1492 --- /dev/null +++ b/backend/node_modules/effect/src/MetricKey.ts @@ -0,0 +1,266 @@ +/** + * @since 2.0.0 + */ +import type * as Duration from "./Duration.js" +import type * as Equal from "./Equal.js" +import * as internal from "./internal/metric/key.js" +import type * as MetricBoundaries from "./MetricBoundaries.js" +import type * as MetricKeyType from "./MetricKeyType.js" +import type * as MetricLabel from "./MetricLabel.js" +import type * as Option from "./Option.js" +import type { Pipeable } from "./Pipeable.js" +import type * as Types from "./Types.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const MetricKeyTypeId: unique symbol = internal.MetricKeyTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type MetricKeyTypeId = typeof MetricKeyTypeId + +/** + * A `MetricKey` is a unique key associated with each metric. The key is based + * on a combination of the metric type, the name and tags associated with the + * metric, an optional description of the key, and any other information to + * describe a metric, such as the boundaries of a histogram. In this way, it is + * impossible to ever create different metrics with conflicting keys. + * + * @since 2.0.0 + * @category models + */ +export interface MetricKey> + extends MetricKey.Variance, Equal.Equal, Pipeable +{ + readonly name: string + readonly keyType: Type + readonly description: Option.Option + readonly tags: ReadonlyArray +} + +/** + * @since 2.0.0 + */ +export declare namespace MetricKey { + /** + * @since 2.0.0 + * @category models + */ + export type Untyped = MetricKey + + /** + * @since 2.0.0 + * @category models + */ + export type Counter = MetricKey> + + /** + * @since 2.0.0 + * @category models + */ + export type Gauge = MetricKey> + + /** + * @since 2.0.0 + * @category models + */ + export type Frequency = MetricKey + + /** + * @since 2.0.0 + * @category models + */ + export type Histogram = MetricKey + + /** + * @since 2.0.0 + * @category models + */ + export type Summary = MetricKey + + /** + * @since 2.0.0 + * @category models + */ + export interface Variance { + readonly [MetricKeyTypeId]: { + _Type: Types.Covariant + } + } +} + +/** + * @since 2.0.0 + * @category refinements + */ +export const isMetricKey: (u: unknown) => u is MetricKey> = + internal.isMetricKey + +/** + * Creates a metric key for a counter, with the specified name. + * + * @since 2.0.0 + * @category constructors + */ +export const counter: { + /** + * Creates a metric key for a counter, with the specified name. + * + * @since 2.0.0 + * @category constructors + */ + ( + name: string, + options?: { + readonly description?: string | undefined + readonly bigint?: false | undefined + readonly incremental?: boolean | undefined + } + ): MetricKey.Counter + /** + * Creates a metric key for a counter, with the specified name. + * + * @since 2.0.0 + * @category constructors + */ + ( + name: string, + options: { + readonly description?: string | undefined + readonly bigint: true + readonly incremental?: boolean | undefined + } + ): MetricKey.Counter +} = internal.counter + +/** + * Creates a metric key for a categorical frequency table, with the specified + * name. + * + * @since 2.0.0 + * @category constructors + */ +export const frequency: ( + name: string, + options?: + | { + readonly description?: string | undefined + readonly preregisteredWords?: ReadonlyArray | undefined + } + | undefined +) => MetricKey.Frequency = internal.frequency + +/** + * Creates a metric key for a gauge, with the specified name. + * + * @since 2.0.0 + * @category constructors + */ +export const gauge: { + /** + * Creates a metric key for a gauge, with the specified name. + * + * @since 2.0.0 + * @category constructors + */ + ( + name: string, + options?: { + readonly description?: string | undefined + readonly bigint?: false | undefined + } + ): MetricKey.Gauge + /** + * Creates a metric key for a gauge, with the specified name. + * + * @since 2.0.0 + * @category constructors + */ + ( + name: string, + options: { + readonly description?: string | undefined + readonly bigint: true + } + ): MetricKey.Gauge +} = internal.gauge + +/** + * Creates a metric key for a histogram, with the specified name and boundaries. + * + * @since 2.0.0 + * @category constructors + */ +export const histogram: ( + name: string, + boundaries: MetricBoundaries.MetricBoundaries, + description?: string +) => MetricKey.Histogram = internal.histogram + +/** + * Creates a metric key for a summary, with the specified name, maxAge, + * maxSize, error, and quantiles. + * + * @since 2.0.0 + * @category constructors + */ +export const summary: ( + options: { + readonly name: string + readonly maxAge: Duration.DurationInput + readonly maxSize: number + readonly error: number + readonly quantiles: ReadonlyArray + readonly description?: string | undefined + } +) => MetricKey.Summary = internal.summary + +/** + * Returns a new `MetricKey` with the specified tag appended. + * + * @since 2.0.0 + * @category constructors + */ +export const tagged: { + /** + * Returns a new `MetricKey` with the specified tag appended. + * + * @since 2.0.0 + * @category constructors + */ + (key: string, value: string): >(self: MetricKey) => MetricKey + /** + * Returns a new `MetricKey` with the specified tag appended. + * + * @since 2.0.0 + * @category constructors + */ + >(self: MetricKey, key: string, value: string): MetricKey +} = internal.tagged + +/** + * Returns a new `MetricKey` with the specified tags appended. + * + * @since 2.0.0 + * @category constructors + */ +export const taggedWithLabels: { + /** + * Returns a new `MetricKey` with the specified tags appended. + * + * @since 2.0.0 + * @category constructors + */ + (extraTags: ReadonlyArray): >(self: MetricKey) => MetricKey + /** + * Returns a new `MetricKey` with the specified tags appended. + * + * @since 2.0.0 + * @category constructors + */ + >(self: MetricKey, extraTags: ReadonlyArray): MetricKey +} = internal.taggedWithLabels diff --git a/backend/node_modules/effect/src/MetricLabel.ts b/backend/node_modules/effect/src/MetricLabel.ts new file mode 100644 index 0000000000000000000000000000000000000000..dddaf77096ba552666632a3e00963fb4c2553c16 --- /dev/null +++ b/backend/node_modules/effect/src/MetricLabel.ts @@ -0,0 +1,47 @@ +/** + * @since 2.0.0 + */ +import type * as Equal from "./Equal.js" +import * as internal from "./internal/metric/label.js" +import type { Pipeable } from "./Pipeable.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const MetricLabelTypeId: unique symbol = internal.MetricLabelTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type MetricLabelTypeId = typeof MetricLabelTypeId + +/** + * A `MetricLabel` represents a key value pair that allows analyzing metrics at + * an additional level of granularity. + * + * For example if a metric tracks the response time of a service labels could + * be used to create separate versions that track response times for different + * clients. + * + * @since 2.0.0 + * @category models + */ +export interface MetricLabel extends Equal.Equal, Pipeable { + readonly [MetricLabelTypeId]: MetricLabelTypeId + readonly key: string + readonly value: string +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const make: (key: string, value: string) => MetricLabel = internal.make + +/** + * @since 2.0.0 + * @category refinements + */ +export const isMetricLabel: (u: unknown) => u is MetricLabel = internal.isMetricLabel diff --git a/backend/node_modules/effect/src/MetricRegistry.ts b/backend/node_modules/effect/src/MetricRegistry.ts new file mode 100644 index 0000000000000000000000000000000000000000..e43d8519b5a1619a6e3baf61b02c60b4e5853158 --- /dev/null +++ b/backend/node_modules/effect/src/MetricRegistry.ts @@ -0,0 +1,48 @@ +/** + * @since 2.0.0 + */ +import * as internal from "./internal/metric/registry.js" +import type * as MetricHook from "./MetricHook.js" +import type * as MetricKey from "./MetricKey.js" +import type * as MetricKeyType from "./MetricKeyType.js" +import type * as MetricPair from "./MetricPair.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const MetricRegistryTypeId: unique symbol = internal.MetricRegistryTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type MetricRegistryTypeId = typeof MetricRegistryTypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface MetricRegistry { + readonly [MetricRegistryTypeId]: MetricRegistryTypeId + snapshot(): Array + get>( + key: MetricKey.MetricKey + ): MetricHook.MetricHook< + MetricKeyType.MetricKeyType.InType, + MetricKeyType.MetricKeyType.OutType + > + getCounter( + key: MetricKey.MetricKey.Counter + ): MetricHook.MetricHook.Counter + getFrequency(key: MetricKey.MetricKey.Frequency): MetricHook.MetricHook.Frequency + getGauge(key: MetricKey.MetricKey.Gauge): MetricHook.MetricHook.Gauge + getHistogram(key: MetricKey.MetricKey.Histogram): MetricHook.MetricHook.Histogram + getSummary(key: MetricKey.MetricKey.Summary): MetricHook.MetricHook.Summary +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const make: (_: void) => MetricRegistry = internal.make diff --git a/backend/node_modules/effect/src/MutableHashSet.ts b/backend/node_modules/effect/src/MutableHashSet.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad202d382d74c045f94060e0939594c7a98d6587 --- /dev/null +++ b/backend/node_modules/effect/src/MutableHashSet.ts @@ -0,0 +1,706 @@ +/** + * # MutableHashSet + * + * A mutable `MutableHashSet` provides a collection of unique values with + * efficient lookup, insertion and removal. Unlike its immutable sibling + * {@link module:HashSet}, a `MutableHashSet` can be modified in-place; + * operations like add, remove, and clear directly modify the original set + * rather than creating a new one. This mutability offers benefits like improved + * performance in scenarios where you need to build or modify a set + * incrementally. + * + * ## What Problem Does It Solve? + * + * `MutableHashSet` solves the problem of maintaining an unsorted collection + * where each value appears exactly once, with fast operations for checking + * membership and adding/removing values, in contexts where mutability is + * preferred for performance or implementation simplicity. + * + * ## When to Use + * + * Use `MutableHashSet` when you need: + * + * - A collection with no duplicate values + * - Efficient membership testing (**`O(1)`** average complexity) + * - In-place modifications for better performance + * - A set that will be built or modified incrementally + * - Local mutability in otherwise immutable code + * + * ## Advanced Features + * + * MutableHashSet provides operations for: + * + * - Adding and removing elements with direct mutation + * - Checking for element existence + * - Clearing all elements at once + * - Converting to/from other collection types + * + * ## Performance Characteristics + * + * - **Lookup** operations ({@link module:MutableHashSet.has}): **`O(1)`** average + * time complexity + * - **Insertion** operations ({@link module:MutableHashSet.add}): **`O(1)`** + * average time complexity + * - **Removal** operations ({@link module:MutableHashSet.remove}): **`O(1)`** + * average time complexity + * - **Iteration**: **`O(n)`** where n is the size of the set + * + * The MutableHashSet data structure implements the following traits: + * + * - {@link Iterable}: allows iterating over the values in the set + * - {@link Pipeable}: allows chaining operations with the pipe operator + * - {@link Inspectable}: allows inspecting the contents of the set + * + * ## Operations Reference + * + * | Category | Operation | Description | Complexity | + * | ------------ | ------------------------------------------ | ----------------------------------- | ---------- | + * | constructors | {@link module:MutableHashSet.empty} | Creates an empty MutableHashSet | O(1) | + * | constructors | {@link module:MutableHashSet.fromIterable} | Creates a set from an iterable | O(n) | + * | constructors | {@link module:MutableHashSet.make} | Creates a set from multiple values | O(n) | + * | | | | | + * | elements | {@link module:MutableHashSet.has} | Checks if a value exists in the set | O(1) avg | + * | elements | {@link module:MutableHashSet.add} | Adds a value to the set | O(1) avg | + * | elements | {@link module:MutableHashSet.remove} | Removes a value from the set | O(1) avg | + * | elements | {@link module:MutableHashSet.size} | Gets the number of elements | O(1) | + * | elements | {@link module:MutableHashSet.clear} | Removes all values from the set | O(1) | + * + * ## Notes + * + * ### Mutability Considerations: + * + * Unlike most data structures in the Effect ecosystem, `MutableHashSet` is + * mutable. This means that operations like `add`, `remove`, and `clear` modify + * the original set rather than creating a new one. This can lead to more + * efficient code in some scenarios, but requires careful handling to avoid + * unexpected side effects. + * + * ### When to Choose `MutableHashSet` vs {@link module:HashSet}: + * + * - Use `MutableHashSet` when you need to build or modify a set incrementally and + * performance is a priority + * - Use `HashSet` when you want immutability guarantees and functional + * programming patterns + * - Consider using {@link module:HashSet}'s bounded mutation context (via + * {@link module:HashSet.beginMutation}, {@link module:HashSet.endMutation}, and + * {@link module:HashSet.mutate} methods) when you need temporary mutability + * within an otherwise immutable context - this approach might be sufficient + * for many use cases without requiring a separate `MutableHashSet` + * - `MutableHashSet` is often useful for local operations where the mutability is + * contained and doesn't leak into the broader application + * + * @module MutableHashSet + * @since 2.0.0 + */ +import * as Dual from "./Function.js" +import { format, type Inspectable, NodeInspectSymbol, toJSON } from "./Inspectable.js" +import * as MutableHashMap from "./MutableHashMap.js" +import type { Pipeable } from "./Pipeable.js" +import { pipeArguments } from "./Pipeable.js" + +const TypeId: unique symbol = Symbol.for("effect/MutableHashSet") as TypeId + +/** + * @since 2.0.0 + * @category symbol + */ +export type TypeId = typeof TypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface MutableHashSet extends Iterable, Pipeable, Inspectable { + readonly [TypeId]: TypeId + + /** @internal */ + readonly keyMap: MutableHashMap.MutableHashMap +} + +const MutableHashSetProto: Omit, "keyMap"> = { + [TypeId]: TypeId, + [Symbol.iterator](this: MutableHashSet): Iterator { + return Array.from(this.keyMap) + .map(([_]) => _)[Symbol.iterator]() + }, + toString() { + return format(this.toJSON()) + }, + toJSON() { + return { + _id: "MutableHashSet", + values: Array.from(this).map(toJSON) + } + }, + [NodeInspectSymbol]() { + return this.toJSON() + }, + pipe() { + return pipeArguments(this, arguments) + } +} + +const fromHashMap = ( + keyMap: MutableHashMap.MutableHashMap +): MutableHashSet => { + const set = Object.create(MutableHashSetProto) + set.keyMap = keyMap + return set +} + +/** + * Creates an empty mutable hash set. + * + * This function initializes and returns an empty `MutableHashSet` instance, + * which allows for efficient storage and manipulation of unique elements. + * + * Time complexity: **`O(1)`** + * + * @memberof MutableHashSet + * @since 2.0.0 + * @category constructors + * @example + * + * ```ts + * import { MutableHashSet } from "effect" + * + * type T = unknown // replace with your type + * + * // in places where the type can't be inferred, replace with your type + * const set: MutableHashSet.MutableHashSet = MutableHashSet.empty() + * ``` + * + * @template K - The type of the elements to be stored in the hash set. Defaults + * to `never` if not specified. + * @returns A new mutable instance of `MutableHashSet` containing no elements + * for the specified type `K`. + * @see Other `MutableHashSet` constructors are {@link module:MutableHashSet.make} {@link module:MutableHashSet.fromIterable} + */ +export const empty = (): MutableHashSet => fromHashMap(MutableHashMap.empty()) + +/** + * Creates a new `MutableHashSet` from an iterable collection of values. + * Duplicate values are omitted. + * + * Time complexity: **`O(n)`** where n is the number of elements in the iterable + * + * Creating a `MutableHashSet` from an {@link Array} + * + * ```ts + * import { MutableHashSet } from "effect" + * + * const array: Iterable = [1, 2, 3, 4, 5, 1, 2, 3] // Array is also Iterable + * const mutableHashSet: MutableHashSet.MutableHashSet = + * MutableHashSet.fromIterable(array) + * + * console.log( + * // MutableHashSet.MutableHashSet is also an Iterable + * Array.from(mutableHashSet) + * ) // Output: [1, 2, 3, 4, 5] + * ``` + * + * Creating a `MutableHashSet` from a {@link Set} + * + * ```ts + * import { MutableHashSet, pipe } from "effect" + * + * console.log( + * pipe( + * // Set is an Iterable + * new Set(["apple", "banana", "orange", "apple"]), + * // constructs MutableHashSet from an Iterable Set + * MutableHashSet.fromIterable, + * // since MutableHashSet it is itself an Iterable, we can pass it to other functions expecting an Iterable + * Array.from + * ) + * ) // Output: ["apple", "banana", "orange"] + * ``` + * + * Creating a `MutableHashSet` from a {@link Generator} + * + * ```ts + * import { MutableHashSet } from "effect" + * + * // Generator functions return iterables + * function* fibonacci(n: number): Generator { + * let [a, b] = [0, 1] + * for (let i = 0; i < n; i++) { + * yield a + * ;[a, b] = [b, a + b] + * } + * } + * + * // Create a MutableHashSet from the first 10 Fibonacci numbers + * const fibonacciSet = MutableHashSet.fromIterable(fibonacci(10)) + * + * console.log(Array.from(fibonacciSet)) + * // Outputs: [0, 1, 2, 3, 5, 8, 13, 21, 34] but in unsorted order + * ``` + * + * Creating a `MutableHashSet` from another {@link module:MutableHashSet} + * + * ```ts + * import { MutableHashSet, pipe } from "effect" + * + * console.log( + * pipe( + * MutableHashSet.make(1, 2, 3, 4), + * MutableHashSet.fromIterable, + * Array.from + * ) + * ) // Output: [1, 2, 3, 4] + * ``` + * + * Creating a `MutableHashSet` from an {@link module:HashSet} + * + * ```ts + * import { HashSet, MutableHashSet, pipe } from "effect" + * + * console.log( + * pipe( + * HashSet.make(1, 2, 3, 4), // it works also with its immutable HashSet sibling + * MutableHashSet.fromIterable, + * Array.from + * ) + * ) // Output: [1, 2, 3, 4] + * ``` + * + * Creating a `MutableHashSet` from other Effect's data structures like + * {@link Chunk} + * + * ```ts + * import { Chunk, MutableHashSet, pipe } from "effect" + * + * console.log( + * pipe( + * Chunk.make(1, 2, 3, 4), // Chunk is also an Iterable + * MutableHashSet.fromIterable, + * Array.from + * ) + * ) // Outputs: [1, 2, 3, 4] + * ``` + * + * @memberof MutableHashSet + * @since 2.0.0 + * @category constructors + * @template K - The type of elements to be stored in the resulting + * `MutableHashSet`. + * @param keys - An `Iterable` collection containing the keys to be added to the + * `MutableHashSet`. + * @returns A new `MutableHashSet` containing just the unique elements from the + * provided iterable. + * @see Other `MutableHashSet` constructors are {@link module:MutableHashSet.empty} {@link module:MutableHashSet.make} + */ +export const fromIterable = (keys: Iterable): MutableHashSet => + fromHashMap( + MutableHashMap.fromIterable(Array.from(keys).map((k) => [k, true])) + ) + +/** + * Construct a new `MutableHashSet` from a variable number of values. + * + * Time complexity: **`O(n)`** where n is the number of elements + * + * @memberof MutableHashSet + * @since 2.0.0 + * @category constructors + * @example + * + * ```ts + * import { Equal, Hash, MutableHashSet } from "effect" + * import assert from "node:assert/strict" + * + * class Character implements Equal.Equal { + * readonly name: string + * readonly trait: string + * + * constructor(name: string, trait: string) { + * this.name = name + * this.trait = trait + * } + * + * // Define equality based on name, and trait + * [Equal.symbol](that: Equal.Equal): boolean { + * if (that instanceof Character) { + * return ( + * Equal.equals(this.name, that.name) && + * Equal.equals(this.trait, that.trait) + * ) + * } + * return false + * } + * + * // Generate a hash code based on the sum of the character's name and trait + * [Hash.symbol](): number { + * return Hash.hash(this.name + this.trait) + * } + * + * static readonly of = (name: string, trait: string): Character => { + * return new Character(name, trait) + * } + * } + * + * const mutableCharacterHashSet = MutableHashSet.make( + * Character.of("Alice", "Curious"), + * Character.of("Alice", "Curious"), + * Character.of("White Rabbit", "Always late"), + * Character.of("Mad Hatter", "Tea enthusiast") + * ) + * + * assert.equal( + * MutableHashSet.has( + * mutableCharacterHashSet, + * Character.of("Alice", "Curious") + * ), + * true + * ) + * assert.equal( + * MutableHashSet.has( + * mutableCharacterHashSet, + * Character.of("Fluffy", "Kind") + * ), + * false + * ) + * ``` + * + * @see Other `MutableHashSet` constructors are {@link module:MutableHashSet.fromIterable} {@link module:MutableHashSet.empty} + */ +export const make = >( + ...keys: Keys +): MutableHashSet => fromIterable(keys) + +/** + * **Checks** whether the `MutableHashSet` contains the given element, and + * **adds** it if not. + * + * Time complexity: **`O(1)`** average + * + * **Syntax** + * + * ```ts + * import { MutableHashSet, pipe } from "effect" + * + * // with data-last, a.k.a. pipeable API + * pipe( + * MutableHashSet.empty(), + * MutableHashSet.add(0), + * MutableHashSet.add(0) + * ) + * + * // or piped with the pipe function + * MutableHashSet.empty().pipe(MutableHashSet.add(0)) + * + * // or with data-first API + * MutableHashSet.add(MutableHashSet.empty(), 0) + * ``` + * + * @memberof MutableHashSet + * @since 2.0.0 + * @category elements + * @see Other `MutableHashSet` elements are {@link module:MutableHashSet.remove} {@link module:MutableHashSet.size} {@link module:MutableHashSet.clear} {@link module:MutableHashSet.has} + */ +export const add: { + /** + * `data-last` a.k.a. `pipeable` API + * + * ```ts + * import { MutableHashSet, pipe } from "effect" + * import assert from "node:assert/strict" + * + * const mutableHashSet = pipe( + * MutableHashSet.empty(), // MutableHashSet.MutableHashSet + * MutableHashSet.add(0), + * MutableHashSet.add(1), + * MutableHashSet.add(1), + * MutableHashSet.add(2) + * ) + * + * assert.deepStrictEqual( + * Array.from(mutableHashSet), // remember that MutableHashSet is also an Iterable + * Array.of(0, 1, 2) + * ) + * ``` + * + * @template V - The type of elements stored in the `MutableHashSet`. + * @param key - The key to be added to the `MutableHashSet` if not already + * present. + * @returns A function that accepts a `MutableHashSet` and returns the + * reference of the updated `MutableHashSet` including the key. + */ + (key: V): (self: MutableHashSet) => MutableHashSet + + /** + * `data-first` API + * + * ```ts + * import { MutableHashSet } from "effect" + * import assert from "node:assert/strict" + * + * const empty = MutableHashSet.empty() + * const withZero = MutableHashSet.add(empty, 0) + * const withOne = MutableHashSet.add(withZero, 1) + * const withTwo = MutableHashSet.add(withOne, 2) + * const withTwoTwo = MutableHashSet.add(withTwo, 2) + * + * assert(Object.is(withTwoTwo, empty)) // proof that it does mutate the original set + * + * assert.deepStrictEqual( + * Array.from(withTwoTwo), // remember that MutableHashSet is also an Iterable + * Array.of(0, 1, 2) + * ) + * ``` + * + * @template V - The type of elements stored in the `MutableHashSet`. + * @param self - The `MutableHashSet` instance from which the key should be + * added to. + * @param key - The key to be added to the `MutableHashSet` if not already + * present. + * @returns The reference of the updated `MutableHashSet` including the key. + */ + (self: MutableHashSet, key: V): MutableHashSet +} = Dual.dual< + (key: V) => (self: MutableHashSet) => MutableHashSet, + (self: MutableHashSet, key: V) => MutableHashSet +>(2, (self, key) => (MutableHashMap.set(self.keyMap, key, true), self)) + +/** + * Checks if the specified value exists in the `MutableHashSet`. + * + * Time complexity: `O(1)` average + * + * **Syntax** + * + * ```ts + * import { MutableHashSet, pipe } from "effect" + * import assert from "node:assert/strict" + * + * assert.equal( + * // with `data-last`, a.k.a. `pipeable` API + * pipe(MutableHashSet.make(0, 1, 2), MutableHashSet.has(3)), + * false + * ) + * + * assert.equal( + * // or piped with the pipe function + * MutableHashSet.make(0, 1, 2).pipe(MutableHashSet.has(3)), + * false + * ) + * + * assert.equal( + * // or with `data-first` API + * MutableHashSet.has(MutableHashSet.make(0, 1, 2), 3), + * false + * ) + * ``` + * + * @memberof MutableHashSet + * @since 2.0.0 + * @category elements + * @see Other `MutableHashSet` elements are {@link module:MutableHashSet.add} {@link module:MutableHashSet.remove} {@link module:MutableHashSet.size} {@link module:MutableHashSet.clear} + */ +export const has: { + /** + * `data-last` a.k.a. `pipeable` API + * + * ```ts + * import * as assert from "node:assert/strict" + * import { MutableHashSet, pipe } from "effect" + * + * const set = MutableHashSet.make(0, 1, 2) + * + * assert.equal(pipe(set, MutableHashSet.has(0)), true) + * assert.equal(pipe(set, MutableHashSet.has(1)), true) + * assert.equal(pipe(set, MutableHashSet.has(2)), true) + * assert.equal(pipe(set, MutableHashSet.has(3)), false) + * ``` + */ + (key: V): (self: MutableHashSet) => boolean + + /** + * `data-first` API + * + * ```ts + * import * as assert from "node:assert/strict" + * import { MutableHashSet, pipe } from "effect" + * + * const set = MutableHashSet.make(0, 1, 2) + * + * assert.equal(MutableHashSet.has(set, 0), true) + * assert.equal(MutableHashSet.has(set, 1), true) + * assert.equal(MutableHashSet.has(set, 2), true) + * assert.equal(MutableHashSet.has(set, 3), false) + * ``` + */ + (self: MutableHashSet, key: V): boolean +} = Dual.dual< + (key: V) => (self: MutableHashSet) => boolean, + (self: MutableHashSet, key: V) => boolean +>(2, (self, key) => MutableHashMap.has(self.keyMap, key)) + +/** + * Removes a value from the `MutableHashSet`. + * + * Time complexity: **`O(1)`** average + * + * **Syntax** + * + * ```ts + * import { MutableHashSet, pipe } from "effect" + * import assert from "node:assert/strict" + * + * assert.equal( + * // with `data-last`, a.k.a. `pipeable` API + * pipe( + * MutableHashSet.make(0, 1, 2), + * MutableHashSet.remove(0), + * MutableHashSet.has(0) + * ), + * false + * ) + * + * assert.equal( + * // or piped with the pipe function + * MutableHashSet.make(0, 1, 2).pipe( + * MutableHashSet.remove(0), + * MutableHashSet.has(0) + * ), + * false + * ) + * + * assert.equal( + * // or with `data-first` API + * MutableHashSet.remove(MutableHashSet.make(0, 1, 2), 0).pipe( + * MutableHashSet.has(0) + * ), + * false + * ) + * ``` + * + * @memberof MutableHashSet + * @since 2.0.0 + * @category elements + * @see Other `MutableHashSet` elements are {@link module:MutableHashSet.add} {@link module:MutableHashSet.has} {@link module:MutableHashSet.size} {@link module:MutableHashSet.clear} + */ +export const remove: { + /** + * `data-last` a.k.a. `pipeable` API + * + * ```ts + * import { MutableHashSet, pipe } from "effect" + * import assert from "node:assert/strict" + * + * const set: MutableHashSet.MutableHashSet = MutableHashSet.make( + * 0, + * 1, + * 2 + * ) + * const result: MutableHashSet.MutableHashSet = pipe( + * set, + * MutableHashSet.remove(0) + * ) + * + * assert(Object.is(set, result)) // set and result have the same identity + * assert.equal(pipe(result, MutableHashSet.has(0)), false) // it has correctly removed 0 + * assert.equal(pipe(set, MutableHashSet.has(0)), false) // another proof that we are mutating the original MutableHashSet + * assert.equal(pipe(result, MutableHashSet.has(1)), true) + * assert.equal(pipe(result, MutableHashSet.has(2)), true) + * ``` + * + * @template V - The type of the elements in the `MutableHashSet`. + * @param key - The key to be removed from the `MutableHashSet`. + * @returns A function that takes a `MutableHashSet` as input and returns the + * reference to the same `MutableHashSet` with the specified key removed. + */ + (key: V): (self: MutableHashSet) => MutableHashSet + + /** + * `data-first` API + * + * ```ts + * import { MutableHashSet, pipe } from "effect" + * import assert from "node:assert/strict" + * + * const set = MutableHashSet.make(0, 1, 2) + * const result = MutableHashSet.remove(set, 0) + * + * assert(Object.is(set, result)) // set and result have the same identity + * assert.equal(MutableHashSet.has(result, 0), false) // it has correctly removed 0 + * assert.equal(MutableHashSet.has(set, 0), false) // it mutates the original MutableHashSet + * assert.equal(MutableHashSet.has(result, 1), true) + * assert.equal(MutableHashSet.has(result, 2), true) + * ``` + * + * @template V - The type of the elements in the `MutableHashSet`. + * @param self - The `MutableHashSet` to which the key will be removed from. + * @param key - The value to be removed from the `MutableHashSet` if present. + * @returns The reference to the updated `MutableHashSet`. + */ + (self: MutableHashSet, key: V): MutableHashSet +} = Dual.dual< + (key: V) => (self: MutableHashSet) => MutableHashSet, + (self: MutableHashSet, key: V) => MutableHashSet +>(2, (self, key) => (MutableHashMap.remove(self.keyMap, key), self)) + +/** + * Calculates the number of values in the `HashSet`. + * + * Time complexity: **`O(1)`** + * + * @memberof MutableHashSet + * @since 2.0.0 + * @category elements + * @example + * + * ```ts + * import { MutableHashSet } from "effect" + * import assert from "node:assert/strict" + * + * assert.equal(MutableHashSet.size(MutableHashSet.empty()), 0) + * + * assert.equal( + * MutableHashSet.size(MutableHashSet.make(1, 2, 2, 3, 4, 3)), + * 4 + * ) + * ``` + * + * @template V - The type of the elements to be stored in the `MutableHashSet`. + * @param self - The `MutableHashSet` instance for which the size is to be + * determined. + * @returns The total number of elements within the `MutableHashSet`. + * @see Other `MutableHashSet` elements are {@link module:MutableHashSet.add} {@link module:MutableHashSet.has} {@link module:MutableHashSet.remove} {@link module:MutableHashSet.clear} + */ +export const size = (self: MutableHashSet): number => MutableHashMap.size(self.keyMap) + +/** + * Removes all values from the `MutableHashSet`. + * + * This function operates by delegating the clearing action to the underlying + * key map associated with the given `MutableHashSet`. It ensures that the hash + * set becomes empty while maintaining its existence and structure. + * + * @memberof MutableHashSet + * @since 2.0.0 + * @category elements + * @example + * + * ```ts + * import { MutableHashSet, pipe } from "effect" + * import assert from "node:assert/strict" + * + * assert.deepStrictEqual( + * pipe( + * MutableHashSet.make(1, 2, 3, 4), + * MutableHashSet.clear, + * MutableHashSet.size + * ), + * 0 + * ) + * ``` + * + * @param self - The `MutableHashSet` to clear. + * @returns The same `MutableHashSet` after all elements have been removed. + * @see Other `MutableHashSet` elements are {@link module:MutableHashSet.add} {@link module:MutableHashSet.has} {@link module:MutableHashSet.remove} {@link module:MutableHashSet.size} + */ +export const clear = (self: MutableHashSet): MutableHashSet => ( + MutableHashMap.clear(self.keyMap), self +) diff --git a/backend/node_modules/effect/src/MutableList.ts b/backend/node_modules/effect/src/MutableList.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c0be6a3d1eb8a4e5d7bf8bd11590a780d22afe2 --- /dev/null +++ b/backend/node_modules/effect/src/MutableList.ts @@ -0,0 +1,333 @@ +/** + * @since 2.0.0 + */ +import * as Dual from "./Function.js" +import { format, NodeInspectSymbol, toJSON } from "./Inspectable.js" +import type { Inspectable } from "./Inspectable.js" +import type { Pipeable } from "./Pipeable.js" +import { pipeArguments } from "./Pipeable.js" + +const TypeId: unique symbol = Symbol.for("effect/MutableList") as TypeId + +/** + * @since 2.0.0 + * @category symbol + */ +export type TypeId = typeof TypeId + +/** + * @since 2.0.0 + * @category model + */ +export interface MutableList extends Iterable, Pipeable, Inspectable { + readonly [TypeId]: TypeId + + /** @internal */ + head: LinkedListNode | undefined + /** @internal */ + tail: LinkedListNode | undefined +} + +const MutableListProto: Omit, "head" | "tail"> = { + [TypeId]: TypeId, + [Symbol.iterator](this: MutableList): Iterator { + let done = false + let head: LinkedListNode | undefined = this.head + return { + next() { + if (done) { + return this.return!() + } + if (head == null) { + done = true + return this.return!() + } + const value = head.value + head = head.next + return { done, value } + }, + return(value?: unknown) { + if (!done) { + done = true + } + return { done: true, value } + } + } + }, + toString() { + return format(this.toJSON()) + }, + toJSON() { + return { + _id: "MutableList", + values: Array.from(this).map(toJSON) + } + }, + [NodeInspectSymbol]() { + return this.toJSON() + }, + pipe() { + return pipeArguments(this, arguments) + } +} + +interface MutableListImpl extends MutableList { + _length: number +} + +/** @internal */ +interface LinkedListNode { + removed: boolean + value: T + prev: LinkedListNode | undefined + next: LinkedListNode | undefined +} + +/** @internal */ +const makeNode = (value: T): LinkedListNode => ({ + value, + removed: false, + prev: undefined, + next: undefined +}) + +/** + * Creates an empty `MutableList`. + * + * @since 2.0.0 + * @category constructors + */ +export const empty = (): MutableList => { + const list = Object.create(MutableListProto) + list.head = undefined + list.tail = undefined + list._length = 0 + return list +} + +/** + * Creates a new `MutableList` from an iterable collection of values. + * + * @since 2.0.0 + * @category constructors + */ +export const fromIterable = (iterable: Iterable): MutableList => { + const list = empty() + for (const element of iterable) { + append(list, element) + } + return list +} + +/** + * Creates a new `MutableList` from the specified elements. + * + * @since 2.0.0 + * @category constructors + */ +export const make = (...elements: ReadonlyArray): MutableList => fromIterable(elements) + +/** + * Returns `true` if the list contains zero elements, `false`, otherwise. + * + * @since 2.0.0 + * @category getters + */ +export const isEmpty = (self: MutableList): boolean => length(self) === 0 + +/** + * Returns the length of the list. + * + * @since 2.0.0 + * @category getters + */ +export const length = (self: MutableList): number => (self as MutableListImpl)._length + +/** + * Returns the last element of the list, if it exists. + * + * @since 2.0.0 + * @category getters + */ +export const tail = (self: MutableList): A | undefined => self.tail === undefined ? undefined : self.tail.value + +/** + * Returns the first element of the list, if it exists. + * + * @since 2.0.0 + * @category getters + */ +export const head = (self: MutableList): A | undefined => self.head === undefined ? undefined : self.head.value + +/** + * Executes the specified function `f` for each element in the list. + * + * @since 2.0.0 + * @category traversing + */ +export const forEach: { + /** + * Executes the specified function `f` for each element in the list. + * + * @since 2.0.0 + * @category traversing + */ + (f: (element: A) => void): (self: MutableList) => void + /** + * Executes the specified function `f` for each element in the list. + * + * @since 2.0.0 + * @category traversing + */ + (self: MutableList, f: (element: A) => void): void +} = Dual.dual< + (f: (element: A) => void) => (self: MutableList) => void, + (self: MutableList, f: (element: A) => void) => void +>(2, (self, f) => { + let current = self.head + while (current !== undefined) { + f(current.value) + current = current.next + } +}) + +/** + * Removes all elements from the doubly-linked list. + * + * @since 2.0.0 + */ +export const reset = (self: MutableList): MutableList => { + ;(self as MutableListImpl)._length = 0 + self.head = undefined + self.tail = undefined + return self +} + +/** + * Appends the specified element to the end of the `MutableList`. + * + * @category concatenating + * @since 2.0.0 + */ +export const append: { + /** + * Appends the specified element to the end of the `MutableList`. + * + * @category concatenating + * @since 2.0.0 + */ + (value: A): (self: MutableList) => MutableList + /** + * Appends the specified element to the end of the `MutableList`. + * + * @category concatenating + * @since 2.0.0 + */ + (self: MutableList, value: A): MutableList +} = Dual.dual< + (value: A) => (self: MutableList) => MutableList, + (self: MutableList, value: A) => MutableList +>(2, (self: MutableList, value: A) => { + const node = makeNode(value) + if (self.head === undefined) { + self.head = node + } + if (self.tail === undefined) { + self.tail = node + } else { + self.tail.next = node + node.prev = self.tail + self.tail = node + } + ;(self as MutableListImpl)._length += 1 + return self +}) + +/** + * Removes the first value from the list and returns it, if it exists. + * + * @since 0.0.1 + */ +export const shift = (self: MutableList): A | undefined => { + const head = self.head + if (head !== undefined) { + remove(self, head) + return head.value + } + return undefined +} + +/** + * Removes the last value from the list and returns it, if it exists. + * + * @since 0.0.1 + */ +export const pop = (self: MutableList): A | undefined => { + const tail = self.tail + if (tail !== undefined) { + remove(self, tail) + return tail.value + } + return undefined +} + +/** + * Prepends the specified value to the beginning of the list. + * + * @category concatenating + * @since 2.0.0 + */ +export const prepend: { + /** + * Prepends the specified value to the beginning of the list. + * + * @category concatenating + * @since 2.0.0 + */ + (value: A): (self: MutableList) => MutableList + /** + * Prepends the specified value to the beginning of the list. + * + * @category concatenating + * @since 2.0.0 + */ + (self: MutableList, value: A): MutableList +} = Dual.dual< + (value: A) => (self: MutableList) => MutableList, + (self: MutableList, value: A) => MutableList +>(2, (self: MutableList, value: A) => { + const node = makeNode(value) + node.next = self.head + if (self.head !== undefined) { + self.head.prev = node + } + self.head = node + if (self.tail === undefined) { + self.tail = node + } + ;(self as MutableListImpl)._length += 1 + return self +}) + +const remove = (self: MutableList, node: LinkedListNode): void => { + if (node.removed) { + return + } + node.removed = true + if (node.prev !== undefined && node.next !== undefined) { + node.prev.next = node.next + node.next.prev = node.prev + } else if (node.prev !== undefined) { + self.tail = node.prev + node.prev.next = undefined + } else if (node.next !== undefined) { + self.head = node.next + node.next.prev = undefined + } else { + self.tail = undefined + self.head = undefined + } + if ((self as MutableListImpl)._length > 0) { + ;(self as MutableListImpl)._length -= 1 + } +} diff --git a/backend/node_modules/effect/src/MutableQueue.ts b/backend/node_modules/effect/src/MutableQueue.ts new file mode 100644 index 0000000000000000000000000000000000000000..bc966eccce1ea0a8e71d00f0eb0803e949eeb9c9 --- /dev/null +++ b/backend/node_modules/effect/src/MutableQueue.ts @@ -0,0 +1,289 @@ +/** + * @since 2.0.0 + */ +import * as Chunk from "./Chunk.js" +import * as Dual from "./Function.js" +import { format, type Inspectable, NodeInspectSymbol, toJSON } from "./Inspectable.js" +import * as MutableList from "./MutableList.js" +import type { Pipeable } from "./Pipeable.js" +import { pipeArguments } from "./Pipeable.js" + +const TypeId: unique symbol = Symbol.for("effect/MutableQueue") as TypeId + +/** + * @since 2.0.0 + * @category symbol + */ +export type TypeId = typeof TypeId + +/** + * @since 2.0.0 + * @category symbol + */ +export const EmptyMutableQueue = Symbol.for("effect/mutable/MutableQueue/Empty") + +/** + * @since 2.0.0 + * @category model + */ +export interface MutableQueue extends Iterable, Pipeable, Inspectable { + readonly [TypeId]: TypeId + + /** @internal */ + queue: MutableList.MutableList + /** @internal */ + capacity: number | undefined +} + +/** + * @since 2.0.0 + */ +export declare namespace MutableQueue { + /** + * @since 2.0.0 + */ + export type Empty = typeof EmptyMutableQueue +} + +const MutableQueueProto: Omit, "queue" | "capacity"> = { + [TypeId]: TypeId, + [Symbol.iterator](this: MutableQueue): Iterator { + return Array.from(this.queue)[Symbol.iterator]() + }, + toString() { + return format(this.toJSON()) + }, + toJSON() { + return { + _id: "MutableQueue", + values: Array.from(this).map(toJSON) + } + }, + [NodeInspectSymbol]() { + return this.toJSON() + }, + pipe() { + return pipeArguments(this, arguments) + } +} + +const make = (capacity: number | undefined): MutableQueue => { + const queue = Object.create(MutableQueueProto) + queue.queue = MutableList.empty() + queue.capacity = capacity + return queue +} + +/** + * Creates a new bounded `MutableQueue`. + * + * @since 2.0.0 + * @category constructors + */ +export const bounded = (capacity: number): MutableQueue => make(capacity) + +/** + * Creates a new unbounded `MutableQueue`. + * + * @since 2.0.0 + * @category constructors + */ +export const unbounded = (): MutableQueue => make(undefined) + +/** + * Returns the current number of elements in the queue. + * + * @since 2.0.0 + * @category getters + */ +export const length = (self: MutableQueue): number => MutableList.length(self.queue) + +/** + * Returns `true` if the queue is empty, `false` otherwise. + * + * @since 2.0.0 + * @category getters + */ +export const isEmpty = (self: MutableQueue): boolean => MutableList.isEmpty(self.queue) + +/** + * Returns `true` if the queue is full, `false` otherwise. + * + * @since 2.0.0 + * @category getters + */ +export const isFull = (self: MutableQueue): boolean => + self.capacity === undefined ? false : MutableList.length(self.queue) === self.capacity + +/** + * The **maximum** number of elements that a queue can hold. + * + * **Note**: unbounded queues can still implement this interface with + * `capacity = Infinity`. + * + * @since 2.0.0 + * @category getters + */ +export const capacity = (self: MutableQueue): number => self.capacity === undefined ? Infinity : self.capacity + +/** + * Offers an element to the queue. + * + * Returns whether the enqueue was successful or not. + * + * @since 2.0.0 + */ +export const offer: { + /** + * Offers an element to the queue. + * + * Returns whether the enqueue was successful or not. + * + * @since 2.0.0 + */ + (self: MutableQueue, value: A): boolean + /** + * Offers an element to the queue. + * + * Returns whether the enqueue was successful or not. + * + * @since 2.0.0 + */ + (value: A): (self: MutableQueue) => boolean +} = Dual.dual< + (value: A) => (self: MutableQueue) => boolean, + (self: MutableQueue, value: A) => boolean +>(2, (self: MutableQueue, value: A) => { + const queueLength = MutableList.length(self.queue) + if (self.capacity !== undefined && queueLength === self.capacity) { + return false + } + MutableList.append(value)(self.queue) + return true +}) + +/** + * Enqueues a collection of values into the queue. + * + * Returns a `Chunk` of the values that were **not** able to be enqueued. + * + * @since 2.0.0 + */ +export const offerAll: { + /** + * Enqueues a collection of values into the queue. + * + * Returns a `Chunk` of the values that were **not** able to be enqueued. + * + * @since 2.0.0 + */ + (values: Iterable): (self: MutableQueue) => Chunk.Chunk + /** + * Enqueues a collection of values into the queue. + * + * Returns a `Chunk` of the values that were **not** able to be enqueued. + * + * @since 2.0.0 + */ + (self: MutableQueue, values: Iterable): Chunk.Chunk +} = Dual.dual< + (values: Iterable) => (self: MutableQueue) => Chunk.Chunk, + (self: MutableQueue, values: Iterable) => Chunk.Chunk +>(2, (self: MutableQueue, values: Iterable) => { + const iterator = values[Symbol.iterator]() + let next: IteratorResult | undefined + let remainder = Chunk.empty() + let offering = true + while (offering && (next = iterator.next()) && !next.done) { + offering = offer(next.value)(self) + } + while (next != null && !next.done) { + remainder = Chunk.prepend(next.value)(remainder) + next = iterator.next() + } + return Chunk.reverse(remainder) +}) + +/** + * Dequeues an element from the queue. + * + * Returns either an element from the queue, or the `def` param. + * + * **Note**: if there is no meaningful default for your type, you can always + * use `poll(MutableQueue.EmptyMutableQueue)`. + * + * @since 2.0.0 + */ +export const poll: { + /** + * Dequeues an element from the queue. + * + * Returns either an element from the queue, or the `def` param. + * + * **Note**: if there is no meaningful default for your type, you can always + * use `poll(MutableQueue.EmptyMutableQueue)`. + * + * @since 2.0.0 + */ + (def: D): (self: MutableQueue) => D | A + /** + * Dequeues an element from the queue. + * + * Returns either an element from the queue, or the `def` param. + * + * **Note**: if there is no meaningful default for your type, you can always + * use `poll(MutableQueue.EmptyMutableQueue)`. + * + * @since 2.0.0 + */ + (self: MutableQueue, def: D): A | D +} = Dual.dual< + (def: D) => (self: MutableQueue) => A | D, + (self: MutableQueue, def: D) => A | D +>(2, (self, def) => { + if (MutableList.isEmpty(self.queue)) { + return def + } + return MutableList.shift(self.queue)! +}) + +/** + * Dequeues up to `n` elements from the queue. + * + * Returns a `List` of up to `n` elements. + * + * @since 2.0.0 + */ +export const pollUpTo: { + /** + * Dequeues up to `n` elements from the queue. + * + * Returns a `List` of up to `n` elements. + * + * @since 2.0.0 + */ + (n: number): (self: MutableQueue) => Chunk.Chunk + /** + * Dequeues up to `n` elements from the queue. + * + * Returns a `List` of up to `n` elements. + * + * @since 2.0.0 + */ + (self: MutableQueue, n: number): Chunk.Chunk +} = Dual.dual< + (n: number) => (self: MutableQueue) => Chunk.Chunk, + (self: MutableQueue, n: number) => Chunk.Chunk +>(2, (self: MutableQueue, n: number) => { + let result = Chunk.empty() + let count = 0 + while (count < n) { + const element = poll(EmptyMutableQueue)(self) + if (element === EmptyMutableQueue) { + break + } + result = Chunk.prepend(element)(result) + count += 1 + } + return Chunk.reverse(result) +}) diff --git a/backend/node_modules/effect/src/MutableRef.ts b/backend/node_modules/effect/src/MutableRef.ts new file mode 100644 index 0000000000000000000000000000000000000000..c89f69de03a48ab0d2159e6bb28e91b58bb0db48 --- /dev/null +++ b/backend/node_modules/effect/src/MutableRef.ts @@ -0,0 +1,258 @@ +/** + * @since 2.0.0 + */ +import * as Equal from "./Equal.js" +import * as Dual from "./Function.js" +import { format, type Inspectable, NodeInspectSymbol, toJSON } from "./Inspectable.js" +import type { Pipeable } from "./Pipeable.js" +import { pipeArguments } from "./Pipeable.js" + +const TypeId: unique symbol = Symbol.for("effect/MutableRef") as TypeId + +/** + * @since 2.0.0 + * @category symbol + */ +export type TypeId = typeof TypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface MutableRef extends Pipeable, Inspectable { + readonly [TypeId]: TypeId + current: T +} + +const MutableRefProto: Omit, "current"> = { + [TypeId]: TypeId, + toString(this: MutableRef): string { + return format(this.toJSON()) + }, + toJSON(this: MutableRef) { + return { + _id: "MutableRef", + current: toJSON(this.current) + } + }, + [NodeInspectSymbol]() { + return this.toJSON() + }, + pipe() { + return pipeArguments(this, arguments) + } +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const make = (value: T): MutableRef => { + const ref = Object.create(MutableRefProto) + ref.current = value + return ref +} + +/** + * @since 2.0.0 + * @category general + */ +export const compareAndSet: { + /** + * @since 2.0.0 + * @category general + */ + (oldValue: T, newValue: T): (self: MutableRef) => boolean + /** + * @since 2.0.0 + * @category general + */ + (self: MutableRef, oldValue: T, newValue: T): boolean +} = Dual.dual< + (oldValue: T, newValue: T) => (self: MutableRef) => boolean, + (self: MutableRef, oldValue: T, newValue: T) => boolean +>(3, (self, oldValue, newValue) => { + if (Equal.equals(oldValue, self.current)) { + self.current = newValue + return true + } + return false +}) + +/** + * @since 2.0.0 + * @category numeric + */ +export const decrement = (self: MutableRef): MutableRef => update(self, (n) => n - 1) + +/** + * @since 2.0.0 + * @category numeric + */ +export const decrementAndGet = (self: MutableRef): number => updateAndGet(self, (n) => n - 1) + +/** + * @since 2.0.0 + * @category general + */ +export const get = (self: MutableRef): T => self.current + +/** + * @since 2.0.0 + * @category numeric + */ +export const getAndDecrement = (self: MutableRef): number => getAndUpdate(self, (n) => n - 1) + +/** + * @since 2.0.0 + * @category numeric + */ +export const getAndIncrement = (self: MutableRef): number => getAndUpdate(self, (n) => n + 1) + +/** + * @since 2.0.0 + * @category general + */ +export const getAndSet: { + /** + * @since 2.0.0 + * @category general + */ + (value: T): (self: MutableRef) => T + /** + * @since 2.0.0 + * @category general + */ + (self: MutableRef, value: T): T +} = Dual.dual< + (value: T) => (self: MutableRef) => T, + (self: MutableRef, value: T) => T +>(2, (self, value) => { + const ret = self.current + self.current = value + return ret +}) + +/** + * @since 2.0.0 + * @category general + */ +export const getAndUpdate: { + /** + * @since 2.0.0 + * @category general + */ + (f: (value: T) => T): (self: MutableRef) => T + /** + * @since 2.0.0 + * @category general + */ + (self: MutableRef, f: (value: T) => T): T +} = Dual.dual< + (f: (value: T) => T) => (self: MutableRef) => T, + (self: MutableRef, f: (value: T) => T) => T +>(2, (self, f) => getAndSet(self, f(get(self)))) + +/** + * @since 2.0.0 + * @category numeric + */ +export const increment = (self: MutableRef): MutableRef => update(self, (n) => n + 1) + +/** + * @since 2.0.0 + * @category numeric + */ +export const incrementAndGet = (self: MutableRef): number => updateAndGet(self, (n) => n + 1) + +/** + * @since 2.0.0 + * @category general + */ +export const set: { + /** + * @since 2.0.0 + * @category general + */ + (value: T): (self: MutableRef) => MutableRef + /** + * @since 2.0.0 + * @category general + */ + (self: MutableRef, value: T): MutableRef +} = Dual.dual< + (value: T) => (self: MutableRef) => MutableRef, + (self: MutableRef, value: T) => MutableRef +>(2, (self, value) => { + self.current = value + return self +}) + +/** + * @since 2.0.0 + * @category general + */ +export const setAndGet: { + /** + * @since 2.0.0 + * @category general + */ + (value: T): (self: MutableRef) => T + /** + * @since 2.0.0 + * @category general + */ + (self: MutableRef, value: T): T +} = Dual.dual< + (value: T) => (self: MutableRef) => T, + (self: MutableRef, value: T) => T +>(2, (self, value) => { + self.current = value + return self.current +}) + +/** + * @since 2.0.0 + * @category general + */ +export const update: { + /** + * @since 2.0.0 + * @category general + */ + (f: (value: T) => T): (self: MutableRef) => MutableRef + /** + * @since 2.0.0 + * @category general + */ + (self: MutableRef, f: (value: T) => T): MutableRef +} = Dual.dual< + (f: (value: T) => T) => (self: MutableRef) => MutableRef, + (self: MutableRef, f: (value: T) => T) => MutableRef +>(2, (self, f) => set(self, f(get(self)))) + +/** + * @since 2.0.0 + * @category general + */ +export const updateAndGet: { + /** + * @since 2.0.0 + * @category general + */ + (f: (value: T) => T): (self: MutableRef) => T + /** + * @since 2.0.0 + * @category general + */ + (self: MutableRef, f: (value: T) => T): T +} = Dual.dual< + (f: (value: T) => T) => (self: MutableRef) => T, + (self: MutableRef, f: (value: T) => T) => T +>(2, (self, f) => setAndGet(self, f(get(self)))) + +/** + * @since 2.0.0 + * @category boolean + */ +export const toggle = (self: MutableRef): MutableRef => update(self, (_) => !_) diff --git a/backend/node_modules/effect/src/ParseResult.ts b/backend/node_modules/effect/src/ParseResult.ts new file mode 100644 index 0000000000000000000000000000000000000000..ce2bb37a100e15b17102d70dde43698e6e2fec7a --- /dev/null +++ b/backend/node_modules/effect/src/ParseResult.ts @@ -0,0 +1,2068 @@ +/** + * @since 3.10.0 + */ + +import * as Arr from "./Array.js" +import * as Cause from "./Cause.js" +import { TaggedError } from "./Data.js" +import * as Effect from "./Effect.js" +import * as Either from "./Either.js" +import * as Exit from "./Exit.js" +import type { LazyArg } from "./Function.js" +import { dual } from "./Function.js" +import { globalValue } from "./GlobalValue.js" +import * as Inspectable from "./Inspectable.js" +import * as util_ from "./internal/schema/util.js" +import * as Option from "./Option.js" +import * as Predicate from "./Predicate.js" +import * as Scheduler from "./Scheduler.js" +import type * as Schema from "./Schema.js" +import * as AST from "./SchemaAST.js" +import type { Concurrency } from "./Types.js" + +/** + * `ParseIssue` is a type that represents the different types of errors that can occur when decoding/encoding a value. + * + * @category model + * @since 3.10.0 + */ +export type ParseIssue = + // leaf + | Type + | Missing + | Unexpected + | Forbidden + // composite + | Pointer + | Refinement + | Transformation + | Composite + +/** + * @category model + * @since 3.10.0 + */ +export type SingleOrNonEmpty = A | Arr.NonEmptyReadonlyArray + +/** + * @category model + * @since 3.10.0 + */ +export type Path = SingleOrNonEmpty + +/** + * @category model + * @since 3.10.0 + */ +export class Pointer { + /** + * @since 3.10.0 + */ + readonly _tag = "Pointer" + constructor( + readonly path: Path, + readonly actual: unknown, + readonly issue: ParseIssue + ) {} +} + +/** + * Error that occurs when an unexpected key or index is present. + * + * @category model + * @since 3.10.0 + */ +export class Unexpected { + /** + * @since 3.10.0 + */ + readonly _tag = "Unexpected" + constructor( + readonly actual: unknown, + /** + * @since 3.10.0 + */ + readonly message?: string + ) {} +} + +/** + * Error that occurs when a required key or index is missing. + * + * @category model + * @since 3.10.0 + */ +export class Missing { + /** + * @since 3.10.0 + */ + readonly _tag = "Missing" + /** + * @since 3.10.0 + */ + readonly actual = undefined + constructor( + /** + * @since 3.10.0 + */ + readonly ast: AST.Type, + /** + * @since 3.10.0 + */ + readonly message?: string + ) {} +} + +/** + * Error that contains multiple issues. + * + * @category model + * @since 3.10.0 + */ +export class Composite { + /** + * @since 3.10.0 + */ + readonly _tag = "Composite" + constructor( + readonly ast: AST.AST, + readonly actual: unknown, + readonly issues: SingleOrNonEmpty, + readonly output?: unknown + ) {} +} + +/** + * Error that occurs when a refinement has an error. + * + * @category model + * @since 3.10.0 + */ +export class Refinement { + /** + * @since 3.10.0 + */ + readonly _tag = "Refinement" + constructor( + readonly ast: AST.Refinement, + readonly actual: unknown, + readonly kind: "From" | "Predicate", + readonly issue: ParseIssue + ) {} +} + +/** + * Error that occurs when a transformation has an error. + * + * @category model + * @since 3.10.0 + */ +export class Transformation { + /** + * @since 3.10.0 + */ + readonly _tag = "Transformation" + constructor( + readonly ast: AST.Transformation, + readonly actual: unknown, + readonly kind: "Encoded" | "Transformation" | "Type", + readonly issue: ParseIssue + ) {} +} + +/** + * The `Type` variant of the `ParseIssue` type represents an error that occurs when the `actual` value is not of the expected type. + * The `ast` field specifies the expected type, and the `actual` field contains the value that caused the error. + * + * @category model + * @since 3.10.0 + */ +export class Type { + /** + * @since 3.10.0 + */ + readonly _tag = "Type" + constructor( + readonly ast: AST.AST, + readonly actual: unknown, + readonly message?: string + ) {} +} + +/** + * The `Forbidden` variant of the `ParseIssue` type represents a forbidden operation, such as when encountering an Effect that is not allowed to execute (e.g., using `runSync`). + * + * @category model + * @since 3.10.0 + */ +export class Forbidden { + /** + * @since 3.10.0 + */ + readonly _tag = "Forbidden" + constructor( + readonly ast: AST.AST, + readonly actual: unknown, + readonly message?: string + ) {} +} + +/** + * @category type id + * @since 3.10.0 + */ +export const ParseErrorTypeId: unique symbol = Symbol.for("effect/Schema/ParseErrorTypeId") + +/** + * @category type id + * @since 3.10.0 + */ +export type ParseErrorTypeId = typeof ParseErrorTypeId + +/** + * @since 3.10.0 + */ +export const isParseError = (u: unknown): u is ParseError => Predicate.hasProperty(u, ParseErrorTypeId) + +/** + * @since 3.10.0 + */ +export class ParseError extends TaggedError("ParseError")<{ readonly issue: ParseIssue }> { + /** + * @since 3.10.0 + */ + readonly [ParseErrorTypeId] = ParseErrorTypeId + + get message() { + return this.toString() + } + /** + * @since 3.10.0 + */ + toString() { + return TreeFormatter.formatIssueSync(this.issue) + } + /** + * @since 3.10.0 + */ + toJSON() { + return { + _id: "ParseError", + message: this.toString() + } + } + /** + * @since 3.10.0 + */ + [Inspectable.NodeInspectSymbol]() { + return this.toJSON() + } +} + +/** + * @category constructors + * @since 3.10.0 + */ +export const parseError = (issue: ParseIssue): ParseError => new ParseError({ issue }) + +/** + * @category constructors + * @since 3.10.0 + */ +export const succeed: (a: A) => Either.Either = Either.right + +/** + * @category constructors + * @since 3.10.0 + */ +export const fail: (issue: ParseIssue) => Either.Either = Either.left + +const _try: (options: { + try: LazyArg + catch: (e: unknown) => ParseIssue +}) => Either.Either = Either.try + +export { + /** + * @category constructors + * @since 3.10.0 + */ + _try as try +} + +/** + * @category constructors + * @since 3.10.0 + */ +export const fromOption: { + /** + * @category constructors + * @since 3.10.0 + */ + (onNone: () => ParseIssue): (self: Option.Option) => Either.Either + /** + * @category constructors + * @since 3.10.0 + */ + (self: Option.Option, onNone: () => ParseIssue): Either.Either +} = Either.fromOption + +const isEither: (self: Effect.Effect) => self is Either.Either = Either.isEither as any + +/** + * @category optimisation + * @since 3.10.0 + */ +export const flatMap: { + /** + * @category optimisation + * @since 3.10.0 + */ + (f: (a: A) => Effect.Effect): (self: Effect.Effect) => Effect.Effect + /** + * @category optimisation + * @since 3.10.0 + */ + (self: Effect.Effect, f: (a: A) => Effect.Effect): Effect.Effect +} = dual(2, ( + self: Effect.Effect, + f: (a: A) => Effect.Effect +): Effect.Effect => { + return isEither(self) ? + Either.match(self, { onLeft: Either.left, onRight: f }) : + Effect.flatMap(self, f) +}) + +/** + * @category optimisation + * @since 3.10.0 + */ +export const map: { + /** + * @category optimisation + * @since 3.10.0 + */ + (f: (a: A) => B): (self: Effect.Effect) => Effect.Effect + /** + * @category optimisation + * @since 3.10.0 + */ + (self: Effect.Effect, f: (a: A) => B): Effect.Effect +} = dual(2, (self: Effect.Effect, f: (a: A) => B): Effect.Effect => { + return isEither(self) ? + Either.map(self, f) : + Effect.map(self, f) +}) + +/** + * @category optimisation + * @since 3.10.0 + */ +export const mapError: { + /** + * @category optimisation + * @since 3.10.0 + */ + (f: (e: E) => E2): (self: Effect.Effect) => Effect.Effect + /** + * @category optimisation + * @since 3.10.0 + */ + (self: Effect.Effect, f: (e: E) => E2): Effect.Effect +} = dual(2, (self: Effect.Effect, f: (e: E) => E2): Effect.Effect => { + return isEither(self) ? + Either.mapLeft(self, f) : + Effect.mapError(self, f) +}) + +// TODO(4.0): remove +/** + * @category optimisation + * @since 3.10.0 + */ +export const eitherOrUndefined = ( + self: Effect.Effect +): Either.Either | undefined => { + if (isEither(self)) { + return self + } +} + +/** + * @category optimisation + * @since 3.10.0 + */ +export const mapBoth: { + /** + * @category optimisation + * @since 3.10.0 + */ + ( + options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } + ): (self: Effect.Effect) => Effect.Effect + /** + * @category optimisation + * @since 3.10.0 + */ + ( + self: Effect.Effect, + options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } + ): Effect.Effect +} = dual(2, ( + self: Effect.Effect, + options: { readonly onFailure: (e: E) => E2; readonly onSuccess: (a: A) => A2 } +): Effect.Effect => { + return isEither(self) ? + Either.mapBoth(self, { onLeft: options.onFailure, onRight: options.onSuccess }) : + Effect.mapBoth(self, options) +}) + +/** + * @category optimisation + * @since 3.10.0 + */ +export const orElse: { + /** + * @category optimisation + * @since 3.10.0 + */ + (f: (e: E) => Effect.Effect): (self: Effect.Effect) => Effect.Effect + /** + * @category optimisation + * @since 3.10.0 + */ + (self: Effect.Effect, f: (e: E) => Effect.Effect): Effect.Effect +} = dual(2, ( + self: Effect.Effect, + f: (e: E) => Effect.Effect +): Effect.Effect => { + return isEither(self) ? + Either.match(self, { onLeft: f, onRight: Either.right }) : + Effect.catchAll(self, f) +}) + +/** + * @since 3.10.0 + */ +export type DecodeUnknown = (u: unknown, options?: AST.ParseOptions) => Effect.Effect + +/** + * @since 3.10.0 + */ +export type DeclarationDecodeUnknown = ( + u: unknown, + options: AST.ParseOptions, + ast: AST.Declaration +) => Effect.Effect + +/** @internal */ +export const mergeInternalOptions = ( + options: InternalOptions | undefined, + overrideOptions: InternalOptions | number | undefined +): InternalOptions | undefined => { + if (overrideOptions === undefined || Predicate.isNumber(overrideOptions)) { + return options + } + if (options === undefined) { + return overrideOptions + } + return { ...options, ...overrideOptions } +} + +const getEither = (ast: AST.AST, isDecoding: boolean, options?: AST.ParseOptions) => { + const parser = goMemo(ast, isDecoding) + return (u: unknown, overrideOptions?: AST.ParseOptions): Either.Either => + parser(u, mergeInternalOptions(options, overrideOptions)) as any +} + +const getSync = (ast: AST.AST, isDecoding: boolean, options?: AST.ParseOptions) => { + const parser = getEither(ast, isDecoding, options) + return (input: unknown, overrideOptions?: AST.ParseOptions) => + Either.getOrThrowWith(parser(input, overrideOptions), parseError) +} + +/** @internal */ +export const getOption = (ast: AST.AST, isDecoding: boolean, options?: AST.ParseOptions) => { + const parser = getEither(ast, isDecoding, options) + return (input: unknown, overrideOptions?: AST.ParseOptions): Option.Option => + Option.getRight(parser(input, overrideOptions)) +} + +const getEffect = (ast: AST.AST, isDecoding: boolean, options?: AST.ParseOptions) => { + const parser = goMemo(ast, isDecoding) + return (input: unknown, overrideOptions?: AST.ParseOptions): Effect.Effect => + parser(input, { ...mergeInternalOptions(options, overrideOptions), isEffectAllowed: true }) +} + +/** + * @throws `ParseError` + * @category decoding + * @since 3.10.0 + */ +export const decodeUnknownSync = ( + schema: Schema.Schema, + options?: AST.ParseOptions +): (u: unknown, overrideOptions?: AST.ParseOptions) => A => getSync(schema.ast, true, options) + +/** + * @category decoding + * @since 3.10.0 + */ +export const decodeUnknownOption = ( + schema: Schema.Schema, + options?: AST.ParseOptions +): (u: unknown, overrideOptions?: AST.ParseOptions) => Option.Option => getOption(schema.ast, true, options) + +/** + * @category decoding + * @since 3.10.0 + */ +export const decodeUnknownEither = ( + schema: Schema.Schema, + options?: AST.ParseOptions +): (u: unknown, overrideOptions?: AST.ParseOptions) => Either.Either => + getEither(schema.ast, true, options) + +/** + * @category decoding + * @since 3.10.0 + */ +export const decodeUnknownPromise = ( + schema: Schema.Schema, + options?: AST.ParseOptions +) => { + const parser = decodeUnknown(schema, options) + return (u: unknown, overrideOptions?: AST.ParseOptions): Promise => Effect.runPromise(parser(u, overrideOptions)) +} + +/** + * @category decoding + * @since 3.10.0 + */ +export const decodeUnknown = ( + schema: Schema.Schema, + options?: AST.ParseOptions +): (u: unknown, overrideOptions?: AST.ParseOptions) => Effect.Effect => + getEffect(schema.ast, true, options) + +/** + * @throws `ParseError` + * @category encoding + * @since 3.10.0 + */ +export const encodeUnknownSync = ( + schema: Schema.Schema, + options?: AST.ParseOptions +): (u: unknown, overrideOptions?: AST.ParseOptions) => I => getSync(schema.ast, false, options) + +/** + * @category encoding + * @since 3.10.0 + */ +export const encodeUnknownOption = ( + schema: Schema.Schema, + options?: AST.ParseOptions +): (u: unknown, overrideOptions?: AST.ParseOptions) => Option.Option => getOption(schema.ast, false, options) + +/** + * @category encoding + * @since 3.10.0 + */ +export const encodeUnknownEither = ( + schema: Schema.Schema, + options?: AST.ParseOptions +): (u: unknown, overrideOptions?: AST.ParseOptions) => Either.Either => + getEither(schema.ast, false, options) + +/** + * @category encoding + * @since 3.10.0 + */ +export const encodeUnknownPromise = ( + schema: Schema.Schema, + options?: AST.ParseOptions +) => { + const parser = encodeUnknown(schema, options) + return (u: unknown, overrideOptions?: AST.ParseOptions): Promise => Effect.runPromise(parser(u, overrideOptions)) +} + +/** + * @category encoding + * @since 3.10.0 + */ +export const encodeUnknown = ( + schema: Schema.Schema, + options?: AST.ParseOptions +): (u: unknown, overrideOptions?: AST.ParseOptions) => Effect.Effect => + getEffect(schema.ast, false, options) + +/** + * @category decoding + * @since 3.10.0 + */ +export const decodeSync: ( + schema: Schema.Schema, + options?: AST.ParseOptions +) => (i: I, overrideOptions?: AST.ParseOptions) => A = decodeUnknownSync + +/** + * @category decoding + * @since 3.10.0 + */ +export const decodeOption: ( + schema: Schema.Schema, + options?: AST.ParseOptions +) => (i: I, overrideOptions?: AST.ParseOptions) => Option.Option = decodeUnknownOption + +/** + * @category decoding + * @since 3.10.0 + */ +export const decodeEither: ( + schema: Schema.Schema, + options?: AST.ParseOptions +) => (i: I, overrideOptions?: AST.ParseOptions) => Either.Either = decodeUnknownEither + +/** + * @category decoding + * @since 3.10.0 + */ +export const decodePromise: ( + schema: Schema.Schema, + options?: AST.ParseOptions +) => (i: I, overrideOptions?: AST.ParseOptions) => Promise = decodeUnknownPromise + +/** + * @category decoding + * @since 3.10.0 + */ +export const decode: ( + schema: Schema.Schema, + options?: AST.ParseOptions +) => (i: I, overrideOptions?: AST.ParseOptions) => Effect.Effect = decodeUnknown + +/** + * @throws `ParseError` + * @category validation + * @since 3.10.0 + */ +export const validateSync = ( + schema: Schema.Schema, + options?: AST.ParseOptions +): (u: unknown, overrideOptions?: AST.ParseOptions) => A => getSync(AST.typeAST(schema.ast), true, options) + +/** + * @category validation + * @since 3.10.0 + */ +export const validateOption = ( + schema: Schema.Schema, + options?: AST.ParseOptions +): (u: unknown, overrideOptions?: AST.ParseOptions) => Option.Option => + getOption(AST.typeAST(schema.ast), true, options) + +/** + * @category validation + * @since 3.10.0 + */ +export const validateEither = ( + schema: Schema.Schema, + options?: AST.ParseOptions +): (u: unknown, overrideOptions?: AST.ParseOptions) => Either.Either => + getEither(AST.typeAST(schema.ast), true, options) + +/** + * @category validation + * @since 3.10.0 + */ +export const validatePromise = ( + schema: Schema.Schema, + options?: AST.ParseOptions +) => { + const parser = validate(schema, options) + return (u: unknown, overrideOptions?: AST.ParseOptions): Promise => Effect.runPromise(parser(u, overrideOptions)) +} + +/** + * @category validation + * @since 3.10.0 + */ +export const validate = ( + schema: Schema.Schema, + options?: AST.ParseOptions +): (a: unknown, overrideOptions?: AST.ParseOptions) => Effect.Effect => + getEffect(AST.typeAST(schema.ast), true, options) + +/** + * By default the option `exact` is set to `true`. + * + * @category validation + * @since 3.10.0 + */ +export const is = (schema: Schema.Schema, options?: AST.ParseOptions) => { + const parser = goMemo(AST.typeAST(schema.ast), true) + return (u: unknown, overrideOptions?: AST.ParseOptions | number): u is A => + Either.isRight(parser(u, { exact: true, ...mergeInternalOptions(options, overrideOptions) }) as any) +} + +/** + * By default the option `exact` is set to `true`. + * + * @throws `ParseError` + * @category validation + * @since 3.10.0 + */ +export const asserts = (schema: Schema.Schema, options?: AST.ParseOptions) => { + const parser = goMemo(AST.typeAST(schema.ast), true) + return (u: unknown, overrideOptions?: AST.ParseOptions): asserts u is A => { + const result: Either.Either = parser(u, { + exact: true, + ...mergeInternalOptions(options, overrideOptions) + }) as any + if (Either.isLeft(result)) { + throw parseError(result.left) + } + } +} + +/** + * @category encoding + * @since 3.10.0 + */ +export const encodeSync: ( + schema: Schema.Schema, + options?: AST.ParseOptions +) => (a: A, overrideOptions?: AST.ParseOptions) => I = encodeUnknownSync + +/** + * @category encoding + * @since 3.10.0 + */ +export const encodeOption: ( + schema: Schema.Schema, + options?: AST.ParseOptions +) => (input: A, overrideOptions?: AST.ParseOptions) => Option.Option = encodeUnknownOption + +/** + * @category encoding + * @since 3.10.0 + */ +export const encodeEither: ( + schema: Schema.Schema, + options?: AST.ParseOptions +) => (a: A, overrideOptions?: AST.ParseOptions) => Either.Either = encodeUnknownEither + +/** + * @category encoding + * @since 3.10.0 + */ +export const encodePromise: ( + schema: Schema.Schema, + options?: AST.ParseOptions +) => (a: A, overrideOptions?: AST.ParseOptions) => Promise = encodeUnknownPromise + +/** + * @category encoding + * @since 3.10.0 + */ +export const encode: ( + schema: Schema.Schema, + options?: AST.ParseOptions +) => (a: A, overrideOptions?: AST.ParseOptions) => Effect.Effect = encodeUnknown + +interface InternalOptions extends AST.ParseOptions { + readonly isEffectAllowed?: boolean +} + +interface Parser { + (i: any, options?: InternalOptions): Effect.Effect +} + +const decodeMemoMap = globalValue( + Symbol.for("effect/ParseResult/decodeMemoMap"), + () => new WeakMap() +) +const encodeMemoMap = globalValue( + Symbol.for("effect/ParseResult/encodeMemoMap"), + () => new WeakMap() +) + +const goMemo = (ast: AST.AST, isDecoding: boolean): Parser => { + const memoMap = isDecoding ? decodeMemoMap : encodeMemoMap + const memo = memoMap.get(ast) + if (memo) { + return memo + } + const raw = go(ast, isDecoding) + const parseOptionsAnnotation = AST.getParseOptionsAnnotation(ast) + const parserWithOptions: Parser = Option.isSome(parseOptionsAnnotation) + ? (i, options) => raw(i, mergeInternalOptions(options, parseOptionsAnnotation.value)) + : raw + const decodingFallbackAnnotation = AST.getDecodingFallbackAnnotation(ast) + const parser: Parser = isDecoding && Option.isSome(decodingFallbackAnnotation) + ? (i, options) => + handleForbidden(orElse(parserWithOptions(i, options), decodingFallbackAnnotation.value), ast, i, options) + : parserWithOptions + memoMap.set(ast, parser) + return parser +} + +const getConcurrency = (ast: AST.AST): Concurrency | undefined => + Option.getOrUndefined(AST.getConcurrencyAnnotation(ast)) + +const getBatching = (ast: AST.AST): boolean | "inherit" | undefined => + Option.getOrUndefined(AST.getBatchingAnnotation(ast)) + +const go = (ast: AST.AST, isDecoding: boolean): Parser => { + switch (ast._tag) { + case "Refinement": { + if (isDecoding) { + const from = goMemo(ast.from, true) + return (i, options) => { + options = options ?? AST.defaultParseOption + const allErrors = options?.errors === "all" + const result = flatMap( + orElse(from(i, options), (ef) => { + const issue = new Refinement(ast, i, "From", ef) + if (allErrors && AST.hasStableFilter(ast) && isComposite(ef)) { + return Option.match( + ast.filter(i, options, ast), + { + onNone: () => Either.left(issue), + onSome: (ep) => Either.left(new Composite(ast, i, [issue, new Refinement(ast, i, "Predicate", ep)])) + } + ) + } + return Either.left(issue) + }), + (a) => + Option.match( + ast.filter(a, options, ast), + { + onNone: () => Either.right(a), + onSome: (ep) => Either.left(new Refinement(ast, i, "Predicate", ep)) + } + ) + ) + return handleForbidden(result, ast, i, options) + } + } else { + const from = goMemo(AST.typeAST(ast), true) + const to = goMemo(dropRightRefinement(ast.from), false) + return (i, options) => handleForbidden(flatMap(from(i, options), (a) => to(a, options)), ast, i, options) + } + } + case "Transformation": { + const transform = getFinalTransformation(ast.transformation, isDecoding) + const from = isDecoding ? goMemo(ast.from, true) : goMemo(ast.to, false) + const to = isDecoding ? goMemo(ast.to, true) : goMemo(ast.from, false) + return (i, options) => + handleForbidden( + flatMap( + mapError( + from(i, options), + (e) => new Transformation(ast, i, isDecoding ? "Encoded" : "Type", e) + ), + (a) => + flatMap( + mapError( + transform(a, options ?? AST.defaultParseOption, ast, i), + (e) => new Transformation(ast, i, "Transformation", e) + ), + (i2) => + mapError( + to(i2, options), + (e) => new Transformation(ast, i, isDecoding ? "Type" : "Encoded", e) + ) + ) + ), + ast, + i, + options + ) + } + case "Declaration": { + const parse = isDecoding + ? ast.decodeUnknown(...ast.typeParameters) + : ast.encodeUnknown(...ast.typeParameters) + return (i, options) => handleForbidden(parse(i, options ?? AST.defaultParseOption, ast), ast, i, options) + } + case "Literal": + return fromRefinement(ast, (u): u is typeof ast.literal => u === ast.literal) + case "UniqueSymbol": + return fromRefinement(ast, (u): u is typeof ast.symbol => u === ast.symbol) + case "UndefinedKeyword": + return fromRefinement(ast, Predicate.isUndefined) + case "NeverKeyword": + return fromRefinement(ast, Predicate.isNever) + case "UnknownKeyword": + case "AnyKeyword": + case "VoidKeyword": + return Either.right + case "StringKeyword": + return fromRefinement(ast, Predicate.isString) + case "NumberKeyword": + return fromRefinement(ast, Predicate.isNumber) + case "BooleanKeyword": + return fromRefinement(ast, Predicate.isBoolean) + case "BigIntKeyword": + return fromRefinement(ast, Predicate.isBigInt) + case "SymbolKeyword": + return fromRefinement(ast, Predicate.isSymbol) + case "ObjectKeyword": + return fromRefinement(ast, Predicate.isObject) + case "Enums": + return fromRefinement(ast, (u): u is any => ast.enums.some(([_, value]) => value === u)) + case "TemplateLiteral": { + const regex = AST.getTemplateLiteralRegExp(ast) + return fromRefinement(ast, (u): u is any => Predicate.isString(u) && regex.test(u)) + } + case "TupleType": { + const elements = ast.elements.map((e) => goMemo(e.type, isDecoding)) + const rest = ast.rest.map((annotatedAST) => goMemo(annotatedAST.type, isDecoding)) + let requiredTypes: Array = ast.elements.filter((e) => !e.isOptional) + if (ast.rest.length > 0) { + requiredTypes = requiredTypes.concat(ast.rest.slice(1)) + } + const requiredLen = requiredTypes.length + const expectedIndexes = ast.elements.length > 0 ? ast.elements.map((_, i) => i).join(" | ") : "never" + const concurrency = getConcurrency(ast) + const batching = getBatching(ast) + return (input: unknown, options) => { + if (!Arr.isArray(input)) { + return Either.left(new Type(ast, input)) + } + const allErrors = options?.errors === "all" + const es: Array<[number, ParseIssue]> = [] + let stepKey = 0 + const output: Array<[number, any]> = [] + // --------------------------------------------- + // handle missing indexes + // --------------------------------------------- + const len = input.length + for (let i = len; i <= requiredLen - 1; i++) { + const e = new Pointer(i, input, new Missing(requiredTypes[i - len])) + if (allErrors) { + es.push([stepKey++, e]) + continue + } else { + return Either.left(new Composite(ast, input, e, output)) + } + } + + // --------------------------------------------- + // handle excess indexes + // --------------------------------------------- + if (ast.rest.length === 0) { + for (let i = ast.elements.length; i <= len - 1; i++) { + const e = new Pointer(i, input, new Unexpected(input[i], `is unexpected, expected: ${expectedIndexes}`)) + if (allErrors) { + es.push([stepKey++, e]) + continue + } else { + return Either.left(new Composite(ast, input, e, output)) + } + } + } + + let i = 0 + type State = { + es: typeof es + output: typeof output + } + let queue: + | Array<(_: State) => Effect.Effect> + | undefined = undefined + + // --------------------------------------------- + // handle elements + // --------------------------------------------- + for (; i < elements.length; i++) { + if (len < i + 1) { + if (ast.elements[i].isOptional) { + // the input element is missing + continue + } + } else { + const parser = elements[i] + const te = parser(input[i], options) + if (isEither(te)) { + if (Either.isLeft(te)) { + // the input element is present but is not valid + const e = new Pointer(i, input, te.left) + if (allErrors) { + es.push([stepKey++, e]) + continue + } else { + return Either.left(new Composite(ast, input, e, sortByIndex(output))) + } + } + output.push([stepKey++, te.right]) + } else { + const nk = stepKey++ + const index = i + if (!queue) { + queue = [] + } + queue.push(({ es, output }: State) => + Effect.flatMap(Effect.either(te), (t) => { + if (Either.isLeft(t)) { + // the input element is present but is not valid + const e = new Pointer(index, input, t.left) + if (allErrors) { + es.push([nk, e]) + return Effect.void + } else { + return Either.left(new Composite(ast, input, e, sortByIndex(output))) + } + } + output.push([nk, t.right]) + return Effect.void + }) + ) + } + } + } + // --------------------------------------------- + // handle rest element + // --------------------------------------------- + if (Arr.isNonEmptyReadonlyArray(rest)) { + const [head, ...tail] = rest + for (; i < len - tail.length; i++) { + const te = head(input[i], options) + if (isEither(te)) { + if (Either.isLeft(te)) { + const e = new Pointer(i, input, te.left) + if (allErrors) { + es.push([stepKey++, e]) + continue + } else { + return Either.left(new Composite(ast, input, e, sortByIndex(output))) + } + } else { + output.push([stepKey++, te.right]) + } + } else { + const nk = stepKey++ + const index = i + if (!queue) { + queue = [] + } + queue.push( + ({ es, output }: State) => + Effect.flatMap(Effect.either(te), (t) => { + if (Either.isLeft(t)) { + const e = new Pointer(index, input, t.left) + if (allErrors) { + es.push([nk, e]) + return Effect.void + } else { + return Either.left(new Composite(ast, input, e, sortByIndex(output))) + } + } else { + output.push([nk, t.right]) + return Effect.void + } + }) + ) + } + } + // --------------------------------------------- + // handle post rest elements + // --------------------------------------------- + for (let j = 0; j < tail.length; j++) { + const index = i + j + if (len < index + 1) { + continue + } else { + const te = tail[j](input[index], options) + if (isEither(te)) { + if (Either.isLeft(te)) { + // the input element is present but is not valid + const e = new Pointer(index, input, te.left) + if (allErrors) { + es.push([stepKey++, e]) + continue + } else { + return Either.left(new Composite(ast, input, e, sortByIndex(output))) + } + } + output.push([stepKey++, te.right]) + } else { + const nk = stepKey++ + if (!queue) { + queue = [] + } + queue.push( + ({ es, output }: State) => + Effect.flatMap(Effect.either(te), (t) => { + if (Either.isLeft(t)) { + // the input element is present but is not valid + const e = new Pointer(index, input, t.left) + if (allErrors) { + es.push([nk, e]) + return Effect.void + } else { + return Either.left(new Composite(ast, input, e, sortByIndex(output))) + } + } + output.push([nk, t.right]) + return Effect.void + }) + ) + } + } + } + } + + // --------------------------------------------- + // compute result + // --------------------------------------------- + const computeResult = ({ es, output }: State) => + Arr.isNonEmptyArray(es) ? + Either.left(new Composite(ast, input, sortByIndex(es), sortByIndex(output))) : + Either.right(sortByIndex(output)) + if (queue && queue.length > 0) { + const cqueue = queue + return Effect.suspend(() => { + const state: State = { + es: Arr.copy(es), + output: Arr.copy(output) + } + return Effect.flatMap( + Effect.forEach(cqueue, (f) => f(state), { concurrency, batching, discard: true }), + () => computeResult(state) + ) + }) + } + return computeResult({ output, es }) + } + } + case "TypeLiteral": { + if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) { + return fromRefinement(ast, Predicate.isNotNullable) + } + + const propertySignatures: Array = [] + const expectedKeysMap: Record = {} + const expectedKeys: Array = [] + for (const ps of ast.propertySignatures) { + propertySignatures.push([goMemo(ps.type, isDecoding), ps]) + expectedKeysMap[ps.name] = null + expectedKeys.push(ps.name) + } + + const indexSignatures = ast.indexSignatures.map((is) => + [ + goMemo(is.parameter, isDecoding), + goMemo(is.type, isDecoding), + is.parameter + ] as const + ) + const expectedAST = AST.Union.make( + ast.indexSignatures.map((is): AST.AST => is.parameter).concat( + expectedKeys.map((key) => Predicate.isSymbol(key) ? new AST.UniqueSymbol(key) : new AST.Literal(key)) + ) + ) + const expected = goMemo(expectedAST, isDecoding) + const concurrency = getConcurrency(ast) + const batching = getBatching(ast) + return (input: unknown, options) => { + if (!Predicate.isRecord(input)) { + return Either.left(new Type(ast, input)) + } + const allErrors = options?.errors === "all" + const es: Array<[number, ParseIssue]> = [] + let stepKey = 0 + + // --------------------------------------------- + // handle excess properties + // --------------------------------------------- + const onExcessPropertyError = options?.onExcessProperty === "error" + const onExcessPropertyPreserve = options?.onExcessProperty === "preserve" + const output: Record = {} + let inputKeys: Array | undefined + if (onExcessPropertyError || onExcessPropertyPreserve) { + inputKeys = Reflect.ownKeys(input) + for (const key of inputKeys) { + const te = expected(key, options) + if (isEither(te) && Either.isLeft(te)) { + // key is unexpected + if (onExcessPropertyError) { + const e = new Pointer( + key, + input, + new Unexpected(input[key], `is unexpected, expected: ${String(expectedAST)}`) + ) + if (allErrors) { + es.push([stepKey++, e]) + continue + } else { + return Either.left(new Composite(ast, input, e, output)) + } + } else { + // preserve key + output[key] = input[key] + } + } + } + } + + // --------------------------------------------- + // handle property signatures + // --------------------------------------------- + type State = { + es: typeof es + output: typeof output + } + let queue: + | Array<(state: State) => Effect.Effect> + | undefined = undefined + + const isExact = options?.exact === true + for (let i = 0; i < propertySignatures.length; i++) { + const ps = propertySignatures[i][1] + const name = ps.name + const hasKey = Object.prototype.hasOwnProperty.call(input, name) + if (!hasKey) { + if (ps.isOptional) { + continue + } else if (isExact) { + const e = new Pointer(name, input, new Missing(ps)) + if (allErrors) { + es.push([stepKey++, e]) + continue + } else { + return Either.left(new Composite(ast, input, e, output)) + } + } + } + const parser = propertySignatures[i][0] + const te = parser(input[name], options) + if (isEither(te)) { + if (Either.isLeft(te)) { + const e = new Pointer(name, input, hasKey ? te.left : new Missing(ps)) + if (allErrors) { + es.push([stepKey++, e]) + continue + } else { + return Either.left(new Composite(ast, input, e, output)) + } + } + output[name] = te.right + } else { + const nk = stepKey++ + const index = name + if (!queue) { + queue = [] + } + queue.push( + ({ es, output }: State) => + Effect.flatMap(Effect.either(te), (t) => { + if (Either.isLeft(t)) { + const e = new Pointer(index, input, hasKey ? t.left : new Missing(ps)) + if (allErrors) { + es.push([nk, e]) + return Effect.void + } else { + return Either.left(new Composite(ast, input, e, output)) + } + } + output[index] = t.right + return Effect.void + }) + ) + } + } + + // --------------------------------------------- + // handle index signatures + // --------------------------------------------- + for (let i = 0; i < indexSignatures.length; i++) { + const indexSignature = indexSignatures[i] + const parameter = indexSignature[0] + const type = indexSignature[1] + const keys = util_.getKeysForIndexSignature(input, indexSignature[2]) + for (const key of keys) { + // --------------------------------------------- + // handle keys + // --------------------------------------------- + const keu = parameter(key, options) + if (isEither(keu) && Either.isRight(keu)) { + // --------------------------------------------- + // handle values + // --------------------------------------------- + const vpr = type(input[key], options) + if (isEither(vpr)) { + if (Either.isLeft(vpr)) { + const e = new Pointer(key, input, vpr.left) + if (allErrors) { + es.push([stepKey++, e]) + continue + } else { + return Either.left(new Composite(ast, input, e, output)) + } + } else { + if (!Object.prototype.hasOwnProperty.call(expectedKeysMap, key)) { + output[key] = vpr.right + } + } + } else { + const nk = stepKey++ + const index = key + if (!queue) { + queue = [] + } + queue.push( + ({ es, output }: State) => + Effect.flatMap( + Effect.either(vpr), + (tv) => { + if (Either.isLeft(tv)) { + const e = new Pointer(index, input, tv.left) + if (allErrors) { + es.push([nk, e]) + return Effect.void + } else { + return Either.left(new Composite(ast, input, e, output)) + } + } else { + if (!Object.prototype.hasOwnProperty.call(expectedKeysMap, key)) { + output[key] = tv.right + } + return Effect.void + } + } + ) + ) + } + } + } + } + // --------------------------------------------- + // compute result + // --------------------------------------------- + const computeResult = ({ es, output }: State) => { + if (Arr.isNonEmptyArray(es)) { + return Either.left(new Composite(ast, input, sortByIndex(es), output)) + } + if (options?.propertyOrder === "original") { + // preserve input keys order + const keys = inputKeys || Reflect.ownKeys(input) + for (const name of expectedKeys) { + if (keys.indexOf(name) === -1) { + keys.push(name) + } + } + const out: any = {} + for (const key of keys) { + if (Object.prototype.hasOwnProperty.call(output, key)) { + out[key] = output[key] + } + } + return Either.right(out) + } + return Either.right(output) + } + if (queue && queue.length > 0) { + const cqueue = queue + return Effect.suspend(() => { + const state: State = { + es: Arr.copy(es), + output: Object.assign({}, output) + } + return Effect.flatMap( + Effect.forEach(cqueue, (f) => f(state), { concurrency, batching, discard: true }), + () => computeResult(state) + ) + }) + } + return computeResult({ es, output }) + } + } + case "Union": { + const searchTree = getSearchTree(ast.types, isDecoding) + const ownKeys = Reflect.ownKeys(searchTree.keys) + const ownKeysLen = ownKeys.length + const astTypesLen = ast.types.length + const map = new Map() + for (let i = 0; i < astTypesLen; i++) { + map.set(ast.types[i], goMemo(ast.types[i], isDecoding)) + } + const concurrency = getConcurrency(ast) ?? 1 + const batching = getBatching(ast) + return (input, options) => { + const es: Array<[number, ParseIssue]> = [] + let stepKey = 0 + let candidates: Array = [] + if (ownKeysLen > 0) { + if (Predicate.isRecordOrArray(input)) { + for (let i = 0; i < ownKeysLen; i++) { + const name = ownKeys[i] + const buckets = searchTree.keys[name].buckets + // for each property that should contain a literal, check if the input contains that property + if (Object.prototype.hasOwnProperty.call(input, name)) { + const literal = String(input[name]) + // check that the value obtained from the input for the property corresponds to an existing bucket + if (Object.prototype.hasOwnProperty.call(buckets, literal)) { + // retrive the minimal set of candidates for decoding + candidates = candidates.concat(buckets[literal]) + } else { + const { candidates, literals } = searchTree.keys[name] + const literalsUnion = AST.Union.make(literals) + const errorAst = candidates.length === astTypesLen + ? new AST.TypeLiteral([new AST.PropertySignature(name, literalsUnion, false, true)], []) + : AST.Union.make(candidates) + es.push([ + stepKey++, + new Composite(errorAst, input, new Pointer(name, input, new Type(literalsUnion, input[name]))) + ]) + } + } else { + const { candidates, literals } = searchTree.keys[name] + const fakePropertySignature = new AST.PropertySignature(name, AST.Union.make(literals), false, true) + const errorAst = candidates.length === astTypesLen + ? new AST.TypeLiteral([fakePropertySignature], []) + : AST.Union.make(candidates) + es.push([ + stepKey++, + new Composite(errorAst, input, new Pointer(name, input, new Missing(fakePropertySignature))) + ]) + } + } + } else { + const errorAst = searchTree.candidates.length === astTypesLen + ? ast + : AST.Union.make(searchTree.candidates) + es.push([stepKey++, new Type(errorAst, input)]) + } + } + if (searchTree.otherwise.length > 0) { + candidates = candidates.concat(searchTree.otherwise) + } + + let queue: + | Array<(state: State) => Effect.Effect> + | undefined = undefined + + type State = { + finalResult?: any + es: typeof es + } + + for (let i = 0; i < candidates.length; i++) { + const candidate = candidates[i] + const pr = map.get(candidate)!(input, options) + // the members of a union are ordered based on which one should be decoded first, + // therefore if one member has added a task, all subsequent members must + // also add a task to the queue even if they are synchronous + if (isEither(pr) && (!queue || queue.length === 0)) { + if (Either.isRight(pr)) { + return pr + } else { + es.push([stepKey++, pr.left]) + } + } else { + const nk = stepKey++ + if (!queue) { + queue = [] + } + queue.push( + (state) => + Effect.suspend(() => { + if ("finalResult" in state) { + return Effect.void + } else { + return Effect.flatMap(Effect.either(pr), (t) => { + if (Either.isRight(t)) { + state.finalResult = t + } else { + state.es.push([nk, t.left]) + } + return Effect.void + }) + } + }) + ) + } + } + + // --------------------------------------------- + // compute result + // --------------------------------------------- + const computeResult = (es: State["es"]) => + Arr.isNonEmptyArray(es) ? + es.length === 1 && es[0][1]._tag === "Type" ? + Either.left(es[0][1]) : + Either.left(new Composite(ast, input, sortByIndex(es))) : + // this should never happen + Either.left(new Type(ast, input)) + + if (queue && queue.length > 0) { + const cqueue = queue + return Effect.suspend(() => { + const state: State = { es: Arr.copy(es) } + return Effect.flatMap( + Effect.forEach(cqueue, (f) => f(state), { concurrency, batching, discard: true }), + () => { + if ("finalResult" in state) { + return state.finalResult + } + return computeResult(state.es) + } + ) + }) + } + return computeResult(es) + } + } + case "Suspend": { + const get = util_.memoizeThunk(() => goMemo(ast.f(), isDecoding)) + return (a, options) => get()(a, options) + } + } +} + +const fromRefinement = (ast: AST.AST, refinement: (u: unknown) => u is A): Parser => (u) => + refinement(u) ? Either.right(u) : Either.left(new Type(ast, u)) + +/** @internal */ +export const getLiterals = ( + ast: AST.AST, + isDecoding: boolean +): ReadonlyArray<[PropertyKey, AST.Literal]> => { + switch (ast._tag) { + case "Declaration": { + const annotation = AST.getSurrogateAnnotation(ast) + if (Option.isSome(annotation)) { + return getLiterals(annotation.value, isDecoding) + } + break + } + case "TypeLiteral": { + const out: Array<[PropertyKey, AST.Literal]> = [] + for (let i = 0; i < ast.propertySignatures.length; i++) { + const propertySignature = ast.propertySignatures[i] + const type = isDecoding ? AST.encodedAST(propertySignature.type) : AST.typeAST(propertySignature.type) + if (AST.isLiteral(type) && !propertySignature.isOptional) { + out.push([propertySignature.name, type]) + } + } + return out + } + case "TupleType": { + const out: Array<[PropertyKey, AST.Literal]> = [] + for (let i = 0; i < ast.elements.length; i++) { + const element = ast.elements[i] + const type = isDecoding ? AST.encodedAST(element.type) : AST.typeAST(element.type) + if (AST.isLiteral(type) && !element.isOptional) { + out.push([i, type]) + } + } + return out + } + case "Refinement": + return getLiterals(ast.from, isDecoding) + case "Suspend": + return getLiterals(ast.f(), isDecoding) + case "Transformation": + return getLiterals(isDecoding ? ast.from : ast.to, isDecoding) + } + return [] +} + +/** + * The purpose of the algorithm is to narrow down the pool of possible + * candidates for decoding as much as possible. + * + * This function separates the schemas into two groups, `keys` and `otherwise`: + * + * - `keys`: the schema has at least one property with a literal value + * - `otherwise`: the schema has no properties with a literal value + * + * If a schema has at least one property with a literal value, so it ends up in + * `keys`, first a namespace is created for the name of the property containing + * the literal, and then within this namespace a "bucket" is created for the + * literal value in which to store all the schemas that have the same property + * and literal value. + * + * @internal + */ +export const getSearchTree = ( + members: ReadonlyArray, + isDecoding: boolean +): { + keys: { + readonly [key: PropertyKey]: { + buckets: { [literal: string]: ReadonlyArray } + literals: ReadonlyArray // this is for error messages + candidates: ReadonlyArray + } + } + otherwise: ReadonlyArray + candidates: ReadonlyArray +} => { + const keys: { + [key: PropertyKey]: { + buckets: { [literal: string]: Array } + literals: Array + candidates: Array + } + } = {} + const otherwise: Array = [] + const candidates: Array = [] + for (let i = 0; i < members.length; i++) { + const member = members[i] + const tags = getLiterals(member, isDecoding) + if (tags.length > 0) { + candidates.push(member) + for (let j = 0; j < tags.length; j++) { + const [key, literal] = tags[j] + const hash = String(literal.literal) + keys[key] = keys[key] || { buckets: {}, literals: [], candidates: [] } + const buckets = keys[key].buckets + if (Object.prototype.hasOwnProperty.call(buckets, hash)) { + if (j < tags.length - 1) { + continue + } + buckets[hash].push(member) + keys[key].literals.push(literal) + keys[key].candidates.push(member) + } else { + buckets[hash] = [member] + keys[key].literals.push(literal) + keys[key].candidates.push(member) + break + } + } + } else { + otherwise.push(member) + } + } + return { keys, otherwise, candidates } +} + +const dropRightRefinement = (ast: AST.AST): AST.AST => AST.isRefinement(ast) ? dropRightRefinement(ast.from) : ast + +const handleForbidden = ( + effect: Effect.Effect, + ast: AST.AST, + actual: unknown, + options: InternalOptions | undefined +): Effect.Effect => { + // If effects are allowed, return the original effect + if (options?.isEffectAllowed === true) { + return effect + } + + // If the effect is already an Either, return it directly + if (isEither(effect)) { + return effect + } + + // Otherwise, attempt to execute the effect synchronously + const scheduler = new Scheduler.SyncScheduler() + const fiber = Effect.runFork(effect as Effect.Effect, { scheduler }) + scheduler.flush() + const exit = fiber.unsafePoll() + + if (exit) { + if (Exit.isSuccess(exit)) { + // If the effect successfully resolves, wrap the value in a Right + return Either.right(exit.value) + } + const cause = exit.cause + if (Cause.isFailType(cause)) { + // The effect executed synchronously but failed due to a ParseIssue + return Either.left(cause.error) + } + // The effect executed synchronously but failed due to a defect (e.g., a missing dependency) + return Either.left(new Forbidden(ast, actual, Cause.pretty(cause))) + } + + // The effect could not be resolved synchronously, meaning it performs async work + return Either.left( + new Forbidden( + ast, + actual, + "cannot be be resolved synchronously, this is caused by using runSync on an effect that performs async work" + ) + ) +} + +const compare = ([a]: [number, ...Array], [b]: [number, ...Array]) => a > b ? 1 : a < b ? -1 : 0 + +function sortByIndex( + es: Arr.NonEmptyArray<[number, T]> +): Arr.NonEmptyArray +function sortByIndex(es: Array<[number, T]>): Array +function sortByIndex(es: Array<[number, any]>) { + return es.sort(compare).map((t) => t[1]) +} + +// ------------------------------------------------------------------------------------- +// transformations interpreter +// ------------------------------------------------------------------------------------- + +/** @internal */ +export const getFinalTransformation = ( + transformation: AST.TransformationKind, + isDecoding: boolean +): ( + fromA: any, + options: AST.ParseOptions, + self: AST.Transformation, + fromI: any +) => Effect.Effect => { + switch (transformation._tag) { + case "FinalTransformation": + return isDecoding ? transformation.decode : transformation.encode + case "ComposeTransformation": + return Either.right + case "TypeLiteralTransformation": + return (input) => { + let out: Effect.Effect = Either.right(input) + + // --------------------------------------------- + // handle property signature transformations + // --------------------------------------------- + for (const pst of transformation.propertySignatureTransformations) { + const [from, to] = isDecoding ? + [pst.from, pst.to] : + [pst.to, pst.from] + const transformation = isDecoding ? pst.decode : pst.encode + const f = (input: any) => { + const o = transformation( + Object.prototype.hasOwnProperty.call(input, from) ? + Option.some(input[from]) : + Option.none() + ) + delete input[from] + if (Option.isSome(o)) { + input[to] = o.value + } + return input + } + out = map(out, f) + } + return out + } + } +} + +// ---------------- +// Formatters +// ---------------- + +interface Forest extends ReadonlyArray> {} + +interface Tree { + readonly value: A + readonly forest: Forest +} + +const makeTree = (value: A, forest: Forest = []): Tree => ({ + value, + forest +}) + +/** + * @category formatting + * @since 3.10.0 + */ +export interface ParseResultFormatter { + readonly formatIssue: (issue: ParseIssue) => Effect.Effect + readonly formatIssueSync: (issue: ParseIssue) => A + readonly formatError: (error: ParseError) => Effect.Effect + readonly formatErrorSync: (error: ParseError) => A +} + +/** + * @category formatting + * @since 3.10.0 + */ +export const TreeFormatter: ParseResultFormatter = { + formatIssue: (issue) => map(formatTree(issue), drawTree), + formatIssueSync: (issue) => { + const e = TreeFormatter.formatIssue(issue) + return isEither(e) ? Either.getOrThrow(e) : Effect.runSync(e) + }, + formatError: (error) => TreeFormatter.formatIssue(error.issue), + formatErrorSync: (error) => TreeFormatter.formatIssueSync(error.issue) +} + +const drawTree = (tree: Tree): string => tree.value + draw("\n", tree.forest) + +const draw = (indentation: string, forest: Forest): string => { + let r = "" + const len = forest.length + let tree: Tree + for (let i = 0; i < len; i++) { + tree = forest[i] + const isLast = i === len - 1 + r += indentation + (isLast ? "└" : "├") + "─ " + tree.value + r += draw(indentation + (len > 1 && !isLast ? "│ " : " "), tree.forest) + } + return r +} + +const formatTransformationKind = (kind: Transformation["kind"]): string => { + switch (kind) { + case "Encoded": + return "Encoded side transformation failure" + case "Transformation": + return "Transformation process failure" + case "Type": + return "Type side transformation failure" + } +} + +const formatRefinementKind = (kind: Refinement["kind"]): string => { + switch (kind) { + case "From": + return "From side refinement failure" + case "Predicate": + return "Predicate refinement failure" + } +} + +const getAnnotated = (issue: ParseIssue): Option.Option => + "ast" in issue ? Option.some(issue.ast) : Option.none() + +interface CurrentMessage { + readonly message: string + readonly override: boolean +} + +// TODO: replace with Either.void when 3.13 lands +const Either_void = Either.right(undefined) + +const getCurrentMessage = (issue: ParseIssue): Effect.Effect => + getAnnotated(issue).pipe( + Option.flatMap(AST.getMessageAnnotation), + Option.match({ + onNone: () => Either_void, + onSome: (messageAnnotation) => { + const union = messageAnnotation(issue) + if (Predicate.isString(union)) { + return Either.right({ message: union, override: false }) + } + if (Effect.isEffect(union)) { + return Effect.map(union, (message) => ({ message, override: false })) + } + if (Predicate.isString(union.message)) { + return Either.right({ message: union.message, override: union.override }) + } + return Effect.map(union.message, (message) => ({ message, override: union.override })) + } + }) + ) + +const createParseIssueGuard = + (tag: T) => (issue: ParseIssue): issue is Extract => + issue._tag === tag + +/** + * Returns `true` if the value is a `Composite`. + * + * @category guards + * @since 3.10.0 + */ +export const isComposite = createParseIssueGuard("Composite") + +const isRefinement = createParseIssueGuard("Refinement") +const isTransformation = createParseIssueGuard("Transformation") + +const getMessage = (issue: ParseIssue): Effect.Effect => + flatMap(getCurrentMessage(issue), (currentMessage) => { + if (currentMessage !== undefined) { + const useInnerMessage = !currentMessage.override && ( + isComposite(issue) || + (isRefinement(issue) && issue.kind === "From") || + (isTransformation(issue) && issue.kind !== "Transformation") + ) + return useInnerMessage + ? isTransformation(issue) || isRefinement(issue) ? getMessage(issue.issue) : Either_void + : Either.right(currentMessage.message) + } + return Either_void + }) + +const getParseIssueTitleAnnotation = (issue: ParseIssue): string | undefined => + getAnnotated(issue).pipe( + Option.flatMap(AST.getParseIssueTitleAnnotation), + Option.flatMapNullable((annotation) => annotation(issue)), + Option.getOrUndefined + ) + +/** @internal */ +export function getRefinementExpected(ast: AST.Refinement): string { + return AST.getDescriptionAnnotation(ast).pipe( + Option.orElse(() => AST.getTitleAnnotation(ast)), + Option.orElse(() => AST.getAutoTitleAnnotation(ast)), + Option.orElse(() => AST.getIdentifierAnnotation(ast)), + Option.getOrElse(() => `{ ${ast.from} | filter }`) + ) +} + +function getDefaultTypeMessage(issue: Type): string { + if (issue.message !== undefined) { + return issue.message + } + const expected = AST.isRefinement(issue.ast) ? getRefinementExpected(issue.ast) : String(issue.ast) + return `Expected ${expected}, actual ${Inspectable.formatUnknown(issue.actual)}` +} + +const formatTypeMessage = (issue: Type): Effect.Effect => + map( + getMessage(issue), + (message) => message ?? getParseIssueTitleAnnotation(issue) ?? getDefaultTypeMessage(issue) + ) + +const getParseIssueTitle = ( + issue: Forbidden | Transformation | Refinement | Composite +): string => getParseIssueTitleAnnotation(issue) ?? String(issue.ast) + +const formatForbiddenMessage = (issue: Forbidden): string => issue.message ?? "is forbidden" + +const formatUnexpectedMessage = (issue: Unexpected): string => issue.message ?? "is unexpected" + +const formatMissingMessage = (issue: Missing): Effect.Effect => { + const missingMessageAnnotation = AST.getMissingMessageAnnotation(issue.ast) + if (Option.isSome(missingMessageAnnotation)) { + const annotation = missingMessageAnnotation.value() + return Predicate.isString(annotation) ? Either.right(annotation) : annotation + } + return Either.right(issue.message ?? "is missing") +} + +const formatTree = (issue: ParseIssue): Effect.Effect> => { + switch (issue._tag) { + case "Type": + return map(formatTypeMessage(issue), makeTree) + case "Forbidden": + return Either.right(makeTree(getParseIssueTitle(issue), [makeTree(formatForbiddenMessage(issue))])) + case "Unexpected": + return Either.right(makeTree(formatUnexpectedMessage(issue))) + case "Missing": + return map(formatMissingMessage(issue), makeTree) + case "Transformation": + return flatMap(getMessage(issue), (message) => { + if (message !== undefined) { + return Either.right(makeTree(message)) + } + return map( + formatTree(issue.issue), + (tree) => makeTree(getParseIssueTitle(issue), [makeTree(formatTransformationKind(issue.kind), [tree])]) + ) + }) + case "Refinement": + return flatMap(getMessage(issue), (message) => { + if (message !== undefined) { + return Either.right(makeTree(message)) + } + return map( + formatTree(issue.issue), + (tree) => makeTree(getParseIssueTitle(issue), [makeTree(formatRefinementKind(issue.kind), [tree])]) + ) + }) + case "Pointer": + return map(formatTree(issue.issue), (tree) => makeTree(util_.formatPath(issue.path), [tree])) + case "Composite": + return flatMap(getMessage(issue), (message) => { + if (message !== undefined) { + return Either.right(makeTree(message)) + } + const parseIssueTitle = getParseIssueTitle(issue) + return util_.isNonEmpty(issue.issues) + ? map(Effect.forEach(issue.issues, formatTree), (forest) => makeTree(parseIssueTitle, forest)) + : map(formatTree(issue.issues), (tree) => makeTree(parseIssueTitle, [tree])) + }) + } +} + +/** + * Represents an issue returned by the {@link ArrayFormatter} formatter. + * + * @category model + * @since 3.10.0 + */ +export interface ArrayFormatterIssue { + /** + * The tag identifying the type of parse issue. + */ + readonly _tag: ParseIssue["_tag"] + + /** + * The path to the property where the issue occurred. + */ + readonly path: ReadonlyArray + + /** + * A descriptive message explaining the issue. + */ + readonly message: string +} + +const makeArrayFormatterIssue = ( + _tag: ArrayFormatterIssue["_tag"], + path: ArrayFormatterIssue["path"], + message: ArrayFormatterIssue["message"] +): ArrayFormatterIssue => ({ _tag, path, message }) + +/** + * @category formatting + * @since 3.10.0 + */ +export const ArrayFormatter: ParseResultFormatter> = { + formatIssue: (issue) => getArrayFormatterIssues(issue, undefined, []), + formatIssueSync: (issue) => { + const e = ArrayFormatter.formatIssue(issue) + return isEither(e) ? Either.getOrThrow(e) : Effect.runSync(e) + }, + formatError: (error) => ArrayFormatter.formatIssue(error.issue), + formatErrorSync: (error) => ArrayFormatter.formatIssueSync(error.issue) +} + +const getArrayFormatterIssues = ( + issue: ParseIssue, + parentTag: ArrayFormatterIssue["_tag"] | undefined, + path: ReadonlyArray +): Effect.Effect> => { + const _tag = issue._tag + switch (_tag) { + case "Type": + return map(formatTypeMessage(issue), (message) => [makeArrayFormatterIssue(parentTag ?? _tag, path, message)]) + case "Forbidden": + return Either.right([makeArrayFormatterIssue(_tag, path, formatForbiddenMessage(issue))]) + case "Unexpected": + return Either.right([makeArrayFormatterIssue(_tag, path, formatUnexpectedMessage(issue))]) + case "Missing": + return map(formatMissingMessage(issue), (message) => [makeArrayFormatterIssue(_tag, path, message)]) + case "Pointer": + return getArrayFormatterIssues(issue.issue, undefined, path.concat(issue.path)) + case "Composite": + return flatMap(getMessage(issue), (message) => { + if (message !== undefined) { + return Either.right([makeArrayFormatterIssue(_tag, path, message)]) + } + return util_.isNonEmpty(issue.issues) + ? map(Effect.forEach(issue.issues, (issue) => getArrayFormatterIssues(issue, undefined, path)), Arr.flatten) + : getArrayFormatterIssues(issue.issues, undefined, path) + }) + case "Refinement": + return flatMap(getMessage(issue), (message) => { + if (message !== undefined) { + return Either.right([makeArrayFormatterIssue(_tag, path, message)]) + } + return getArrayFormatterIssues(issue.issue, issue.kind === "Predicate" ? _tag : undefined, path) + }) + case "Transformation": + return flatMap(getMessage(issue), (message) => { + if (message !== undefined) { + return Either.right([makeArrayFormatterIssue(_tag, path, message)]) + } + return getArrayFormatterIssues(issue.issue, issue.kind === "Transformation" ? _tag : undefined, path) + }) + } +} diff --git a/backend/node_modules/effect/src/PartitionedSemaphore.ts b/backend/node_modules/effect/src/PartitionedSemaphore.ts new file mode 100644 index 0000000000000000000000000000000000000000..3a64a4efb391cd31ea62caa3eb17b347cb4c2162 --- /dev/null +++ b/backend/node_modules/effect/src/PartitionedSemaphore.ts @@ -0,0 +1,200 @@ +/** + * @since 3.19.4 + * @experimental + */ +import * as Effect from "./Effect.js" +import * as Iterable from "./Iterable.js" +import * as MutableHashMap from "./MutableHashMap.js" +import * as Option from "./Option.js" + +/** + * @since 3.19.4 + * @category Models + * @experimental + */ +export const TypeId: TypeId = "~effect/PartitionedSemaphore" + +/** + * @since 3.19.4 + * @category Models + * @experimental + */ +export type TypeId = "~effect/PartitionedSemaphore" + +/** + * A `PartitionedSemaphore` is a concurrency primitive that can be used to + * control concurrent access to a resource across multiple partitions identified + * by keys. + * + * The total number of permits is shared across all partitions, with waiting + * permits equally distributed among partitions using a round-robin strategy. + * + * This is useful when you want to limit the total number of concurrent accesses + * to a resource, while still allowing for fair distribution of access across + * different partitions. + * + * @since 3.19.4 + * @category Models + * @experimental + */ +export interface PartitionedSemaphore { + readonly [TypeId]: TypeId + + readonly withPermits: ( + key: K, + permits: number + ) => (effect: Effect.Effect) => Effect.Effect +} + +/** + * A `PartitionedSemaphore` is a concurrency primitive that can be used to + * control concurrent access to a resource across multiple partitions identified + * by keys. + * + * The total number of permits is shared across all partitions, with waiting + * permits equally distributed among partitions using a round-robin strategy. + * + * This is useful when you want to limit the total number of concurrent accesses + * to a resource, while still allowing for fair distribution of access across + * different partitions. + * + * @since 3.19.4 + * @category Constructors + * @experimental + */ +export const makeUnsafe = (options: { + readonly permits: number +}): PartitionedSemaphore => { + const maxPermits = Math.max(0, options.permits) + + if (!Number.isFinite(maxPermits)) { + return { + [TypeId]: TypeId, + withPermits: () => (effect) => effect + } + } + + let totalPermits = maxPermits + let waitingPermits = 0 + + type Waiter = { + permits: number + readonly resume: () => void + } + const partitions = MutableHashMap.empty>() + + const take = (key: K, permits: number) => + Effect.async((resume) => { + if (maxPermits < permits) { + return resume(Effect.never) + } else if (totalPermits >= permits) { + totalPermits -= permits + return resume(Effect.void) + } + + const needed = permits - totalPermits + const taken = permits - needed + if (totalPermits > 0) { + totalPermits = 0 + } + waitingPermits += needed + + const waiters = Option.getOrElse( + MutableHashMap.get(partitions, key), + () => { + const set = new Set() + MutableHashMap.set(partitions, key, set) + return set + } + ) + + const entry: Waiter = { + permits: needed, + resume() { + cleanup() + resume(Effect.void) + } + } + function cleanup() { + waiters.delete(entry) + if (waiters.size === 0) { + MutableHashMap.remove(partitions, key) + } + } + waiters.add(entry) + return Effect.sync(() => { + cleanup() + waitingPermits -= entry.permits + if (taken > 0) { + releaseUnsafe(taken) + } + }) + }) + + let iterator = partitions[Symbol.iterator]() + const releaseUnsafe = (permits: number) => { + while (permits > 0) { + if (waitingPermits === 0) { + totalPermits += permits + return + } + + let state = iterator.next() + if (state.done) { + iterator = partitions[Symbol.iterator]() + state = iterator.next() + if (state.done) return + } + + const entry = Iterable.unsafeHead(state.value[1]) + entry.permits-- + waitingPermits-- + if (entry.permits === 0) entry.resume() + permits-- + } + } + + return { + [TypeId]: TypeId, + withPermits: (key, permits) => { + const takePermits = take(key, permits) + const release: (effect: Effect.Effect) => Effect.Effect = Effect.matchCauseEffect({ + onFailure(cause) { + releaseUnsafe(permits) + return Effect.failCause(cause) + }, + onSuccess(value) { + releaseUnsafe(permits) + return Effect.succeed(value) + } + }) + return (effect) => + Effect.uninterruptibleMask((restore) => + Effect.flatMap( + restore(takePermits), + () => release(restore(effect)) + ) + ) + } + } +} + +/** + * A `PartitionedSemaphore` is a concurrency primitive that can be used to + * control concurrent access to a resource across multiple partitions identified + * by keys. + * + * The total number of permits is shared across all partitions, with waiting + * permits equally distributed among partitions using a round-robin strategy. + * + * This is useful when you want to limit the total number of concurrent accesses + * to a resource, while still allowing for fair distribution of access across + * different partitions. + * + * @since 3.19.4 + * @category Constructors + * @experimental + */ +export const make = (options: { + readonly permits: number +}): Effect.Effect> => Effect.sync(() => makeUnsafe(options)) diff --git a/backend/node_modules/effect/src/Pool.ts b/backend/node_modules/effect/src/Pool.ts new file mode 100644 index 0000000000000000000000000000000000000000..ac19e12e0e1d7491652f62d408d868db8f36d658 --- /dev/null +++ b/backend/node_modules/effect/src/Pool.ts @@ -0,0 +1,220 @@ +/** + * @since 2.0.0 + */ +import type * as Duration from "./Duration.js" +import type * as Effect from "./Effect.js" +import * as internal from "./internal/pool.js" +import type { Pipeable } from "./Pipeable.js" +import type * as Scope from "./Scope.js" +import type * as Types from "./Types.js" +import type * as Unify from "./Unify.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const PoolTypeId: unique symbol = internal.PoolTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type PoolTypeId = typeof PoolTypeId + +/** + * A `Pool` is a pool of items of type `A`, each of which may be + * associated with the acquisition and release of resources. An attempt to get + * an item `A` from a pool may fail with an error of type `E`. + * + * @since 2.0.0 + * @category models + */ +export interface Pool extends Pool.Variance, Effect.Effect, Pipeable { + /** + * Retrieves an item from the pool in a scoped effect. Note that if + * acquisition fails, then the returned effect will fail for that same reason. + * Retrying a failed acquisition attempt will repeat the acquisition attempt. + */ + readonly get: Effect.Effect + + /** + * Invalidates the specified item. This will cause the pool to eventually + * reallocate the item, although this reallocation may occur lazily rather + * than eagerly. + */ + invalidate(item: A): Effect.Effect + + readonly [Unify.typeSymbol]?: unknown + readonly [Unify.unifySymbol]?: PoolUnify + readonly [Unify.ignoreSymbol]?: PoolUnifyIgnore +} + +/** + * @category models + * @since 3.9.0 + */ +export interface PoolUnify extends Effect.EffectUnify { + Pool?: () => Extract> extends Pool | infer _ ? + A0 extends any ? Extract> extends Pool ? Pool + : never + : never : + never +} + +/** + * @category models + * @since 3.9.0 + */ +export interface PoolUnifyIgnore extends Effect.EffectUnifyIgnore { + Effect?: true +} + +/** + * @since 2.0.0 + */ +export declare namespace Pool { + /** + * @since 2.0.0 + * @category models + */ + export interface Variance { + readonly [PoolTypeId]: { + readonly _A: Types.Invariant + readonly _E: Types.Covariant + } + } +} + +/** + * Returns `true` if the specified value is a `Pool`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isPool: (u: unknown) => u is Pool = internal.isPool + +/** + * Makes a new pool of the specified fixed size. The pool is returned in a + * `Scope`, which governs the lifetime of the pool. When the pool is shutdown + * because the `Scope` is closed, the individual items allocated by the pool + * will be released in some unspecified order. + * + * By setting the `concurrency` parameter, you can control the level of concurrent + * access per pool item. By default, the number of permits is set to `1`. + * + * `targetUtilization` determines when to create new pool items. It is a value + * between 0 and 1, where 1 means only create new pool items when all the existing + * items are fully utilized. + * + * A `targetUtilization` of 0.5 will create new pool items when the existing items are + * 50% utilized. + * + * @since 2.0.0 + * @category constructors + */ +export const make: ( + options: { + readonly acquire: Effect.Effect + readonly size: number + readonly concurrency?: number | undefined + readonly targetUtilization?: number | undefined + } +) => Effect.Effect, never, Scope.Scope | R> = internal.make + +/** + * Makes a new pool with the specified minimum and maximum sizes and time to + * live before a pool whose excess items are not being used will be shrunk + * down to the minimum size. The pool is returned in a `Scope`, which governs + * the lifetime of the pool. When the pool is shutdown because the `Scope` is + * used, the individual items allocated by the pool will be released in some + * unspecified order. + * + * By setting the `concurrency` parameter, you can control the level of concurrent + * access per pool item. By default, the number of permits is set to `1`. + * + * `targetUtilization` determines when to create new pool items. It is a value + * between 0 and 1, where 1 means only create new pool items when all the existing + * items are fully utilized. + * + * A `targetUtilization` of 0.5 will create new pool items when the existing items are + * 50% utilized. + * + * The `timeToLiveStrategy` determines how items are invalidated. If set to + * "creation", then items are invalidated based on their creation time. If set + * to "usage", then items are invalidated based on pool usage. + * + * By default, the `timeToLiveStrategy` is set to "usage". + * + * ```ts skip-type-checking + * import { createConnection } from "mysql2"; + * import { Duration, Effect, Pool } from "effect" + * + * const acquireDBConnection = Effect.acquireRelease( + * Effect.sync(() => createConnection('mysql://...')), + * (connection) => Effect.sync(() => connection.end(() => {})), + * ) + * + * const connectionPool = Effect.flatMap( + * Pool.makeWithTTL({ + * acquire: acquireDBConnection, + * min: 10, + * max: 20, + * timeToLive: Duration.seconds(60) + * }), + * (pool) => pool.get + * ) + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export const makeWithTTL: ( + options: { + readonly acquire: Effect.Effect + readonly min: number + readonly max: number + readonly concurrency?: number | undefined + readonly targetUtilization?: number | undefined + readonly timeToLive: Duration.DurationInput + readonly timeToLiveStrategy?: "creation" | "usage" | undefined + } +) => Effect.Effect, never, Scope.Scope | R> = internal.makeWithTTL + +/** + * Retrieves an item from the pool in a scoped effect. Note that if + * acquisition fails, then the returned effect will fail for that same reason. + * Retrying a failed acquisition attempt will repeat the acquisition attempt. + * + * @since 2.0.0 + * @category getters + */ +export const get: (self: Pool) => Effect.Effect = internal.get + +/** + * Invalidates the specified item. This will cause the pool to eventually + * reallocate the item, although this reallocation may occur lazily rather + * than eagerly. + * + * @since 2.0.0 + * @category combinators + */ +export const invalidate: { + /** + * Invalidates the specified item. This will cause the pool to eventually + * reallocate the item, although this reallocation may occur lazily rather + * than eagerly. + * + * @since 2.0.0 + * @category combinators + */ + (value: A): (self: Pool) => Effect.Effect + /** + * Invalidates the specified item. This will cause the pool to eventually + * reallocate the item, although this reallocation may occur lazily rather + * than eagerly. + * + * @since 2.0.0 + * @category combinators + */ + (self: Pool, value: A): Effect.Effect +} = internal.invalidate diff --git a/backend/node_modules/effect/src/Queue.ts b/backend/node_modules/effect/src/Queue.ts new file mode 100644 index 0000000000000000000000000000000000000000..b2709577c7008bace3c959a4b77b2b3dfa423058 --- /dev/null +++ b/backend/node_modules/effect/src/Queue.ts @@ -0,0 +1,748 @@ +/** + * @since 2.0.0 + */ +import type * as Chunk from "./Chunk.js" +import type * as Deferred from "./Deferred.js" +import type * as Effect from "./Effect.js" +import * as internal from "./internal/queue.js" +import type * as MutableQueue from "./MutableQueue.js" +import type * as MutableRef from "./MutableRef.js" +import type * as Option from "./Option.js" +import type { Pipeable } from "./Pipeable.js" +import type * as Types from "./Types.js" +import type * as Unify from "./Unify.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const EnqueueTypeId: unique symbol = internal.EnqueueTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type EnqueueTypeId = typeof EnqueueTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export const DequeueTypeId: unique symbol = internal.DequeueTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type DequeueTypeId = typeof DequeueTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export const QueueStrategyTypeId: unique symbol = internal.QueueStrategyTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type QueueStrategyTypeId = typeof QueueStrategyTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export const BackingQueueTypeId: unique symbol = internal.BackingQueueTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type BackingQueueTypeId = typeof BackingQueueTypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface Queue extends Enqueue, Dequeue { + /** @internal */ + readonly queue: BackingQueue + /** @internal */ + readonly takers: MutableQueue.MutableQueue> + /** @internal */ + readonly shutdownHook: Deferred.Deferred + /** @internal */ + readonly shutdownFlag: MutableRef.MutableRef + /** @internal */ + readonly strategy: Strategy + + readonly [Unify.typeSymbol]?: unknown + readonly [Unify.unifySymbol]?: QueueUnify + readonly [Unify.ignoreSymbol]?: QueueUnifyIgnore +} + +/** + * @category models + * @since 3.8.0 + */ +export interface QueueUnify extends DequeueUnify { + Queue?: () => Extract> +} + +/** + * @category models + * @since 3.8.0 + */ +export interface QueueUnifyIgnore extends DequeueUnifyIgnore { + Dequeue?: true +} + +/** + * @since 2.0.0 + * @category models + */ +export interface Enqueue extends Queue.EnqueueVariance, BaseQueue, Pipeable { + /** + * Places one value in the queue. + */ + offer(value: A): Effect.Effect + + /** + * Places one value in the queue when possible without needing the fiber runtime. + */ + unsafeOffer(value: A): boolean + + /** + * For Bounded Queue: uses the `BackPressure` Strategy, places the values in + * the queue and always returns true. If the queue has reached capacity, then + * the fiber performing the `offerAll` will be suspended until there is room + * in the queue. + * + * For Unbounded Queue: Places all values in the queue and returns true. + * + * For Sliding Queue: uses `Sliding` Strategy If there is room in the queue, + * it places the values otherwise it removes the old elements and enqueues the + * new ones. Always returns true. + * + * For Dropping Queue: uses `Dropping` Strategy, It places the values in the + * queue but if there is no room it will not enqueue them and return false. + */ + offerAll(iterable: Iterable): Effect.Effect +} + +/** + * @since 2.0.0 + * @category models + */ +export interface Dequeue extends Effect.Effect, Queue.DequeueVariance, BaseQueue { + /** + * Takes the oldest value in the queue. If the queue is empty, this will return + * a computation that resumes when an item has been added to the queue. + */ + readonly take: Effect.Effect + + /** + * Takes all the values in the queue and returns the values. If the queue is + * empty returns an empty collection. + */ + readonly takeAll: Effect.Effect> + + /** + * Takes up to max number of values from the queue. + */ + takeUpTo(max: number): Effect.Effect> + + /** + * Takes a number of elements from the queue between the specified minimum and + * maximum. If there are fewer than the minimum number of elements available, + * suspends until at least the minimum number of elements have been collected. + */ + takeBetween(min: number, max: number): Effect.Effect> + + readonly [Unify.typeSymbol]?: unknown + readonly [Unify.unifySymbol]?: DequeueUnify + readonly [Unify.ignoreSymbol]?: DequeueUnifyIgnore +} + +/** + * @category models + * @since 3.8.0 + */ +export interface DequeueUnify extends Effect.EffectUnify { + Dequeue?: () => A[Unify.typeSymbol] extends Dequeue | infer _ ? Dequeue : never +} + +/** + * @category models + * @since 3.8.0 + */ +export interface DequeueUnifyIgnore extends Effect.EffectUnifyIgnore { + Effect?: true +} + +/** + * The base interface that all `Queue`s must implement. + * + * @since 2.0.0 + * @category models + */ +export interface BaseQueue { + /** + * Returns the number of elements the queue can hold. + */ + capacity(): number + + /** + * Returns false if shutdown has been called. + */ + isActive(): boolean + + /** + * Retrieves the size of the queue, which is equal to the number of elements + * in the queue. This may be negative if fibers are suspended waiting for + * elements to be added to the queue. + */ + readonly size: Effect.Effect + + /** + * Retrieves the size of the queue, which is equal to the number of elements + * in the queue. This may be negative if fibers are suspended waiting for + * elements to be added to the queue. Returns None if shutdown has been called + */ + unsafeSize(): Option.Option + + /** + * Returns `true` if the `Queue` contains at least one element, `false` + * otherwise. + */ + readonly isFull: Effect.Effect + + /** + * Returns `true` if the `Queue` contains zero elements, `false` otherwise. + */ + readonly isEmpty: Effect.Effect + + /** + * Interrupts any fibers that are suspended on `offer` or `take`. Future calls + * to `offer*` and `take*` will be interrupted immediately. + */ + readonly shutdown: Effect.Effect + + /** + * Returns `true` if `shutdown` has been called, otherwise returns `false`. + */ + readonly isShutdown: Effect.Effect + + /** + * Waits until the queue is shutdown. The `Effect` returned by this method will + * not resume until the queue has been shutdown. If the queue is already + * shutdown, the `Effect` will resume right away. + */ + readonly awaitShutdown: Effect.Effect +} + +/** + * @since 2.0.0 + * @category models + */ +export interface Strategy extends Queue.StrategyVariance { + /** + * Returns the number of surplus values that were unable to be added to the + * `Queue` + */ + surplusSize(): number + + /** + * Determines how the `Queue.Strategy` should shut down when the `Queue` is + * shut down. + */ + readonly shutdown: Effect.Effect + + /** + * Determines the behavior of the `Queue.Strategy` when there are surplus + * values that could not be added to the `Queue` following an `offer` + * operation. + */ + handleSurplus( + iterable: Iterable, + queue: BackingQueue, + takers: MutableQueue.MutableQueue>, + isShutdown: MutableRef.MutableRef + ): Effect.Effect + + /** + * It is called when the backing queue is empty but there are some + * takers that can be completed + */ + onCompleteTakersWithEmptyQueue( + takers: MutableQueue.MutableQueue> + ): void + + /** + * Determines the behavior of the `Queue.Strategy` when the `Queue` has empty + * slots following a `take` operation. + */ + unsafeOnQueueEmptySpace( + queue: BackingQueue, + takers: MutableQueue.MutableQueue> + ): void +} + +/** + * @since 2.0.0 + * @category models + */ +export interface BackingQueue extends Queue.BackingQueueVariance { + /** + * Dequeues an element from the queue. + * Returns either an element from the queue, or the `def` param. + */ + poll(def: Def): A | Def + /** + * Dequeues up to `limit` elements from the queue. + */ + pollUpTo(limit: number): Chunk.Chunk + /** + * Enqueues a collection of values into the queue. + * + * Returns a `Chunk` of the values that were **not** able to be enqueued. + */ + offerAll(elements: Iterable): Chunk.Chunk + /** + * Offers an element to the queue. + * + * Returns whether the enqueue was successful or not. + */ + offer(element: A): boolean + /** + * The **maximum** number of elements that a queue can hold. + * + * **Note**: unbounded queues can still implement this interface with + * `capacity = Infinity`. + */ + capacity(): number + /** + * Returns the number of elements currently in the queue + */ + length(): number +} + +/** + * @since 2.0.0 + */ +export declare namespace Queue { + /** + * @since 2.0.0 + * @category models + */ + export interface EnqueueVariance { + readonly [EnqueueTypeId]: { + readonly _In: Types.Contravariant + } + } + + /** + * @since 2.0.0 + * @category models + */ + export interface DequeueVariance { + readonly [DequeueTypeId]: { + readonly _Out: Types.Covariant + } + } + + /** + * @since 2.0.0 + * @category models + */ + export interface StrategyVariance { + readonly [QueueStrategyTypeId]: { + readonly _A: Types.Invariant + } + } + + /** + * @since 2.0.0 + * @category models + */ + export interface BackingQueueVariance { + readonly [BackingQueueTypeId]: { + readonly _A: Types.Invariant + } + } +} + +/** + * Returns `true` if the specified value is a `Queue`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isQueue: (u: unknown) => u is Queue = internal.isQueue + +/** + * Returns `true` if the specified value is a `Dequeue`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isDequeue: (u: unknown) => u is Dequeue = internal.isDequeue + +/** + * Returns `true` if the specified value is a `Enqueue`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isEnqueue: (u: unknown) => u is Enqueue = internal.isEnqueue + +/** + * @since 2.0.0 + * @category strategies + */ +export const backPressureStrategy: () => Strategy = internal.backPressureStrategy + +/** + * @since 2.0.0 + * @category strategies + */ +export const droppingStrategy: () => Strategy = internal.droppingStrategy + +/** + * @since 2.0.0 + * @category strategies + */ +export const slidingStrategy: () => Strategy = internal.slidingStrategy + +/** + * @since 2.0.0 + * @category constructors + */ +export const make: (queue: BackingQueue, strategy: Strategy) => Effect.Effect> = internal.make + +/** + * Makes a new bounded `Queue`. When the capacity of the queue is reached, any + * additional calls to `offer` will be suspended until there is more room in + * the queue. + * + * **Note**: When possible use only power of 2 capacities; this will provide + * better performance by utilising an optimised version of the underlying + * `RingBuffer`. + * + * @since 2.0.0 + * @category constructors + */ +export const bounded: (requestedCapacity: number) => Effect.Effect> = internal.bounded + +/** + * Makes a new bounded `Queue` with the dropping strategy. + * + * When the capacity of the queue is reached, new elements will be dropped and the + * old elements will remain. + * + * **Note**: When possible use only power of 2 capacities; this will provide + * better performance by utilising an optimised version of the underlying + * `RingBuffer`. + * + * @since 2.0.0 + * @category constructors + */ +export const dropping: (requestedCapacity: number) => Effect.Effect> = internal.dropping + +/** + * Makes a new bounded `Queue` with the sliding strategy. + * + * When the capacity of the queue is reached, new elements will be added and the + * old elements will be dropped. + * + * **Note**: When possible use only power of 2 capacities; this will provide + * better performance by utilising an optimised version of the underlying + * `RingBuffer`. + * + * @since 2.0.0 + * @category constructors + */ +export const sliding: (requestedCapacity: number) => Effect.Effect> = internal.sliding + +/** + * Creates a new unbounded `Queue`. + * + * @since 2.0.0 + * @category constructors + */ +export const unbounded: () => Effect.Effect> = internal.unbounded + +/** + * Returns the number of elements the queue can hold. + * + * @since 2.0.0 + * @category getters + */ +export const capacity: (self: Dequeue | Enqueue) => number = internal.capacity + +/** + * Retrieves the size of the queue, which is equal to the number of elements + * in the queue. This may be negative if fibers are suspended waiting for + * elements to be added to the queue. + * + * @since 2.0.0 + * @category getters + */ +export const size: (self: Dequeue | Enqueue) => Effect.Effect = internal.size + +/** + * Returns `true` if the `Queue` contains zero elements, `false` otherwise. + * + * @since 2.0.0 + * @category getters + */ +export const isEmpty: (self: Dequeue | Enqueue) => Effect.Effect = internal.isEmpty + +/** + * Returns `true` if the `Queue` contains at least one element, `false` + * otherwise. + * + * @since 2.0.0 + * @category getters + */ +export const isFull: (self: Dequeue | Enqueue) => Effect.Effect = internal.isFull + +/** + * Returns `true` if `shutdown` has been called, otherwise returns `false`. + * + * @since 2.0.0 + * @category getters + */ +export const isShutdown: (self: Dequeue | Enqueue) => Effect.Effect = internal.isShutdown + +/** + * Waits until the queue is shutdown. The `Effect` returned by this method will + * not resume until the queue has been shutdown. If the queue is already + * shutdown, the `Effect` will resume right away. + * + * @since 2.0.0 + * @category utils + */ +export const awaitShutdown: (self: Dequeue | Enqueue) => Effect.Effect = internal.awaitShutdown + +/** + * Interrupts any fibers that are suspended on `offer` or `take`. Future calls + * to `offer*` and `take*` will be interrupted immediately. + * + * @since 2.0.0 + * @category utils + */ +export const shutdown: (self: Dequeue | Enqueue) => Effect.Effect = internal.shutdown + +/** + * Places one value in the queue. + * + * @since 2.0.0 + * @category utils + */ +export const offer: { + /** + * Places one value in the queue. + * + * @since 2.0.0 + * @category utils + */ + (value: A): (self: Enqueue) => Effect.Effect + /** + * Places one value in the queue. + * + * @since 2.0.0 + * @category utils + */ + (self: Enqueue, value: A): Effect.Effect +} = internal.offer + +/** + * Places one value in the queue. + * + * @since 2.0.0 + * @category utils + */ +export const unsafeOffer: { + /** + * Places one value in the queue. + * + * @since 2.0.0 + * @category utils + */ + (value: A): (self: Enqueue) => boolean + /** + * Places one value in the queue. + * + * @since 2.0.0 + * @category utils + */ + (self: Enqueue, value: A): boolean +} = internal.unsafeOffer + +/** + * For Bounded Queue: uses the `BackPressure` Strategy, places the values in + * the queue and always returns true. If the queue has reached capacity, then + * the fiber performing the `offerAll` will be suspended until there is room + * in the queue. + * + * For Unbounded Queue: Places all values in the queue and returns true. + * + * For Sliding Queue: uses `Sliding` Strategy If there is room in the queue, + * it places the values otherwise it removes the old elements and enqueues the + * new ones. Always returns true. + * + * For Dropping Queue: uses `Dropping` Strategy, It places the values in the + * queue but if there is no room it will not enqueue them and return false. + * + * @since 2.0.0 + * @category utils + */ +export const offerAll: { + /** + * For Bounded Queue: uses the `BackPressure` Strategy, places the values in + * the queue and always returns true. If the queue has reached capacity, then + * the fiber performing the `offerAll` will be suspended until there is room + * in the queue. + * + * For Unbounded Queue: Places all values in the queue and returns true. + * + * For Sliding Queue: uses `Sliding` Strategy If there is room in the queue, + * it places the values otherwise it removes the old elements and enqueues the + * new ones. Always returns true. + * + * For Dropping Queue: uses `Dropping` Strategy, It places the values in the + * queue but if there is no room it will not enqueue them and return false. + * + * @since 2.0.0 + * @category utils + */ + (iterable: Iterable): (self: Enqueue) => Effect.Effect + /** + * For Bounded Queue: uses the `BackPressure` Strategy, places the values in + * the queue and always returns true. If the queue has reached capacity, then + * the fiber performing the `offerAll` will be suspended until there is room + * in the queue. + * + * For Unbounded Queue: Places all values in the queue and returns true. + * + * For Sliding Queue: uses `Sliding` Strategy If there is room in the queue, + * it places the values otherwise it removes the old elements and enqueues the + * new ones. Always returns true. + * + * For Dropping Queue: uses `Dropping` Strategy, It places the values in the + * queue but if there is no room it will not enqueue them and return false. + * + * @since 2.0.0 + * @category utils + */ + (self: Enqueue, iterable: Iterable): Effect.Effect +} = internal.offerAll + +/** + * Returns the first value in the `Queue` as a `Some`, or `None` if the queue + * is empty. + * + * @since 2.0.0 + * @category utils + */ +export const poll: (self: Dequeue) => Effect.Effect> = internal.poll + +/** + * Takes the oldest value in the queue. If the queue is empty, this will return + * a computation that resumes when an item has been added to the queue. + * + * @since 2.0.0 + * @category utils + */ +export const take: (self: Dequeue) => Effect.Effect = internal.take + +/** + * Takes all the values in the queue and returns the values. If the queue is + * empty returns an empty collection. + * + * @since 2.0.0 + * @category utils + */ +export const takeAll: (self: Dequeue) => Effect.Effect> = internal.takeAll + +/** + * Takes up to max number of values from the queue. + * + * @since 2.0.0 + * @category utils + */ +export const takeUpTo: { + /** + * Takes up to max number of values from the queue. + * + * @since 2.0.0 + * @category utils + */ + (max: number): (self: Dequeue) => Effect.Effect> + /** + * Takes up to max number of values from the queue. + * + * @since 2.0.0 + * @category utils + */ + (self: Dequeue, max: number): Effect.Effect> +} = internal.takeUpTo + +/** + * Takes a number of elements from the queue between the specified minimum and + * maximum. If there are fewer than the minimum number of elements available, + * suspends until at least the minimum number of elements have been collected. + * + * @since 2.0.0 + * @category utils + */ +export const takeBetween: { + /** + * Takes a number of elements from the queue between the specified minimum and + * maximum. If there are fewer than the minimum number of elements available, + * suspends until at least the minimum number of elements have been collected. + * + * @since 2.0.0 + * @category utils + */ + (min: number, max: number): (self: Dequeue) => Effect.Effect> + /** + * Takes a number of elements from the queue between the specified minimum and + * maximum. If there are fewer than the minimum number of elements available, + * suspends until at least the minimum number of elements have been collected. + * + * @since 2.0.0 + * @category utils + */ + (self: Dequeue, min: number, max: number): Effect.Effect> +} = internal.takeBetween + +/** + * Takes the specified number of elements from the queue. If there are fewer + * than the specified number of elements available, it suspends until they + * become available. + * + * @since 2.0.0 + * @category utils + */ +export const takeN: { + /** + * Takes the specified number of elements from the queue. If there are fewer + * than the specified number of elements available, it suspends until they + * become available. + * + * @since 2.0.0 + * @category utils + */ + (n: number): (self: Dequeue) => Effect.Effect> + /** + * Takes the specified number of elements from the queue. If there are fewer + * than the specified number of elements available, it suspends until they + * become available. + * + * @since 2.0.0 + * @category utils + */ + (self: Dequeue, n: number): Effect.Effect> +} = internal.takeN diff --git a/backend/node_modules/effect/src/RateLimiter.ts b/backend/node_modules/effect/src/RateLimiter.ts new file mode 100644 index 0000000000000000000000000000000000000000..6d84e67e24fc2b86ffefd6fa91b63ea79a209134 --- /dev/null +++ b/backend/node_modules/effect/src/RateLimiter.ts @@ -0,0 +1,138 @@ +/** + * Limits the number of calls to a resource to a maximum amount in some interval. + * + * @since 2.0.0 + */ +import type { DurationInput } from "./Duration.js" +import type { Effect } from "./Effect.js" +import * as internal from "./internal/rateLimiter.js" +import type { Scope } from "./Scope.js" + +/** + * Limits the number of calls to a resource to a maximum amount in some interval. + * + * Note that only the moment of starting the effect is rate limited: the number + * of concurrent executions is not bounded. + * + * @since 2.0.0 + * @category models + */ +export interface RateLimiter { + (task: Effect): Effect +} + +/** + * @since 2.0.0 + */ +export declare namespace RateLimiter { + /** + * @since 2.0.0 + * @category models + */ + export interface Options { + /** + * The maximum number of requests that should be allowed. + */ + readonly limit: number + /** + * The interval to utilize for rate-limiting requests. The semantics of the + * specified `interval` vary depending on the chosen `algorithm`: + * + * `token-bucket`: The maximum number of requests will be spread out over + * the provided interval if no tokens are available. + * + * For example, for a `RateLimiter` using the `token-bucket` algorithm with + * a `limit` of `10` and an `interval` of `1 seconds`, `1` request can be + * made every `100 millis`. + * + * `fixed-window`: The maximum number of requests will be reset during each + * interval. For example, for a `RateLimiter` using the `fixed-window` + * algorithm with a `limit` of `10` and an `interval` of `1 seconds`, a + * maximum of `10` requests can be made each second. + */ + readonly interval: DurationInput + /** + * The algorithm to utilize for rate-limiting requests. + * + * Defaults to `token-bucket`. + */ + readonly algorithm?: "fixed-window" | "token-bucket" + } +} + +/** + * Constructs a new `RateLimiter` which will utilize the specified algorithm + * to limit requests (defaults to `token-bucket`). + * + * Notes + * - Only the moment of starting the effect is rate limited. The number of concurrent executions is not bounded. + * - Instances of `RateLimiter` can be composed. + * - The "cost" per effect can be changed. See {@link withCost} + * + * @example + * ```ts + * import { Effect, RateLimiter } from "effect"; + * import { compose } from "effect/Function" + * + * const program = Effect.scoped( + * Effect.gen(function* ($) { + * const perMinuteRL = yield* $(RateLimiter.make({ limit: 30, interval: "1 minutes" })) + * const perSecondRL = yield* $(RateLimiter.make({ limit: 2, interval: "1 seconds" })) + * + * // This rate limiter respects both the 30 calls per minute + * // and the 2 calls per second constraints. + * const rateLimit = compose(perMinuteRL, perSecondRL) + * + * // simulate repeated calls + * for (let n = 0; n < 100; n++) { + * // wrap the effect we want to limit with rateLimit + * yield* $(rateLimit(Effect.log("Calling RateLimited Effect"))); + * } + * }) + * ); + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export const make: (options: RateLimiter.Options) => Effect = internal.make + +/** + * Alters the per-effect cost of the rate-limiter. + * + * This can be used for "credit" based rate-limiting where different API endpoints + * cost a different number of credits within a time window. + * Eg: 1000 credits / hour, where a query costs 1 credit and a mutation costs 5 credits. + * + * @example + * ```ts + * import { Effect, RateLimiter } from "effect"; + * import { compose } from "effect/Function"; + * + * const program = Effect.scoped( + * Effect.gen(function* ($) { + * // Create a rate limiter that has an hourly limit of 1000 credits + * const rateLimiter = yield* $(RateLimiter.make({ limit: 1000, interval: "1 hours" })); + * // Query API costs 1 credit per call ( 1 is the default cost ) + * const queryAPIRL = compose(rateLimiter, RateLimiter.withCost(1)); + * // Mutation API costs 5 credits per call + * const mutationAPIRL = compose(rateLimiter, RateLimiter.withCost(5)); + + * // Use the pre-defined rate limiters + * yield* $(queryAPIRL(Effect.log("Sample Query"))); + * yield* $(mutationAPIRL(Effect.log("Sample Mutation"))); + * + * // Or set a cost on-the-fly + * yield* $( + * rateLimiter(Effect.log("Another query with a different cost")).pipe( + * RateLimiter.withCost(3) + * ) + * ); + * }) + * ); + * ``` + * + * @since 2.0.0 + * @category combinators + */ +export const withCost: (cost: number) => (effect: Effect) => Effect = internal.withCost diff --git a/backend/node_modules/effect/src/RcMap.ts b/backend/node_modules/effect/src/RcMap.ts new file mode 100644 index 0000000000000000000000000000000000000000..c59e6578af93f69e22c996b4dd3e9d65c8358201 --- /dev/null +++ b/backend/node_modules/effect/src/RcMap.ts @@ -0,0 +1,248 @@ +/** + * @since 3.5.0 + */ +import type * as Cause from "./Cause.js" +import type * as Duration from "./Duration.js" +import type * as Effect from "./Effect.js" +import * as internal from "./internal/rcMap.js" +import { type Pipeable } from "./Pipeable.js" +import type * as Scope from "./Scope.js" +import type * as Types from "./Types.js" + +/** + * @since 3.5.0 + * @category type ids + */ +export const TypeId: unique symbol = internal.TypeId + +/** + * @since 3.5.0 + * @category type ids + */ +export type TypeId = typeof TypeId + +/** + * @since 3.5.0 + * @category models + */ +export interface RcMap extends Pipeable { + readonly [TypeId]: RcMap.Variance +} + +/** + * @since 3.5.0 + * @category models + */ +export declare namespace RcMap { + /** + * @since 3.5.0 + * @category models + */ + export interface Variance { + readonly _K: Types.Contravariant + readonly _A: Types.Covariant + readonly _E: Types.Covariant + } +} + +/** + * An `RcMap` can contain multiple reference counted resources that can be indexed + * by a key. The resources are lazily acquired on the first call to `get` and + * released when the last reference is released. + * + * Complex keys can extend `Equal` and `Hash` to allow lookups by value. + * + * **Options** + * + * - `capacity`: The maximum number of resources that can be held in the map. + * - `idleTimeToLive`: When the reference count reaches zero, the resource will be released after this duration. + * Can be a static duration or a function that returns a duration based on the key. + * + * @since 3.5.0 + * @category models + * @example + * ```ts + * import { Effect, RcMap } from "effect" + * + * Effect.gen(function*() { + * const map = yield* RcMap.make({ + * lookup: (key: string) => + * Effect.acquireRelease( + * Effect.succeed(`acquired ${key}`), + * () => Effect.log(`releasing ${key}`) + * ) + * }) + * + * // Get "foo" from the map twice, which will only acquire it once. + * // It will then be released once the scope closes. + * yield* RcMap.get(map, "foo").pipe( + * Effect.andThen(RcMap.get(map, "foo")), + * Effect.scoped + * ) + * }) + * ``` + */ +export const make: { + /** + * An `RcMap` can contain multiple reference counted resources that can be indexed + * by a key. The resources are lazily acquired on the first call to `get` and + * released when the last reference is released. + * + * Complex keys can extend `Equal` and `Hash` to allow lookups by value. + * + * **Options** + * + * - `capacity`: The maximum number of resources that can be held in the map. + * - `idleTimeToLive`: When the reference count reaches zero, the resource will be released after this duration. + * Can be a static duration or a function that returns a duration based on the key. + * + * @since 3.5.0 + * @category models + * @example + * ```ts + * import { Effect, RcMap } from "effect" + * + * Effect.gen(function*() { + * const map = yield* RcMap.make({ + * lookup: (key: string) => + * Effect.acquireRelease( + * Effect.succeed(`acquired ${key}`), + * () => Effect.log(`releasing ${key}`) + * ) + * }) + * + * // Get "foo" from the map twice, which will only acquire it once. + * // It will then be released once the scope closes. + * yield* RcMap.get(map, "foo").pipe( + * Effect.andThen(RcMap.get(map, "foo")), + * Effect.scoped + * ) + * }) + * ``` + */ + ( + options: { + readonly lookup: (key: K) => Effect.Effect + readonly idleTimeToLive?: Duration.DurationInput | ((key: K) => Duration.DurationInput) | undefined + readonly capacity?: undefined + } + ): Effect.Effect, never, Scope.Scope | R> + /** + * An `RcMap` can contain multiple reference counted resources that can be indexed + * by a key. The resources are lazily acquired on the first call to `get` and + * released when the last reference is released. + * + * Complex keys can extend `Equal` and `Hash` to allow lookups by value. + * + * **Options** + * + * - `capacity`: The maximum number of resources that can be held in the map. + * - `idleTimeToLive`: When the reference count reaches zero, the resource will be released after this duration. + * Can be a static duration or a function that returns a duration based on the key. + * + * @since 3.5.0 + * @category models + * @example + * ```ts + * import { Effect, RcMap } from "effect" + * + * Effect.gen(function*() { + * const map = yield* RcMap.make({ + * lookup: (key: string) => + * Effect.acquireRelease( + * Effect.succeed(`acquired ${key}`), + * () => Effect.log(`releasing ${key}`) + * ) + * }) + * + * // Get "foo" from the map twice, which will only acquire it once. + * // It will then be released once the scope closes. + * yield* RcMap.get(map, "foo").pipe( + * Effect.andThen(RcMap.get(map, "foo")), + * Effect.scoped + * ) + * }) + * ``` + */ + ( + options: { + readonly lookup: (key: K) => Effect.Effect + readonly idleTimeToLive?: Duration.DurationInput | ((key: K) => Duration.DurationInput) | undefined + readonly capacity: number + } + ): Effect.Effect, never, Scope.Scope | R> +} = internal.make + +/** + * @since 3.5.0 + * @category combinators + */ +export const get: { + /** + * @since 3.5.0 + * @category combinators + */ + (key: K): (self: RcMap) => Effect.Effect + /** + * @since 3.5.0 + * @category combinators + */ + (self: RcMap, key: K): Effect.Effect +} = internal.get + +/** + * @since 3.17.7 + * @category combinators + */ +export const has: { + /** + * @since 3.17.7 + * @category combinators + */ + (key: K): (self: RcMap) => Effect.Effect + /** + * @since 3.17.7 + * @category combinators + */ + (self: RcMap, key: K): Effect.Effect +} = internal.has + +/** + * @since 3.8.0 + * @category combinators + */ +export const keys: (self: RcMap) => Effect.Effect> = internal.keys + +/** + * @since 3.13.0 + * @category combinators + */ +export const invalidate: { + /** + * @since 3.13.0 + * @category combinators + */ + (key: K): (self: RcMap) => Effect.Effect + /** + * @since 3.13.0 + * @category combinators + */ + (self: RcMap, key: K): Effect.Effect +} = internal.invalidate + +/** + * @since 3.13.0 + * @category combinators + */ +export const touch: { + /** + * @since 3.13.0 + * @category combinators + */ + (key: K): (self: RcMap) => Effect.Effect + /** + * @since 3.13.0 + * @category combinators + */ + (self: RcMap, key: K): Effect.Effect +} = internal.touch diff --git a/backend/node_modules/effect/src/RcRef.ts b/backend/node_modules/effect/src/RcRef.ts new file mode 100644 index 0000000000000000000000000000000000000000..af2bd217ca551485362692e7295bebed26d856df --- /dev/null +++ b/backend/node_modules/effect/src/RcRef.ts @@ -0,0 +1,122 @@ +/** + * @since 3.5.0 + */ +import type * as Duration from "./Duration.js" +import type * as Effect from "./Effect.js" +import * as internal from "./internal/rcRef.js" +import type * as Readable from "./Readable.js" +import type * as Scope from "./Scope.js" +import type * as Types from "./Types.js" +import type * as Unify from "./Unify.js" + +/** + * @since 3.5.0 + * @category type ids + */ +export const TypeId: unique symbol = internal.TypeId + +/** + * @since 3.5.0 + * @category type ids + */ +export type TypeId = typeof TypeId + +/** + * @since 3.5.0 + * @category models + */ +export interface RcRef + extends Effect.Effect, Readable.Readable +{ + readonly [TypeId]: RcRef.Variance + readonly [Unify.typeSymbol]?: unknown + readonly [Unify.unifySymbol]?: RcRefUnify + readonly [Unify.ignoreSymbol]?: RcRefUnifyIgnore +} + +/** + * @category models + * @since 3.8.0 + */ +export interface RcRefUnify extends Effect.EffectUnify { + RcRef?: () => A[Unify.typeSymbol] extends RcRef | infer _ ? RcRef + : never +} + +/** + * @category models + * @since 3.8.0 + */ +export interface RcRefUnifyIgnore extends Effect.EffectUnifyIgnore { + Effect?: true +} +/** + * @since 3.5.0 + * @category models + */ +export declare namespace RcRef { + /** + * @since 3.5.0 + * @category models + */ + export interface Variance { + readonly _A: Types.Covariant + readonly _E: Types.Covariant + } +} + +/** + * Create an `RcRef` from an acquire `Effect`. + * + * An RcRef wraps a reference counted resource that can be acquired and released + * multiple times. + * + * The resource is lazily acquired on the first call to `get` and released when + * the last reference is released. + * + * @since 3.5.0 + * @category constructors + * @example + * ```ts + * import { Effect, RcRef } from "effect" + * + * Effect.gen(function*() { + * const ref = yield* RcRef.make({ + * acquire: Effect.acquireRelease( + * Effect.succeed("foo"), + * () => Effect.log("release foo") + * ) + * }) + * + * // will only acquire the resource once, and release it + * // when the scope is closed + * yield* RcRef.get(ref).pipe( + * Effect.andThen(RcRef.get(ref)), + * Effect.scoped + * ) + * }) + * ``` + */ +export const make: ( + options: { + readonly acquire: Effect.Effect + /** + * When the reference count reaches zero, the resource will be released + * after this duration. + */ + readonly idleTimeToLive?: Duration.DurationInput | undefined + } +) => Effect.Effect, never, R | Scope.Scope> = internal.make + +/** + * @since 3.5.0 + * @category combinators + */ +export const get: (self: RcRef) => Effect.Effect = internal.get + +/** + * @since 3.19.6 + * @category combinators + * @experimental + */ +export const invalidate: (self: RcRef) => Effect.Effect = internal.invalidate diff --git a/backend/node_modules/effect/src/Readable.ts b/backend/node_modules/effect/src/Readable.ts new file mode 100644 index 0000000000000000000000000000000000000000..42c5b1ca716252036e29d80b9a42c01011318f72 --- /dev/null +++ b/backend/node_modules/effect/src/Readable.ts @@ -0,0 +1,104 @@ +/** + * @since 2.0.0 + */ +import type { Effect } from "./Effect.js" +import { dual } from "./Function.js" +import * as core from "./internal/core.js" +import { type Pipeable, pipeArguments } from "./Pipeable.js" +import { hasProperty } from "./Predicate.js" +import type { NoInfer } from "./Types.js" + +/** + * @since 2.0.0 + * @category type ids + */ +export const TypeId: unique symbol = Symbol.for("effect/Readable") + +/** + * @since 2.0.0 + * @category type ids + */ +export type TypeId = typeof TypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface Readable extends Pipeable { + readonly [TypeId]: TypeId + readonly get: Effect +} + +/** + * @since 2.0.0 + * @category refinements + */ +export const isReadable = (u: unknown): u is Readable => hasProperty(u, TypeId) + +const Proto: Omit, "get"> = { + [TypeId]: TypeId, + pipe() { + return pipeArguments(this, arguments) + } +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const make = (get: Effect): Readable => { + const self = Object.create(Proto) + self.get = get + return self +} + +/** + * @since 2.0.0 + * @category combinators + */ +export const map: { + /** + * @since 2.0.0 + * @category combinators + */ + (f: (a: NoInfer) => B): (fa: Readable) => Readable + /** + * @since 2.0.0 + * @category combinators + */ + (self: Readable, f: (a: NoInfer) => B): Readable +} = dual( + 2, + (self: Readable, f: (a: NoInfer) => B): Readable => make(core.map(self.get, f)) +) + +/** + * @since 2.0.0 + * @category combinators + */ +export const mapEffect: { + /** + * @since 2.0.0 + * @category combinators + */ + (f: (a: NoInfer) => Effect): (fa: Readable) => Readable + /** + * @since 2.0.0 + * @category combinators + */ + (self: Readable, f: (a: NoInfer) => Effect): Readable +} = dual(2, ( + self: Readable, + f: (a: NoInfer) => Effect +): Readable => make(core.flatMap(self.get, f))) + +/** + * @since 2.0.0 + * @category constructors + */ +export const unwrap = ( + effect: Effect, E1, R1> +): Readable => + make( + core.flatMap(effect, (s) => s.get) + ) diff --git a/backend/node_modules/effect/src/RedBlackTree.ts b/backend/node_modules/effect/src/RedBlackTree.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f0253e9c4c9785a9e0732e5d5dc18de63a9fc42 --- /dev/null +++ b/backend/node_modules/effect/src/RedBlackTree.ts @@ -0,0 +1,725 @@ +/** + * @since 2.0.0 + */ +import type { Chunk } from "./Chunk.js" +import type { Equal } from "./Equal.js" +import type { Inspectable } from "./Inspectable.js" +import * as RBT from "./internal/redBlackTree.js" +import * as RBTI from "./internal/redBlackTree/iterator.js" +import type { Option } from "./Option.js" +import type { Order } from "./Order.js" +import type { Pipeable } from "./Pipeable.js" +import type * as Types from "./Types.js" + +const TypeId: unique symbol = RBT.RedBlackTreeTypeId as TypeId + +/** + * @since 2.0.0 + * @category symbol + */ +export type TypeId = typeof TypeId + +/** + * @since 2.0.0 + * @category constants + */ +export const Direction = RBTI.Direction + +/** + * A Red-Black Tree. + * + * @since 2.0.0 + * @category models + */ +export interface RedBlackTree extends Iterable<[Key, Value]>, Equal, Pipeable, Inspectable { + readonly [TypeId]: { + readonly _Key: Types.Invariant + readonly _Value: Types.Covariant + } +} + +/** + * @since 2.0.0 + */ +export declare namespace RedBlackTree { + /** + * @since 2.0.0 + */ + export type Direction = number & { + readonly Direction: unique symbol + } +} + +/** + * @since 2.0.0 + * @category refinements + */ +export const isRedBlackTree: { + /** + * @since 2.0.0 + * @category refinements + */ + (u: Iterable): u is RedBlackTree + /** + * @since 2.0.0 + * @category refinements + */ + (u: unknown): u is RedBlackTree +} = RBT.isRedBlackTree + +/** + * Creates an empty `RedBlackTree`. + * + * @since 2.0.0 + * @category constructors + */ +export const empty: (ord: Order) => RedBlackTree = RBT.empty + +/** + * Creates a new `RedBlackTree` from an iterable collection of key/value pairs. + * + * @since 2.0.0 + * @category constructors + */ +export const fromIterable: { + /** + * Creates a new `RedBlackTree` from an iterable collection of key/value pairs. + * + * @since 2.0.0 + * @category constructors + */ + (ord: Order): (entries: Iterable) => RedBlackTree + /** + * Creates a new `RedBlackTree` from an iterable collection of key/value pairs. + * + * @since 2.0.0 + * @category constructors + */ + (entries: Iterable, ord: Order): RedBlackTree +} = RBT.fromIterable + +/** + * Constructs a new `RedBlackTree` from the specified entries. + * + * @since 2.0.0 + * @category constructors + */ +export const make: ( + ord: Order +) => >( + ...entries: Entries +) => RedBlackTree = RBT.make + +/** + * Returns an iterator that points to the element at the specified index of the + * tree. + * + * **Note**: The iterator will run through elements in order. + * + * @since 2.0.0 + * @category traversing + */ +export const at: { + /** + * Returns an iterator that points to the element at the specified index of the + * tree. + * + * **Note**: The iterator will run through elements in order. + * + * @since 2.0.0 + * @category traversing + */ + (index: number): (self: RedBlackTree) => Iterable<[K, V]> + /** + * Returns an iterator that points to the element at the specified index of the + * tree. + * + * **Note**: The iterator will run through elements in order. + * + * @since 2.0.0 + * @category traversing + */ + (self: RedBlackTree, index: number): Iterable<[K, V]> +} = RBT.atForwards + +/** + * Returns an iterator that points to the element at the specified index of the + * tree. + * + * **Note**: The iterator will run through elements in reverse order. + * + * @since 2.0.0 + * @category traversing + */ +export const atReversed: { + /** + * Returns an iterator that points to the element at the specified index of the + * tree. + * + * **Note**: The iterator will run through elements in reverse order. + * + * @since 2.0.0 + * @category traversing + */ + (index: number): (self: RedBlackTree) => Iterable<[K, V]> + /** + * Returns an iterator that points to the element at the specified index of the + * tree. + * + * **Note**: The iterator will run through elements in reverse order. + * + * @since 2.0.0 + * @category traversing + */ + (self: RedBlackTree, index: number): Iterable<[K, V]> +} = RBT.atBackwards + +/** + * Finds all values in the tree associated with the specified key. + * + * @since 2.0.0 + * @category elements + */ +export const findAll: { + /** + * Finds all values in the tree associated with the specified key. + * + * @since 2.0.0 + * @category elements + */ + (key: K): (self: RedBlackTree) => Chunk + /** + * Finds all values in the tree associated with the specified key. + * + * @since 2.0.0 + * @category elements + */ + (self: RedBlackTree, key: K): Chunk +} = RBT.findAll + +/** + * Finds the first value in the tree associated with the specified key, if it exists. + * + * @category elements + * @since 2.0.0 + */ +export const findFirst: { + /** + * Finds the first value in the tree associated with the specified key, if it exists. + * + * @category elements + * @since 2.0.0 + */ + (key: K): (self: RedBlackTree) => Option + /** + * Finds the first value in the tree associated with the specified key, if it exists. + * + * @category elements + * @since 2.0.0 + */ + (self: RedBlackTree, key: K): Option +} = RBT.findFirst + +/** + * Returns the first entry in the tree, if it exists. + * + * @since 2.0.0 + * @category getters + */ +export const first: (self: RedBlackTree) => Option<[K, V]> = RBT.first + +/** + * Returns the element at the specified index within the tree or `None` if the + * specified index does not exist. + * + * @since 2.0.0 + * @category elements + */ +export const getAt: { + /** + * Returns the element at the specified index within the tree or `None` if the + * specified index does not exist. + * + * @since 2.0.0 + * @category elements + */ + (index: number): (self: RedBlackTree) => Option<[K, V]> + /** + * Returns the element at the specified index within the tree or `None` if the + * specified index does not exist. + * + * @since 2.0.0 + * @category elements + */ + (self: RedBlackTree, index: number): Option<[K, V]> +} = RBT.getAt + +/** + * Gets the `Order` that the `RedBlackTree` is using. + * + * @since 2.0.0 + * @category getters + */ +export const getOrder: (self: RedBlackTree) => Order = RBT.getOrder + +/** + * Returns an iterator that traverse entries in order with keys greater than the + * specified key. + * + * @since 2.0.0 + * @category traversing + */ +export const greaterThan: { + /** + * Returns an iterator that traverse entries in order with keys greater than the + * specified key. + * + * @since 2.0.0 + * @category traversing + */ + (key: K): (self: RedBlackTree) => Iterable<[K, V]> + /** + * Returns an iterator that traverse entries in order with keys greater than the + * specified key. + * + * @since 2.0.0 + * @category traversing + */ + (self: RedBlackTree, key: K): Iterable<[K, V]> +} = RBT.greaterThanForwards + +/** + * Returns an iterator that traverse entries in reverse order with keys greater + * than the specified key. + * + * @since 2.0.0 + * @category traversing + */ +export const greaterThanReversed: { + /** + * Returns an iterator that traverse entries in reverse order with keys greater + * than the specified key. + * + * @since 2.0.0 + * @category traversing + */ + (key: K): (self: RedBlackTree) => Iterable<[K, V]> + /** + * Returns an iterator that traverse entries in reverse order with keys greater + * than the specified key. + * + * @since 2.0.0 + * @category traversing + */ + (self: RedBlackTree, key: K): Iterable<[K, V]> +} = RBT.greaterThanBackwards + +/** + * Returns an iterator that traverse entries in order with keys greater than or + * equal to the specified key. + * + * @since 2.0.0 + * @category traversing + */ +export const greaterThanEqual: { + /** + * Returns an iterator that traverse entries in order with keys greater than or + * equal to the specified key. + * + * @since 2.0.0 + * @category traversing + */ + (key: K): (self: RedBlackTree) => Iterable<[K, V]> + /** + * Returns an iterator that traverse entries in order with keys greater than or + * equal to the specified key. + * + * @since 2.0.0 + * @category traversing + */ + (self: RedBlackTree, key: K): Iterable<[K, V]> +} = RBT.greaterThanEqualForwards + +/** + * Returns an iterator that traverse entries in reverse order with keys greater + * than or equal to the specified key. + * + * @since 2.0.0 + * @category traversing + */ +export const greaterThanEqualReversed: { + /** + * Returns an iterator that traverse entries in reverse order with keys greater + * than or equal to the specified key. + * + * @since 2.0.0 + * @category traversing + */ + (key: K): (self: RedBlackTree) => Iterable<[K, V]> + /** + * Returns an iterator that traverse entries in reverse order with keys greater + * than or equal to the specified key. + * + * @since 2.0.0 + * @category traversing + */ + (self: RedBlackTree, key: K): Iterable<[K, V]> +} = RBT.greaterThanEqualBackwards + +/** + * Finds the item with key, if it exists. + * + * @since 2.0.0 + * @category elements + */ +export const has: { + /** + * Finds the item with key, if it exists. + * + * @since 2.0.0 + * @category elements + */ + (key: K): (self: RedBlackTree) => boolean + /** + * Finds the item with key, if it exists. + * + * @since 2.0.0 + * @category elements + */ + (self: RedBlackTree, key: K): boolean +} = RBT.has + +/** + * Insert a new item into the tree. + * + * @since 2.0.0 + */ +export const insert: { + /** + * Insert a new item into the tree. + * + * @since 2.0.0 + */ + (key: K, value: V): (self: RedBlackTree) => RedBlackTree + /** + * Insert a new item into the tree. + * + * @since 2.0.0 + */ + (self: RedBlackTree, key: K, value: V): RedBlackTree +} = RBT.insert + +/** + * Get all the keys present in the tree in order. + * + * @since 2.0.0 + * @category getters + */ +export const keys: (self: RedBlackTree) => IterableIterator = RBT.keysForward + +/** + * Get all the keys present in the tree in reverse order. + * + * @since 2.0.0 + * @category getters + */ +export const keysReversed: (self: RedBlackTree) => IterableIterator = RBT.keysBackward + +/** + * Returns the last entry in the tree, if it exists. + * + * @since 2.0.0 + * @category getters + */ +export const last: (self: RedBlackTree) => Option<[K, V]> = RBT.last + +/** + * Returns an iterator that traverse entries in order with keys less than the + * specified key. + * + * @since 2.0.0 + * @category traversing + */ +export const lessThan: { + /** + * Returns an iterator that traverse entries in order with keys less than the + * specified key. + * + * @since 2.0.0 + * @category traversing + */ + (key: K): (self: RedBlackTree) => Iterable<[K, V]> + /** + * Returns an iterator that traverse entries in order with keys less than the + * specified key. + * + * @since 2.0.0 + * @category traversing + */ + (self: RedBlackTree, key: K): Iterable<[K, V]> +} = RBT.lessThanForwards + +/** + * Returns an iterator that traverse entries in reverse order with keys less + * than the specified key. + * + * @since 2.0.0 + * @category traversing + */ +export const lessThanReversed: { + /** + * Returns an iterator that traverse entries in reverse order with keys less + * than the specified key. + * + * @since 2.0.0 + * @category traversing + */ + (key: K): (self: RedBlackTree) => Iterable<[K, V]> + /** + * Returns an iterator that traverse entries in reverse order with keys less + * than the specified key. + * + * @since 2.0.0 + * @category traversing + */ + (self: RedBlackTree, key: K): Iterable<[K, V]> +} = RBT.lessThanBackwards + +/** + * Returns an iterator that traverse entries in order with keys less than or + * equal to the specified key. + * + * @since 2.0.0 + * @category traversing + */ +export const lessThanEqual: { + /** + * Returns an iterator that traverse entries in order with keys less than or + * equal to the specified key. + * + * @since 2.0.0 + * @category traversing + */ + (key: K): (self: RedBlackTree) => Iterable<[K, V]> + /** + * Returns an iterator that traverse entries in order with keys less than or + * equal to the specified key. + * + * @since 2.0.0 + * @category traversing + */ + (self: RedBlackTree, key: K): Iterable<[K, V]> +} = RBT.lessThanEqualForwards + +/** + * Returns an iterator that traverse entries in reverse order with keys less + * than or equal to the specified key. + * + * @since 2.0.0 + * @category traversing + */ +export const lessThanEqualReversed: { + /** + * Returns an iterator that traverse entries in reverse order with keys less + * than or equal to the specified key. + * + * @since 2.0.0 + * @category traversing + */ + (key: K): (self: RedBlackTree) => Iterable<[K, V]> + /** + * Returns an iterator that traverse entries in reverse order with keys less + * than or equal to the specified key. + * + * @since 2.0.0 + * @category traversing + */ + (self: RedBlackTree, key: K): Iterable<[K, V]> +} = RBT.lessThanEqualBackwards + +/** + * Execute the specified function for each node of the tree, in order. + * + * @since 2.0.0 + * @category traversing + */ +export const forEach: { + /** + * Execute the specified function for each node of the tree, in order. + * + * @since 2.0.0 + * @category traversing + */ + (f: (key: K, value: V) => void): (self: RedBlackTree) => void + /** + * Execute the specified function for each node of the tree, in order. + * + * @since 2.0.0 + * @category traversing + */ + (self: RedBlackTree, f: (key: K, value: V) => void): void +} = RBT.forEach + +/** + * Visit each node of the tree in order with key greater then or equal to max. + * + * @since 2.0.0 + * @category traversing + */ +export const forEachGreaterThanEqual: { + /** + * Visit each node of the tree in order with key greater then or equal to max. + * + * @since 2.0.0 + * @category traversing + */ + (min: K, f: (key: K, value: V) => void): (self: RedBlackTree) => void + /** + * Visit each node of the tree in order with key greater then or equal to max. + * + * @since 2.0.0 + * @category traversing + */ + (self: RedBlackTree, min: K, f: (key: K, value: V) => void): void +} = RBT.forEachGreaterThanEqual + +/** + * Visit each node of the tree in order with key lower then max. + * + * @since 2.0.0 + * @category traversing + */ +export const forEachLessThan: { + /** + * Visit each node of the tree in order with key lower then max. + * + * @since 2.0.0 + * @category traversing + */ + (max: K, f: (key: K, value: V) => void): (self: RedBlackTree) => void + /** + * Visit each node of the tree in order with key lower then max. + * + * @since 2.0.0 + * @category traversing + */ + (self: RedBlackTree, max: K, f: (key: K, value: V) => void): void +} = RBT.forEachLessThan + +/** + * Visit each node of the tree in order with key lower than max and greater + * than or equal to min. + * + * @since 2.0.0 + * @category traversing + */ +export const forEachBetween: { + /** + * Visit each node of the tree in order with key lower than max and greater + * than or equal to min. + * + * @since 2.0.0 + * @category traversing + */ + ( + options: { + readonly min: K + readonly max: K + readonly body: (key: K, value: V) => void + } + ): (self: RedBlackTree) => void + /** + * Visit each node of the tree in order with key lower than max and greater + * than or equal to min. + * + * @since 2.0.0 + * @category traversing + */ + ( + self: RedBlackTree, + options: { + readonly min: K + readonly max: K + readonly body: (key: K, value: V) => void + } + ): void +} = RBT.forEachBetween + +/** + * Reduce a state over the entries of the tree. + * + * @since 2.0.0 + * @category folding + */ +export const reduce: { + /** + * Reduce a state over the entries of the tree. + * + * @since 2.0.0 + * @category folding + */ + (zero: Z, f: (accumulator: Z, value: V, key: K) => Z): (self: RedBlackTree) => Z + /** + * Reduce a state over the entries of the tree. + * + * @since 2.0.0 + * @category folding + */ + ( + self: RedBlackTree, + zero: Z, + f: (accumulator: Z, value: V, key: K) => Z + ): Z +} = RBT.reduce + +/** + * Removes the entry with the specified key, if it exists. + * + * @since 2.0.0 + */ +export const removeFirst: { + /** + * Removes the entry with the specified key, if it exists. + * + * @since 2.0.0 + */ + (key: K): (self: RedBlackTree) => RedBlackTree + /** + * Removes the entry with the specified key, if it exists. + * + * @since 2.0.0 + */ + (self: RedBlackTree, key: K): RedBlackTree +} = RBT.removeFirst + +/** + * Traverse the tree in reverse order. + * + * @since 2.0.0 + * @category traversing + */ +export const reversed: (self: RedBlackTree) => Iterable<[K, V]> = RBT.reversed + +/** + * Returns the size of the tree. + * + * @since 2.0.0 + * @category getters + */ +export const size: (self: RedBlackTree) => number = RBT.size + +/** + * Get all values present in the tree in order. + * + * @since 2.0.0 + * @category getters + */ +export const values: (self: RedBlackTree) => IterableIterator = RBT.valuesForward + +/** + * Get all values present in the tree in reverse order. + * + * @since 2.0.0 + * @category getters + */ +export const valuesReversed: (self: RedBlackTree) => IterableIterator = RBT.valuesBackward diff --git a/backend/node_modules/effect/src/Redacted.ts b/backend/node_modules/effect/src/Redacted.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e9b7b849888110f7d8d41954434c934cd736958 --- /dev/null +++ b/backend/node_modules/effect/src/Redacted.ts @@ -0,0 +1,144 @@ +/** + * The Redacted module provides functionality for handling sensitive information + * securely within your application. By using the `Redacted` data type, you can + * ensure that sensitive values are not accidentally exposed in logs or error + * messages. + * + * @since 3.3.0 + */ +import type * as Equal from "./Equal.js" +import * as Equivalence from "./Equivalence.js" +import * as redacted_ from "./internal/redacted.js" +import type { Pipeable } from "./Pipeable.js" +import type { Covariant } from "./Types.js" + +/** + * @since 3.3.0 + * @category symbols + */ +export const RedactedTypeId: unique symbol = redacted_.RedactedTypeId + +/** + * @since 3.3.0 + * @category symbols + */ +export type RedactedTypeId = typeof RedactedTypeId + +/** + * @since 3.3.0 + * @category models + */ +export interface Redacted extends Redacted.Variance, Equal.Equal, Pipeable { +} + +/** + * @since 3.3.0 + */ +export declare namespace Redacted { + /** + * @since 3.3.0 + * @category models + */ + export interface Variance { + readonly [RedactedTypeId]: { + readonly _A: Covariant + } + } + + /** + * @since 3.3.0 + * @category type-level + */ + export type Value> = [T] extends [Redacted] ? _A : never +} + +/** + * @since 3.3.0 + * @category refinements + */ +export const isRedacted: (u: unknown) => u is Redacted = redacted_.isRedacted + +/** + * This function creates a `Redacted` instance from a given value `A`, + * securely hiding its content. + * + * @example + * ```ts + * import { Redacted } from "effect" + * + * const API_KEY = Redacted.make("1234567890") + * ``` + * + * @since 3.3.0 + * @category constructors + */ +export const make: (value: A) => Redacted = redacted_.make + +/** + * Retrieves the original value from a `Redacted` instance. Use this function + * with caution, as it exposes the sensitive data. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Redacted } from "effect" + * + * const API_KEY = Redacted.make("1234567890") + * + * assert.equal(Redacted.value(API_KEY), "1234567890") + * ``` + * + * @since 3.3.0 + * @category getters + */ +export const value: (self: Redacted) => A = redacted_.value + +/** + * Erases the underlying value of a `Redacted` instance, rendering it unusable. + * This function is intended to ensure that sensitive data does not remain in + * memory longer than necessary. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Redacted } from "effect" + * + * const API_KEY = Redacted.make("1234567890") + * + * assert.equal(Redacted.value(API_KEY), "1234567890") + * + * Redacted.unsafeWipe(API_KEY) + * + * assert.throws(() => Redacted.value(API_KEY), new Error("Unable to get redacted value")) + * ``` + * + * @since 3.3.0 + * @category unsafe + */ +export const unsafeWipe: (self: Redacted) => boolean = redacted_.unsafeWipe + +/** + * Generates an equivalence relation for `Redacted` values based on an + * equivalence relation for the underlying values `A`. This function is useful + * for comparing `Redacted` instances without exposing their contents. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Redacted, Equivalence } from "effect" + * + * const API_KEY1 = Redacted.make("1234567890") + * const API_KEY2 = Redacted.make("1-34567890") + * const API_KEY3 = Redacted.make("1234567890") + * + * const equivalence = Redacted.getEquivalence(Equivalence.string) + * + * assert.equal(equivalence(API_KEY1, API_KEY2), false) + * assert.equal(equivalence(API_KEY1, API_KEY3), true) + * ``` + * + * @category equivalence + * @since 3.3.0 + */ +export const getEquivalence = (isEquivalent: Equivalence.Equivalence): Equivalence.Equivalence> => + Equivalence.make((x, y) => isEquivalent(value(x), value(y))) diff --git a/backend/node_modules/effect/src/RuntimeFlagsPatch.ts b/backend/node_modules/effect/src/RuntimeFlagsPatch.ts new file mode 100644 index 0000000000000000000000000000000000000000..b983f4970a84ec2ec683443e3c9a811b56d74384 --- /dev/null +++ b/backend/node_modules/effect/src/RuntimeFlagsPatch.ts @@ -0,0 +1,295 @@ +/** + * @since 2.0.0 + */ +import * as runtimeFlags from "./internal/runtimeFlags.js" +import * as internal from "./internal/runtimeFlagsPatch.js" +import type * as RuntimeFlags from "./RuntimeFlags.js" + +/** + * @since 2.0.0 + * @category models + */ +export type RuntimeFlagsPatch = number & { + readonly RuntimeFlagsPatch: unique symbol +} + +/** + * The empty `RuntimeFlagsPatch`. + * + * @since 2.0.0 + * @category constructors + */ +export const empty: RuntimeFlagsPatch = internal.empty + +/** + * @since 2.0.0 + * @category constructors + */ +export const make: (active: number, enabled: number) => RuntimeFlagsPatch = internal.make + +/** + * Creates a `RuntimeFlagsPatch` describing enabling the provided `RuntimeFlag`. + * + * @since 2.0.0 + * @category constructors + */ +export const enable: (flag: RuntimeFlags.RuntimeFlag) => RuntimeFlagsPatch = internal.enable + +/** + * Creates a `RuntimeFlagsPatch` describing disabling the provided `RuntimeFlag`. + * + * @since 2.0.0 + * @category constructors + */ +export const disable: (flag: RuntimeFlags.RuntimeFlag) => RuntimeFlagsPatch = internal.disable + +/** + * Returns `true` if the specified `RuntimeFlagsPatch` is empty. + * + * @since 2.0.0 + * @category getters + */ +export const isEmpty: (patch: RuntimeFlagsPatch) => boolean = internal.isEmpty + +/** + * Returns `true` if the `RuntimeFlagsPatch` describes the specified + * `RuntimeFlag` as active. + * + * @since 2.0.0 + * @category elements + */ +export const isActive: { + /** + * Returns `true` if the `RuntimeFlagsPatch` describes the specified + * `RuntimeFlag` as active. + * + * @since 2.0.0 + * @category elements + */ + (flag: RuntimeFlagsPatch): (self: RuntimeFlagsPatch) => boolean + /** + * Returns `true` if the `RuntimeFlagsPatch` describes the specified + * `RuntimeFlag` as active. + * + * @since 2.0.0 + * @category elements + */ + (self: RuntimeFlagsPatch, flag: RuntimeFlagsPatch): boolean +} = internal.isActive + +/** + * Returns `true` if the `RuntimeFlagsPatch` describes the specified + * `RuntimeFlag` as enabled. + * + * @since 2.0.0 + * @category elements + */ +export const isEnabled: { + /** + * Returns `true` if the `RuntimeFlagsPatch` describes the specified + * `RuntimeFlag` as enabled. + * + * @since 2.0.0 + * @category elements + */ + (flag: RuntimeFlags.RuntimeFlag): (self: RuntimeFlagsPatch) => boolean + /** + * Returns `true` if the `RuntimeFlagsPatch` describes the specified + * `RuntimeFlag` as enabled. + * + * @since 2.0.0 + * @category elements + */ + (self: RuntimeFlagsPatch, flag: RuntimeFlags.RuntimeFlag): boolean +} = internal.isEnabled + +/** + * Returns `true` if the `RuntimeFlagsPatch` describes the specified + * `RuntimeFlag` as disabled. + * + * @since 2.0.0 + * @category elements + */ +export const isDisabled: { + /** + * Returns `true` if the `RuntimeFlagsPatch` describes the specified + * `RuntimeFlag` as disabled. + * + * @since 2.0.0 + * @category elements + */ + (flag: RuntimeFlags.RuntimeFlag): (self: RuntimeFlagsPatch) => boolean + /** + * Returns `true` if the `RuntimeFlagsPatch` describes the specified + * `RuntimeFlag` as disabled. + * + * @since 2.0.0 + * @category elements + */ + (self: RuntimeFlagsPatch, flag: RuntimeFlags.RuntimeFlag): boolean +} = internal.isDisabled + +/** + * Returns `true` if the `RuntimeFlagsPatch` includes the specified + * `RuntimeFlag`, `false` otherwise. + * + * @since 2.0.0 + * @category elements + */ +export const includes: { + /** + * Returns `true` if the `RuntimeFlagsPatch` includes the specified + * `RuntimeFlag`, `false` otherwise. + * + * @since 2.0.0 + * @category elements + */ + (flag: RuntimeFlagsPatch): (self: RuntimeFlagsPatch) => boolean + /** + * Returns `true` if the `RuntimeFlagsPatch` includes the specified + * `RuntimeFlag`, `false` otherwise. + * + * @since 2.0.0 + * @category elements + */ + (self: RuntimeFlagsPatch, flag: RuntimeFlagsPatch): boolean +} = internal.isActive + +/** + * Creates a `RuntimeFlagsPatch` describing the application of the `self` patch, + * followed by `that` patch. + * + * @since 2.0.0 + * @category utils + */ +export const andThen: { + /** + * Creates a `RuntimeFlagsPatch` describing the application of the `self` patch, + * followed by `that` patch. + * + * @since 2.0.0 + * @category utils + */ + (that: RuntimeFlagsPatch): (self: RuntimeFlagsPatch) => RuntimeFlagsPatch + /** + * Creates a `RuntimeFlagsPatch` describing the application of the `self` patch, + * followed by `that` patch. + * + * @since 2.0.0 + * @category utils + */ + (self: RuntimeFlagsPatch, that: RuntimeFlagsPatch): RuntimeFlagsPatch +} = internal.andThen + +/** + * Creates a `RuntimeFlagsPatch` describing application of both the `self` patch + * and `that` patch. + * + * @since 2.0.0 + * @category utils + */ +export const both: { + /** + * Creates a `RuntimeFlagsPatch` describing application of both the `self` patch + * and `that` patch. + * + * @since 2.0.0 + * @category utils + */ + (that: RuntimeFlagsPatch): (self: RuntimeFlagsPatch) => RuntimeFlagsPatch + /** + * Creates a `RuntimeFlagsPatch` describing application of both the `self` patch + * and `that` patch. + * + * @since 2.0.0 + * @category utils + */ + (self: RuntimeFlagsPatch, that: RuntimeFlagsPatch): RuntimeFlagsPatch +} = internal.both + +/** + * Creates a `RuntimeFlagsPatch` describing application of either the `self` + * patch or `that` patch. + * + * @since 2.0.0 + * @category utils + */ +export const either: { + /** + * Creates a `RuntimeFlagsPatch` describing application of either the `self` + * patch or `that` patch. + * + * @since 2.0.0 + * @category utils + */ + (that: RuntimeFlagsPatch): (self: RuntimeFlagsPatch) => RuntimeFlagsPatch + /** + * Creates a `RuntimeFlagsPatch` describing application of either the `self` + * patch or `that` patch. + * + * @since 2.0.0 + * @category utils + */ + (self: RuntimeFlagsPatch, that: RuntimeFlagsPatch): RuntimeFlagsPatch +} = internal.either + +/** + * Creates a `RuntimeFlagsPatch` which describes exclusion of the specified + * `RuntimeFlag` from the set of `RuntimeFlags`. + * + * @category utils + * @since 2.0.0 + */ +export const exclude: { + /** + * Creates a `RuntimeFlagsPatch` which describes exclusion of the specified + * `RuntimeFlag` from the set of `RuntimeFlags`. + * + * @category utils + * @since 2.0.0 + */ + (flag: RuntimeFlags.RuntimeFlag): (self: RuntimeFlagsPatch) => RuntimeFlagsPatch + /** + * Creates a `RuntimeFlagsPatch` which describes exclusion of the specified + * `RuntimeFlag` from the set of `RuntimeFlags`. + * + * @category utils + * @since 2.0.0 + */ + (self: RuntimeFlagsPatch, flag: RuntimeFlags.RuntimeFlag): RuntimeFlagsPatch +} = internal.exclude + +/** + * Creates a `RuntimeFlagsPatch` which describes the inverse of the patch + * specified by the provided `RuntimeFlagsPatch`. + * + * @since 2.0.0 + * @category utils + */ +export const inverse: (patch: RuntimeFlagsPatch) => RuntimeFlagsPatch = internal.inverse + +/** + * Returns a `ReadonlySet` containing the `RuntimeFlags` described as + * enabled by the specified `RuntimeFlagsPatch`. + * + * @since 2.0.0 + * @category destructors + */ +export const enabledSet: (self: RuntimeFlagsPatch) => ReadonlySet = runtimeFlags.enabledSet + +/** + * Returns a `ReadonlySet` containing the `RuntimeFlags` described as + * disabled by the specified `RuntimeFlagsPatch`. + * + * @since 2.0.0 + * @category destructors + */ +export const disabledSet: (self: RuntimeFlagsPatch) => ReadonlySet = runtimeFlags.disabledSet + +/** + * Renders the provided `RuntimeFlagsPatch` to a string. + * + * @since 2.0.0 + * @category destructors + */ +export const render: (self: RuntimeFlagsPatch) => string = runtimeFlags.renderPatch diff --git a/backend/node_modules/effect/src/STM.ts b/backend/node_modules/effect/src/STM.ts new file mode 100644 index 0000000000000000000000000000000000000000..7c863f5ca079e57b2e22da971d93c49ac100c9c9 --- /dev/null +++ b/backend/node_modules/effect/src/STM.ts @@ -0,0 +1,3091 @@ +/** + * @since 2.0.0 + */ +import * as Cause from "./Cause.js" +import * as Chunk from "./Chunk.js" +import type * as Context from "./Context.js" +import type * as Effect from "./Effect.js" +import type * as Either from "./Either.js" +import type * as FiberId from "./FiberId.js" +import type { LazyArg } from "./Function.js" +import type { TypeLambda } from "./HKT.js" +import * as core from "./internal/stm/core.js" +import * as stm from "./internal/stm/stm.js" +import type * as Option from "./Option.js" +import type { Pipeable } from "./Pipeable.js" +import type { Predicate, Refinement } from "./Predicate.js" +import type { Covariant, MergeRecord, NoExcessProperties, NoInfer } from "./Types.js" +import type * as Unify from "./Unify.js" +import type { YieldWrap } from "./Utils.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const STMTypeId: unique symbol = core.STMTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type STMTypeId = typeof STMTypeId + +/** + * `STM` represents an effect that can be performed transactionally, + * resulting in a failure `E` or a value `A` that may require an environment + * `R` to execute. + * + * Software Transactional Memory is a technique which allows composition of + * arbitrary atomic operations. It is the software analog of transactions in + * database systems. + * + * The API is lifted directly from the Haskell package Control.Concurrent.STM + * although the implementation does not resemble the Haskell one at all. + * + * See http://hackage.haskell.org/package/stm-2.5.0.0/docs/Control-Concurrent-STM.html + * + * STM in Haskell was introduced in: + * + * Composable memory transactions, by Tim Harris, Simon Marlow, Simon Peyton + * Jones, and Maurice Herlihy, in ACM Conference on Principles and Practice of + * Parallel Programming 2005. + * + * See https://www.microsoft.com/en-us/research/publication/composable-memory-transactions/ + * + * See also: + * Lock Free Data Structures using STMs in Haskell, by Anthony Discolo, Tim + * Harris, Simon Marlow, Simon Peyton Jones, Satnam Singh) FLOPS 2006: Eighth + * International Symposium on Functional and Logic Programming, Fuji Susono, + * JAPAN, April 2006 + * + * https://www.microsoft.com/en-us/research/publication/lock-free-data-structures-using-stms-in-haskell/ + * + * The implemtation is based on the ZIO STM module, while JS environments have + * no race conditions from multiple threads STM provides greater benefits for + * synchronization of Fibers and transactional data-types can be quite useful. + * + * @since 2.0.0 + * @category models + */ +export interface STM + extends Effect.Effect, STM.Variance, Pipeable +{ + [Unify.typeSymbol]?: unknown + [Unify.unifySymbol]?: STMUnify + [Unify.ignoreSymbol]?: STMUnifyIgnore + [Symbol.iterator](): Effect.EffectGenerator> +} + +/** + * @since 2.0.0 + * @category models + */ +export interface STMUnify extends Effect.EffectUnify { + STM?: () => A[Unify.typeSymbol] extends STM | infer _ ? STM : never +} + +/** + * @category models + * @since 2.0.0 + */ +export interface STMUnifyIgnore extends Effect.EffectUnifyIgnore { + Effect?: true +} + +/** + * @category type lambdas + * @since 2.0.0 + */ +export interface STMTypeLambda extends TypeLambda { + readonly type: STM +} + +/** + * @since 2.0.0 + * @category models + */ +declare module "./Context.js" { + interface Tag extends STM {} + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Reference extends STM {} +} + +/** + * @since 2.0.0 + * @category models + */ +declare module "./Either.js" { + interface Left extends STM { + readonly _tag: "Left" + } + interface Right extends STM { + readonly _tag: "Right" + } +} + +/** + * @since 2.0.0 + * @category models + */ +declare module "./Option.js" { + interface None extends STM { + readonly _tag: "None" + } + interface Some extends STM { + readonly _tag: "Some" + } +} + +/** + * @since 2.0.0 + */ +export declare namespace STM { + /** + * @since 2.0.0 + * @category models + */ + export interface Variance { + readonly [STMTypeId]: { + readonly _A: Covariant + readonly _E: Covariant + readonly _R: Covariant + } + } +} + +/** + * Returns `true` if the provided value is an `STM`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isSTM: (u: unknown) => u is STM = core.isSTM + +/** + * Treats the specified `acquire` transaction as the acquisition of a + * resource. The `acquire` transaction will be executed interruptibly. If it + * is a success and is committed the specified `release` workflow will be + * executed uninterruptibly as soon as the `use` workflow completes execution. + * + * @since 2.0.0 + * @category constructors + */ +export const acquireUseRelease: { + /** + * Treats the specified `acquire` transaction as the acquisition of a + * resource. The `acquire` transaction will be executed interruptibly. If it + * is a success and is committed the specified `release` workflow will be + * executed uninterruptibly as soon as the `use` workflow completes execution. + * + * @since 2.0.0 + * @category constructors + */ + ( + use: (resource: A) => STM, + release: (resource: A) => STM + ): (acquire: STM) => Effect.Effect + /** + * Treats the specified `acquire` transaction as the acquisition of a + * resource. The `acquire` transaction will be executed interruptibly. If it + * is a success and is committed the specified `release` workflow will be + * executed uninterruptibly as soon as the `use` workflow completes execution. + * + * @since 2.0.0 + * @category constructors + */ + ( + acquire: STM, + use: (resource: A) => STM, + release: (resource: A) => STM + ): Effect.Effect +} = stm.acquireUseRelease + +/** + * @since 2.0.0 + * @category utils + */ +export declare namespace All { + type STMAny = STM + + type ReturnTuple>, Discard extends boolean> = STM< + Discard extends true ? void + : T[number] extends never ? [] + : { -readonly [K in keyof T]: [T[K]] extends [STM] ? A : never }, + T[number] extends never ? never + : [T[number]] extends [{ [STMTypeId]: { _E: (_: never) => infer E } }] ? E + : never, + T[number] extends never ? never + : [T[number]] extends [{ [STMTypeId]: { _R: (_: never) => infer R } }] ? R + : never + > extends infer X ? X : never + + type ReturnIterable, Discard extends boolean> = [T] extends + [Iterable>] ? STM, E, R> : never + + type ReturnObject, Discard extends boolean> = STM< + Discard extends true ? void + : { -readonly [K in keyof T]: [T[K]] extends [STM.Variance] ? A : never }, + keyof T extends never ? never + : [T[keyof T]] extends [{ [STMTypeId]: { _E: (_: never) => infer E } }] ? E + : never, + keyof T extends never ? never + : [T[keyof T]] extends [{ [STMTypeId]: { _R: (_: never) => infer R } }] ? R + : never + > + + /** + * @since 2.0.0 + * @category utils + */ + export type Options = { + readonly discard?: boolean | undefined + } + type IsDiscard = [Extract] extends [never] ? false : true + type Narrow = (A extends [] ? [] : never) | A + + /** + * @since 2.0.0 + * @category utils + */ + export interface Signature { + < + Arg extends ReadonlyArray | Iterable | Record, + O extends NoExcessProperties + >( + arg: Narrow, + options?: O + ): [Arg] extends [ReadonlyArray] ? ReturnTuple> + : [Arg] extends [Iterable] ? ReturnIterable> + : [Arg] extends [Record] ? ReturnObject> + : never + } +} + +/** + * Runs all the provided transactional effects in sequence respecting the + * structure provided in input. + * + * Supports multiple arguments, a single argument tuple / array or record / + * struct. + * + * @since 2.0.0 + * @category constructors + */ +export const all: All.Signature = stm.all + +/** + * Maps the success value of this effect to the specified constant value. + * + * @since 2.0.0 + * @category mapping + */ +export const as: { + /** + * Maps the success value of this effect to the specified constant value. + * + * @since 2.0.0 + * @category mapping + */ + (value: A2): (self: STM) => STM + /** + * Maps the success value of this effect to the specified constant value. + * + * @since 2.0.0 + * @category mapping + */ + (self: STM, value: A2): STM +} = stm.as + +/** + * Maps the success value of this effect to an optional value. + * + * @since 2.0.0 + * @category mapping + */ +export const asSome: (self: STM) => STM, E, R> = stm.asSome + +/** + * Maps the error value of this effect to an optional value. + * + * @since 2.0.0 + * @category mapping + */ +export const asSomeError: (self: STM) => STM, R> = stm.asSomeError + +/** + * This function maps the success value of an `STM` to `void`. If the original + * `STM` succeeds, the returned `STM` will also succeed. If the original `STM` + * fails, the returned `STM` will fail with the same error. + * + * @since 2.0.0 + * @category mapping + */ +export const asVoid: (self: STM) => STM = stm.asVoid + +/** + * Creates an `STM` value from a partial (but pure) function. + * + * @since 2.0.0 + * @category constructors + */ +export const attempt: (evaluate: LazyArg) => STM = stm.attempt + +/** + * Recovers from all errors. + * + * @since 2.0.0 + * @category error handling + */ +export const catchAll: { + /** + * Recovers from all errors. + * + * @since 2.0.0 + * @category error handling + */ + (f: (e: E) => STM): (self: STM) => STM + /** + * Recovers from all errors. + * + * @since 2.0.0 + * @category error handling + */ + (self: STM, f: (e: E) => STM): STM +} = core.catchAll + +/** + * Recovers from some or all of the error cases. + * + * @since 2.0.0 + * @category error handling + */ +export const catchSome: { + /** + * Recovers from some or all of the error cases. + * + * @since 2.0.0 + * @category error handling + */ + (pf: (error: E) => Option.Option>): (self: STM) => STM + /** + * Recovers from some or all of the error cases. + * + * @since 2.0.0 + * @category error handling + */ + (self: STM, pf: (error: E) => Option.Option>): STM +} = stm.catchSome + +/** + * Recovers from the specified tagged error. + * + * @since 2.0.0 + * @category error handling + */ +export const catchTag: { + /** + * Recovers from the specified tagged error. + * + * @since 2.0.0 + * @category error handling + */ + (k: K, f: (e: Extract) => STM): (self: STM) => STM, R1 | R> + /** + * Recovers from the specified tagged error. + * + * @since 2.0.0 + * @category error handling + */ + ( + self: STM, + k: K, + f: (e: Extract) => STM + ): STM, R | R1> +} = stm.catchTag + +/** + * Recovers from multiple tagged errors. + * + * @since 2.0.0 + * @category error handling + */ +export const catchTags: { + /** + * Recovers from multiple tagged errors. + * + * @since 2.0.0 + * @category error handling + */ + < + E extends { _tag: string }, + Cases extends { [K in E["_tag"]]+?: ((error: Extract) => STM) } + >(cases: Cases): ( + self: STM + ) => STM< + | A + | { [K in keyof Cases]: Cases[K] extends (...args: Array) => STM ? A : never }[keyof Cases], + | Exclude + | { [K in keyof Cases]: Cases[K] extends (...args: Array) => STM ? E : never }[keyof Cases], + | R + | { [K in keyof Cases]: Cases[K] extends (...args: Array) => STM ? R : never }[keyof Cases] + > + /** + * Recovers from multiple tagged errors. + * + * @since 2.0.0 + * @category error handling + */ + < + R, + E extends { _tag: string }, + A, + Cases extends { [K in E["_tag"]]+?: ((error: Extract) => STM) } + >(self: STM, cases: Cases): STM< + | A + | { [K in keyof Cases]: Cases[K] extends (...args: Array) => STM ? A : never }[keyof Cases], + | Exclude + | { [K in keyof Cases]: Cases[K] extends (...args: Array) => STM ? E : never }[keyof Cases], + | R + | { [K in keyof Cases]: Cases[K] extends (...args: Array) => STM ? R : never }[keyof Cases] + > +} = stm.catchTags + +/** + * Checks the condition, and if it's true, returns unit, otherwise, retries. + * + * @since 2.0.0 + * @category constructors + */ +export const check: (predicate: LazyArg) => STM = stm.check + +/** + * Simultaneously filters and maps the value produced by this effect. + * + * @since 2.0.0 + * @category mutations + */ +export const collect: { + /** + * Simultaneously filters and maps the value produced by this effect. + * + * @since 2.0.0 + * @category mutations + */ + (pf: (a: A) => Option.Option): (self: STM) => STM + /** + * Simultaneously filters and maps the value produced by this effect. + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, pf: (a: A) => Option.Option): STM +} = stm.collect + +/** + * Simultaneously filters and maps the value produced by this effect. + * + * @since 2.0.0 + * @category mutations + */ +export const collectSTM: { + /** + * Simultaneously filters and maps the value produced by this effect. + * + * @since 2.0.0 + * @category mutations + */ + (pf: (a: A) => Option.Option>): (self: STM) => STM + /** + * Simultaneously filters and maps the value produced by this effect. + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, pf: (a: A) => Option.Option>): STM +} = stm.collectSTM + +/** + * Commits this transaction atomically. + * + * @since 2.0.0 + * @category destructors + */ +export const commit: (self: STM) => Effect.Effect = core.commit + +/** + * Commits this transaction atomically, regardless of whether the transaction + * is a success or a failure. + * + * @since 2.0.0 + * @category destructors + */ +export const commitEither: (self: STM) => Effect.Effect = stm.commitEither + +/** + * Similar to Either.cond, evaluate the predicate, return the given A as + * success if predicate returns true, and the given E as error otherwise + * + * @since 2.0.0 + * @category constructors + */ +export const cond: (predicate: LazyArg, error: LazyArg, result: LazyArg) => STM = stm.cond + +/** + * Retrieves the environment inside an stm. + * + * @since 2.0.0 + * @category constructors + */ +export const context: () => STM, never, R> = core.context + +/** + * Accesses the environment of the transaction to perform a transaction. + * + * @since 2.0.0 + * @category constructors + */ +export const contextWith: (f: (environment: Context.Context) => R) => STM = core.contextWith + +/** + * Accesses the environment of the transaction to perform a transaction. + * + * @since 2.0.0 + * @category constructors + */ +export const contextWithSTM: ( + f: (environment: Context.Context) => STM +) => STM = core.contextWithSTM + +/** + * Transforms the environment being provided to this effect with the specified + * function. + * + * @since 2.0.0 + * @category context + */ +export const mapInputContext: { + /** + * Transforms the environment being provided to this effect with the specified + * function. + * + * @since 2.0.0 + * @category context + */ + (f: (context: Context.Context) => Context.Context): (self: STM) => STM + /** + * Transforms the environment being provided to this effect with the specified + * function. + * + * @since 2.0.0 + * @category context + */ + ( + self: STM, + f: (context: Context.Context) => Context.Context + ): STM +} = core.mapInputContext + +/** + * Fails the transactional effect with the specified defect. + * + * @since 2.0.0 + * @category constructors + */ +export const die: (defect: unknown) => STM = core.die + +/** + * Kills the fiber running the effect with a `Cause.RuntimeException` that + * contains the specified message. + * + * @since 2.0.0 + * @category constructors + */ +export const dieMessage: (message: string) => STM = core.dieMessage + +/** + * Fails the transactional effect with the specified lazily evaluated defect. + * + * @since 2.0.0 + * @category constructors + */ +export const dieSync: (evaluate: LazyArg) => STM = core.dieSync + +/** + * Converts the failure channel into an `Either`. + * + * @since 2.0.0 + * @category mutations + */ +export const either: (self: STM) => STM, never, R> = stm.either + +/** + * Executes the specified finalization transaction whether or not this effect + * succeeds. Note that as with all STM transactions, if the full transaction + * fails, everything will be rolled back. + * + * @since 2.0.0 + * @category finalization + */ +export const ensuring: { + /** + * Executes the specified finalization transaction whether or not this effect + * succeeds. Note that as with all STM transactions, if the full transaction + * fails, everything will be rolled back. + * + * @since 2.0.0 + * @category finalization + */ + (finalizer: STM): (self: STM) => STM + /** + * Executes the specified finalization transaction whether or not this effect + * succeeds. Note that as with all STM transactions, if the full transaction + * fails, everything will be rolled back. + * + * @since 2.0.0 + * @category finalization + */ + (self: STM, finalizer: STM): STM +} = core.ensuring + +/** + * Returns an effect that ignores errors and runs repeatedly until it + * eventually succeeds. + * + * @since 2.0.0 + * @category mutations + */ +export const eventually: (self: STM) => STM = stm.eventually + +/** + * Determines whether all elements of the `Iterable` satisfy the effectual + * predicate. + * + * @since 2.0.0 + * @category constructors + */ +export const every: { + /** + * Determines whether all elements of the `Iterable` satisfy the effectual + * predicate. + * + * @since 2.0.0 + * @category constructors + */ + (predicate: (a: NoInfer) => STM): (iterable: Iterable) => STM + /** + * Determines whether all elements of the `Iterable` satisfy the effectual + * predicate. + * + * @since 2.0.0 + * @category constructors + */ + (iterable: Iterable, predicate: (a: A) => STM): STM +} = stm.every + +/** + * Determines whether any element of the `Iterable[A]` satisfies the effectual + * predicate `f`. + * + * @since 2.0.0 + * @category constructors + */ +export const exists: { + /** + * Determines whether any element of the `Iterable[A]` satisfies the effectual + * predicate `f`. + * + * @since 2.0.0 + * @category constructors + */ + (predicate: (a: NoInfer) => STM): (iterable: Iterable) => STM + /** + * Determines whether any element of the `Iterable[A]` satisfies the effectual + * predicate `f`. + * + * @since 2.0.0 + * @category constructors + */ + (iterable: Iterable, predicate: (a: A) => STM): STM +} = stm.exists + +/** + * Fails the transactional effect with the specified error. + * + * @since 2.0.0 + * @category constructors + */ +export const fail: (error: E) => STM = core.fail + +/** + * Fails the transactional effect with the specified lazily evaluated error. + * + * @since 2.0.0 + * @category constructors + */ +export const failSync: (evaluate: LazyArg) => STM = core.failSync + +/** + * Returns the fiber id of the fiber committing the transaction. + * + * @since 2.0.0 + * @category constructors + */ +export const fiberId: STM = stm.fiberId + +/** + * Filters the collection using the specified effectual predicate. + * + * @since 2.0.0 + * @category constructors + */ +export const filter: { + /** + * Filters the collection using the specified effectual predicate. + * + * @since 2.0.0 + * @category constructors + */ + (predicate: (a: NoInfer) => STM): (iterable: Iterable) => STM, E, R> + /** + * Filters the collection using the specified effectual predicate. + * + * @since 2.0.0 + * @category constructors + */ + (iterable: Iterable, predicate: (a: A) => STM): STM, E, R> +} = stm.filter + +/** + * Filters the collection using the specified effectual predicate, removing + * all elements that satisfy the predicate. + * + * @since 2.0.0 + * @category constructors + */ +export const filterNot: { + /** + * Filters the collection using the specified effectual predicate, removing + * all elements that satisfy the predicate. + * + * @since 2.0.0 + * @category constructors + */ + (predicate: (a: NoInfer) => STM): (iterable: Iterable) => STM, E, R> + /** + * Filters the collection using the specified effectual predicate, removing + * all elements that satisfy the predicate. + * + * @since 2.0.0 + * @category constructors + */ + (iterable: Iterable, predicate: (a: A) => STM): STM, E, R> +} = stm.filterNot + +/** + * Dies with specified defect if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ +export const filterOrDie: { + /** + * Dies with specified defect if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + (refinement: Refinement, B>, defect: LazyArg): (self: STM) => STM + /** + * Dies with specified defect if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + (predicate: Predicate>, defect: LazyArg): (self: STM) => STM + /** + * Dies with specified defect if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + (self: STM, refinement: Refinement, defect: LazyArg): STM + /** + * Dies with specified defect if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + (self: STM, predicate: Predicate, defect: LazyArg): STM +} = stm.filterOrDie + +/** + * Dies with a `Cause.RuntimeException` having the specified message if the + * predicate fails. + * + * @since 2.0.0 + * @category filtering + */ +export const filterOrDieMessage: { + /** + * Dies with a `Cause.RuntimeException` having the specified message if the + * predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + (refinement: Refinement, B>, message: string): (self: STM) => STM + /** + * Dies with a `Cause.RuntimeException` having the specified message if the + * predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + (predicate: Predicate>, message: string): (self: STM) => STM + /** + * Dies with a `Cause.RuntimeException` having the specified message if the + * predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + (self: STM, refinement: Refinement, message: string): STM + /** + * Dies with a `Cause.RuntimeException` having the specified message if the + * predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + (self: STM, predicate: Predicate, message: string): STM +} = stm.filterOrDieMessage + +/** + * Supplies `orElse` if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ +export const filterOrElse: { + /** + * Supplies `orElse` if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + ( + refinement: Refinement, B>, + orElse: (a: NoInfer) => STM + ): (self: STM) => STM + /** + * Supplies `orElse` if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + ( + predicate: Predicate>, + orElse: (a: NoInfer) => STM + ): (self: STM) => STM + /** + * Supplies `orElse` if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + ( + self: STM, + refinement: Refinement, + orElse: (a: A) => STM + ): STM + /** + * Supplies `orElse` if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + ( + self: STM, + predicate: Predicate, + orElse: (a: A) => STM + ): STM +} = stm.filterOrElse + +/** + * Fails with the specified error if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ +export const filterOrFail: { + /** + * Fails with the specified error if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + (refinement: Refinement, B>, orFailWith: (a: NoInfer) => E2): (self: STM) => STM + /** + * Fails with the specified error if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + (predicate: Predicate>, orFailWith: (a: NoInfer) => E2): (self: STM) => STM + /** + * Fails with the specified error if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + (self: STM, refinement: Refinement, orFailWith: (a: A) => E2): STM + /** + * Fails with the specified error if the predicate fails. + * + * @since 2.0.0 + * @category filtering + */ + (self: STM, predicate: Predicate, orFailWith: (a: A) => E2): STM +} = stm.filterOrFail + +/** + * Feeds the value produced by this effect to the specified function, and then + * runs the returned effect as well to produce its results. + * + * @since 2.0.0 + * @category sequencing + */ +export const flatMap: { + /** + * Feeds the value produced by this effect to the specified function, and then + * runs the returned effect as well to produce its results. + * + * @since 2.0.0 + * @category sequencing + */ + (f: (a: A) => STM): (self: STM) => STM + /** + * Feeds the value produced by this effect to the specified function, and then + * runs the returned effect as well to produce its results. + * + * @since 2.0.0 + * @category sequencing + */ + (self: STM, f: (a: A) => STM): STM +} = core.flatMap + +/** + * Flattens out a nested `STM` effect. + * + * @since 2.0.0 + * @category sequencing + */ +export const flatten: (self: STM, E, R>) => STM = stm.flatten + +/** + * Flips the success and failure channels of this transactional effect. This + * allows you to use all methods on the error channel, possibly before + * flipping back. + * + * @since 2.0.0 + * @category mutations + */ +export const flip: (self: STM) => STM = stm.flip + +/** + * Swaps the error/value parameters, applies the function `f` and flips the + * parameters back + * + * @since 2.0.0 + * @category mutations + */ +export const flipWith: { + /** + * Swaps the error/value parameters, applies the function `f` and flips the + * parameters back + * + * @since 2.0.0 + * @category mutations + */ + (f: (stm: STM) => STM): (self: STM) => STM + /** + * Swaps the error/value parameters, applies the function `f` and flips the + * parameters back + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, f: (stm: STM) => STM): STM +} = stm.flipWith + +/** + * Folds over the `STM` effect, handling both failure and success, but not + * retry. + * + * @since 2.0.0 + * @category folding + */ +export const match: { + /** + * Folds over the `STM` effect, handling both failure and success, but not + * retry. + * + * @since 2.0.0 + * @category folding + */ + ( + options: { readonly onFailure: (error: E) => A2; readonly onSuccess: (value: A) => A3 } + ): (self: STM) => STM + /** + * Folds over the `STM` effect, handling both failure and success, but not + * retry. + * + * @since 2.0.0 + * @category folding + */ + ( + self: STM, + options: { readonly onFailure: (error: E) => A2; readonly onSuccess: (value: A) => A3 } + ): STM +} = stm.match + +/** + * Effectfully folds over the `STM` effect, handling both failure and success. + * + * @since 2.0.0 + * @category folding + */ +export const matchSTM: { + /** + * Effectfully folds over the `STM` effect, handling both failure and success. + * + * @since 2.0.0 + * @category folding + */ + ( + options: { readonly onFailure: (e: E) => STM; readonly onSuccess: (a: A) => STM } + ): (self: STM) => STM + /** + * Effectfully folds over the `STM` effect, handling both failure and success. + * + * @since 2.0.0 + * @category folding + */ + ( + self: STM, + options: { readonly onFailure: (e: E) => STM; readonly onSuccess: (a: A) => STM } + ): STM +} = core.matchSTM + +/** + * Applies the function `f` to each element of the `Iterable` and returns + * a transactional effect that produces a new `Chunk`. + * + * @since 2.0.0 + * @category traversing + */ +export const forEach: { + /** + * Applies the function `f` to each element of the `Iterable` and returns + * a transactional effect that produces a new `Chunk`. + * + * @since 2.0.0 + * @category traversing + */ + ( + f: (a: A) => STM, + options?: { readonly discard?: false | undefined } | undefined + ): (elements: Iterable) => STM, E, R> + /** + * Applies the function `f` to each element of the `Iterable` and returns + * a transactional effect that produces a new `Chunk`. + * + * @since 2.0.0 + * @category traversing + */ + (f: (a: A) => STM, options: { readonly discard: true }): (elements: Iterable) => STM + /** + * Applies the function `f` to each element of the `Iterable` and returns + * a transactional effect that produces a new `Chunk`. + * + * @since 2.0.0 + * @category traversing + */ + ( + elements: Iterable, + f: (a: A) => STM, + options?: { readonly discard?: false | undefined } | undefined + ): STM, E, R> + /** + * Applies the function `f` to each element of the `Iterable` and returns + * a transactional effect that produces a new `Chunk`. + * + * @since 2.0.0 + * @category traversing + */ + ( + elements: Iterable, + f: (a: A) => STM, + options: { readonly discard: true } + ): STM +} = stm.forEach + +/** + * Lifts an `Either` into a `STM`. + * + * @since 2.0.0 + * @category constructors + */ +export const fromEither: (either: Either.Either) => STM = stm.fromEither + +/** + * Lifts an `Option` into a `STM`. + * + * @since 2.0.0 + * @category constructors + */ +export const fromOption: (option: Option.Option) => STM> = stm.fromOption + +/** + * @since 2.0.0 + * @category models + */ +export interface Adapter { + (self: STM): STM + (a: A, ab: (a: A) => STM<_A, _E, _R>): STM<_A, _E, _R> + (a: A, ab: (a: A) => B, bc: (b: B) => STM<_A, _E, _R>): STM<_A, _E, _R> + (a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => STM<_A, _E, _R>): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: F) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (g: H) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => S, + st: (s: S) => STM<_A, _E, _R> + ): STM<_A, _E, _R> + ( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => S, + st: (s: S) => T, + tu: (s: T) => STM<_A, _E, _R> + ): STM<_A, _E, _R> +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const gen: >, AEff>( + ...args: + | [ + self: Self, + body: (this: Self, resume: Adapter) => Generator + ] + | [body: (resume: Adapter) => Generator] +) => STM< + AEff, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? E : never, + [Eff] extends [never] ? never : [Eff] extends [YieldWrap>] ? R : never +> = stm.gen + +/** + * Returns a successful effect with the head of the list if the list is + * non-empty or fails with the error `None` if the list is empty. + * + * @since 2.0.0 + * @category getters + */ +export const head: (self: STM, E, R>) => STM, R> = stm.head + +const if_: { + (options: { + readonly onTrue: STM + readonly onFalse: STM /** + * Flattens out a nested `STM` effect. + * + * @since 2.0.0 + * @category sequencing + */ + }): (self: boolean | STM) => STM + ( + self: boolean, + options: { readonly onTrue: STM; readonly onFalse: STM } + ): STM + ( + self: STM, + options: { readonly onTrue: STM; readonly onFalse: STM } + ): STM +} = stm.if_ + +export { + /** + * Runs `onTrue` if the result of `b` is `true` and `onFalse` otherwise. + * + * @since 2.0.0 + * @category mutations + */ + if_ as if +} + +/** + * Returns a new effect that ignores the success or failure of this effect. + * + * @since 2.0.0 + * @category mutations + */ +export const ignore: (self: STM) => STM = stm.ignore + +/** + * Interrupts the fiber running the effect. + * + * @since 2.0.0 + * @category constructors + */ +export const interrupt: STM = core.interrupt + +/** + * Interrupts the fiber running the effect with the specified `FiberId`. + * + * @since 2.0.0 + * @category constructors + */ +export const interruptAs: (fiberId: FiberId.FiberId) => STM = core.interruptAs + +/** + * Returns whether this transactional effect is a failure. + * + * @since 2.0.0 + * @category getters + */ +export const isFailure: (self: STM) => STM = stm.isFailure + +/** + * Returns whether this transactional effect is a success. + * + * @since 2.0.0 + * @category getters + */ +export const isSuccess: (self: STM) => STM = stm.isSuccess + +/** + * Iterates with the specified transactional function. The moral equivalent + * of: + * + * ```ts skip-type-checking + * const s = initial + * + * while (cont(s)) { + * s = body(s) + * } + * + * return s + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export const iterate: ( + initial: Z, + options: { + readonly while: Predicate + readonly body: (z: Z) => STM + } +) => STM = stm.iterate + +/** + * Loops with the specified transactional function, collecting the results + * into a list. The moral equivalent of: + * + * ```ts skip-type-checking + * const as = [] + * let s = initial + * + * while (cont(s)) { + * as.push(body(s)) + * s = inc(s) + * } + * + * return as + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export const loop: { + /** + * Loops with the specified transactional function, collecting the results + * into a list. The moral equivalent of: + * + * ```ts skip-type-checking + * const as = [] + * let s = initial + * + * while (cont(s)) { + * as.push(body(s)) + * s = inc(s) + * } + * + * return as + * ``` + * + * @since 2.0.0 + * @category constructors + */ + ( + initial: Z, + options: { + readonly while: (z: Z) => boolean + readonly step: (z: Z) => Z + readonly body: (z: Z) => STM + readonly discard?: false | undefined + } + ): STM, E, R> + /** + * Loops with the specified transactional function, collecting the results + * into a list. The moral equivalent of: + * + * ```ts skip-type-checking + * const as = [] + * let s = initial + * + * while (cont(s)) { + * as.push(body(s)) + * s = inc(s) + * } + * + * return as + * ``` + * + * @since 2.0.0 + * @category constructors + */ + ( + initial: Z, + options: { + readonly while: (z: Z) => boolean + readonly step: (z: Z) => Z + readonly body: (z: Z) => STM + readonly discard: true + } + ): STM +} = stm.loop + +/** + * Maps the value produced by the effect. + * + * @since 2.0.0 + * @category mapping + */ +export const map: { + /** + * Maps the value produced by the effect. + * + * @since 2.0.0 + * @category mapping + */ + (f: (a: A) => B): (self: STM) => STM + /** + * Maps the value produced by the effect. + * + * @since 2.0.0 + * @category mapping + */ + (self: STM, f: (a: A) => B): STM +} = core.map + +/** + * Maps the value produced by the effect with the specified function that may + * throw exceptions but is otherwise pure, translating any thrown exceptions + * into typed failed effects. + * + * @since 2.0.0 + * @category mapping + */ +export const mapAttempt: { + /** + * Maps the value produced by the effect with the specified function that may + * throw exceptions but is otherwise pure, translating any thrown exceptions + * into typed failed effects. + * + * @since 2.0.0 + * @category mapping + */ + (f: (a: A) => B): (self: STM) => STM + /** + * Maps the value produced by the effect with the specified function that may + * throw exceptions but is otherwise pure, translating any thrown exceptions + * into typed failed effects. + * + * @since 2.0.0 + * @category mapping + */ + (self: STM, f: (a: A) => B): STM +} = stm.mapAttempt + +/** + * Returns an `STM` effect whose failure and success channels have been mapped + * by the specified pair of functions, `f` and `g`. + * + * @since 2.0.0 + * @category mapping + */ +export const mapBoth: { + /** + * Returns an `STM` effect whose failure and success channels have been mapped + * by the specified pair of functions, `f` and `g`. + * + * @since 2.0.0 + * @category mapping + */ + ( + options: { readonly onFailure: (error: E) => E2; readonly onSuccess: (value: A) => A2 } + ): (self: STM) => STM + /** + * Returns an `STM` effect whose failure and success channels have been mapped + * by the specified pair of functions, `f` and `g`. + * + * @since 2.0.0 + * @category mapping + */ + ( + self: STM, + options: { readonly onFailure: (error: E) => E2; readonly onSuccess: (value: A) => A2 } + ): STM +} = stm.mapBoth + +/** + * Maps from one error type to another. + * + * @since 2.0.0 + * @category mapping + */ +export const mapError: { + /** + * Maps from one error type to another. + * + * @since 2.0.0 + * @category mapping + */ + (f: (error: E) => E2): (self: STM) => STM + /** + * Maps from one error type to another. + * + * @since 2.0.0 + * @category mapping + */ + (self: STM, f: (error: E) => E2): STM +} = stm.mapError + +/** + * Returns a new effect where the error channel has been merged into the + * success channel to their common combined type. + * + * @since 2.0.0 + * @category mutations + */ +export const merge: (self: STM) => STM = stm.merge + +/** + * Merges an `Iterable` to a single `STM`, working sequentially. + * + * @since 2.0.0 + * @category constructors + */ +export const mergeAll: { + /** + * Merges an `Iterable` to a single `STM`, working sequentially. + * + * @since 2.0.0 + * @category constructors + */ + (zero: A2, f: (a2: A2, a: A) => A2): (iterable: Iterable>) => STM + /** + * Merges an `Iterable` to a single `STM`, working sequentially. + * + * @since 2.0.0 + * @category constructors + */ + (iterable: Iterable>, zero: A2, f: (a2: A2, a: A) => A2): STM +} = stm.mergeAll + +/** + * Returns a new effect where boolean value of this effect is negated. + * + * @since 2.0.0 + * @category mutations + */ +export const negate: (self: STM) => STM = stm.negate + +/** + * Requires the option produced by this value to be `None`. + * + * @since 2.0.0 + * @category mutations + */ +export const none: (self: STM, E, R>) => STM, R> = stm.none + +/** + * Converts the failure channel into an `Option`. + * + * @since 2.0.0 + * @category mutations + */ +export const option: (self: STM) => STM, never, R> = stm.option + +/** + * Translates `STM` effect failure into death of the fiber, making all + * failures unchecked and not a part of the type of the effect. + * + * @since 2.0.0 + * @category error handling + */ +export const orDie: (self: STM) => STM = stm.orDie + +/** + * Keeps none of the errors, and terminates the fiber running the `STM` effect + * with them, using the specified function to convert the `E` into a defect. + * + * @since 2.0.0 + * @category error handling + */ +export const orDieWith: { + /** + * Keeps none of the errors, and terminates the fiber running the `STM` effect + * with them, using the specified function to convert the `E` into a defect. + * + * @since 2.0.0 + * @category error handling + */ + (f: (error: E) => unknown): (self: STM) => STM + /** + * Keeps none of the errors, and terminates the fiber running the `STM` effect + * with them, using the specified function to convert the `E` into a defect. + * + * @since 2.0.0 + * @category error handling + */ + (self: STM, f: (error: E) => unknown): STM +} = stm.orDieWith + +/** + * Tries this effect first, and if it fails or retries, tries the other + * effect. + * + * @since 2.0.0 + * @category error handling + */ +export const orElse: { + /** + * Tries this effect first, and if it fails or retries, tries the other + * effect. + * + * @since 2.0.0 + * @category error handling + */ + (that: LazyArg>): (self: STM) => STM + /** + * Tries this effect first, and if it fails or retries, tries the other + * effect. + * + * @since 2.0.0 + * @category error handling + */ + (self: STM, that: LazyArg>): STM +} = stm.orElse + +/** + * Returns a transactional effect that will produce the value of this effect + * in left side, unless it fails or retries, in which case, it will produce + * the value of the specified effect in right side. + * + * @since 2.0.0 + * @category error handling + */ +export const orElseEither: { + /** + * Returns a transactional effect that will produce the value of this effect + * in left side, unless it fails or retries, in which case, it will produce + * the value of the specified effect in right side. + * + * @since 2.0.0 + * @category error handling + */ + (that: LazyArg>): (self: STM) => STM, E2, R2 | R> + /** + * Returns a transactional effect that will produce the value of this effect + * in left side, unless it fails or retries, in which case, it will produce + * the value of the specified effect in right side. + * + * @since 2.0.0 + * @category error handling + */ + (self: STM, that: LazyArg>): STM, E2, R | R2> +} = stm.orElseEither + +/** + * Tries this effect first, and if it fails or retries, fails with the + * specified error. + * + * @since 2.0.0 + * @category error handling + */ +export const orElseFail: { + /** + * Tries this effect first, and if it fails or retries, fails with the + * specified error. + * + * @since 2.0.0 + * @category error handling + */ + (error: LazyArg): (self: STM) => STM + /** + * Tries this effect first, and if it fails or retries, fails with the + * specified error. + * + * @since 2.0.0 + * @category error handling + */ + (self: STM, error: LazyArg): STM +} = stm.orElseFail + +/** + * Returns an effect that will produce the value of this effect, unless it + * fails with the `None` value, in which case it will produce the value of the + * specified effect. + * + * @since 2.0.0 + * @category error handling + */ +export const orElseOptional: { + /** + * Returns an effect that will produce the value of this effect, unless it + * fails with the `None` value, in which case it will produce the value of the + * specified effect. + * + * @since 2.0.0 + * @category error handling + */ + (that: LazyArg, R2>>): (self: STM, R>) => STM, R2 | R> + /** + * Returns an effect that will produce the value of this effect, unless it + * fails with the `None` value, in which case it will produce the value of the + * specified effect. + * + * @since 2.0.0 + * @category error handling + */ + ( + self: STM, R>, + that: LazyArg, R2>> + ): STM, R | R2> +} = stm.orElseOptional + +/** + * Tries this effect first, and if it fails or retries, succeeds with the + * specified value. + * + * @since 2.0.0 + * @category error handling + */ +export const orElseSucceed: { + /** + * Tries this effect first, and if it fails or retries, succeeds with the + * specified value. + * + * @since 2.0.0 + * @category error handling + */ + (value: LazyArg): (self: STM) => STM + /** + * Tries this effect first, and if it fails or retries, succeeds with the + * specified value. + * + * @since 2.0.0 + * @category error handling + */ + (self: STM, value: LazyArg): STM +} = stm.orElseSucceed + +/** + * Tries this effect first, and if it enters retry, then it tries the other + * effect. This is an equivalent of Haskell's orElse. + * + * @since 2.0.0 + * @category error handling + */ +export const orTry: { + /** + * Tries this effect first, and if it enters retry, then it tries the other + * effect. This is an equivalent of Haskell's orElse. + * + * @since 2.0.0 + * @category error handling + */ + (that: LazyArg>): (self: STM) => STM + /** + * Tries this effect first, and if it enters retry, then it tries the other + * effect. This is an equivalent of Haskell's orElse. + * + * @since 2.0.0 + * @category error handling + */ + (self: STM, that: LazyArg>): STM +} = core.orTry + +/** + * Feeds elements of type `A` to a function `f` that returns an effect. + * Collects all successes and failures in a tupled fashion. + * + * @since 2.0.0 + * @category traversing + */ +export const partition: { + /** + * Feeds elements of type `A` to a function `f` that returns an effect. + * Collects all successes and failures in a tupled fashion. + * + * @since 2.0.0 + * @category traversing + */ + (f: (a: A) => STM): (elements: Iterable) => STM<[excluded: Array, satisfying: Array], never, R> + /** + * Feeds elements of type `A` to a function `f` that returns an effect. + * Collects all successes and failures in a tupled fashion. + * + * @since 2.0.0 + * @category traversing + */ + (elements: Iterable, f: (a: A) => STM): STM<[excluded: Array, satisfying: Array], never, R> +} = stm.partition + +/** + * Provides the transaction its required environment, which eliminates its + * dependency on `R`. + * + * @since 2.0.0 + * @category context + */ +export const provideContext: { + /** + * Provides the transaction its required environment, which eliminates its + * dependency on `R`. + * + * @since 2.0.0 + * @category context + */ + (env: Context.Context): (self: STM) => STM + /** + * Provides the transaction its required environment, which eliminates its + * dependency on `R`. + * + * @since 2.0.0 + * @category context + */ + (self: STM, env: Context.Context): STM +} = stm.provideContext + +/** + * Splits the context into two parts, providing one part using the + * specified layer and leaving the remainder `R0`. + * + * @since 2.0.0 + * @category context + */ +export const provideSomeContext: { + /** + * Splits the context into two parts, providing one part using the + * specified layer and leaving the remainder `R0`. + * + * @since 2.0.0 + * @category context + */ + (context: Context.Context): (self: STM) => STM> + /** + * Splits the context into two parts, providing one part using the + * specified layer and leaving the remainder `R0`. + * + * @since 2.0.0 + * @category context + */ + (self: STM, context: Context.Context): STM> +} = stm.provideSomeContext + +/** + * Provides the effect with the single service it requires. If the transactional + * effect requires more than one service use `provideEnvironment` instead. + * + * @since 2.0.0 + * @category context + */ +export const provideService: { + /** + * Provides the effect with the single service it requires. If the transactional + * effect requires more than one service use `provideEnvironment` instead. + * + * @since 2.0.0 + * @category context + */ + (tag: Context.Tag, resource: NoInfer): (self: STM) => STM> + /** + * Provides the effect with the single service it requires. If the transactional + * effect requires more than one service use `provideEnvironment` instead. + * + * @since 2.0.0 + * @category context + */ + (self: STM, tag: Context.Tag, resource: NoInfer): STM> +} = stm.provideService + +/** + * Provides the effect with the single service it requires. If the transactional + * effect requires more than one service use `provideEnvironment` instead. + * + * @since 2.0.0 + * @category context + */ +export const provideServiceSTM: { + /** + * Provides the effect with the single service it requires. If the transactional + * effect requires more than one service use `provideEnvironment` instead. + * + * @since 2.0.0 + * @category context + */ + (tag: Context.Tag, stm: STM, E1, R1>): (self: STM) => STM> + /** + * Provides the effect with the single service it requires. If the transactional + * effect requires more than one service use `provideEnvironment` instead. + * + * @since 2.0.0 + * @category context + */ + (self: STM, tag: Context.Tag, stm: STM, E1, R1>): STM> +} = stm.provideServiceSTM + +/** + * Folds an `Iterable` using an effectual function f, working sequentially + * from left to right. + * + * @since 2.0.0 + * @category constructors + */ +export const reduce: { + /** + * Folds an `Iterable` using an effectual function f, working sequentially + * from left to right. + * + * @since 2.0.0 + * @category constructors + */ + (zero: S, f: (s: S, a: A) => STM): (iterable: Iterable) => STM + /** + * Folds an `Iterable` using an effectual function f, working sequentially + * from left to right. + * + * @since 2.0.0 + * @category constructors + */ + (iterable: Iterable, zero: S, f: (s: S, a: A) => STM): STM +} = stm.reduce + +/** + * Reduces an `Iterable` to a single `STM`, working sequentially. + * + * @since 2.0.0 + * @category constructors + */ +export const reduceAll: { + /** + * Reduces an `Iterable` to a single `STM`, working sequentially. + * + * @since 2.0.0 + * @category constructors + */ + (initial: STM, f: (x: A, y: A) => A): (iterable: Iterable>) => STM + /** + * Reduces an `Iterable` to a single `STM`, working sequentially. + * + * @since 2.0.0 + * @category constructors + */ + ( + iterable: Iterable>, + initial: STM, + f: (x: A, y: A) => A + ): STM +} = stm.reduceAll + +/** + * Folds an `Iterable` using an effectual function f, working sequentially + * from right to left. + * + * @since 2.0.0 + * @category constructors + */ +export const reduceRight: { + /** + * Folds an `Iterable` using an effectual function f, working sequentially + * from right to left. + * + * @since 2.0.0 + * @category constructors + */ + (zero: S, f: (s: S, a: A) => STM): (iterable: Iterable) => STM + /** + * Folds an `Iterable` using an effectual function f, working sequentially + * from right to left. + * + * @since 2.0.0 + * @category constructors + */ + (iterable: Iterable, zero: S, f: (s: S, a: A) => STM): STM +} = stm.reduceRight + +/** + * Keeps some of the errors, and terminates the fiber with the rest. + * + * @since 2.0.0 + * @category mutations + */ +export const refineOrDie: { + /** + * Keeps some of the errors, and terminates the fiber with the rest. + * + * @since 2.0.0 + * @category mutations + */ + (pf: (error: E) => Option.Option): (self: STM) => STM + /** + * Keeps some of the errors, and terminates the fiber with the rest. + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, pf: (error: E) => Option.Option): STM +} = stm.refineOrDie + +/** + * Keeps some of the errors, and terminates the fiber with the rest, using the + * specified function to convert the `E` into a `Throwable`. + * + * @since 2.0.0 + * @category mutations + */ +export const refineOrDieWith: { + /** + * Keeps some of the errors, and terminates the fiber with the rest, using the + * specified function to convert the `E` into a `Throwable`. + * + * @since 2.0.0 + * @category mutations + */ + (pf: (error: E) => Option.Option, f: (error: E) => unknown): (self: STM) => STM + /** + * Keeps some of the errors, and terminates the fiber with the rest, using the + * specified function to convert the `E` into a `Throwable`. + * + * @since 2.0.0 + * @category mutations + */ + ( + self: STM, + pf: (error: E) => Option.Option, + f: (error: E) => unknown + ): STM +} = stm.refineOrDieWith + +/** + * Fail with the returned value if the `PartialFunction` matches, otherwise + * continue with our held value. + * + * @since 2.0.0 + * @category mutations + */ +export const reject: { + /** + * Fail with the returned value if the `PartialFunction` matches, otherwise + * continue with our held value. + * + * @since 2.0.0 + * @category mutations + */ + (pf: (a: A) => Option.Option): (self: STM) => STM + /** + * Fail with the returned value if the `PartialFunction` matches, otherwise + * continue with our held value. + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, pf: (a: A) => Option.Option): STM +} = stm.reject + +/** + * Continue with the returned computation if the specified partial function + * matches, translating the successful match into a failure, otherwise continue + * with our held value. + * + * @since 2.0.0 + * @category mutations + */ +export const rejectSTM: { + /** + * Continue with the returned computation if the specified partial function + * matches, translating the successful match into a failure, otherwise continue + * with our held value. + * + * @since 2.0.0 + * @category mutations + */ + (pf: (a: A) => Option.Option>): (self: STM) => STM + /** + * Continue with the returned computation if the specified partial function + * matches, translating the successful match into a failure, otherwise continue + * with our held value. + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, pf: (a: A) => Option.Option>): STM +} = stm.rejectSTM + +/** + * Repeats this `STM` effect until its result satisfies the specified + * predicate. + * + * **WARNING**: `repeatUntil` uses a busy loop to repeat the effect and will + * consume a thread until it completes (it cannot yield). This is because STM + * describes a single atomic transaction which must either complete, retry or + * fail a transaction before yielding back to the Effect runtime. + * - Use `retryUntil` instead if you don't need to maintain transaction + * state for repeats. + * - Ensure repeating the STM effect will eventually satisfy the predicate. + * + * @since 2.0.0 + * @category mutations + */ +export const repeatUntil: { + /** + * Repeats this `STM` effect until its result satisfies the specified + * predicate. + * + * **WARNING**: `repeatUntil` uses a busy loop to repeat the effect and will + * consume a thread until it completes (it cannot yield). This is because STM + * describes a single atomic transaction which must either complete, retry or + * fail a transaction before yielding back to the Effect runtime. + * - Use `retryUntil` instead if you don't need to maintain transaction + * state for repeats. + * - Ensure repeating the STM effect will eventually satisfy the predicate. + * + * @since 2.0.0 + * @category mutations + */ + (predicate: Predicate): (self: STM) => STM + /** + * Repeats this `STM` effect until its result satisfies the specified + * predicate. + * + * **WARNING**: `repeatUntil` uses a busy loop to repeat the effect and will + * consume a thread until it completes (it cannot yield). This is because STM + * describes a single atomic transaction which must either complete, retry or + * fail a transaction before yielding back to the Effect runtime. + * - Use `retryUntil` instead if you don't need to maintain transaction + * state for repeats. + * - Ensure repeating the STM effect will eventually satisfy the predicate. + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, predicate: Predicate): STM +} = stm.repeatUntil + +/** + * Repeats this `STM` effect while its result satisfies the specified + * predicate. + * + * **WARNING**: `repeatWhile` uses a busy loop to repeat the effect and will + * consume a thread until it completes (it cannot yield). This is because STM + * describes a single atomic transaction which must either complete, retry or + * fail a transaction before yielding back to the Effect runtime. + * - Use `retryWhile` instead if you don't need to maintain transaction + * state for repeats. + * - Ensure repeating the STM effect will eventually not satisfy the + * predicate. + * + * @since 2.0.0 + * @category mutations + */ +export const repeatWhile: { + /** + * Repeats this `STM` effect while its result satisfies the specified + * predicate. + * + * **WARNING**: `repeatWhile` uses a busy loop to repeat the effect and will + * consume a thread until it completes (it cannot yield). This is because STM + * describes a single atomic transaction which must either complete, retry or + * fail a transaction before yielding back to the Effect runtime. + * - Use `retryWhile` instead if you don't need to maintain transaction + * state for repeats. + * - Ensure repeating the STM effect will eventually not satisfy the + * predicate. + * + * @since 2.0.0 + * @category mutations + */ + (predicate: Predicate): (self: STM) => STM + /** + * Repeats this `STM` effect while its result satisfies the specified + * predicate. + * + * **WARNING**: `repeatWhile` uses a busy loop to repeat the effect and will + * consume a thread until it completes (it cannot yield). This is because STM + * describes a single atomic transaction which must either complete, retry or + * fail a transaction before yielding back to the Effect runtime. + * - Use `retryWhile` instead if you don't need to maintain transaction + * state for repeats. + * - Ensure repeating the STM effect will eventually not satisfy the + * predicate. + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, predicate: Predicate): STM +} = stm.repeatWhile + +/** + * Replicates the given effect n times. If 0 or negative numbers are given, an + * empty `Chunk` will be returned. + * + * @since 2.0.0 + * @category constructors + */ +export const replicate: { + /** + * Replicates the given effect n times. If 0 or negative numbers are given, an + * empty `Chunk` will be returned. + * + * @since 2.0.0 + * @category constructors + */ + (n: number): (self: STM) => Array> + /** + * Replicates the given effect n times. If 0 or negative numbers are given, an + * empty `Chunk` will be returned. + * + * @since 2.0.0 + * @category constructors + */ + (self: STM, n: number): Array> +} = stm.replicate + +/** + * Performs this transaction the specified number of times and collects the + * results. + * + * @since 2.0.0 + * @category constructors + */ +export const replicateSTM: { + /** + * Performs this transaction the specified number of times and collects the + * results. + * + * @since 2.0.0 + * @category constructors + */ + (n: number): (self: STM) => STM, E, R> + /** + * Performs this transaction the specified number of times and collects the + * results. + * + * @since 2.0.0 + * @category constructors + */ + (self: STM, n: number): STM, E, R> +} = stm.replicateSTM + +/** + * Performs this transaction the specified number of times, discarding the + * results. + * + * @since 2.0.0 + * @category constructors + */ +export const replicateSTMDiscard: { + /** + * Performs this transaction the specified number of times, discarding the + * results. + * + * @since 2.0.0 + * @category constructors + */ + (n: number): (self: STM) => STM + /** + * Performs this transaction the specified number of times, discarding the + * results. + * + * @since 2.0.0 + * @category constructors + */ + (self: STM, n: number): STM +} = stm.replicateSTMDiscard + +/** + * Abort and retry the whole transaction when any of the underlying + * transactional variables have changed. + * + * @since 2.0.0 + * @category error handling + */ +export const retry: STM = core.retry + +/** + * Filters the value produced by this effect, retrying the transaction until + * the predicate returns `true` for the value. + * + * @since 2.0.0 + * @category mutations + */ +export const retryUntil: { + /** + * Filters the value produced by this effect, retrying the transaction until + * the predicate returns `true` for the value. + * + * @since 2.0.0 + * @category mutations + */ + (refinement: Refinement, B>): (self: STM) => STM + /** + * Filters the value produced by this effect, retrying the transaction until + * the predicate returns `true` for the value. + * + * @since 2.0.0 + * @category mutations + */ + (predicate: Predicate): (self: STM) => STM + /** + * Filters the value produced by this effect, retrying the transaction until + * the predicate returns `true` for the value. + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, refinement: Refinement): STM + /** + * Filters the value produced by this effect, retrying the transaction until + * the predicate returns `true` for the value. + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, predicate: Predicate): STM +} = stm.retryUntil + +/** + * Filters the value produced by this effect, retrying the transaction while + * the predicate returns `true` for the value. + * + * @since 2.0.0 + * @category mutations + */ +export const retryWhile: { + /** + * Filters the value produced by this effect, retrying the transaction while + * the predicate returns `true` for the value. + * + * @since 2.0.0 + * @category mutations + */ + (predicate: Predicate): (self: STM) => STM + /** + * Filters the value produced by this effect, retrying the transaction while + * the predicate returns `true` for the value. + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, predicate: Predicate): STM +} = stm.retryWhile + +/** + * Converts an option on values into an option on errors. + * + * @since 2.0.0 + * @category getters + */ +export const some: (self: STM, E, R>) => STM, R> = stm.some + +/** + * Returns an `STM` effect that succeeds with the specified value. + * + * @since 2.0.0 + * @category constructors + */ +export const succeed: (value: A) => STM = core.succeed + +/** + * Returns an effect with the empty value. + * + * @since 2.0.0 + * @category constructors + */ +export const succeedNone: STM> = stm.succeedNone + +/** + * Returns an effect with the optional value. + * + * @since 2.0.0 + * @category constructors + */ +export const succeedSome: (value: A) => STM> = stm.succeedSome + +/** + * Summarizes a `STM` effect by computing a provided value before and after + * execution, and then combining the values to produce a summary, together + * with the result of execution. + * + * @since 2.0.0 + * @category mutations + */ +export const summarized: { + /** + * Summarizes a `STM` effect by computing a provided value before and after + * execution, and then combining the values to produce a summary, together + * with the result of execution. + * + * @since 2.0.0 + * @category mutations + */ + (summary: STM, f: (before: A2, after: A2) => A3): (self: STM) => STM<[A3, A], E2 | E, R2 | R> + /** + * Summarizes a `STM` effect by computing a provided value before and after + * execution, and then combining the values to produce a summary, together + * with the result of execution. + * + * @since 2.0.0 + * @category mutations + */ + ( + self: STM, + summary: STM, + f: (before: A2, after: A2) => A3 + ): STM<[A3, A], E | E2, R | R2> +} = stm.summarized + +/** + * Suspends creation of the specified transaction lazily. + * + * @since 2.0.0 + * @category constructors + */ +export const suspend: (evaluate: LazyArg>) => STM = stm.suspend + +/** + * Returns an `STM` effect that succeeds with the specified lazily evaluated + * value. + * + * @since 2.0.0 + * @category constructors + */ +export const sync: (evaluate: () => A) => STM = core.sync + +/** + * "Peeks" at the success of transactional effect. + * + * @since 2.0.0 + * @category sequencing + */ +export const tap: { + /** + * "Peeks" at the success of transactional effect. + * + * @since 2.0.0 + * @category sequencing + */ + (f: (a: A) => STM): (self: STM) => STM + /** + * "Peeks" at the success of transactional effect. + * + * @since 2.0.0 + * @category sequencing + */ + (self: STM, f: (a: A) => STM): STM +} = stm.tap + +/** + * "Peeks" at both sides of an transactional effect. + * + * @since 2.0.0 + * @category sequencing + */ +export const tapBoth: { + /** + * "Peeks" at both sides of an transactional effect. + * + * @since 2.0.0 + * @category sequencing + */ + ( + options: { readonly onFailure: (error: XE) => STM; readonly onSuccess: (value: XA) => STM } + ): (self: STM) => STM + /** + * "Peeks" at both sides of an transactional effect. + * + * @since 2.0.0 + * @category sequencing + */ + ( + self: STM, + options: { readonly onFailure: (error: XE) => STM; readonly onSuccess: (value: XA) => STM } + ): STM +} = stm.tapBoth + +/** + * "Peeks" at the error of the transactional effect. + * + * @since 2.0.0 + * @category sequencing + */ +export const tapError: { + /** + * "Peeks" at the error of the transactional effect. + * + * @since 2.0.0 + * @category sequencing + */ + (f: (error: NoInfer) => STM): (self: STM) => STM + /** + * "Peeks" at the error of the transactional effect. + * + * @since 2.0.0 + * @category sequencing + */ + (self: STM, f: (error: E) => STM): STM +} = stm.tapError + +const try_: { + (options: { + readonly try: LazyArg + readonly catch: (u: unknown) => E + }): STM + (try_: LazyArg): STM +} = stm.try_ + +export { + /** + * Imports a synchronous side-effect into a pure value, translating any thrown + * exceptions into typed failed effects. + * + * @since 2.0.0 + * @category constructors + */ + try_ as try +} + +/** + * The moral equivalent of `if (!p) exp` + * + * @since 2.0.0 + * @category mutations + */ +export const unless: { + /** + * The moral equivalent of `if (!p) exp` + * + * @since 2.0.0 + * @category mutations + */ + (predicate: LazyArg): (self: STM) => STM, E, R> + /** + * The moral equivalent of `if (!p) exp` + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, predicate: LazyArg): STM, E, R> +} = stm.unless + +/** + * The moral equivalent of `if (!p) exp` when `p` has side-effects + * + * @since 2.0.0 + * @category mutations + */ +export const unlessSTM: { + /** + * The moral equivalent of `if (!p) exp` when `p` has side-effects + * + * @since 2.0.0 + * @category mutations + */ + (predicate: STM): (self: STM) => STM, E2 | E, R2 | R> + /** + * The moral equivalent of `if (!p) exp` when `p` has side-effects + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, predicate: STM): STM, E | E2, R | R2> +} = stm.unlessSTM + +/** + * Converts an option on errors into an option on values. + * + * @since 2.0.0 + * @category getters + */ +export const unsome: (self: STM, R>) => STM, E, R> = stm.unsome + +const void_: STM = stm.void +export { + /** + * Returns an `STM` effect that succeeds with `void`. + * + * @since 2.0.0 + * @category constructors + */ + void_ as void +} + +/** + * Feeds elements of type `A` to `f` and accumulates all errors in error + * channel or successes in success channel. + * + * This combinator is lossy meaning that if there are errors all successes + * will be lost. To retain all information please use `STM.partition`. + * + * @since 2.0.0 + * @category mutations + */ +export const validateAll: { + /** + * Feeds elements of type `A` to `f` and accumulates all errors in error + * channel or successes in success channel. + * + * This combinator is lossy meaning that if there are errors all successes + * will be lost. To retain all information please use `STM.partition`. + * + * @since 2.0.0 + * @category mutations + */ + (f: (a: A) => STM): (elements: Iterable) => STM, [E, ...Array], R> + /** + * Feeds elements of type `A` to `f` and accumulates all errors in error + * channel or successes in success channel. + * + * This combinator is lossy meaning that if there are errors all successes + * will be lost. To retain all information please use `STM.partition`. + * + * @since 2.0.0 + * @category mutations + */ + (elements: Iterable, f: (a: A) => STM): STM, [E, ...Array], R> +} = stm.validateAll + +/** + * Feeds elements of type `A` to `f` until it succeeds. Returns first success + * or the accumulation of all errors. + * + * @since 2.0.0 + * @category mutations + */ +export const validateFirst: { + /** + * Feeds elements of type `A` to `f` until it succeeds. Returns first success + * or the accumulation of all errors. + * + * @since 2.0.0 + * @category mutations + */ + (f: (a: A) => STM): (elements: Iterable) => STM, R> + /** + * Feeds elements of type `A` to `f` until it succeeds. Returns first success + * or the accumulation of all errors. + * + * @since 2.0.0 + * @category mutations + */ + (elements: Iterable, f: (a: A) => STM): STM, R> +} = stm.validateFirst + +/** + * The moral equivalent of `if (p) exp`. + * + * @since 2.0.0 + * @category mutations + */ +export const when: { + /** + * The moral equivalent of `if (p) exp`. + * + * @since 2.0.0 + * @category mutations + */ + (predicate: LazyArg): (self: STM) => STM, E, R> + /** + * The moral equivalent of `if (p) exp`. + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, predicate: LazyArg): STM, E, R> +} = stm.when + +/** + * The moral equivalent of `if (p) exp` when `p` has side-effects. + * + * @since 2.0.0 + * @category mutations + */ +export const whenSTM: { + /** + * The moral equivalent of `if (p) exp` when `p` has side-effects. + * + * @since 2.0.0 + * @category mutations + */ + (predicate: STM): (self: STM) => STM, E2 | E, R2 | R> + /** + * The moral equivalent of `if (p) exp` when `p` has side-effects. + * + * @since 2.0.0 + * @category mutations + */ + (self: STM, predicate: STM): STM, E | E2, R | R2> +} = stm.whenSTM + +/** + * Sequentially zips this value with the specified one. + * + * @since 2.0.0 + * @category zipping + */ +export const zip: { + /** + * Sequentially zips this value with the specified one. + * + * @since 2.0.0 + * @category zipping + */ + (that: STM): (self: STM) => STM<[A, A1], E1 | E, R1 | R> + /** + * Sequentially zips this value with the specified one. + * + * @since 2.0.0 + * @category zipping + */ + (self: STM, that: STM): STM<[A, A1], E | E1, R | R1> +} = core.zip + +/** + * Sequentially zips this value with the specified one, discarding the second + * element of the tuple. + * + * @since 2.0.0 + * @category zipping + */ +export const zipLeft: { + /** + * Sequentially zips this value with the specified one, discarding the second + * element of the tuple. + * + * @since 2.0.0 + * @category zipping + */ + (that: STM): (self: STM) => STM + /** + * Sequentially zips this value with the specified one, discarding the second + * element of the tuple. + * + * @since 2.0.0 + * @category zipping + */ + (self: STM, that: STM): STM +} = core.zipLeft + +/** + * Sequentially zips this value with the specified one, discarding the first + * element of the tuple. + * + * @since 2.0.0 + * @category zipping + */ +export const zipRight: { + /** + * Sequentially zips this value with the specified one, discarding the first + * element of the tuple. + * + * @since 2.0.0 + * @category zipping + */ + (that: STM): (self: STM) => STM + /** + * Sequentially zips this value with the specified one, discarding the first + * element of the tuple. + * + * @since 2.0.0 + * @category zipping + */ + (self: STM, that: STM): STM +} = core.zipRight + +/** + * Sequentially zips this value with the specified one, combining the values + * using the specified combiner function. + * + * @since 2.0.0 + * @category zipping + */ +export const zipWith: { + /** + * Sequentially zips this value with the specified one, combining the values + * using the specified combiner function. + * + * @since 2.0.0 + * @category zipping + */ + (that: STM, f: (a: A, b: A1) => A2): (self: STM) => STM + /** + * Sequentially zips this value with the specified one, combining the values + * using the specified combiner function. + * + * @since 2.0.0 + * @category zipping + */ + (self: STM, that: STM, f: (a: A, b: A1) => A2): STM +} = core.zipWith + +/** + * This function takes an iterable of `STM` values and returns a new + * `STM` value that represents the first `STM` value in the iterable + * that succeeds. If all of the `Effect` values in the iterable fail, then + * the resulting `STM` value will fail as well. + * + * This function is sequential, meaning that the `STM` values in the + * iterable will be executed in sequence, and the first one that succeeds + * will determine the outcome of the resulting `STM` value. + * + * Returns a new `STM` value that represents the first successful + * `STM` value in the iterable, or a failed `STM` value if all of the + * `STM` values in the iterable fail. + * + * @since 2.0.0 + * @category elements + */ +export const firstSuccessOf = (effects: Iterable>): STM => + suspend(() => { + const list = Chunk.fromIterable(effects) + if (!Chunk.isNonEmpty(list)) { + return dieSync(() => new Cause.IllegalArgumentException(`Received an empty collection of effects`)) + } + return Chunk.reduce( + Chunk.tailNonEmpty(list), + Chunk.headNonEmpty(list), + (left, right) => orElse(left, () => right) + ) + }) + +/** + * @category do notation + * @since 2.0.0 + */ +export const Do: STM<{}> = succeed({}) + +/** + * @category do notation + * @since 2.0.0 + */ +export const bind: { + /** + * @category do notation + * @since 2.0.0 + */ + (tag: Exclude, f: (_: NoInfer) => STM): (self: STM) => STM, E2 | E, R2 | R> + /** + * @category do notation + * @since 2.0.0 + */ + ( + self: STM, + tag: Exclude, + f: (_: NoInfer) => STM + ): STM, E | E2, R | R2> +} = stm.bind + +const let_: { + ( + tag: Exclude, + f: (_: NoInfer) => A + ): (self: STM) => STM, E, R> + ( + self: STM, + tag: Exclude, + f: (_: NoInfer) => A + ): STM, E, R> +} = stm.let_ + +export { + /** + * @category do notation + * @since 2.0.0 + */ + let_ as let +} + +/** + * @category do notation + * @since 2.0.0 + */ +export const bindTo: { + /** + * @category do notation + * @since 2.0.0 + */ + (tag: N): (self: STM) => STM, E, R> + /** + * @category do notation + * @since 2.0.0 + */ + (self: STM, tag: N): STM, E, R> +} = stm.bindTo diff --git a/backend/node_modules/effect/src/Schedule.ts b/backend/node_modules/effect/src/Schedule.ts new file mode 100644 index 0000000000000000000000000000000000000000..261279c4436f49a7d75cb5348a684f6fd762e049 --- /dev/null +++ b/backend/node_modules/effect/src/Schedule.ts @@ -0,0 +1,3740 @@ +/** + * @since 2.0.0 + */ +import type * as Cause from "./Cause.js" +import type * as Chunk from "./Chunk.js" +import type * as Context from "./Context.js" +import type * as Cron from "./Cron.js" +import type * as DateTime from "./DateTime.js" +import type * as Duration from "./Duration.js" +import type * as Effect from "./Effect.js" +import type * as Either from "./Either.js" +import type { LazyArg } from "./Function.js" +import * as internal from "./internal/schedule.js" +import type * as Option from "./Option.js" +import type { Pipeable } from "./Pipeable.js" +import type { Predicate } from "./Predicate.js" +import type * as Ref from "./Ref.js" +import type * as ScheduleDecision from "./ScheduleDecision.js" +import type * as Intervals from "./ScheduleIntervals.js" +import type * as Types from "./Types.js" + +/** + * @since 2.0.0 + * @category Symbols + */ +export const ScheduleTypeId: unique symbol = internal.ScheduleTypeId + +/** + * @since 2.0.0 + * @category Symbols + */ +export type ScheduleTypeId = typeof ScheduleTypeId + +/** + * @since 2.0.0 + * @category Symbols + */ +export const ScheduleDriverTypeId: unique symbol = internal.ScheduleDriverTypeId + +/** + * @since 2.0.0 + * @category Symbols + */ +export type ScheduleDriverTypeId = typeof ScheduleDriverTypeId + +/** + * A `Schedule` defines a recurring schedule, which consumes values + * of type `In`, and which returns values of type `Out`. + * + * The `Schedule` type is structured as follows: + * + * ```ts skip-type-checking + * // ┌─── The type of output produced by the schedule + * // │ ┌─── The type of input consumed by the schedule + * // │ │ ┌─── Additional requirements for the schedule + * // ▼ ▼ ▼ + * Schedule + * ``` + * + * A schedule operates by consuming values of type `In` (such as errors in the + * case of `Effect.retry`, or values in the case of `Effect.repeat`) and + * producing values of type `Out`. It determines when to halt or continue the + * execution based on input values and its internal state. + * + * The inclusion of a `Requirements` parameter allows the schedule to leverage + * additional services or resources as needed. + * + * Schedules are defined as a possibly infinite set of intervals spread out over + * time. Each interval defines a window in which recurrence is possible. + * + * When schedules are used to repeat or retry effects, the starting boundary of + * each interval produced by a schedule is used as the moment when the effect + * will be executed again. + * + * Schedules can be composed in different ways: + * + * - Union: Combines two schedules and recurs if either schedule wants to + * continue, using the shorter delay. + * - Intersection: Combines two schedules and recurs only if both schedules want + * to continue, using the longer delay. + * - Sequencing: Combines two schedules by running the first one fully, then + * switching to the second. + * + * In addition, schedule inputs and outputs can be transformed, filtered (to + * terminate a schedule early in response to some input or output), and so + * forth. + * + * A variety of other operators exist for transforming and combining schedules, + * and the companion object for `Schedule` contains all common types of + * schedules, both for performing retrying, as well as performing repetition. + * + * @category Model + * @since 2.0.0 + */ +export interface Schedule extends Schedule.Variance, Pipeable { + /** + * Initial State + */ + readonly initial: any + /** + * Schedule Step + */ + step( + now: number, + input: In, + state: any + ): Effect.Effect +} + +/** + * @since 2.0.0 + */ +export declare namespace Schedule { + /** + * @since 2.0.0 + * @category Models + */ + export interface Variance { + readonly [ScheduleTypeId]: { + readonly _Out: Types.Covariant + readonly _In: Types.Contravariant + readonly _R: Types.Covariant + } + } + + /** + * @since 2.0.0 + */ + export interface DriverVariance { + readonly [ScheduleDriverTypeId]: { + readonly _Out: Types.Covariant + readonly _In: Types.Contravariant + readonly _R: Types.Covariant + } + } +} + +/** + * @since 2.0.0 + * @category Models + */ +export interface ScheduleDriver extends Schedule.DriverVariance { + readonly state: Effect.Effect + readonly iterationMeta: Ref.Ref + readonly last: Effect.Effect + readonly reset: Effect.Effect + next(input: In): Effect.Effect, R> +} + +/** + * Creates a new schedule with a custom state and step function. + * + * **Details** + * + * This function constructs a `Schedule` by defining its initial state and a + * step function, which determines how the schedule progresses over time. The + * step function is called on each iteration with the current time, an input + * value, and the schedule's current state. It returns the next state, an output + * value, and a decision on whether the schedule should continue or stop. + * + * This function is useful for creating custom scheduling logic that goes beyond + * predefined schedules like fixed intervals or exponential backoff. It allows + * full control over how the schedule behaves at each step. + * + * @since 2.0.0 + * @category Constructors + */ +export const makeWithState: ( + initial: S, + step: ( + now: number, + input: In, + state: S + ) => Effect.Effect +) => Schedule = internal.makeWithState + +/** + * Checks whether a given value is a `Schedule`. + * + * @since 2.0.0 + * @category Guards + */ +export const isSchedule: (u: unknown) => u is Schedule = internal.isSchedule + +/** + * Adds a delay to every interval in a schedule. + * + * **Details** + * + * This function modifies a given schedule by applying an additional delay to + * every interval it defines. The delay is determined by the provided function, + * which takes the schedule's output and returns a delay duration. + * + * @see {@link addDelayEffect} If you need to compute the delay using an effectful function. + * + * @since 2.0.0 + * @category Timing & Delay + */ +export const addDelay: { + /** + * Adds a delay to every interval in a schedule. + * + * **Details** + * + * This function modifies a given schedule by applying an additional delay to + * every interval it defines. The delay is determined by the provided function, + * which takes the schedule's output and returns a delay duration. + * + * @see {@link addDelayEffect} If you need to compute the delay using an effectful function. + * + * @since 2.0.0 + * @category Timing & Delay + */ + (f: (out: Out) => Duration.DurationInput): (self: Schedule) => Schedule + /** + * Adds a delay to every interval in a schedule. + * + * **Details** + * + * This function modifies a given schedule by applying an additional delay to + * every interval it defines. The delay is determined by the provided function, + * which takes the schedule's output and returns a delay duration. + * + * @see {@link addDelayEffect} If you need to compute the delay using an effectful function. + * + * @since 2.0.0 + * @category Timing & Delay + */ + (self: Schedule, f: (out: Out) => Duration.DurationInput): Schedule +} = internal.addDelay + +/** + * Adds an effectfully computed delay to every interval in a schedule. + * + * **Details** + * + * This function modifies a given schedule by applying an additional delay to + * each interval, where the delay is determined by an effectful function. The + * function takes the schedule’s output and returns an effect that produces a + * delay duration. + * + * @see {@link addDelay} If you need to compute the delay using a pure function. + * + * @since 2.0.0 + * @category Timing & Delay + */ +export const addDelayEffect: { + /** + * Adds an effectfully computed delay to every interval in a schedule. + * + * **Details** + * + * This function modifies a given schedule by applying an additional delay to + * each interval, where the delay is determined by an effectful function. The + * function takes the schedule’s output and returns an effect that produces a + * delay duration. + * + * @see {@link addDelay} If you need to compute the delay using a pure function. + * + * @since 2.0.0 + * @category Timing & Delay + */ + (f: (out: Out) => Effect.Effect): (self: Schedule) => Schedule + /** + * Adds an effectfully computed delay to every interval in a schedule. + * + * **Details** + * + * This function modifies a given schedule by applying an additional delay to + * each interval, where the delay is determined by an effectful function. The + * function takes the schedule’s output and returns an effect that produces a + * delay duration. + * + * @see {@link addDelay} If you need to compute the delay using a pure function. + * + * @since 2.0.0 + * @category Timing & Delay + */ + ( + self: Schedule, + f: (out: Out) => Effect.Effect + ): Schedule +} = internal.addDelayEffect + +/** + * Runs two schedules sequentially, merging their outputs. + * + * **Details** + * + * This function executes two schedules one after the other. The first schedule + * runs to completion, and then the second schedule begins execution. Unlike + * {@link andThenEither}, this function merges the outputs instead of wrapping + * them in `Either`, allowing both schedules to contribute their results + * directly. + * + * This is useful when a workflow consists of two phases where the second phase + * should start only after the first one has fully completed. + * + * @see {@link andThenEither} If you need to keep track of which schedule + * produced each result. + * + * @since 2.0.0 + * @category Sequential Composition + */ +export const andThen: { + /** + * Runs two schedules sequentially, merging their outputs. + * + * **Details** + * + * This function executes two schedules one after the other. The first schedule + * runs to completion, and then the second schedule begins execution. Unlike + * {@link andThenEither}, this function merges the outputs instead of wrapping + * them in `Either`, allowing both schedules to contribute their results + * directly. + * + * This is useful when a workflow consists of two phases where the second phase + * should start only after the first one has fully completed. + * + * @see {@link andThenEither} If you need to keep track of which schedule + * produced each result. + * + * @since 2.0.0 + * @category Sequential Composition + */ + (that: Schedule): (self: Schedule) => Schedule + /** + * Runs two schedules sequentially, merging their outputs. + * + * **Details** + * + * This function executes two schedules one after the other. The first schedule + * runs to completion, and then the second schedule begins execution. Unlike + * {@link andThenEither}, this function merges the outputs instead of wrapping + * them in `Either`, allowing both schedules to contribute their results + * directly. + * + * This is useful when a workflow consists of two phases where the second phase + * should start only after the first one has fully completed. + * + * @see {@link andThenEither} If you need to keep track of which schedule + * produced each result. + * + * @since 2.0.0 + * @category Sequential Composition + */ + (self: Schedule, that: Schedule): Schedule +} = internal.andThen + +/** + * Runs two schedules sequentially, collecting results in an `Either`. + * + * **Details** + * + * This function combines two schedules in sequence. The first schedule runs to + * completion, and then the second schedule starts and runs to completion as + * well. The outputs of both schedules are collected into an `Either` structure: + * - `Either.Left` contains the output of the second schedule. + * - `Either.Right` contains the output of the first schedule. + * + * This is useful when you need to switch from one schedule to another after the + * first one finishes, while still keeping track of which schedule produced each + * result. + * + * @see {@link andThen} If you need to merge the outputs of both schedules. + * + * @since 2.0.0 + * @category Sequential Composition + */ +export const andThenEither: { + /** + * Runs two schedules sequentially, collecting results in an `Either`. + * + * **Details** + * + * This function combines two schedules in sequence. The first schedule runs to + * completion, and then the second schedule starts and runs to completion as + * well. The outputs of both schedules are collected into an `Either` structure: + * - `Either.Left` contains the output of the second schedule. + * - `Either.Right` contains the output of the first schedule. + * + * This is useful when you need to switch from one schedule to another after the + * first one finishes, while still keeping track of which schedule produced each + * result. + * + * @see {@link andThen} If you need to merge the outputs of both schedules. + * + * @since 2.0.0 + * @category Sequential Composition + */ + (that: Schedule): (self: Schedule) => Schedule, In & In2, R2 | R> + /** + * Runs two schedules sequentially, collecting results in an `Either`. + * + * **Details** + * + * This function combines two schedules in sequence. The first schedule runs to + * completion, and then the second schedule starts and runs to completion as + * well. The outputs of both schedules are collected into an `Either` structure: + * - `Either.Left` contains the output of the second schedule. + * - `Either.Right` contains the output of the first schedule. + * + * This is useful when you need to switch from one schedule to another after the + * first one finishes, while still keeping track of which schedule produced each + * result. + * + * @see {@link andThen} If you need to merge the outputs of both schedules. + * + * @since 2.0.0 + * @category Sequential Composition + */ + (self: Schedule, that: Schedule): Schedule, In & In2, R | R2> +} = internal.andThenEither + +/** + * Transforms a schedule to always produce a constant output. + * + * **Details** + * + * This function modifies a given schedule so that instead of returning its + * computed outputs, it always returns a constant value. + * + * This is useful when you need a schedule for timing but don’t care about its + * actual output, or when you want to standardize results across different + * scheduling strategies. + * + * @since 2.0.0 + * @category Mapping + */ +export const as: { + /** + * Transforms a schedule to always produce a constant output. + * + * **Details** + * + * This function modifies a given schedule so that instead of returning its + * computed outputs, it always returns a constant value. + * + * This is useful when you need a schedule for timing but don’t care about its + * actual output, or when you want to standardize results across different + * scheduling strategies. + * + * @since 2.0.0 + * @category Mapping + */ + (out: Out2): (self: Schedule) => Schedule + /** + * Transforms a schedule to always produce a constant output. + * + * **Details** + * + * This function modifies a given schedule so that instead of returning its + * computed outputs, it always returns a constant value. + * + * This is useful when you need a schedule for timing but don’t care about its + * actual output, or when you want to standardize results across different + * scheduling strategies. + * + * @since 2.0.0 + * @category Mapping + */ + (self: Schedule, out: Out2): Schedule +} = internal.as + +/** + * Transforms a schedule to always return `void` instead of its output. + * + * **Details** + * + * This function modifies a given schedule so that it no longer returns + * meaningful output—each execution produces `void`. This is useful when the + * schedule is used only for timing purposes and the actual output of the + * schedule is irrelevant. + * + * The schedule still determines when executions should occur, but the results + * are discarded. + * + * @since 2.0.0 + * @category Mapping + */ +export const asVoid: (self: Schedule) => Schedule = internal.asVoid + +// TODO(4.0): rename to `zip`? +/** + * Combines two schedules, preserving both their inputs and outputs. + * + * **Details** + * + * This function merges two schedules so that both their input types and output + * types are retained. When executed, the resulting schedule will take inputs + * from both original schedules and produce a tuple containing both outputs. + * + * It recurs if either schedule wants to continue, using the shorter delay. + * + * This is useful when you want to track multiple schedules simultaneously, + * ensuring that both receive the same inputs and produce combined results. + * + * @since 2.0.0 + * @category Zipping + */ +export const bothInOut: { + // TODO(4.0): rename to `zip`? + /** + * Combines two schedules, preserving both their inputs and outputs. + * + * **Details** + * + * This function merges two schedules so that both their input types and output + * types are retained. When executed, the resulting schedule will take inputs + * from both original schedules and produce a tuple containing both outputs. + * + * It recurs if either schedule wants to continue, using the shorter delay. + * + * This is useful when you want to track multiple schedules simultaneously, + * ensuring that both receive the same inputs and produce combined results. + * + * @since 2.0.0 + * @category Zipping + */ + (that: Schedule): (self: Schedule) => Schedule<[Out, Out2], readonly [In, In2], R2 | R> + // TODO(4.0): rename to `zip`? + /** + * Combines two schedules, preserving both their inputs and outputs. + * + * **Details** + * + * This function merges two schedules so that both their input types and output + * types are retained. When executed, the resulting schedule will take inputs + * from both original schedules and produce a tuple containing both outputs. + * + * It recurs if either schedule wants to continue, using the shorter delay. + * + * This is useful when you want to track multiple schedules simultaneously, + * ensuring that both receive the same inputs and produce combined results. + * + * @since 2.0.0 + * @category Zipping + */ + (self: Schedule, that: Schedule): Schedule<[Out, Out2], readonly [In, In2], R | R2> +} = internal.bothInOut + +/** + * Filters schedule executions based on a custom condition. + * + * **Details** + * + * This function modifies a schedule by applying a custom test function to each + * input-output pair. The test function determines whether the schedule should + * continue or stop. If the function returns `true`, the schedule proceeds as + * usual; if it returns `false`, the schedule terminates. + * + * This is useful for conditional retries, custom stop conditions, or + * dynamically controlling execution based on observed inputs and outputs. + * + * @see {@link checkEffect} If you need to use an effectful test function. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const check: { + /** + * Filters schedule executions based on a custom condition. + * + * **Details** + * + * This function modifies a schedule by applying a custom test function to each + * input-output pair. The test function determines whether the schedule should + * continue or stop. If the function returns `true`, the schedule proceeds as + * usual; if it returns `false`, the schedule terminates. + * + * This is useful for conditional retries, custom stop conditions, or + * dynamically controlling execution based on observed inputs and outputs. + * + * @see {@link checkEffect} If you need to use an effectful test function. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (test: (input: In, output: Out) => boolean): (self: Schedule) => Schedule + /** + * Filters schedule executions based on a custom condition. + * + * **Details** + * + * This function modifies a schedule by applying a custom test function to each + * input-output pair. The test function determines whether the schedule should + * continue or stop. If the function returns `true`, the schedule proceeds as + * usual; if it returns `false`, the schedule terminates. + * + * This is useful for conditional retries, custom stop conditions, or + * dynamically controlling execution based on observed inputs and outputs. + * + * @see {@link checkEffect} If you need to use an effectful test function. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (self: Schedule, test: (input: In, output: Out) => boolean): Schedule +} = internal.check + +/** + * Conditionally filters schedule executions using an effectful function. + * + * **Details** + * + * This function modifies a schedule by applying a custom effectful test + * function to each input-output pair. The test function determines whether the + * schedule should continue (`true`) or stop (`false`). + * + * This is useful when the decision to continue depends on external factors such + * as database lookups, API calls, or other asynchronous computations. + * + * @see {@link check} If you need to use a pure test function. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const checkEffect: { + /** + * Conditionally filters schedule executions using an effectful function. + * + * **Details** + * + * This function modifies a schedule by applying a custom effectful test + * function to each input-output pair. The test function determines whether the + * schedule should continue (`true`) or stop (`false`). + * + * This is useful when the decision to continue depends on external factors such + * as database lookups, API calls, or other asynchronous computations. + * + * @see {@link check} If you need to use a pure test function. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (test: (input: In, output: Out) => Effect.Effect): (self: Schedule) => Schedule + /** + * Conditionally filters schedule executions using an effectful function. + * + * **Details** + * + * This function modifies a schedule by applying a custom effectful test + * function to each input-output pair. The test function determines whether the + * schedule should continue (`true`) or stop (`false`). + * + * This is useful when the decision to continue depends on external factors such + * as database lookups, API calls, or other asynchronous computations. + * + * @see {@link check} If you need to use a pure test function. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + ( + self: Schedule, + test: (input: In, output: Out) => Effect.Effect + ): Schedule +} = internal.checkEffect + +/** + * A schedule that collects all inputs into a `Chunk`. + * + * **Details** + * + * This function creates a schedule that never terminates and continuously + * collects every input it receives into a `Chunk`. Each time the schedule runs, + * it appends the new input to the collected list. + * + * This is useful when you need to track all received inputs over time, such as + * logging user actions, recording retry attempts, or accumulating data for + * later processing. + * + * @see {@link collectAllOutputs} If you need to collect outputs instead of + * inputs. + * + * @since 2.0.0 + * @category Collecting + */ +export const collectAllInputs: () => Schedule, A> = internal.collectAllInputs + +/** + * Collects all outputs of a schedule into a `Chunk`. + * + * **Details** + * + * This function modifies a given schedule so that instead of returning + * individual outputs, it accumulates them into a `Chunk`. The schedule + * continues to run, appending each output to the collected list. + * + * This is useful when you need to track all results over time, such as logging + * outputs, aggregating data, or keeping a history of previous values. + * + * @see {@link collectAllInputs} If you need to collect inputs instead of + * outputs. + * + * @since 2.0.0 + * @category Collecting + */ +export const collectAllOutputs: (self: Schedule) => Schedule, In, R> = + internal.collectAllOutputs + +/** + * Collects all inputs into a `Chunk` until a condition fails. + * + * **Details** + * + * This function creates a schedule that continuously collects inputs into a + * `Chunk` until the given predicate function `f` evaluates to `false`. Once the + * condition fails, the schedule stops. + * + * @since 2.0.0 + * @category Collecting + */ +export const collectUntil: (f: Predicate) => Schedule, A> = internal.collectUntil + +/** + * Collects all inputs into a `Chunk` until an effectful condition fails. + * + * **Details** + * + * This function creates a schedule that continuously collects inputs into a + * `Chunk` until the given effectful predicate `f` returns `false`. The + * predicate runs as an effect, meaning it can involve asynchronous computations + * like API calls, database lookups, or randomness. + * + * @since 2.0.0 + * @category Collecting + */ +export const collectUntilEffect: ( + f: (a: A) => Effect.Effect +) => Schedule, A, R> = internal.collectUntilEffect + +/** + * Collects all inputs into a `Chunk` while a condition holds. + * + * **Details** + * + * This function creates a schedule that continuously collects inputs into a + * `Chunk` while the given predicate function `f` evaluates to `true`. As soon + * as the condition fails, the schedule stops. + * + * @since 2.0.0 + * @category Collecting + */ +export const collectWhile: (f: Predicate) => Schedule, A> = internal.collectWhile + +/** + * Collects all inputs into a `Chunk` while an effectful condition holds. + * + * **Details** + * + * This function creates a schedule that continuously collects inputs into a + * `Chunk` while the given effectful predicate `f` returns `true`. The predicate + * returns an effect, meaning it can depend on external state, such as database + * queries, API responses, or real-time user conditions. + * + * As soon as the effectful condition returns `false`, the schedule stops. This + * is useful for dynamically controlled data collection, where stopping depends + * on an external or asynchronous factor. + * + * @since 2.0.0 + * @category Collecting + */ +export const collectWhileEffect: ( + f: (a: A) => Effect.Effect +) => Schedule, A, R> = internal.collectWhileEffect + +/** + * Chains two schedules, passing the output of the first as the input to the + * second, while selecting the shorter delay between them. + * + * **Details** + * + * This function composes two schedules so that the output of the first schedule + * becomes the input of the second schedule. The first schedule executes first, + * and once it produces a result, the second schedule receives that result and + * continues execution based on it. + * + * This is useful for building complex scheduling workflows where one schedule's + * behavior determines how the next schedule behaves. + * + * @since 2.0.0 + * @category Composition + */ +export const compose: { + /** + * Chains two schedules, passing the output of the first as the input to the + * second, while selecting the shorter delay between them. + * + * **Details** + * + * This function composes two schedules so that the output of the first schedule + * becomes the input of the second schedule. The first schedule executes first, + * and once it produces a result, the second schedule receives that result and + * continues execution based on it. + * + * This is useful for building complex scheduling workflows where one schedule's + * behavior determines how the next schedule behaves. + * + * @since 2.0.0 + * @category Composition + */ + (that: Schedule): (self: Schedule) => Schedule + /** + * Chains two schedules, passing the output of the first as the input to the + * second, while selecting the shorter delay between them. + * + * **Details** + * + * This function composes two schedules so that the output of the first schedule + * becomes the input of the second schedule. The first schedule executes first, + * and once it produces a result, the second schedule receives that result and + * continues execution based on it. + * + * This is useful for building complex scheduling workflows where one schedule's + * behavior determines how the next schedule behaves. + * + * @since 2.0.0 + * @category Composition + */ + (self: Schedule, that: Schedule): Schedule +} = internal.compose + +/** + * Transforms the input type of a schedule. + * + * **Details** + * + * This function modifies a given schedule by applying a transformation function + * to its inputs. Instead of directly receiving values of type `In`, the + * schedule will now accept values of type `In2`, which are converted to `In` + * using the provided mapping function `f`. + * + * This is useful when you have a schedule that expects a specific input type + * but you need to adapt it to work with a different type. + * + * @see {@link mapInputEffect} If you need to use an effectful transformation function. + * + * @since 2.0.0 + * @category Mapping + */ +export const mapInput: { + /** + * Transforms the input type of a schedule. + * + * **Details** + * + * This function modifies a given schedule by applying a transformation function + * to its inputs. Instead of directly receiving values of type `In`, the + * schedule will now accept values of type `In2`, which are converted to `In` + * using the provided mapping function `f`. + * + * This is useful when you have a schedule that expects a specific input type + * but you need to adapt it to work with a different type. + * + * @see {@link mapInputEffect} If you need to use an effectful transformation function. + * + * @since 2.0.0 + * @category Mapping + */ + (f: (in2: In2) => In): (self: Schedule) => Schedule + /** + * Transforms the input type of a schedule. + * + * **Details** + * + * This function modifies a given schedule by applying a transformation function + * to its inputs. Instead of directly receiving values of type `In`, the + * schedule will now accept values of type `In2`, which are converted to `In` + * using the provided mapping function `f`. + * + * This is useful when you have a schedule that expects a specific input type + * but you need to adapt it to work with a different type. + * + * @see {@link mapInputEffect} If you need to use an effectful transformation function. + * + * @since 2.0.0 + * @category Mapping + */ + (self: Schedule, f: (in2: In2) => In): Schedule +} = internal.mapInput + +/** + * Transforms the input type of a schedule using an effectful function. + * + * **Details** + * + * This function modifies a schedule by applying an effectful transformation to + * its inputs. Instead of directly receiving values of type `In`, the schedule + * will now accept values of type `In2`, which are converted to `In` via an + * effectful function `f`. + * + * This is useful when the input transformation involves external dependencies, + * such as API calls, database lookups, or other asynchronous computations. + * + * @see {@link mapInput} If you need to use a pure transformation function. + * + * @since 2.0.0 + * @category Mapping + */ +export const mapInputEffect: { + /** + * Transforms the input type of a schedule using an effectful function. + * + * **Details** + * + * This function modifies a schedule by applying an effectful transformation to + * its inputs. Instead of directly receiving values of type `In`, the schedule + * will now accept values of type `In2`, which are converted to `In` via an + * effectful function `f`. + * + * This is useful when the input transformation involves external dependencies, + * such as API calls, database lookups, or other asynchronous computations. + * + * @see {@link mapInput} If you need to use a pure transformation function. + * + * @since 2.0.0 + * @category Mapping + */ + (f: (in2: In2) => Effect.Effect): (self: Schedule) => Schedule + /** + * Transforms the input type of a schedule using an effectful function. + * + * **Details** + * + * This function modifies a schedule by applying an effectful transformation to + * its inputs. Instead of directly receiving values of type `In`, the schedule + * will now accept values of type `In2`, which are converted to `In` via an + * effectful function `f`. + * + * This is useful when the input transformation involves external dependencies, + * such as API calls, database lookups, or other asynchronous computations. + * + * @see {@link mapInput} If you need to use a pure transformation function. + * + * @since 2.0.0 + * @category Mapping + */ + (self: Schedule, f: (in2: In2) => Effect.Effect): Schedule +} = internal.mapInputEffect + +/** + * Transforms the required context of a schedule. + * + * **Details** + * + * This function modifies a schedule by mapping its required context (`R`) into + * a new context (`R0`) using the provided function `f`. + * + * This is useful when you need to adapt a schedule to work with a different + * dependency environment without changing its core logic. + * + * @since 2.0.0 + * @category Mapping + */ +export const mapInputContext: { + /** + * Transforms the required context of a schedule. + * + * **Details** + * + * This function modifies a schedule by mapping its required context (`R`) into + * a new context (`R0`) using the provided function `f`. + * + * This is useful when you need to adapt a schedule to work with a different + * dependency environment without changing its core logic. + * + * @since 2.0.0 + * @category Mapping + */ + (f: (env0: Context.Context) => Context.Context): (self: Schedule) => Schedule + /** + * Transforms the required context of a schedule. + * + * **Details** + * + * This function modifies a schedule by mapping its required context (`R`) into + * a new context (`R0`) using the provided function `f`. + * + * This is useful when you need to adapt a schedule to work with a different + * dependency environment without changing its core logic. + * + * @since 2.0.0 + * @category Mapping + */ + ( + self: Schedule, + f: (env0: Context.Context) => Context.Context + ): Schedule +} = internal.mapInputContext + +/** + * A schedule that recurs indefinitely, counting the number of recurrences. + * + * **Details** + * + * This schedule never stops and simply counts how many times it has executed. + * Each recurrence increases the count, starting from `0`. + * + * This is useful when tracking the number of attempts in retry policies, + * measuring execution loops, or implementing infinite polling scenarios. + * + * @since 2.0.0 + * @category Constructors + */ +export const count: Schedule = internal.count + +/** + * Creates a schedule that recurs based on a cron expression. + * + * **Details** + * + * This schedule automatically executes at intervals defined by a cron + * expression. It triggers at the beginning of each matched interval and + * produces timestamps representing the start and end of the cron window. + * + * The cron `expression` is validated lazily, meaning errors may only be + * detected when the schedule is executed. + * + * @since 2.0.0 + * @category Cron + */ +export const cron: { + /** + * Creates a schedule that recurs based on a cron expression. + * + * **Details** + * + * This schedule automatically executes at intervals defined by a cron + * expression. It triggers at the beginning of each matched interval and + * produces timestamps representing the start and end of the cron window. + * + * The cron `expression` is validated lazily, meaning errors may only be + * detected when the schedule is executed. + * + * @since 2.0.0 + * @category Cron + */ + (cron: Cron.Cron): Schedule<[number, number]> + /** + * Creates a schedule that recurs based on a cron expression. + * + * **Details** + * + * This schedule automatically executes at intervals defined by a cron + * expression. It triggers at the beginning of each matched interval and + * produces timestamps representing the start and end of the cron window. + * + * The cron `expression` is validated lazily, meaning errors may only be + * detected when the schedule is executed. + * + * @since 2.0.0 + * @category Cron + */ + (expression: string, tz?: DateTime.TimeZone | string): Schedule<[number, number]> +} = internal.cron + +/** + * Cron-like schedule that recurs at a specific second of each minute. + * + * **Details** + * + * This schedule triggers at the specified `second` of each minute, + * starting at zero nanoseconds. It produces a count of executions + * (0, 1, 2, ...). The `second` parameter is validated lazily, meaning + * invalid values will only be caught at runtime. + * + * @since 2.0.0 + * @category Cron + */ +export const secondOfMinute: (second: number) => Schedule = internal.secondOfMinute + +/** + * Creates a schedule that recurs every specified minute of each hour. + * + * **Details** + * + * This schedule triggers once per hour at the specified `minute`, starting + * exactly at `minute:00` (zero seconds). The schedule produces a count of + * executions (`0, 1, 2, ...`), representing how many times it has run. + * + * The `minute` parameter must be between `0` and `59`. It is validated lazily, + * meaning an invalid value will cause errors only when the schedule is + * executed. + * + * @since 2.0.0 + * @category Cron + */ +export const minuteOfHour: (minute: number) => Schedule = internal.minuteOfHour + +/** + * Creates a schedule that recurs at a specific hour of each day. + * + * **Details** + * + * This schedule triggers once per day at the specified `hour`, starting at zero + * minutes of that hour. The schedule produces a count of executions (`0, 1, 2, + * ...`), indicating how many times it has been triggered. + * + * The `hour` parameter must be between `0` (midnight) and `23` (11 PM). It is + * validated lazily, meaning an invalid value will cause errors only when the + * schedule is executed. + * + * This is useful for scheduling daily recurring tasks at a fixed time, such as + * running batch jobs or refreshing data. + * + * @since 2.0.0 + * @category Cron + */ +export const hourOfDay: (hour: number) => Schedule = internal.hourOfDay + +/** + * Creates a schedule that recurs on a specific day of the month. + * + * **Details** + * + * This schedule triggers at midnight on the specified day of each month. It + * will not execute in months that have fewer days than the given day. For + * example, if the schedule is set to run on the 31st, it will not execute in + * months with only 30 days. + * + * The schedule produces a count of executions, starting at 0 and incrementing + * with each recurrence. + * + * The `day` parameter is validated lazily, meaning errors may only be detected + * when the schedule is executed. + * + * @since 2.0.0 + * @category Cron + */ +export const dayOfMonth: (day: number) => Schedule = internal.dayOfMonth + +/** + * Creates a schedule that recurs on a specific day of the week. + * + * **Details** + * + * This schedule triggers at midnight on the specified day of the week. The + * `day` parameter follows the standard convention where `Monday = 1` and + * `Sunday = 7`. The schedule produces a count of executions, starting at 0 and + * incrementing with each recurrence. + * + * The `day` parameter is validated lazily, meaning errors may only be detected + * when the schedule is executed. + * + * @since 2.0.0 + * @category Cron + */ +export const dayOfWeek: (day: number) => Schedule = internal.dayOfWeek + +/** + * Modifies a schedule by adding a computed delay before each execution. + * + * **Details** + * + * This function adjusts an existing schedule by applying a transformation to + * its delays. Instead of using the default interval, each delay is modified + * using the provided function `f`, which takes the current delay and returns a + * new delay. + * + * This is useful for dynamically adjusting wait times between executions, such + * as introducing jitter, exponential backoff, or custom delay logic. + * + * @see {@link delayedEffect} If you need to compute the delay using an effectful function. + * + * @since 2.0.0 + * @category Timing & Delay + */ +export const delayed: { + /** + * Modifies a schedule by adding a computed delay before each execution. + * + * **Details** + * + * This function adjusts an existing schedule by applying a transformation to + * its delays. Instead of using the default interval, each delay is modified + * using the provided function `f`, which takes the current delay and returns a + * new delay. + * + * This is useful for dynamically adjusting wait times between executions, such + * as introducing jitter, exponential backoff, or custom delay logic. + * + * @see {@link delayedEffect} If you need to compute the delay using an effectful function. + * + * @since 2.0.0 + * @category Timing & Delay + */ + (f: (duration: Duration.Duration) => Duration.DurationInput): (self: Schedule) => Schedule + /** + * Modifies a schedule by adding a computed delay before each execution. + * + * **Details** + * + * This function adjusts an existing schedule by applying a transformation to + * its delays. Instead of using the default interval, each delay is modified + * using the provided function `f`, which takes the current delay and returns a + * new delay. + * + * This is useful for dynamically adjusting wait times between executions, such + * as introducing jitter, exponential backoff, or custom delay logic. + * + * @see {@link delayedEffect} If you need to compute the delay using an effectful function. + * + * @since 2.0.0 + * @category Timing & Delay + */ + ( + self: Schedule, + f: (duration: Duration.Duration) => Duration.DurationInput + ): Schedule +} = internal.delayed + +/** + * Modifies a schedule by adding an effectfully computed delay before each + * execution. + * + * **Details** + * + * This function adjusts an existing schedule by introducing a delay that is + * computed via an effect. Instead of using a fixed delay, each interval is + * dynamically adjusted based on an effectful function `f`, which takes the + * current delay and returns a new delay wrapped in an `Effect`. + * + * This is useful for adaptive scheduling where delays depend on external + * factors, such as API calls, database queries, or dynamic system conditions. + * + * @see {@link delayed} If you need to compute the delay using a pure function. + * + * @since 2.0.0 + * @category Timing & Delay + */ +export const delayedEffect: { + /** + * Modifies a schedule by adding an effectfully computed delay before each + * execution. + * + * **Details** + * + * This function adjusts an existing schedule by introducing a delay that is + * computed via an effect. Instead of using a fixed delay, each interval is + * dynamically adjusted based on an effectful function `f`, which takes the + * current delay and returns a new delay wrapped in an `Effect`. + * + * This is useful for adaptive scheduling where delays depend on external + * factors, such as API calls, database queries, or dynamic system conditions. + * + * @see {@link delayed} If you need to compute the delay using a pure function. + * + * @since 2.0.0 + * @category Timing & Delay + */ + ( + f: (duration: Duration.Duration) => Effect.Effect + ): (self: Schedule) => Schedule + /** + * Modifies a schedule by adding an effectfully computed delay before each + * execution. + * + * **Details** + * + * This function adjusts an existing schedule by introducing a delay that is + * computed via an effect. Instead of using a fixed delay, each interval is + * dynamically adjusted based on an effectful function `f`, which takes the + * current delay and returns a new delay wrapped in an `Effect`. + * + * This is useful for adaptive scheduling where delays depend on external + * factors, such as API calls, database queries, or dynamic system conditions. + * + * @see {@link delayed} If you need to compute the delay using a pure function. + * + * @since 2.0.0 + * @category Timing & Delay + */ + ( + self: Schedule, + f: (duration: Duration.Duration) => Effect.Effect + ): Schedule +} = internal.delayedEffect + +/** + * Uses the delays produced by a schedule to further delay its intervals. + * + * **Details** + * + * This function modifies a schedule by using its own output delays to control + * its execution timing. Instead of executing immediately at each interval, the + * schedule will be delayed by the duration it produces. + * + * @since 2.0.0 + * @category Timing & Delay + */ +export const delayedSchedule: ( + schedule: Schedule +) => Schedule = internal.delayedSchedule + +/** + * Transforms a schedule to output the delay between each occurrence. + * + * **Details** + * + * This function modifies an existing schedule so that instead of producing its + * original output, it now returns the delay between each scheduled execution. + * + * @since 2.0.0 + * @category Monitoring + */ +export const delays: (self: Schedule) => Schedule = internal.delays + +/** + * Transforms both the input and output of a schedule. + * + * **Details** + * + * This function modifies an existing schedule by applying a transformation to + * both its input values and its output values. The provided transformation + * functions `onInput` and `onOutput` allow you to map the schedule to work with + * a different input type while modifying its outputs as well. + * + * @see {@link mapBothEffect} If you need to use effectful transformation functions. + * + * @since 2.0.0 + * @category Mapping + */ +export const mapBoth: { + /** + * Transforms both the input and output of a schedule. + * + * **Details** + * + * This function modifies an existing schedule by applying a transformation to + * both its input values and its output values. The provided transformation + * functions `onInput` and `onOutput` allow you to map the schedule to work with + * a different input type while modifying its outputs as well. + * + * @see {@link mapBothEffect} If you need to use effectful transformation functions. + * + * @since 2.0.0 + * @category Mapping + */ + ( + options: { readonly onInput: (in2: In2) => In; readonly onOutput: (out: Out) => Out2 } + ): (self: Schedule) => Schedule + /** + * Transforms both the input and output of a schedule. + * + * **Details** + * + * This function modifies an existing schedule by applying a transformation to + * both its input values and its output values. The provided transformation + * functions `onInput` and `onOutput` allow you to map the schedule to work with + * a different input type while modifying its outputs as well. + * + * @see {@link mapBothEffect} If you need to use effectful transformation functions. + * + * @since 2.0.0 + * @category Mapping + */ + ( + self: Schedule, + options: { readonly onInput: (in2: In2) => In; readonly onOutput: (out: Out) => Out2 } + ): Schedule +} = internal.mapBoth + +/** + * Transforms both the input and output of a schedule using effectful + * computations. + * + * **Details** + * + * This function modifies an existing schedule by applying effectful + * transformations to both its input values and its output values. The provided + * effectful functions `onInput` and `onOutput` allow you to transform inputs + * and outputs using computations that may involve additional logic, resource + * access, or side effects. + * + * @see {@link mapBoth} If you need to use pure transformation functions. + * + * @since 2.0.0 + * @category Mapping + */ +export const mapBothEffect: { + /** + * Transforms both the input and output of a schedule using effectful + * computations. + * + * **Details** + * + * This function modifies an existing schedule by applying effectful + * transformations to both its input values and its output values. The provided + * effectful functions `onInput` and `onOutput` allow you to transform inputs + * and outputs using computations that may involve additional logic, resource + * access, or side effects. + * + * @see {@link mapBoth} If you need to use pure transformation functions. + * + * @since 2.0.0 + * @category Mapping + */ + ( + options: { + readonly onInput: (input: In2) => Effect.Effect + readonly onOutput: (out: Out) => Effect.Effect + } + ): (self: Schedule) => Schedule + /** + * Transforms both the input and output of a schedule using effectful + * computations. + * + * **Details** + * + * This function modifies an existing schedule by applying effectful + * transformations to both its input values and its output values. The provided + * effectful functions `onInput` and `onOutput` allow you to transform inputs + * and outputs using computations that may involve additional logic, resource + * access, or side effects. + * + * @see {@link mapBoth} If you need to use pure transformation functions. + * + * @since 2.0.0 + * @category Mapping + */ + ( + self: Schedule, + options: { + readonly onInput: (input: In2) => Effect.Effect + readonly onOutput: (out: Out) => Effect.Effect + } + ): Schedule +} = internal.mapBothEffect + +/** + * Creates a driver to manually control the execution of a schedule. + * + * **Details** + * + * This function returns a `ScheduleDriver`, which allows stepping through a + * schedule manually while handling delays and sleeping appropriately. A driver + * is useful when you need fine-grained control over how a schedule progresses, + * rather than relying on automatic execution. + * + * The returned driver exposes methods for retrieving the current state, + * executing the next step, and resetting the schedule when needed. + * + * @since 2.0.0 + * @category getter + */ +export const driver: ( + self: Schedule +) => Effect.Effect> = internal.driver + +// TODO(4.0): remove? +/** + * Alias of {@link fromDelay}. + * + * @since 2.0.0 + * @category Constructors + */ +export const duration: (duration: Duration.DurationInput) => Schedule = internal.duration + +// TODO(4.0): remove? +/** + * Alias of {@link union}. + * + * @since 2.0.0 + * @category Alternatives + */ +export const either: { + // TODO(4.0): remove? + /** + * Alias of {@link union}. + * + * @since 2.0.0 + * @category Alternatives + */ + (that: Schedule): (self: Schedule) => Schedule<[Out, Out2], In & In2, R2 | R> + // TODO(4.0): remove? + /** + * Alias of {@link union}. + * + * @since 2.0.0 + * @category Alternatives + */ + (self: Schedule, that: Schedule): Schedule<[Out, Out2], In & In2, R | R2> +} = internal.either + +// TODO(4.0): remove? +/** + * Alias of {@link unionWith}. + * + * @since 2.0.0 + * @category Alternatives + */ +export const eitherWith: { + // TODO(4.0): remove? + /** + * Alias of {@link unionWith}. + * + * @since 2.0.0 + * @category Alternatives + */ + ( + that: Schedule, + f: (x: Intervals.Intervals, y: Intervals.Intervals) => Intervals.Intervals + ): (self: Schedule) => Schedule<[Out, Out2], In & In2, R2 | R> + // TODO(4.0): remove? + /** + * Alias of {@link unionWith}. + * + * @since 2.0.0 + * @category Alternatives + */ + ( + self: Schedule, + that: Schedule, + f: (x: Intervals.Intervals, y: Intervals.Intervals) => Intervals.Intervals + ): Schedule<[Out, Out2], In & In2, R | R2> +} = internal.eitherWith + +/** + * Creates a schedule that tracks the total elapsed duration since it started. + * + * **Details** + * + * This schedule executes continuously and returns the total time that has + * passed since the first execution. The duration keeps increasing with each + * step, providing a way to measure elapsed time. + * + * This is useful for tracking execution time, monitoring delays, or + * implementing logic based on how long a process has been running. + * + * @since 2.0.0 + * @category Constructors + */ +export const elapsed: Schedule = internal.elapsed + +/** + * Attaches a finalizer to a schedule that runs when the schedule completes. + * + * **Details** + * + * This function returns a new schedule that executes a given finalizer when the + * schedule reaches completion. Unlike `Effect.ensuring`, this method does not + * guarantee the finalizer will run in all cases. If the schedule never + * initializes or is not driven to completion, the finalizer may not execute. + * However, if the schedule decides not to continue, the finalizer will be + * invoked. + * + * This is useful for cleaning up resources, logging, or executing other side + * effects when a schedule completes. + * + * @since 2.0.0 + * @category Finalization + */ +export const ensuring: { + /** + * Attaches a finalizer to a schedule that runs when the schedule completes. + * + * **Details** + * + * This function returns a new schedule that executes a given finalizer when the + * schedule reaches completion. Unlike `Effect.ensuring`, this method does not + * guarantee the finalizer will run in all cases. If the schedule never + * initializes or is not driven to completion, the finalizer may not execute. + * However, if the schedule decides not to continue, the finalizer will be + * invoked. + * + * This is useful for cleaning up resources, logging, or executing other side + * effects when a schedule completes. + * + * @since 2.0.0 + * @category Finalization + */ + (finalizer: Effect.Effect): (self: Schedule) => Schedule + /** + * Attaches a finalizer to a schedule that runs when the schedule completes. + * + * **Details** + * + * This function returns a new schedule that executes a given finalizer when the + * schedule reaches completion. Unlike `Effect.ensuring`, this method does not + * guarantee the finalizer will run in all cases. If the schedule never + * initializes or is not driven to completion, the finalizer may not execute. + * However, if the schedule decides not to continue, the finalizer will be + * invoked. + * + * This is useful for cleaning up resources, logging, or executing other side + * effects when a schedule completes. + * + * @since 2.0.0 + * @category Finalization + */ + (self: Schedule, finalizer: Effect.Effect): Schedule +} = internal.ensuring + +/** + * Creates a schedule that recurs indefinitely with exponentially increasing + * delays. + * + * **Details** + * + * This schedule starts with an initial delay of `base` and increases the delay + * exponentially on each repetition using the formula `base * factor^n`, where + * `n` is the number of times the schedule has executed so far. If no `factor` + * is provided, it defaults to `2`, causing the delay to double after each + * execution. + * + * @since 2.0.0 + * @category Constructors + */ +export const exponential: ( + base: Duration.DurationInput, + factor?: number +) => Schedule = internal.exponential + +/** + * Creates a schedule that recurs indefinitely with Fibonacci-based increasing + * delays. + * + * **Details** + * + * This schedule starts with an initial delay of `one` and increases subsequent + * delays by summing the two previous delays, following the Fibonacci sequence. + * The delay pattern follows: `one, one, one + one, (one + one) + one, ...`, + * resulting in `1s, 1s, 2s, 3s, 5s, 8s, 13s, ...` if `one = 1s`. + * + * This is useful for progressive backoff strategies, where delays grow + * naturally over time without increasing as aggressively as an exponential + * schedule. + * + * @since 2.0.0 + * @category Constructors + */ +export const fibonacci: (one: Duration.DurationInput) => Schedule = internal.fibonacci + +/** + * Creates a schedule that recurs at a fixed interval. + * + * **Details** + * + * This schedule executes at regular, evenly spaced intervals, returning the + * number of times it has run so far. If the action being executed takes longer + * than the interval, the next execution will happen immediately to prevent + * "pile-ups," ensuring that the schedule remains consistent without overlapping + * executions. + * + * ```text + * |-----interval-----|-----interval-----|-----interval-----| + * |---------action--------||action|-----|action|-----------| + * ``` + * + * @see {@link spaced} If you need to run from the end of the last execution. + * + * @since 2.0.0 + * @category Constructors + */ +export const fixed: (interval: Duration.DurationInput) => Schedule = internal.fixed + +/** + * Creates a schedule that recurs indefinitely, producing a count of + * repetitions. + * + * **Details** + * + * This schedule runs indefinitely, returning an increasing count of executions + * (`0, 1, 2, 3, ...`). Each step increments the count by one, allowing tracking + * of how many times it has executed. + * + * @since 2.0.0 + * @category Constructors + */ +export const forever: Schedule = internal.forever + +/** + * Creates a schedule that recurs once after a specified duration. + * + * **Details** + * + * This schedule executes a single time after waiting for the given duration. + * Once it has executed, it does not repeat. + * + * @see {@link fromDelays} If you need to create a schedule with multiple delays. + * + * @since 2.0.0 + * @category Constructors + */ +export const fromDelay: (delay: Duration.DurationInput) => Schedule = internal.fromDelay + +/** + * Creates a schedule that recurs once for each specified duration, applying the + * given delays sequentially. + * + * **Details** + * + * This schedule executes multiple times, each time waiting for the + * corresponding duration from the provided list of delays. The first execution + * waits for `delay`, the next for the second value in `delays`, and so on. Once + * all delays have been used, the schedule stops executing. + * + * This is useful for defining a custom delay sequence that does not follow a + * fixed pattern like exponential or Fibonacci backoff. + * + * @since 2.0.0 + * @category Constructors + */ +export const fromDelays: ( + delay: Duration.DurationInput, + ...delays: Array +) => Schedule = internal.fromDelays + +/** + * Creates a schedule that always recurs, transforming input values using the + * specified function. + * + * **Details** + * + * This schedule continuously executes and applies the given function `f` to + * each input value, producing a transformed output. The schedule itself does + * not control delays or stopping conditions; it simply transforms the input + * values as they are processed. + * + * This is useful when defining schedules that map inputs to outputs, allowing + * dynamic transformations of incoming data. + * + * @since 2.0.0 + * @category Constructors + */ +export const fromFunction: (f: (a: A) => B) => Schedule = internal.fromFunction + +/** + * Creates a schedule that always recurs, passing inputs directly as outputs. + * + * **Details** + * + * This schedule runs indefinitely, returning each input value as its output + * without modification. It effectively acts as a pass-through that simply + * echoes its input values at each step. + * + * @since 2.0.0 + * @category Constructors + */ +export const identity: () => Schedule = internal.identity + +/** + * Transforms a schedule to pass through its inputs as outputs. + * + * **Details** + * + * This function modifies an existing schedule so that it returns its input + * values instead of its original output values. The schedule's timing remains + * unchanged, but its outputs are replaced with whatever inputs it receives. + * + * @since 2.0.0 + */ +export const passthrough: (self: Schedule) => Schedule = internal.passthrough + +/** + * Combines two schedules, continuing only if both schedules want to continue, + * using the longer delay. + * + * **Details** + * + * This function takes two schedules and creates a new schedule that only + * continues execution if both schedules allow it. The interval between + * recurrences is determined by the longer delay between the two schedules. + * + * The output of the resulting schedule is a tuple containing the outputs of + * both schedules. The input type is the intersection of both schedules' input + * types. + * + * This is useful when coordinating multiple scheduling conditions where + * execution should proceed only when both schedules permit it. + * + * @see {@link intersectWith} If you need to use a custom merge function. + * + * @since 2.0.0 + * @category Composition + */ +export const intersect: { + /** + * Combines two schedules, continuing only if both schedules want to continue, + * using the longer delay. + * + * **Details** + * + * This function takes two schedules and creates a new schedule that only + * continues execution if both schedules allow it. The interval between + * recurrences is determined by the longer delay between the two schedules. + * + * The output of the resulting schedule is a tuple containing the outputs of + * both schedules. The input type is the intersection of both schedules' input + * types. + * + * This is useful when coordinating multiple scheduling conditions where + * execution should proceed only when both schedules permit it. + * + * @see {@link intersectWith} If you need to use a custom merge function. + * + * @since 2.0.0 + * @category Composition + */ + (that: Schedule): (self: Schedule) => Schedule<[Out, Out2], In & In2, R2 | R> + /** + * Combines two schedules, continuing only if both schedules want to continue, + * using the longer delay. + * + * **Details** + * + * This function takes two schedules and creates a new schedule that only + * continues execution if both schedules allow it. The interval between + * recurrences is determined by the longer delay between the two schedules. + * + * The output of the resulting schedule is a tuple containing the outputs of + * both schedules. The input type is the intersection of both schedules' input + * types. + * + * This is useful when coordinating multiple scheduling conditions where + * execution should proceed only when both schedules permit it. + * + * @see {@link intersectWith} If you need to use a custom merge function. + * + * @since 2.0.0 + * @category Composition + */ + (self: Schedule, that: Schedule): Schedule<[Out, Out2], In & In2, R | R2> +} = internal.intersect + +/** + * Combines two schedules, continuing only if both want to continue, merging + * intervals using a custom function. + * + * **Details** + * + * This function takes two schedules and creates a new schedule that only + * continues execution if both schedules allow it. Instead of automatically + * using the longer delay (like {@link intersect}), this function applies a + * user-provided merge function `f` to determine the next interval between + * executions. + * + * The output of the resulting schedule is a tuple containing the outputs of + * both schedules, and the input type is the intersection of both schedules' + * input types. + * + * @since 2.0.0 + * @category Composition + */ +export const intersectWith: { + /** + * Combines two schedules, continuing only if both want to continue, merging + * intervals using a custom function. + * + * **Details** + * + * This function takes two schedules and creates a new schedule that only + * continues execution if both schedules allow it. Instead of automatically + * using the longer delay (like {@link intersect}), this function applies a + * user-provided merge function `f` to determine the next interval between + * executions. + * + * The output of the resulting schedule is a tuple containing the outputs of + * both schedules, and the input type is the intersection of both schedules' + * input types. + * + * @since 2.0.0 + * @category Composition + */ + ( + that: Schedule, + f: (x: Intervals.Intervals, y: Intervals.Intervals) => Intervals.Intervals + ): (self: Schedule) => Schedule<[Out, Out2], In & In2, R2 | R> + /** + * Combines two schedules, continuing only if both want to continue, merging + * intervals using a custom function. + * + * **Details** + * + * This function takes two schedules and creates a new schedule that only + * continues execution if both schedules allow it. Instead of automatically + * using the longer delay (like {@link intersect}), this function applies a + * user-provided merge function `f` to determine the next interval between + * executions. + * + * The output of the resulting schedule is a tuple containing the outputs of + * both schedules, and the input type is the intersection of both schedules' + * input types. + * + * @since 2.0.0 + * @category Composition + */ + ( + self: Schedule, + that: Schedule, + f: (x: Intervals.Intervals, y: Intervals.Intervals) => Intervals.Intervals + ): Schedule<[Out, Out2], In & In2, R | R2> +} = internal.intersectWith + +/** + * Returns a new schedule that randomly adjusts the interval size within a + * range. + * + * **Details** + * + * This function modifies a schedule so that its delay between executions is + * randomly varied within a range. By default, the delay is adjusted between + * `80%` (`0.8 * interval`) and `120%` (`1.2 * interval`) of the original + * interval size. + * + * This is useful for adding randomness to repeated executions, reducing + * contention in distributed systems, and avoiding synchronized execution + * patterns that can cause bottlenecks. + * + * @see {@link jitteredWith} If you need to specify custom min/max values. + * + * @since 2.0.0 + * @category Timing & Delay + */ +export const jittered: (self: Schedule) => Schedule = internal.jittered + +/** + * Returns a new schedule that randomly adjusts the interval size within a + * user-defined range. + * + * **Details** + * + * This function modifies a schedule so that its delay between executions is + * randomly varied within a specified range. Instead of using the default `0.8 - + * 1.2` range like {@link jittered}, this function allows customizing the `min` + * and `max` multipliers. + * + * The delay for each step will be adjusted within `min * original_interval` and + * `max * original_interval`. If `min` and `max` are not provided, the defaults + * are `0.8` and `1.2`, respectively. + * + * This is useful for introducing randomness into scheduling behavior while + * having precise control over the jitter range. + * + * @since 2.0.0 + * @category Timing & Delay + */ +export const jitteredWith: { + /** + * Returns a new schedule that randomly adjusts the interval size within a + * user-defined range. + * + * **Details** + * + * This function modifies a schedule so that its delay between executions is + * randomly varied within a specified range. Instead of using the default `0.8 - + * 1.2` range like {@link jittered}, this function allows customizing the `min` + * and `max` multipliers. + * + * The delay for each step will be adjusted within `min * original_interval` and + * `max * original_interval`. If `min` and `max` are not provided, the defaults + * are `0.8` and `1.2`, respectively. + * + * This is useful for introducing randomness into scheduling behavior while + * having precise control over the jitter range. + * + * @since 2.0.0 + * @category Timing & Delay + */ + (options: { min?: number | undefined; max?: number | undefined }): (self: Schedule) => Schedule + /** + * Returns a new schedule that randomly adjusts the interval size within a + * user-defined range. + * + * **Details** + * + * This function modifies a schedule so that its delay between executions is + * randomly varied within a specified range. Instead of using the default `0.8 - + * 1.2` range like {@link jittered}, this function allows customizing the `min` + * and `max` multipliers. + * + * The delay for each step will be adjusted within `min * original_interval` and + * `max * original_interval`. If `min` and `max` are not provided, the defaults + * are `0.8` and `1.2`, respectively. + * + * This is useful for introducing randomness into scheduling behavior while + * having precise control over the jitter range. + * + * @since 2.0.0 + * @category Timing & Delay + */ + ( + self: Schedule, + options: { min?: number | undefined; max?: number | undefined } + ): Schedule +} = internal.jitteredWith + +/** + * Creates a schedule that recurs indefinitely, increasing the delay linearly. + * + * **Details** + * + * This schedule starts with an initial delay of `base` and increases the delay + * on each recurrence in a linear fashion, following the formula: + * + * `delay = base * n` + * + * where `n` is the number of times the schedule has executed so far. This + * results in increasing intervals between executions. + * + * This is useful for implementing linear backoff strategies where the wait time + * between retries increases at a steady rate. + * + * @since 2.0.0 + * @category Constructors + */ +export const linear: (base: Duration.DurationInput) => Schedule = internal.linear + +/** + * Returns a new schedule that transforms its output using the specified + * function. + * + * **Details** + * + * This function modifies an existing schedule so that its outputs are + * transformed by the provided function `f`. The timing and recurrence behavior + * of the schedule remain unchanged, but the values it produces are mapped to + * new values. + * + * This is useful when composing schedules where you need to adjust the output + * format or apply additional processing. + * + * @see {@link mapEffect} If you need to use an effectful transformation + * function. + * + * @since 2.0.0 + * @category Mapping + */ +export const map: { + /** + * Returns a new schedule that transforms its output using the specified + * function. + * + * **Details** + * + * This function modifies an existing schedule so that its outputs are + * transformed by the provided function `f`. The timing and recurrence behavior + * of the schedule remain unchanged, but the values it produces are mapped to + * new values. + * + * This is useful when composing schedules where you need to adjust the output + * format or apply additional processing. + * + * @see {@link mapEffect} If you need to use an effectful transformation + * function. + * + * @since 2.0.0 + * @category Mapping + */ + (f: (out: Out) => Out2): (self: Schedule) => Schedule + /** + * Returns a new schedule that transforms its output using the specified + * function. + * + * **Details** + * + * This function modifies an existing schedule so that its outputs are + * transformed by the provided function `f`. The timing and recurrence behavior + * of the schedule remain unchanged, but the values it produces are mapped to + * new values. + * + * This is useful when composing schedules where you need to adjust the output + * format or apply additional processing. + * + * @see {@link mapEffect} If you need to use an effectful transformation + * function. + * + * @since 2.0.0 + * @category Mapping + */ + (self: Schedule, f: (out: Out) => Out2): Schedule +} = internal.map + +/** + * Returns a new schedule that applies an effectful transformation to its + * output. + * + * **Details** + * + * This function modifies an existing schedule by applying an effectful function + * `f` to its output values. The timing and recurrence behavior of the schedule + * remain unchanged, but each output is mapped to a new value within an + * `Effect`. + * + * This is useful when you need to perform side effects or asynchronous + * transformations before passing the output forward. + * + * @see {@link map} If you need to use a pure transformation function. + * + * @since 2.0.0 + * @category Mapping + */ +export const mapEffect: { + /** + * Returns a new schedule that applies an effectful transformation to its + * output. + * + * **Details** + * + * This function modifies an existing schedule by applying an effectful function + * `f` to its output values. The timing and recurrence behavior of the schedule + * remain unchanged, but each output is mapped to a new value within an + * `Effect`. + * + * This is useful when you need to perform side effects or asynchronous + * transformations before passing the output forward. + * + * @see {@link map} If you need to use a pure transformation function. + * + * @since 2.0.0 + * @category Mapping + */ + (f: (out: Out) => Effect.Effect): (self: Schedule) => Schedule + /** + * Returns a new schedule that applies an effectful transformation to its + * output. + * + * **Details** + * + * This function modifies an existing schedule by applying an effectful function + * `f` to its output values. The timing and recurrence behavior of the schedule + * remain unchanged, but each output is mapped to a new value within an + * `Effect`. + * + * This is useful when you need to perform side effects or asynchronous + * transformations before passing the output forward. + * + * @see {@link map} If you need to use a pure transformation function. + * + * @since 2.0.0 + * @category Mapping + */ + ( + self: Schedule, + f: (out: Out) => Effect.Effect + ): Schedule +} = internal.mapEffect + +/** + * Returns a new schedule that modifies the delay between executions using a + * custom function. + * + * **Details** + * + * This function transforms an existing schedule by applying `f` to modify the + * delay before each execution. The function receives both the schedule's output + * (`out`) and the originally computed delay (`duration`), and returns a new + * adjusted delay. + * + * @see {@link modifyDelayEffect} If you need to use an effectful function. + * + * @since 2.0.0 + * @category Timing & Delay + */ +export const modifyDelay: { + /** + * Returns a new schedule that modifies the delay between executions using a + * custom function. + * + * **Details** + * + * This function transforms an existing schedule by applying `f` to modify the + * delay before each execution. The function receives both the schedule's output + * (`out`) and the originally computed delay (`duration`), and returns a new + * adjusted delay. + * + * @see {@link modifyDelayEffect} If you need to use an effectful function. + * + * @since 2.0.0 + * @category Timing & Delay + */ + (f: (out: Out, duration: Duration.Duration) => Duration.DurationInput): (self: Schedule) => Schedule + /** + * Returns a new schedule that modifies the delay between executions using a + * custom function. + * + * **Details** + * + * This function transforms an existing schedule by applying `f` to modify the + * delay before each execution. The function receives both the schedule's output + * (`out`) and the originally computed delay (`duration`), and returns a new + * adjusted delay. + * + * @see {@link modifyDelayEffect} If you need to use an effectful function. + * + * @since 2.0.0 + * @category Timing & Delay + */ + ( + self: Schedule, + f: (out: Out, duration: Duration.Duration) => Duration.DurationInput + ): Schedule +} = internal.modifyDelay + +/** + * Returns a new schedule that modifies the delay before execution using an + * effectful function. + * + * **Details** + * + * This function takes an existing schedule and applies an effectful function + * `f` to dynamically adjust the delay before each execution. The function + * receives both the schedule's output (`out`) and the originally computed delay + * (`duration`), returning a new adjusted delay wrapped in an `Effect`. + * + * @see {@link modifyDelay} If you need to use a pure function. + * + * @since 2.0.0 + * @category Timing & Delay + */ +export const modifyDelayEffect: { + /** + * Returns a new schedule that modifies the delay before execution using an + * effectful function. + * + * **Details** + * + * This function takes an existing schedule and applies an effectful function + * `f` to dynamically adjust the delay before each execution. The function + * receives both the schedule's output (`out`) and the originally computed delay + * (`duration`), returning a new adjusted delay wrapped in an `Effect`. + * + * @see {@link modifyDelay} If you need to use a pure function. + * + * @since 2.0.0 + * @category Timing & Delay + */ + ( + f: (out: Out, duration: Duration.Duration) => Effect.Effect + ): (self: Schedule) => Schedule + /** + * Returns a new schedule that modifies the delay before execution using an + * effectful function. + * + * **Details** + * + * This function takes an existing schedule and applies an effectful function + * `f` to dynamically adjust the delay before each execution. The function + * receives both the schedule's output (`out`) and the originally computed delay + * (`duration`), returning a new adjusted delay wrapped in an `Effect`. + * + * @see {@link modifyDelay} If you need to use a pure function. + * + * @since 2.0.0 + * @category Timing & Delay + */ + ( + self: Schedule, + f: (out: Out, duration: Duration.Duration) => Effect.Effect + ): Schedule +} = internal.modifyDelayEffect + +/** + * Returns a new schedule that executes an effect every time the schedule makes + * a decision. + * + * **Details** + * + * This function enhances an existing schedule by running an effectful function + * `f` whenever a scheduling decision is made. The function receives the current + * schedule output (`out`) and the decision (`ScheduleDecision`), allowing + * additional logic to be executed, such as logging, monitoring, or side + * effects. + * + * @since 2.0.0 + */ +export const onDecision: { + /** + * Returns a new schedule that executes an effect every time the schedule makes + * a decision. + * + * **Details** + * + * This function enhances an existing schedule by running an effectful function + * `f` whenever a scheduling decision is made. The function receives the current + * schedule output (`out`) and the decision (`ScheduleDecision`), allowing + * additional logic to be executed, such as logging, monitoring, or side + * effects. + * + * @since 2.0.0 + */ + ( + f: (out: Out, decision: ScheduleDecision.ScheduleDecision) => Effect.Effect + ): (self: Schedule) => Schedule + /** + * Returns a new schedule that executes an effect every time the schedule makes + * a decision. + * + * **Details** + * + * This function enhances an existing schedule by running an effectful function + * `f` whenever a scheduling decision is made. The function receives the current + * schedule output (`out`) and the decision (`ScheduleDecision`), allowing + * additional logic to be executed, such as logging, monitoring, or side + * effects. + * + * @since 2.0.0 + */ + ( + self: Schedule, + f: (out: Out, decision: ScheduleDecision.ScheduleDecision) => Effect.Effect + ): Schedule +} = internal.onDecision + +/** + * A schedule that executes only once and then stops. + * + * **Details** + * + * This schedule triggers a single execution and then terminates. It does not + * repeat or apply any additional logic. + * + * @since 2.0.0 + * @category Constructors + */ +export const once: Schedule = internal.once + +/** + * Returns a new schedule with a provided context, eliminating the need for + * external dependencies. + * + * **Details** + * + * This function supplies a required `context` to a schedule, allowing it to run + * without requiring external dependencies. After calling this function, the + * schedule can be used freely without needing to pass a context at execution + * time. + * + * This is useful when working with schedules that rely on contextual + * information, such as logging services, database connections, or configuration + * settings. + * + * @since 2.0.0 + * @category Context + */ +export const provideContext: { + /** + * Returns a new schedule with a provided context, eliminating the need for + * external dependencies. + * + * **Details** + * + * This function supplies a required `context` to a schedule, allowing it to run + * without requiring external dependencies. After calling this function, the + * schedule can be used freely without needing to pass a context at execution + * time. + * + * This is useful when working with schedules that rely on contextual + * information, such as logging services, database connections, or configuration + * settings. + * + * @since 2.0.0 + * @category Context + */ + (context: Context.Context): (self: Schedule) => Schedule + /** + * Returns a new schedule with a provided context, eliminating the need for + * external dependencies. + * + * **Details** + * + * This function supplies a required `context` to a schedule, allowing it to run + * without requiring external dependencies. After calling this function, the + * schedule can be used freely without needing to pass a context at execution + * time. + * + * This is useful when working with schedules that rely on contextual + * information, such as logging services, database connections, or configuration + * settings. + * + * @since 2.0.0 + * @category Context + */ + (self: Schedule, context: Context.Context): Schedule +} = internal.provideContext + +/** + * Returns a new schedule with a single required service provided, eliminating + * the need for external dependencies. + * + * **Details** + * + * This function supplies a single service dependency to a schedule, allowing it + * to run without requiring that service externally. If a schedule depends on + * multiple services, consider using `provideContext` instead. + * + * This is useful when working with schedules that require a specific service, + * such as logging, metrics, or configuration retrieval. + * + * @since 2.0.0 + * @category Context + */ +export const provideService: { + /** + * Returns a new schedule with a single required service provided, eliminating + * the need for external dependencies. + * + * **Details** + * + * This function supplies a single service dependency to a schedule, allowing it + * to run without requiring that service externally. If a schedule depends on + * multiple services, consider using `provideContext` instead. + * + * This is useful when working with schedules that require a specific service, + * such as logging, metrics, or configuration retrieval. + * + * @since 2.0.0 + * @category Context + */ + (tag: Context.Tag, service: Types.NoInfer): (self: Schedule) => Schedule> + /** + * Returns a new schedule with a single required service provided, eliminating + * the need for external dependencies. + * + * **Details** + * + * This function supplies a single service dependency to a schedule, allowing it + * to run without requiring that service externally. If a schedule depends on + * multiple services, consider using `provideContext` instead. + * + * This is useful when working with schedules that require a specific service, + * such as logging, metrics, or configuration retrieval. + * + * @since 2.0.0 + * @category Context + */ + ( + self: Schedule, + tag: Context.Tag, + service: Types.NoInfer + ): Schedule> +} = internal.provideService + +/** + * A schedule that recurs until the given predicate evaluates to true. + * + * **Details** + * + * This schedule will continue executing as long as the provided predicate `f` + * returns `false` for the input value. Once `f` evaluates to `true`, the + * schedule stops recurring. + * + * This is useful for defining schedules that should stop when a certain + * condition is met, such as detecting a success state, reaching a threshold, or + * avoiding unnecessary retries. + * + * @see {@link recurUntilEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const recurUntil: (f: Predicate) => Schedule = internal.recurUntil + +/** + * A schedule that recurs until the given effectful predicate evaluates to true. + * + * **Details** + * + * This schedule continues executing as long as the provided effectful predicate + * `f` returns `false`. Once `f` evaluates to `true`, the schedule stops + * recurring. Unlike {@link recurUntil}, this function allows the stopping + * condition to be computed asynchronously or based on external dependencies. + * + * This is useful when the stopping condition depends on an effectful + * computation, such as checking a database, making an API call, or retrieving + * system state dynamically. + * + * @see {@link recurUntil} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const recurUntilEffect: (f: (a: A) => Effect.Effect) => Schedule = + internal.recurUntilEffect + +/** + * A schedule that recurs until the input value matches a partial function, then + * maps the value. + * + * **Details** + * + * This schedule continues executing until the provided partial function `pf` + * returns `Some(value)`. At that point, it stops and maps the resulting value + * to an `Option`. If `pf` returns `None`, the schedule continues. + * + * This is useful when defining schedules that should stop once a certain + * condition is met and transform the final value before completion. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const recurUntilOption: (pf: (a: A) => Option.Option) => Schedule, A> = + internal.recurUntilOption + +/** + * A schedule that recurs until the specified duration has elapsed. + * + * **Details** + * + * This schedule continues executing for the given `duration`, after which it + * stops. The schedule outputs the elapsed time on each recurrence. + * + * This is useful for limiting the duration of retries, enforcing time-based + * constraints, or ensuring that an operation does not run indefinitely. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const recurUpTo: (duration: Duration.DurationInput) => Schedule = internal.recurUpTo + +/** + * A schedule that recurs as long as the given predicate evaluates to true. + * + * **Details* + * + * This schedule continues executing as long as the provided predicate `f` + * returns `true` for the input value. Once `f` evaluates to `false`, the + * schedule stops recurring. + * + * @see {@link recurWhileEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const recurWhile: (f: Predicate) => Schedule = internal.recurWhile + +/** + * A schedule that recurs as long as the given effectful predicate evaluates to + * true. + * + * **Details** + * + * This schedule continues executing as long as the provided effectful predicate + * `f` returns `true`. Once `f` evaluates to `false`, the schedule stops + * recurring. Unlike {@link recurWhile}, this function allows the condition to + * be computed dynamically using an effectful computation. + * + * @see {@link recurWhile} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const recurWhileEffect: (f: (a: A) => Effect.Effect) => Schedule = + internal.recurWhileEffect + +/** + * A schedule that recurs a fixed number of times before terminating. + * + * **Details** + * + * This schedule will continue executing until it has been stepped `n` times, + * after which it will stop. The output of the schedule is the current count of + * recurrences. + * + * @category Constructors + * @since 2.0.0 + */ +export const recurs: (n: number) => Schedule = internal.recurs + +/** + * Returns a new schedule that folds over the outputs of this one. + * + * **Details** + * + * This schedule transforms the output by accumulating values over time using a + * reducer function `f`. It starts with an initial value `zero` and updates it + * each time the schedule produces an output. + * + * This is useful for tracking statistics, aggregating results, or summarizing + * data across multiple executions. + * + * @see {@link reduceEffect} If you need to use an effectful reducer function. + * + * @since 2.0.0 + * @category Reducing + */ +export const reduce: { + /** + * Returns a new schedule that folds over the outputs of this one. + * + * **Details** + * + * This schedule transforms the output by accumulating values over time using a + * reducer function `f`. It starts with an initial value `zero` and updates it + * each time the schedule produces an output. + * + * This is useful for tracking statistics, aggregating results, or summarizing + * data across multiple executions. + * + * @see {@link reduceEffect} If you need to use an effectful reducer function. + * + * @since 2.0.0 + * @category Reducing + */ + (zero: Z, f: (z: Z, out: Out) => Z): (self: Schedule) => Schedule + /** + * Returns a new schedule that folds over the outputs of this one. + * + * **Details** + * + * This schedule transforms the output by accumulating values over time using a + * reducer function `f`. It starts with an initial value `zero` and updates it + * each time the schedule produces an output. + * + * This is useful for tracking statistics, aggregating results, or summarizing + * data across multiple executions. + * + * @see {@link reduceEffect} If you need to use an effectful reducer function. + * + * @since 2.0.0 + * @category Reducing + */ + (self: Schedule, zero: Z, f: (z: Z, out: Out) => Z): Schedule +} = internal.reduce + +/** + * Returns a new schedule that effectfully folds over the outputs of this one. + * + * **Details** + * + * This schedule accumulates outputs over time using an effectful reducer + * function `f`. It starts with an initial value `zero` and updates it + * asynchronously or based on external dependencies. + * + * This is useful for asynchronous state tracking, logging, external metrics + * aggregation, or any scenario where accumulation needs to involve an effectful + * computation. + * + * @see {@link reduce} If you need to use a pure reducer function. + * + * @since 2.0.0 + * @category Reducing + */ +export const reduceEffect: { + /** + * Returns a new schedule that effectfully folds over the outputs of this one. + * + * **Details** + * + * This schedule accumulates outputs over time using an effectful reducer + * function `f`. It starts with an initial value `zero` and updates it + * asynchronously or based on external dependencies. + * + * This is useful for asynchronous state tracking, logging, external metrics + * aggregation, or any scenario where accumulation needs to involve an effectful + * computation. + * + * @see {@link reduce} If you need to use a pure reducer function. + * + * @since 2.0.0 + * @category Reducing + */ + (zero: Z, f: (z: Z, out: Out) => Effect.Effect): (self: Schedule) => Schedule + /** + * Returns a new schedule that effectfully folds over the outputs of this one. + * + * **Details** + * + * This schedule accumulates outputs over time using an effectful reducer + * function `f`. It starts with an initial value `zero` and updates it + * asynchronously or based on external dependencies. + * + * This is useful for asynchronous state tracking, logging, external metrics + * aggregation, or any scenario where accumulation needs to involve an effectful + * computation. + * + * @see {@link reduce} If you need to use a pure reducer function. + * + * @since 2.0.0 + * @category Reducing + */ + ( + self: Schedule, + zero: Z, + f: (z: Z, out: Out) => Effect.Effect + ): Schedule +} = internal.reduceEffect + +// TODO(4.0): remove? +/** + * Alias of {@link forever}. + * + * @since 2.0.0 + * @category Constructors + */ +export const repeatForever: Schedule = internal.forever + +/** + * Returns a new schedule that outputs the number of repetitions of this one. + * + * **Details** + * + * This schedule tracks how many times the given schedule has executed and + * outputs the count instead of the original values. The first execution starts + * at `0`, and the count increases with each recurrence. + * + * @since 2.0.0 + * @category Monitoring + */ +export const repetitions: (self: Schedule) => Schedule = internal.repetitions + +/** + * Returns a new schedule that automatically resets to its initial state after a + * period of inactivity defined by `duration`. + * + * **Details** + * + * This function modifies a schedule so that if no inputs are received for the + * specified `duration`, the schedule resets as if it were new. + * + * @see {@link resetWhen} If you need to reset based on output values. + * + * @since 2.0.0 + * @category State Management + */ +export const resetAfter: { + /** + * Returns a new schedule that automatically resets to its initial state after a + * period of inactivity defined by `duration`. + * + * **Details** + * + * This function modifies a schedule so that if no inputs are received for the + * specified `duration`, the schedule resets as if it were new. + * + * @see {@link resetWhen} If you need to reset based on output values. + * + * @since 2.0.0 + * @category State Management + */ + (duration: Duration.DurationInput): (self: Schedule) => Schedule + /** + * Returns a new schedule that automatically resets to its initial state after a + * period of inactivity defined by `duration`. + * + * **Details** + * + * This function modifies a schedule so that if no inputs are received for the + * specified `duration`, the schedule resets as if it were new. + * + * @see {@link resetWhen} If you need to reset based on output values. + * + * @since 2.0.0 + * @category State Management + */ + (self: Schedule, duration: Duration.DurationInput): Schedule +} = internal.resetAfter + +/** + * Resets the schedule when the specified predicate on the schedule output + * evaluates to `true`. + * + * **Details** + * + * This function modifies a schedule so that it resets to its initial state + * whenever the provided predicate `f` returns `true` for an output value. + * + * @see {@link resetAfter} If you need to reset based on inactivity. + * + * @since 2.0.0 + * @category State Management + */ +export const resetWhen: { + /** + * Resets the schedule when the specified predicate on the schedule output + * evaluates to `true`. + * + * **Details** + * + * This function modifies a schedule so that it resets to its initial state + * whenever the provided predicate `f` returns `true` for an output value. + * + * @see {@link resetAfter} If you need to reset based on inactivity. + * + * @since 2.0.0 + * @category State Management + */ + (f: Predicate): (self: Schedule) => Schedule + /** + * Resets the schedule when the specified predicate on the schedule output + * evaluates to `true`. + * + * **Details** + * + * This function modifies a schedule so that it resets to its initial state + * whenever the provided predicate `f` returns `true` for an output value. + * + * @see {@link resetAfter} If you need to reset based on inactivity. + * + * @since 2.0.0 + * @category State Management + */ + (self: Schedule, f: Predicate): Schedule +} = internal.resetWhen + +/** + * Runs a schedule using the provided inputs and collects all outputs. + * + * **Details** + * + * This function executes a given schedule with a sequence of input values and + * accumulates all outputs into a `Chunk`. The schedule starts execution at the + * specified `now` timestamp and proceeds according to its defined behavior. + * + * This is useful for batch processing, simulating execution, or testing + * schedules with predefined input sequences. + * + * @since 2.0.0 + * @category Execution + */ +export const run: { + /** + * Runs a schedule using the provided inputs and collects all outputs. + * + * **Details** + * + * This function executes a given schedule with a sequence of input values and + * accumulates all outputs into a `Chunk`. The schedule starts execution at the + * specified `now` timestamp and proceeds according to its defined behavior. + * + * This is useful for batch processing, simulating execution, or testing + * schedules with predefined input sequences. + * + * @since 2.0.0 + * @category Execution + */ + (now: number, input: Iterable): (self: Schedule) => Effect.Effect, never, R> + /** + * Runs a schedule using the provided inputs and collects all outputs. + * + * **Details** + * + * This function executes a given schedule with a sequence of input values and + * accumulates all outputs into a `Chunk`. The schedule starts execution at the + * specified `now` timestamp and proceeds according to its defined behavior. + * + * This is useful for batch processing, simulating execution, or testing + * schedules with predefined input sequences. + * + * @since 2.0.0 + * @category Execution + */ + (self: Schedule, now: number, input: Iterable): Effect.Effect, never, R> +} = internal.run + +/** + * Returns a schedule that recurs continuously, with each repetition + * spaced by the specified `duration` from the last run. + * + * **Details** + * + * This schedule ensures that executions occur at a fixed interval, + * maintaining a consistent delay between repetitions. The delay starts + * from the end of the last execution, not from the schedule start time. + * + * @see {@link fixed} If you need to run at a fixed interval from the start. + * + * @since 2.0.0 + * @category Constructors + */ +export const spaced: (duration: Duration.DurationInput) => Schedule = internal.spaced + +/** + * A schedule that does not recur and stops immediately. + * + * @since 2.0.0 + * @category Constructors + */ +export const stop: Schedule = internal.stop + +/** + * Returns a schedule that recurs indefinitely, always producing the specified + * constant value. + * + * @since 2.0.0 + * @category Constructors + */ +export const succeed: (value: A) => Schedule = internal.succeed + +/** + * Returns a schedule that recurs indefinitely, evaluating the given function to + * produce a constant value. + * + * @category Constructors + * @since 2.0.0 + */ +export const sync: (evaluate: LazyArg) => Schedule = internal.sync + +/** + * Returns a new schedule that runs the given effectful function for each input + * before continuing execution. + * + * **Details** + * + * This function allows side effects to be performed on each input processed by + * the schedule. It does not modify the schedule’s behavior but ensures that the + * provided function `f` runs before each step. + * + * @since 2.0.0 + * @category Tapping + */ +export const tapInput: { + /** + * Returns a new schedule that runs the given effectful function for each input + * before continuing execution. + * + * **Details** + * + * This function allows side effects to be performed on each input processed by + * the schedule. It does not modify the schedule’s behavior but ensures that the + * provided function `f` runs before each step. + * + * @since 2.0.0 + * @category Tapping + */ + (f: (input: In2) => Effect.Effect): (self: Schedule) => Schedule + /** + * Returns a new schedule that runs the given effectful function for each input + * before continuing execution. + * + * **Details** + * + * This function allows side effects to be performed on each input processed by + * the schedule. It does not modify the schedule’s behavior but ensures that the + * provided function `f` runs before each step. + * + * @since 2.0.0 + * @category Tapping + */ + (self: Schedule, f: (input: In2) => Effect.Effect): Schedule +} = internal.tapInput + +/** + * Returns a new schedule that runs the given effectful function for each output + * before continuing execution. + * + * **Details** + * + * This function allows side effects to be performed on each output produced by + * the schedule. It does not modify the schedule’s behavior but ensures that the + * provided function `f` runs after each step. + * + * @since 2.0.0 + * @category Tapping + */ +export const tapOutput: { + /** + * Returns a new schedule that runs the given effectful function for each output + * before continuing execution. + * + * **Details** + * + * This function allows side effects to be performed on each output produced by + * the schedule. It does not modify the schedule’s behavior but ensures that the + * provided function `f` runs after each step. + * + * @since 2.0.0 + * @category Tapping + */ + (f: (out: Types.NoInfer) => Effect.Effect): (self: Schedule) => Schedule + /** + * Returns a new schedule that runs the given effectful function for each output + * before continuing execution. + * + * **Details** + * + * This function allows side effects to be performed on each output produced by + * the schedule. It does not modify the schedule’s behavior but ensures that the + * provided function `f` runs after each step. + * + * @since 2.0.0 + * @category Tapping + */ + (self: Schedule, f: (out: Out) => Effect.Effect): Schedule +} = internal.tapOutput + +/** + * Creates a schedule that repeatedly applies a function to transform a state + * value, producing a sequence of values. + * + * **Details** + * + * This function starts with an `initial` value and applies `f` recursively to + * generate the next state at each step. The schedule continues indefinitely, + * producing a stream of values by unfolding the state over time. + * + * @since 2.0.0 + * @category Constructors + */ +export const unfold: (initial: A, f: (a: A) => A) => Schedule = internal.unfold + +/** + * Combines two schedules, continuing execution as long as at least one of them + * allows it, using the shorter delay. + * + * **Details** + * + * This function combines two schedules into a single schedule that executes in + * parallel. If either schedule allows continuation, the merged schedule + * continues. When both schedules produce delays, the schedule selects the + * shorter delay to determine the next step. + * + * The output of the new schedule is a tuple containing the outputs of both + * schedules. The input type is the intersection of both schedules' input types. + * + * This is useful for scenarios where multiple scheduling conditions should be + * considered, ensuring execution proceeds if at least one schedule permits it. + * + * @see {@link unionWith} If you need to use a custom merge function. + * + * @since 2.0.0 + * @category Composition + */ +export const union: { + /** + * Combines two schedules, continuing execution as long as at least one of them + * allows it, using the shorter delay. + * + * **Details** + * + * This function combines two schedules into a single schedule that executes in + * parallel. If either schedule allows continuation, the merged schedule + * continues. When both schedules produce delays, the schedule selects the + * shorter delay to determine the next step. + * + * The output of the new schedule is a tuple containing the outputs of both + * schedules. The input type is the intersection of both schedules' input types. + * + * This is useful for scenarios where multiple scheduling conditions should be + * considered, ensuring execution proceeds if at least one schedule permits it. + * + * @see {@link unionWith} If you need to use a custom merge function. + * + * @since 2.0.0 + * @category Composition + */ + (that: Schedule): (self: Schedule) => Schedule<[Out, Out2], In & In2, R2 | R> + /** + * Combines two schedules, continuing execution as long as at least one of them + * allows it, using the shorter delay. + * + * **Details** + * + * This function combines two schedules into a single schedule that executes in + * parallel. If either schedule allows continuation, the merged schedule + * continues. When both schedules produce delays, the schedule selects the + * shorter delay to determine the next step. + * + * The output of the new schedule is a tuple containing the outputs of both + * schedules. The input type is the intersection of both schedules' input types. + * + * This is useful for scenarios where multiple scheduling conditions should be + * considered, ensuring execution proceeds if at least one schedule permits it. + * + * @see {@link unionWith} If you need to use a custom merge function. + * + * @since 2.0.0 + * @category Composition + */ + (self: Schedule, that: Schedule): Schedule<[Out, Out2], In & In2, R | R2> +} = internal.union + +/** + * Combines two schedules, continuing execution as long as at least one of them + * wants to continue, merging their intervals using a custom merge function. + * + * **Details** + * + * This function allows you to combine two schedules while defining how their + * intervals should be merged. Unlike {@link union}, which simply selects the + * shorter delay, this function lets you specify a custom merging strategy for + * the schedules’ intervals. + * + * The merged schedule continues execution as long as at least one of the input + * schedules allows it. The next interval is determined by applying the provided + * merge function to the intervals of both schedules. + * + * The output of the resulting schedule is a tuple containing the outputs of + * both schedules. The input type is the intersection of both schedules' input + * types. + * + * @see {@link union} If you need to use the shorter delay. + * + * @since 2.0.0 + * @category Composition + */ +export const unionWith: { + /** + * Combines two schedules, continuing execution as long as at least one of them + * wants to continue, merging their intervals using a custom merge function. + * + * **Details** + * + * This function allows you to combine two schedules while defining how their + * intervals should be merged. Unlike {@link union}, which simply selects the + * shorter delay, this function lets you specify a custom merging strategy for + * the schedules’ intervals. + * + * The merged schedule continues execution as long as at least one of the input + * schedules allows it. The next interval is determined by applying the provided + * merge function to the intervals of both schedules. + * + * The output of the resulting schedule is a tuple containing the outputs of + * both schedules. The input type is the intersection of both schedules' input + * types. + * + * @see {@link union} If you need to use the shorter delay. + * + * @since 2.0.0 + * @category Composition + */ + ( + that: Schedule, + f: (x: Intervals.Intervals, y: Intervals.Intervals) => Intervals.Intervals + ): (self: Schedule) => Schedule<[Out, Out2], In & In2, R2 | R> + /** + * Combines two schedules, continuing execution as long as at least one of them + * wants to continue, merging their intervals using a custom merge function. + * + * **Details** + * + * This function allows you to combine two schedules while defining how their + * intervals should be merged. Unlike {@link union}, which simply selects the + * shorter delay, this function lets you specify a custom merging strategy for + * the schedules’ intervals. + * + * The merged schedule continues execution as long as at least one of the input + * schedules allows it. The next interval is determined by applying the provided + * merge function to the intervals of both schedules. + * + * The output of the resulting schedule is a tuple containing the outputs of + * both schedules. The input type is the intersection of both schedules' input + * types. + * + * @see {@link union} If you need to use the shorter delay. + * + * @since 2.0.0 + * @category Composition + */ + ( + self: Schedule, + that: Schedule, + f: (x: Intervals.Intervals, y: Intervals.Intervals) => Intervals.Intervals + ): Schedule<[Out, Out2], In & In2, R | R2> +} = internal.unionWith + +/** + * Returns a new schedule that stops execution when the given predicate on the + * input evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it continues executing + * only while the provided predicate returns `false` for incoming inputs. Once + * an input satisfies the condition, the schedule terminates immediately. + * + * @see {@link untilInputEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const untilInput: { + /** + * Returns a new schedule that stops execution when the given predicate on the + * input evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it continues executing + * only while the provided predicate returns `false` for incoming inputs. Once + * an input satisfies the condition, the schedule terminates immediately. + * + * @see {@link untilInputEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (f: Predicate): (self: Schedule) => Schedule + /** + * Returns a new schedule that stops execution when the given predicate on the + * input evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it continues executing + * only while the provided predicate returns `false` for incoming inputs. Once + * an input satisfies the condition, the schedule terminates immediately. + * + * @see {@link untilInputEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (self: Schedule, f: Predicate): Schedule +} = internal.untilInput + +/** + * Returns a new schedule that stops execution when the given effectful + * predicate on the input evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it continues executing + * only while the provided effectful predicate returns `false` for incoming + * inputs. The predicate is an `Effect`, meaning it can involve asynchronous + * computations or dependency-based logic. + * + * @see {@link untilInput} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const untilInputEffect: { + /** + * Returns a new schedule that stops execution when the given effectful + * predicate on the input evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it continues executing + * only while the provided effectful predicate returns `false` for incoming + * inputs. The predicate is an `Effect`, meaning it can involve asynchronous + * computations or dependency-based logic. + * + * @see {@link untilInput} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (f: (input: In) => Effect.Effect): (self: Schedule) => Schedule + /** + * Returns a new schedule that stops execution when the given effectful + * predicate on the input evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it continues executing + * only while the provided effectful predicate returns `false` for incoming + * inputs. The predicate is an `Effect`, meaning it can involve asynchronous + * computations or dependency-based logic. + * + * @see {@link untilInput} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + ( + self: Schedule, + f: (input: In) => Effect.Effect + ): Schedule +} = internal.untilInputEffect + +/** + * Returns a new schedule that stops execution when the given predicate on the + * output evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * executing while the given predicate returns false for its output values. Once + * the predicate evaluates to `true`, execution stops. + * + * The output of the resulting schedule remains the same, but its duration is + * now constrained by a stopping condition based on its own output. + * + * @see {@link untilOutputEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const untilOutput: { + /** + * Returns a new schedule that stops execution when the given predicate on the + * output evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * executing while the given predicate returns false for its output values. Once + * the predicate evaluates to `true`, execution stops. + * + * The output of the resulting schedule remains the same, but its duration is + * now constrained by a stopping condition based on its own output. + * + * @see {@link untilOutputEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (f: Predicate): (self: Schedule) => Schedule + /** + * Returns a new schedule that stops execution when the given predicate on the + * output evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * executing while the given predicate returns false for its output values. Once + * the predicate evaluates to `true`, execution stops. + * + * The output of the resulting schedule remains the same, but its duration is + * now constrained by a stopping condition based on its own output. + * + * @see {@link untilOutputEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (self: Schedule, f: Predicate): Schedule +} = internal.untilOutput + +/** + * Returns a new schedule that stops execution when the given effectful + * predicate on the output evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * executing while the provided effectful predicate returns `false` for its + * output values. Once the predicate returns `true`, execution stops. + * + * @see {@link untilOutput} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const untilOutputEffect: { + /** + * Returns a new schedule that stops execution when the given effectful + * predicate on the output evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * executing while the provided effectful predicate returns `false` for its + * output values. Once the predicate returns `true`, execution stops. + * + * @see {@link untilOutput} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (f: (out: Out) => Effect.Effect): (self: Schedule) => Schedule + /** + * Returns a new schedule that stops execution when the given effectful + * predicate on the output evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * executing while the provided effectful predicate returns `false` for its + * output values. Once the predicate returns `true`, execution stops. + * + * @see {@link untilOutput} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + ( + self: Schedule, + f: (out: Out) => Effect.Effect + ): Schedule +} = internal.untilOutputEffect + +/** + * Returns a new schedule that limits execution to a fixed duration. + * + * **Details** + * + * This function modifies an existing schedule to stop execution after a + * specified duration has passed. The schedule continues as normal until the + * duration is reached, at which point it stops automatically. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const upTo: { + /** + * Returns a new schedule that limits execution to a fixed duration. + * + * **Details** + * + * This function modifies an existing schedule to stop execution after a + * specified duration has passed. The schedule continues as normal until the + * duration is reached, at which point it stops automatically. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (duration: Duration.DurationInput): (self: Schedule) => Schedule + /** + * Returns a new schedule that limits execution to a fixed duration. + * + * **Details** + * + * This function modifies an existing schedule to stop execution after a + * specified duration has passed. The schedule continues as normal until the + * duration is reached, at which point it stops automatically. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (self: Schedule, duration: Duration.DurationInput): Schedule +} = internal.upTo + +/** + * Returns a new schedule that continues execution as long as the given + * predicate on the input is true. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * execution while a specified predicate holds true for its input. If the + * predicate evaluates to `false` at any step, the schedule stops. + * + * @see {@link whileInputEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const whileInput: { + /** + * Returns a new schedule that continues execution as long as the given + * predicate on the input is true. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * execution while a specified predicate holds true for its input. If the + * predicate evaluates to `false` at any step, the schedule stops. + * + * @see {@link whileInputEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (f: Predicate): (self: Schedule) => Schedule + /** + * Returns a new schedule that continues execution as long as the given + * predicate on the input is true. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * execution while a specified predicate holds true for its input. If the + * predicate evaluates to `false` at any step, the schedule stops. + * + * @see {@link whileInputEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (self: Schedule, f: Predicate): Schedule +} = internal.whileInput + +/** + * Returns a new schedule that continues execution for as long as the given + * effectful predicate on the input evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * execution while an effectful predicate holds true for its input. If the + * predicate evaluates to `false` at any step, the schedule stops. + * + * @see {@link whileInput} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const whileInputEffect: { + /** + * Returns a new schedule that continues execution for as long as the given + * effectful predicate on the input evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * execution while an effectful predicate holds true for its input. If the + * predicate evaluates to `false` at any step, the schedule stops. + * + * @see {@link whileInput} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (f: (input: In) => Effect.Effect): (self: Schedule) => Schedule + /** + * Returns a new schedule that continues execution for as long as the given + * effectful predicate on the input evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * execution while an effectful predicate holds true for its input. If the + * predicate evaluates to `false` at any step, the schedule stops. + * + * @see {@link whileInput} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + ( + self: Schedule, + f: (input: In) => Effect.Effect + ): Schedule +} = internal.whileInputEffect + +/** + * Returns a new schedule that continues execution for as long as the given + * predicate on the output evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * execution while a provided condition holds true for its output. If the + * predicate returns `false`, the schedule stops. + * + * @see {@link whileOutputEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const whileOutput: { + /** + * Returns a new schedule that continues execution for as long as the given + * predicate on the output evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * execution while a provided condition holds true for its output. If the + * predicate returns `false`, the schedule stops. + * + * @see {@link whileOutputEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (f: Predicate): (self: Schedule) => Schedule + /** + * Returns a new schedule that continues execution for as long as the given + * predicate on the output evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * execution while a provided condition holds true for its output. If the + * predicate returns `false`, the schedule stops. + * + * @see {@link whileOutputEffect} If you need to use an effectful predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (self: Schedule, f: Predicate): Schedule +} = internal.whileOutput + +/** + * Returns a new schedule that continues execution for as long as the given + * effectful predicate on the output evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * execution while an effectful condition holds true for its output. If the + * effectful predicate returns `false`, the schedule stops. + * + * @see {@link whileOutput} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ +export const whileOutputEffect: { + /** + * Returns a new schedule that continues execution for as long as the given + * effectful predicate on the output evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * execution while an effectful condition holds true for its output. If the + * effectful predicate returns `false`, the schedule stops. + * + * @see {@link whileOutput} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + (f: (out: Out) => Effect.Effect): (self: Schedule) => Schedule + /** + * Returns a new schedule that continues execution for as long as the given + * effectful predicate on the output evaluates to `true`. + * + * **Details** + * + * This function modifies an existing schedule so that it only continues + * execution while an effectful condition holds true for its output. If the + * effectful predicate returns `false`, the schedule stops. + * + * @see {@link whileOutput} If you need to use a pure predicate. + * + * @since 2.0.0 + * @category Recurrence Conditions + */ + ( + self: Schedule, + f: (out: Out) => Effect.Effect + ): Schedule +} = internal.whileOutputEffect + +/** + * Creates a schedule that divides time into fixed `interval`-long windows, + * triggering execution at the start of each new window. + * + * **Details** + * + * This function produces a schedule that waits until the next time window + * boundary before executing. Each window spans a fixed duration specified by + * `interval`. If an action completes midway through a window, the schedule + * waits until the next full window starts before proceeding. + * + * For example, `windowed(Duration.seconds(10))` would produce a schedule as + * follows: + * + * ```text + * 10s 10s 10s 10s + * |----------|----------|----------|----------| + * |action------|sleep---|act|-sleep|action----| + * ``` + * + * @since 2.0.0 + * @category Constructors + */ +export const windowed: (interval: Duration.DurationInput) => Schedule = internal.windowed + +/** + * The same as {@link intersect} but ignores the right output. + * + * @since 2.0.0 + * @category Composition + */ +export const zipLeft: { + /** + * The same as {@link intersect} but ignores the right output. + * + * @since 2.0.0 + * @category Composition + */ + (that: Schedule): (self: Schedule) => Schedule + /** + * The same as {@link intersect} but ignores the right output. + * + * @since 2.0.0 + * @category Composition + */ + (self: Schedule, that: Schedule): Schedule +} = internal.zipLeft + +/** + * The same as {@link intersect} but ignores the left output. + * + * @since 2.0.0 + * @category Composition + */ +export const zipRight: { + /** + * The same as {@link intersect} but ignores the left output. + * + * @since 2.0.0 + * @category Composition + */ + (that: Schedule): (self: Schedule) => Schedule + /** + * The same as {@link intersect} but ignores the left output. + * + * @since 2.0.0 + * @category Composition + */ + (self: Schedule, that: Schedule): Schedule +} = internal.zipRight + +/** + * Equivalent to {@link intersect} followed by {@link map}. + * + * @since 2.0.0 + * @category Composition + */ +export const zipWith: { + /** + * Equivalent to {@link intersect} followed by {@link map}. + * + * @since 2.0.0 + * @category Composition + */ + (that: Schedule, f: (out: Out, out2: Out2) => Out3): (self: Schedule) => Schedule + /** + * Equivalent to {@link intersect} followed by {@link map}. + * + * @since 2.0.0 + * @category Composition + */ + ( + self: Schedule, + that: Schedule, + f: (out: Out, out2: Out2) => Out3 + ): Schedule +} = internal.zipWith + +/** + * @since 3.15.0 + * @category models + */ +export interface CurrentIterationMetadata { + readonly _: unique symbol +} + +/** + * @since 3.15.0 + * @category models + */ +export interface IterationMetadata { + readonly input: unknown + readonly output: unknown + readonly recurrence: number + readonly start: number + readonly now: number + readonly elapsed: Duration.Duration + readonly elapsedSincePrevious: Duration.Duration +} + +/** + * @since 3.15.0 + * @category models + */ +export const CurrentIterationMetadata: Context.Reference< + CurrentIterationMetadata, + IterationMetadata +> = internal.CurrentIterationMetadata diff --git a/backend/node_modules/effect/src/Scheduler.ts b/backend/node_modules/effect/src/Scheduler.ts new file mode 100644 index 0000000000000000000000000000000000000000..301a0b7a166486db5c9121d7b940bd7c337bd897 --- /dev/null +++ b/backend/node_modules/effect/src/Scheduler.ts @@ -0,0 +1,364 @@ +/** + * @since 2.0.0 + */ + +import type { Effect } from "./Effect.js" +import type { RuntimeFiber } from "./Fiber.js" +import type { FiberRef } from "./FiberRef.js" +import { dual } from "./Function.js" +import { globalValue } from "./GlobalValue.js" +import * as core from "./internal/core.js" + +/** + * @since 2.0.0 + * @category models + */ +export type Task = () => void + +/** + * @since 2.0.0 + * @category models + */ +export interface Scheduler { + shouldYield(fiber: RuntimeFiber): number | false + scheduleTask(task: Task, priority: number, fiber?: RuntimeFiber): void +} + +/** + * @since 3.20.0 + * @category models + */ +export class SchedulerRunner { + running = false + tasks = new PriorityBuckets() + + constructor( + readonly scheduleDrain: (depth: number, drain: (depth: number) => void) => void + ) {} + + private starveInternal = (depth: number) => { + const tasks = this.tasks.buckets + this.tasks.buckets = [] + for (const [_, toRun] of tasks) { + for (let i = 0; i < toRun.length; i++) { + toRun[i]() + } + } + if (this.tasks.buckets.length === 0) { + this.running = false + } else { + this.starve(depth) + } + } + + private starve(depth = 0) { + this.scheduleDrain(depth, this.starveInternal) + } + + scheduleTask(task: Task, priority: number) { + this.tasks.scheduleTask(task, priority) + if (!this.running) { + this.running = true + this.starve() + } + } + /** + * @since 3.20.0 + * @category constructors + */ + static cached( + scheduleDrain: (depth: number, drain: (depth: number) => void) => void + ) { + const fallback = new SchedulerRunner(scheduleDrain) + const runners = new WeakMap, SchedulerRunner>() + + return (fiber?: RuntimeFiber) => { + if (fiber === undefined) { + return fallback + } + let runner = runners.get(fiber) + if (runner === undefined) { + runner = new SchedulerRunner(scheduleDrain) + runners.set(fiber, runner) + } + return runner + } + } +} + +/** + * @since 2.0.0 + * @category utils + */ +export class PriorityBuckets { + /** + * @since 2.0.0 + */ + public buckets: Array<[number, Array]> = [] + /** + * @since 2.0.0 + */ + scheduleTask(task: T, priority: number) { + const length = this.buckets.length + let bucket: [number, Array] | undefined = undefined + let index = 0 + for (; index < length; index++) { + if (this.buckets[index][0] <= priority) { + bucket = this.buckets[index] + } else { + break + } + } + if (bucket && bucket[0] === priority) { + bucket[1].push(task) + } else if (index === length) { + this.buckets.push([priority, [task]]) + } else { + this.buckets.splice(index, 0, [priority, [task]]) + } + } +} + +/** + * @since 2.0.0 + * @category constructors + */ +export class MixedScheduler implements Scheduler { + private readonly getRunner = SchedulerRunner.cached((depth, drain) => { + if (depth >= this.maxNextTickBeforeTimer) { + setTimeout(() => drain(0), 0) + } else { + Promise.resolve(void 0).then(() => drain(depth + 1)) + } + }) + + constructor( + /** + * @since 2.0.0 + */ + readonly maxNextTickBeforeTimer: number + ) {} + + /** + * @since 2.0.0 + */ + shouldYield(fiber: RuntimeFiber): number | false { + return fiber.currentOpCount > fiber.getFiberRef(core.currentMaxOpsBeforeYield) + ? fiber.getFiberRef(core.currentSchedulingPriority) + : false + } + + /** + * @since 2.0.0 + */ + scheduleTask(task: Task, priority: number, fiber?: RuntimeFiber) { + this.getRunner(fiber).scheduleTask(task, priority) + } +} + +/** + * @since 2.0.0 + * @category schedulers + */ +export const defaultScheduler: Scheduler = globalValue( + Symbol.for("effect/Scheduler/defaultScheduler"), + () => new MixedScheduler(2048) +) + +/** + * @since 2.0.0 + * @category constructors + */ +export class SyncScheduler implements Scheduler { + /** + * @since 2.0.0 + */ + tasks = new PriorityBuckets() + + /** + * @since 2.0.0 + */ + deferred = false + + /** + * @since 2.0.0 + */ + scheduleTask(task: Task, priority: number, fiber?: RuntimeFiber) { + if (this.deferred) { + defaultScheduler.scheduleTask(task, priority, fiber) + } else { + this.tasks.scheduleTask(task, priority) + } + } + + /** + * @since 2.0.0 + */ + shouldYield(fiber: RuntimeFiber): number | false { + return fiber.currentOpCount > fiber.getFiberRef(core.currentMaxOpsBeforeYield) + ? fiber.getFiberRef(core.currentSchedulingPriority) + : false + } + + /** + * @since 2.0.0 + */ + flush() { + while (this.tasks.buckets.length > 0) { + const tasks = this.tasks.buckets + this.tasks.buckets = [] + for (const [_, toRun] of tasks) { + for (let i = 0; i < toRun.length; i++) { + toRun[i]() + } + } + } + this.deferred = true + } +} + +/** + * @since 2.0.0 + * @category constructors + */ +export class ControlledScheduler implements Scheduler { + /** + * @since 2.0.0 + */ + tasks = new PriorityBuckets() + + /** + * @since 2.0.0 + */ + deferred = false + + /** + * @since 2.0.0 + */ + scheduleTask(task: Task, priority: number, fiber?: RuntimeFiber) { + if (this.deferred) { + defaultScheduler.scheduleTask(task, priority, fiber) + } else { + this.tasks.scheduleTask(task, priority) + } + } + + /** + * @since 2.0.0 + */ + shouldYield(fiber: RuntimeFiber): number | false { + return fiber.currentOpCount > fiber.getFiberRef(core.currentMaxOpsBeforeYield) + ? fiber.getFiberRef(core.currentSchedulingPriority) + : false + } + + /** + * @since 2.0.0 + */ + step() { + const tasks = this.tasks.buckets + this.tasks.buckets = [] + for (const [_, toRun] of tasks) { + for (let i = 0; i < toRun.length; i++) { + toRun[i]() + } + } + } +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const makeMatrix = (...record: Array<[number, Scheduler]>): Scheduler => { + const index = record.sort(([p0], [p1]) => p0 < p1 ? -1 : p0 > p1 ? 1 : 0) + return { + shouldYield(fiber) { + for (const scheduler of record) { + const priority = scheduler[1].shouldYield(fiber) + if (priority !== false) { + return priority + } + } + return false + }, + scheduleTask(task, priority, fiber) { + let scheduler: Scheduler | undefined = undefined + for (const i of index) { + if (priority >= i[0]) { + scheduler = i[1] + } else { + return (scheduler ?? defaultScheduler).scheduleTask(task, priority, fiber) + } + } + return (scheduler ?? defaultScheduler).scheduleTask(task, priority, fiber) + } + } +} + +/** + * @since 2.0.0 + * @category utilities + */ +export const defaultShouldYield: Scheduler["shouldYield"] = (fiber) => { + return fiber.currentOpCount > fiber.getFiberRef(core.currentMaxOpsBeforeYield) + ? fiber.getFiberRef(core.currentSchedulingPriority) + : false +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const make = ( + scheduleTask: Scheduler["scheduleTask"], + shouldYield: Scheduler["shouldYield"] = defaultShouldYield +): Scheduler => ({ + scheduleTask, + shouldYield +}) + +/** + * @since 2.0.0 + * @category constructors + */ +export const makeBatched = ( + callback: (runBatch: () => void) => void, + shouldYield: Scheduler["shouldYield"] = defaultShouldYield +) => { + const getRunner = SchedulerRunner.cached((_, drain) => { + callback(() => drain(0)) + }) + + return make((task, priority, fiber) => { + getRunner(fiber).scheduleTask(task, priority) + }, shouldYield) +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const timer = (ms: number, shouldYield: Scheduler["shouldYield"] = defaultShouldYield) => + make((task) => setTimeout(task, ms), shouldYield) + +/** + * @since 2.0.0 + * @category constructors + */ +export const timerBatched = (ms: number, shouldYield: Scheduler["shouldYield"] = defaultShouldYield) => + makeBatched((task) => setTimeout(task, ms), shouldYield) + +/** @internal */ +export const currentScheduler: FiberRef = globalValue( + Symbol.for("effect/FiberRef/currentScheduler"), + () => core.fiberRefUnsafeMake(defaultScheduler) +) + +/** @internal */ +export const withScheduler = dual< + /** @internal */ + (scheduler: Scheduler) => (self: Effect) => Effect, + /** @internal */ + (self: Effect, scheduler: Scheduler) => Effect +>(2, (self, scheduler) => core.fiberRefLocally(self, currentScheduler, scheduler)) diff --git a/backend/node_modules/effect/src/Schema.ts b/backend/node_modules/effect/src/Schema.ts new file mode 100644 index 0000000000000000000000000000000000000000..2eaf695253f902f42945a1702b032b0e7cb9553f --- /dev/null +++ b/backend/node_modules/effect/src/Schema.ts @@ -0,0 +1,11443 @@ +/** + * @since 3.10.0 + */ + +import type { StandardSchemaV1 } from "@standard-schema/spec" +import type { ArbitraryAnnotation, ArbitraryGenerationContext, LazyArbitrary } from "./Arbitrary.js" +import * as array_ from "./Array.js" +import * as bigDecimal_ from "./BigDecimal.js" +import * as bigInt_ from "./BigInt.js" +import * as boolean_ from "./Boolean.js" +import type { Brand } from "./Brand.js" +import * as cause_ from "./Cause.js" +import * as chunk_ from "./Chunk.js" +import * as config_ from "./Config.js" +import * as configError_ from "./ConfigError.js" +import * as data_ from "./Data.js" +import * as dateTime from "./DateTime.js" +import * as duration_ from "./Duration.js" +import * as Effect from "./Effect.js" +import * as either_ from "./Either.js" +import * as Encoding from "./Encoding.js" +import * as Equal from "./Equal.js" +import * as Equivalence from "./Equivalence.js" +import * as exit_ from "./Exit.js" +import * as fastCheck_ from "./FastCheck.js" +import * as fiberId_ from "./FiberId.js" +import type { LazyArg } from "./Function.js" +import { dual, identity } from "./Function.js" +import { globalValue } from "./GlobalValue.js" +import * as hashMap_ from "./HashMap.js" +import * as hashSet_ from "./HashSet.js" +import * as Inspectable from "./Inspectable.js" +import * as internalCause_ from "./internal/cause.js" +import * as errors_ from "./internal/schema/errors.js" +import * as schemaId_ from "./internal/schema/schemaId.js" +import * as util_ from "./internal/schema/util.js" +import * as list_ from "./List.js" +import * as number_ from "./Number.js" +import * as option_ from "./Option.js" +import type * as Order from "./Order.js" +import * as ParseResult from "./ParseResult.js" +import type { Pipeable } from "./Pipeable.js" +import { pipeArguments } from "./Pipeable.js" +import * as Predicate from "./Predicate.js" +import type * as pretty_ from "./Pretty.js" +import * as redacted_ from "./Redacted.js" +import * as Request from "./Request.js" +import * as scheduler_ from "./Scheduler.js" +import type { ParseOptions } from "./SchemaAST.js" +import * as AST from "./SchemaAST.js" +import * as sortedSet_ from "./SortedSet.js" +import * as string_ from "./String.js" +import * as struct_ from "./Struct.js" +import type * as Types from "./Types.js" + +/** + * @since 3.10.0 + */ +export type Simplify = { [K in keyof A]: A[K] } & {} + +/** + * @since 3.10.0 + */ +export type SimplifyMutable = { + -readonly [K in keyof A]: A[K] +} extends infer B ? B : never + +/** + * @since 3.10.0 + * @category symbol + */ +export const TypeId: unique symbol = Symbol.for("effect/Schema") + +/** + * @since 3.10.0 + * @category symbol + */ +export type TypeId = typeof TypeId + +/** + * @category model + * @since 3.10.0 + */ +export interface Schema extends Schema.Variance, Pipeable { + readonly Type: A + readonly Encoded: I + readonly Context: R + readonly ast: AST.AST + /** + * Merges a set of new annotations with existing ones, potentially overwriting + * any duplicates. + */ + annotations(annotations: Annotations.GenericSchema): Schema +} + +/** + * @category annotations + * @since 3.10.0 + */ +export interface Annotable, A, I = A, R = never> extends Schema { + annotations(annotations: Annotations.GenericSchema): Self +} + +/** + * @category annotations + * @since 3.10.0 + */ +export interface AnnotableClass, A, I = A, R = never> extends Annotable { + new(_: never): Schema.Variance +} + +/** + * @category model + * @since 3.10.0 + */ +export interface SchemaClass extends AnnotableClass, A, I, R> {} + +/** + * @category constructors + * @since 3.10.0 + */ +export function make(ast: AST.AST): SchemaClass { + return class SchemaClass { + [TypeId] = variance + static ast = ast + static annotations(annotations: Annotations.GenericSchema) { + return make(mergeSchemaAnnotations(this.ast, annotations)) + } + static pipe() { + return pipeArguments(this, arguments) + } + static toString() { + return String(ast) + } + static Type: A + static Encoded: I + static Context: R + static [TypeId] = variance + } +} + +const variance = { + /* c8 ignore next */ + _A: (_: any) => _, + /* c8 ignore next */ + _I: (_: any) => _, + /* c8 ignore next */ + _R: (_: never) => _ +} + +const makeStandardResult = (exit: exit_.Exit>): StandardSchemaV1.Result => + exit_.isSuccess(exit) ? exit.value : makeStandardFailureResult(cause_.pretty(exit.cause)) + +const makeStandardFailureResult = (message: string): StandardSchemaV1.FailureResult => ({ + issues: [{ message }] +}) + +const makeStandardFailureFromParseIssue = ( + issue: ParseResult.ParseIssue +): Effect.Effect => + Effect.map(ParseResult.ArrayFormatter.formatIssue(issue), (issues) => ({ + issues: issues.map((issue) => ({ + path: issue.path, + message: issue.message + })) + })) + +/** + * Returns a "Standard Schema" object conforming to the [Standard Schema + * v1](https://standardschema.dev/) specification. + * + * This function creates a schema whose `validate` method attempts to decode and + * validate the provided input synchronously. If the underlying `Schema` + * includes any asynchronous components (e.g., asynchronous message resolutions + * or checks), then validation will necessarily return a `Promise` instead. + * + * Any detected defects will be reported via a single issue containing no + * `path`. + * + * @example + * ```ts + * import { Schema } from "effect" + * + * const schema = Schema.Struct({ + * name: Schema.String + * }) + * + * // ┌─── StandardSchemaV1<{ readonly name: string; }> + * // ▼ + * const standardSchema = Schema.standardSchemaV1(schema) + * ``` + * + * @category Standard Schema + * @since 3.13.0 + */ +export const standardSchemaV1 = ( + schema: Schema, + overrideOptions?: AST.ParseOptions +): StandardSchemaV1 & SchemaClass => { + const decodeUnknown = ParseResult.decodeUnknown(schema, { errors: "all" }) + return class StandardSchemaV1Class extends make(schema.ast) { + static "~standard" = { + version: 1, + vendor: "effect", + validate(value) { + const scheduler = new scheduler_.SyncScheduler() + const fiber = Effect.runFork( + Effect.matchEffect(decodeUnknown(value, overrideOptions), { + onFailure: makeStandardFailureFromParseIssue, + onSuccess: (value) => Effect.succeed({ value }) + }), + { scheduler } + ) + scheduler.flush() + const exit = fiber.unsafePoll() + if (exit) { + return makeStandardResult(exit) + } + return new Promise((resolve) => { + fiber.addObserver((exit) => { + resolve(makeStandardResult(exit)) + }) + }) + } + } + } +} + +interface AllAnnotations> + extends Annotations.Schema, PropertySignature.Annotations +{} + +const builtInAnnotations = { + typeConstructor: AST.TypeConstructorAnnotationId, + schemaId: AST.SchemaIdAnnotationId, + message: AST.MessageAnnotationId, + missingMessage: AST.MissingMessageAnnotationId, + identifier: AST.IdentifierAnnotationId, + title: AST.TitleAnnotationId, + description: AST.DescriptionAnnotationId, + examples: AST.ExamplesAnnotationId, + default: AST.DefaultAnnotationId, + documentation: AST.DocumentationAnnotationId, + jsonSchema: AST.JSONSchemaAnnotationId, + arbitrary: AST.ArbitraryAnnotationId, + pretty: AST.PrettyAnnotationId, + equivalence: AST.EquivalenceAnnotationId, + concurrency: AST.ConcurrencyAnnotationId, + batching: AST.BatchingAnnotationId, + parseIssueTitle: AST.ParseIssueTitleAnnotationId, + parseOptions: AST.ParseOptionsAnnotationId, + decodingFallback: AST.DecodingFallbackAnnotationId +} + +const toASTAnnotations = >( + annotations?: AllAnnotations +): AST.Annotations => { + if (!annotations) { + return {} + } + const out: Types.Mutable = { ...annotations } + + for (const key in builtInAnnotations) { + if (key in annotations) { + const id = builtInAnnotations[key as keyof typeof builtInAnnotations] + out[id] = annotations[key as keyof typeof annotations] + delete out[key] + } + } + + return out +} + +const mergeSchemaAnnotations = (ast: AST.AST, annotations: Annotations.Schema): AST.AST => + AST.annotations(ast, toASTAnnotations(annotations)) + +/** + * @category annotations + * @since 3.10.0 + */ +export declare namespace Annotable { + /** + * @since 3.10.0 + */ + export type Self = ReturnType + + /** + * @since 3.10.0 + */ + export type Any = Annotable + + /** + * @since 3.10.0 + */ + export type All = + | Any + | Annotable + | Annotable + | Annotable +} + +/** + * @since 3.10.0 + */ +export function asSchema( + schema: S +): Schema, Schema.Encoded, Schema.Context> { + return schema as any +} + +/** + * @category formatting + * @since 3.10.0 + */ +export const format = (schema: S): string => String(schema.ast) + +/** + * @since 3.10.0 + */ +export declare namespace Schema { + /** + * @since 3.10.0 + */ + export interface Variance { + readonly [TypeId]: { + readonly _A: Types.Invariant + readonly _I: Types.Invariant + readonly _R: Types.Covariant + } + } + + /** + * @since 3.10.0 + */ + export type Type = S extends Schema.Variance ? A : never + + /** + * @since 3.10.0 + */ + export type Encoded = S extends Schema.Variance ? I : never + + /** + * @since 3.10.0 + */ + export type Context = S extends Schema.Variance ? R : never + + /** + * @since 3.10.0 + */ + export type ToAsserts = ( + input: unknown, + options?: AST.ParseOptions + ) => asserts input is Schema.Type + + /** + * Any schema, except for `never`. + * + * @since 3.10.0 + */ + export type Any = Schema + + /** + * Any schema with `Context = never`, except for `never`. + * + * @since 3.10.0 + */ + export type AnyNoContext = Schema + + /** + * Any schema, including `never`. + * + * @since 3.10.0 + */ + export type All = + | Any + | Schema + | Schema + | Schema + + /** + * Type-level counterpart of `Schema.asSchema` function. + * + * @since 3.10.0 + */ + export type AsSchema = Schema, Encoded, Context> +} + +/** + * The `encodedSchema` function allows you to extract the `Encoded` portion of a + * schema, creating a new schema that conforms to the properties defined in the + * original schema without retaining any refinements or transformations that + * were applied previously. + * + * @since 3.10.0 + */ +export const encodedSchema = (schema: Schema): SchemaClass => make(AST.encodedAST(schema.ast)) + +/** + * The `encodedBoundSchema` function is similar to `encodedSchema` but preserves + * the refinements up to the first transformation point in the original schema. + * + * @since 3.10.0 + */ +export const encodedBoundSchema = (schema: Schema): SchemaClass => + make(AST.encodedBoundAST(schema.ast)) + +/** + * The `typeSchema` function allows you to extract the `Type` portion of a + * schema, creating a new schema that conforms to the properties defined in the + * original schema without considering the initial encoding or transformation + * processes. + * + * @since 3.10.0 + */ +export const typeSchema = (schema: Schema): SchemaClass => make(AST.typeAST(schema.ast)) + +/* c8 ignore start */ +export { + /** + * By default the option `exact` is set to `true`. + * + * @throws `ParseError` + * @category validation + * @since 3.10.0 + */ + asserts, + /** + * @category decoding + * @since 3.10.0 + */ + decodeOption, + /** + * @throws `ParseError` + * @category decoding + * @since 3.10.0 + */ + decodeSync, + /** + * @category decoding + * @since 3.10.0 + */ + decodeUnknownOption, + /** + * @throws `ParseError` + * @category decoding + * @since 3.10.0 + */ + decodeUnknownSync, + /** + * @category encoding + * @since 3.10.0 + */ + encodeOption, + /** + * @throws `ParseError` + * @category encoding + * @since 3.10.0 + */ + encodeSync, + /** + * @category encoding + * @since 3.10.0 + */ + encodeUnknownOption, + /** + * @throws `ParseError` + * @category encoding + * @since 3.10.0 + */ + encodeUnknownSync, + /** + * By default the option `exact` is set to `true`. + * + * @category validation + * @since 3.10.0 + */ + is, + /** + * @category validation + * @since 3.10.0 + */ + validateOption, + /** + * @throws `ParseError` + * @category validation + * @since 3.10.0 + */ + validateSync +} from "./ParseResult.js" +/* c8 ignore end */ + +/** + * @category encoding + * @since 3.10.0 + */ +export const encodeUnknown = ( + schema: Schema, + options?: ParseOptions +) => { + const encodeUnknown = ParseResult.encodeUnknown(schema, options) + return (u: unknown, overrideOptions?: ParseOptions): Effect.Effect => + ParseResult.mapError(encodeUnknown(u, overrideOptions), ParseResult.parseError) +} + +/** + * @category encoding + * @since 3.10.0 + */ +export const encodeUnknownEither = ( + schema: Schema, + options?: ParseOptions +) => { + const encodeUnknownEither = ParseResult.encodeUnknownEither(schema, options) + return (u: unknown, overrideOptions?: ParseOptions): either_.Either => + either_.mapLeft(encodeUnknownEither(u, overrideOptions), ParseResult.parseError) +} + +/** + * @category encoding + * @since 3.10.0 + */ +export const encodeUnknownPromise = ( + schema: Schema, + options?: ParseOptions +) => { + const parser = encodeUnknown(schema, options) + return (u: unknown, overrideOptions?: ParseOptions): Promise => Effect.runPromise(parser(u, overrideOptions)) +} + +/** + * @category encoding + * @since 3.10.0 + */ +export const encode: ( + schema: Schema, + options?: ParseOptions +) => (a: A, overrideOptions?: ParseOptions) => Effect.Effect = encodeUnknown + +/** + * @category encoding + * @since 3.10.0 + */ +export const encodeEither: ( + schema: Schema, + options?: ParseOptions +) => (a: A, overrideOptions?: ParseOptions) => either_.Either = encodeUnknownEither + +/** + * @category encoding + * @since 3.10.0 + */ +export const encodePromise: ( + schema: Schema, + options?: ParseOptions +) => (a: A, overrideOptions?: ParseOptions) => Promise = encodeUnknownPromise + +/** + * @category decoding + * @since 3.10.0 + */ +export const decodeUnknown = ( + schema: Schema, + options?: ParseOptions +) => { + const decodeUnknown = ParseResult.decodeUnknown(schema, options) + return (u: unknown, overrideOptions?: ParseOptions): Effect.Effect => + ParseResult.mapError(decodeUnknown(u, overrideOptions), ParseResult.parseError) +} + +/** + * @category decoding + * @since 3.10.0 + */ +export const decodeUnknownEither = ( + schema: Schema, + options?: ParseOptions +) => { + const decodeUnknownEither = ParseResult.decodeUnknownEither(schema, options) + return (u: unknown, overrideOptions?: ParseOptions): either_.Either => + either_.mapLeft(decodeUnknownEither(u, overrideOptions), ParseResult.parseError) +} + +/** + * @category decoding + * @since 3.10.0 + */ +export const decodeUnknownPromise = ( + schema: Schema, + options?: ParseOptions +) => { + const parser = decodeUnknown(schema, options) + return (u: unknown, overrideOptions?: ParseOptions): Promise => Effect.runPromise(parser(u, overrideOptions)) +} + +/** + * @category decoding + * @since 3.10.0 + */ +export const decode: ( + schema: Schema, + options?: ParseOptions +) => (i: I, overrideOptions?: ParseOptions) => Effect.Effect = decodeUnknown + +/** + * @category decoding + * @since 3.10.0 + */ +export const decodeEither: ( + schema: Schema, + options?: ParseOptions +) => (i: I, overrideOptions?: ParseOptions) => either_.Either = decodeUnknownEither + +/** + * @category decoding + * @since 3.10.0 + */ +export const decodePromise: ( + schema: Schema, + options?: ParseOptions +) => (i: I, overrideOptions?: ParseOptions) => Promise = decodeUnknownPromise + +/** + * @category validation + * @since 3.10.0 + */ +export const validate = ( + schema: Schema, + options?: ParseOptions +) => { + const validate = ParseResult.validate(schema, options) + return (u: unknown, overrideOptions?: ParseOptions): Effect.Effect => + ParseResult.mapError(validate(u, overrideOptions), ParseResult.parseError) +} + +/** + * @category validation + * @since 3.10.0 + */ +export const validateEither = ( + schema: Schema, + options?: ParseOptions +) => { + const validateEither = ParseResult.validateEither(schema, options) + return (u: unknown, overrideOptions?: ParseOptions): either_.Either => + either_.mapLeft(validateEither(u, overrideOptions), ParseResult.parseError) +} + +/** + * @category validation + * @since 3.10.0 + */ +export const validatePromise = ( + schema: Schema, + options?: ParseOptions +) => { + const parser = validate(schema, options) + return (u: unknown, overrideOptions?: ParseOptions): Promise => Effect.runPromise(parser(u, overrideOptions)) +} + +/** + * Tests if a value is a `Schema`. + * + * @category guards + * @since 3.10.0 + */ +export const isSchema = (u: unknown): u is Schema.Any => + Predicate.hasProperty(u, TypeId) && Predicate.isObject(u[TypeId]) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Literal> + extends AnnotableClass, Literals[number]> +{ + readonly literals: Readonly +} + +function getDefaultLiteralAST>( + literals: Literals +): AST.AST { + return AST.isMembers(literals) + ? AST.Union.make(AST.mapMembers(literals, (literal) => new AST.Literal(literal))) + : new AST.Literal(literals[0]) +} + +function makeLiteralClass>( + literals: Literals, + ast: AST.AST = getDefaultLiteralAST(literals) +): Literal { + return class LiteralClass extends make(ast) { + static override annotations(annotations: Annotations.Schema): Literal { + return makeLiteralClass(this.literals, mergeSchemaAnnotations(this.ast, annotations)) + } + static literals = [...literals] as Literals + } +} + +/** + * @category constructors + * @since 3.10.0 + */ +export function Literal>( + ...literals: Literals +): Literal +export function Literal(): Never +export function Literal>( + ...literals: Literals +): SchemaClass +export function Literal>( + ...literals: Literals +): SchemaClass | Never { + return array_.isNonEmptyReadonlyArray(literals) ? makeLiteralClass(literals) : Never +} + +/** + * Creates a new `Schema` from a literal schema. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Either, Schema } from "effect" + * + * const schema = Schema.Literal("a", "b", "c").pipe(Schema.pickLiteral("a", "b")) + * + * assert.deepStrictEqual(Schema.decodeSync(schema)("a"), "a") + * assert.deepStrictEqual(Schema.decodeSync(schema)("b"), "b") + * assert.strictEqual(Either.isLeft(Schema.decodeUnknownEither(schema)("c")), true) + * ``` + * + * @category constructors + * @since 3.10.0 + */ +export const pickLiteral = + >(...literals: L) => + (_schema: Schema): Literal<[...L]> => Literal(...literals) + +/** + * @category constructors + * @since 3.10.0 + */ +export const UniqueSymbolFromSelf = (symbol: S): SchemaClass => make(new AST.UniqueSymbol(symbol)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Enums extends AnnotableClass, A[keyof A]> { + readonly enums: A +} + +/** + * @since 3.10.0 + */ +export type EnumsDefinition = { [x: string]: string | number } + +const getDefaultEnumsAST = (enums: A) => + new AST.Enums( + Object.keys(enums).filter( + (key) => typeof enums[enums[key]] !== "number" + ).map((key) => [key, enums[key]]) + ) + +const makeEnumsClass = ( + enums: A, + ast: AST.AST = getDefaultEnumsAST(enums) +): Enums => (class EnumsClass extends make(ast) { + static override annotations(annotations: Annotations.Schema) { + return makeEnumsClass(this.enums, mergeSchemaAnnotations(this.ast, annotations)) + } + + static enums = { ...enums } +}) + +/** + * @category constructors + * @since 3.10.0 + */ +export const Enums = (enums: A): Enums => makeEnumsClass(enums) + +type AppendType< + Template extends string, + Next +> = Next extends AST.LiteralValue ? `${Template}${Next}` + : Next extends Schema ? `${Template}${A}` + : never + +type GetTemplateLiteralType = Params extends [...infer Init, infer Last] ? + AppendType, Last> + : `` + +/** + * @category API interface + * @since 3.10.0 + */ +export interface TemplateLiteral extends SchemaClass {} + +type TemplateLiteralParameter = Schema.AnyNoContext | AST.LiteralValue + +/** + * @category template literal + * @since 3.10.0 + */ +export const TemplateLiteral = >( + ...[head, ...tail]: Params +): TemplateLiteral> => { + const spans: Array = [] + let h = "" + let ts = tail + + if (isSchema(head)) { + if (AST.isLiteral(head.ast)) { + h = String(head.ast.literal) + } else { + ts = [head, ...ts] + } + } else { + h = String(head) + } + + for (let i = 0; i < ts.length; i++) { + const item = ts[i] + if (isSchema(item)) { + if (i < ts.length - 1) { + const next = ts[i + 1] + if (isSchema(next)) { + if (AST.isLiteral(next.ast)) { + spans.push(new AST.TemplateLiteralSpan(item.ast, String(next.ast.literal))) + i++ + continue + } + } else { + spans.push(new AST.TemplateLiteralSpan(item.ast, String(next))) + i++ + continue + } + } + spans.push(new AST.TemplateLiteralSpan(item.ast, "")) + } else { + spans.push(new AST.TemplateLiteralSpan(new AST.Literal(item), "")) + } + } + + if (array_.isNonEmptyArray(spans)) { + return make(new AST.TemplateLiteral(h, spans)) + } else { + return make(new AST.TemplateLiteral("", [new AST.TemplateLiteralSpan(new AST.Literal(h), "")])) + } +} + +type TemplateLiteralParserParameters = Schema.Any | AST.LiteralValue + +type GetTemplateLiteralParserType = Params extends [infer Head, ...infer Tail] ? readonly [ + Head extends Schema ? A : Head, + ...GetTemplateLiteralParserType + ] + : [] + +type AppendEncoded< + Template extends string, + Next +> = Next extends AST.LiteralValue ? `${Template}${Next}` + : Next extends Schema ? `${Template}${I}` + : never + +type GetTemplateLiteralParserEncoded = Params extends [...infer Init, infer Last] ? + AppendEncoded, Last> + : `` + +/** + * @category API interface + * @since 3.10.0 + */ +export interface TemplateLiteralParser> + extends + Schema< + GetTemplateLiteralParserType, + GetTemplateLiteralParserEncoded, + Schema.Context + > +{ + readonly params: Params +} + +function getTemplateLiteralParserCoercedElement(encoded: Schema.Any, schema: Schema.Any): Schema.Any | undefined { + const ast = encoded.ast + switch (ast._tag) { + case "Literal": { + const literal = ast.literal + if (!Predicate.isString(literal)) { + const s = String(literal) + return transform(Literal(s), schema, { + strict: true, + decode: () => literal, + encode: () => s + }) + } + break + } + case "NumberKeyword": + return compose(NumberFromString, schema) + case "Union": { + const members: Array = [] + let hasCoercions = false + for (const member of ast.types) { + const schema = make(member) + const encoded = encodedSchema(schema) + const coerced = getTemplateLiteralParserCoercedElement(encoded, schema) + if (coerced) { + hasCoercions = true + } + members.push(coerced ?? schema) + } + return hasCoercions ? compose(Union(...members), schema) : schema + } + } +} + +/** + * @category template literal + * @since 3.10.0 + */ +export const TemplateLiteralParser = >( + ...params: Params +): TemplateLiteralParser => { + const encodedSchemas: Array = [] + const elements: Array = [] + const schemas: Array = [] + let coerced = false + for (let i = 0; i < params.length; i++) { + const param = params[i] + const schema = isSchema(param) ? param : Literal(param) + schemas.push(schema) + const encoded = encodedSchema(schema) + encodedSchemas.push(encoded) + const element = getTemplateLiteralParserCoercedElement(encoded, schema) + if (element) { + elements.push(element) + coerced = true + } else { + elements.push(schema) + } + } + const from = TemplateLiteral(...encodedSchemas as any) + const re = AST.getTemplateLiteralCapturingRegExp(from.ast as AST.TemplateLiteral) + let to = Tuple(...elements) + if (coerced) { + to = to.annotations({ [AST.AutoTitleAnnotationId]: format(Tuple(...schemas)) }) + } + return class TemplateLiteralParserClass extends transformOrFail(from, to, { + strict: false, + decode: (i, _, ast) => { + const match = re.exec(i) + return match + ? ParseResult.succeed(match.slice(1, params.length + 1)) + : ParseResult.fail(new ParseResult.Type(ast, i, `${re.source}: no match for ${JSON.stringify(i)}`)) + }, + encode: (tuple) => ParseResult.succeed(tuple.join("")) + }) { + static params = params.slice() + } as any +} + +const declareConstructor = < + const TypeParameters extends ReadonlyArray, + I, + A +>( + typeParameters: TypeParameters, + options: { + readonly decode: ( + ...typeParameters: { + readonly [K in keyof TypeParameters]: Schema< + Schema.Type, + Schema.Encoded, + never + > + } + ) => ( + input: unknown, + options: ParseOptions, + ast: AST.Declaration + ) => Effect.Effect + readonly encode: ( + ...typeParameters: { + readonly [K in keyof TypeParameters]: Schema< + Schema.Type, + Schema.Encoded, + never + > + } + ) => ( + input: unknown, + options: ParseOptions, + ast: AST.Declaration + ) => Effect.Effect + }, + annotations?: Annotations.Schema +): SchemaClass> => + makeDeclareClass( + typeParameters, + new AST.Declaration( + typeParameters.map((tp) => tp.ast), + (...typeParameters) => options.decode(...typeParameters.map(make) as any), + (...typeParameters) => options.encode(...typeParameters.map(make) as any), + toASTAnnotations(annotations) + ) + ) + +const declarePrimitive = ( + is: (input: unknown) => input is A, + annotations?: Annotations.Schema +): SchemaClass => { + const decodeUnknown = () => (input: unknown, _: ParseOptions, ast: AST.Declaration) => + is(input) ? ParseResult.succeed(input) : ParseResult.fail(new ParseResult.Type(ast, input)) + const encodeUnknown = decodeUnknown + return makeDeclareClass([], new AST.Declaration([], decodeUnknown, encodeUnknown, toASTAnnotations(annotations))) +} + +/** + * @category api interface + * @since 3.13.3 + */ +export interface declare< + A, + I = A, + P extends ReadonlyArray = readonly [], + R = Schema.Context +> extends AnnotableClass, A, I, R> { + readonly typeParameters: Readonly

+} + +/** + * @category api interface + * @since 3.13.3 + */ +export interface AnnotableDeclare< + Self extends declare, + A, + I = A, + P extends ReadonlyArray = readonly [], + R = Schema.Context +> extends declare { + annotations(annotations: Annotations.Schema): Self +} + +function makeDeclareClass

, A, I, R>( + typeParameters: P, + ast: AST.AST +): declare { + return class DeclareClass extends make(ast) { + static override annotations(annotations: Annotations.Schema): declare { + return makeDeclareClass(this.typeParameters, mergeSchemaAnnotations(this.ast, annotations)) + } + static typeParameters = [...typeParameters] as any as P + } +} + +/** + * The constraint `R extends Schema.Context` enforces dependencies solely from `typeParameters`. + * This ensures that when you call `Schema.to` or `Schema.from`, you receive a schema with a `never` context. + * + * @category constructors + * @since 3.10.0 + */ +export const declare: { + /** + * The constraint `R extends Schema.Context` enforces dependencies solely from `typeParameters`. + * This ensures that when you call `Schema.to` or `Schema.from`, you receive a schema with a `never` context. + * + * @category constructors + * @since 3.10.0 + */ + (is: (input: unknown) => input is A, annotations?: Annotations.Schema): declare + /** + * The constraint `R extends Schema.Context` enforces dependencies solely from `typeParameters`. + * This ensures that when you call `Schema.to` or `Schema.from`, you receive a schema with a `never` context. + * + * @category constructors + * @since 3.10.0 + */ + >( + typeParameters: P, + options: { + readonly decode: ( + ...typeParameters: { readonly [K in keyof P]: Schema, Schema.Encoded, never> } + ) => ( + input: unknown, + options: ParseOptions, + ast: AST.Declaration + ) => Effect.Effect + readonly encode: ( + ...typeParameters: { readonly [K in keyof P]: Schema, Schema.Encoded, never> } + ) => ( + input: unknown, + options: ParseOptions, + ast: AST.Declaration + ) => Effect.Effect + }, + annotations?: Annotations.Schema }> + ): declare +} = function() { + if (Array.isArray(arguments[0])) { + const typeParameters = arguments[0] + const options = arguments[1] + const annotations = arguments[2] + return declareConstructor(typeParameters, options, annotations) + } + const is = arguments[0] + const annotations = arguments[1] + return declarePrimitive(is, annotations) +} as any + +/** + * @category schema id + * @since 3.10.0 + */ +export const BrandSchemaId: unique symbol = Symbol.for("effect/SchemaId/Brand") + +/** + * @category constructors + * @since 3.10.0 + */ +export const fromBrand = , A extends Brand.Unbranded>( + constructor: Brand.Constructor, + annotations?: Annotations.Filter +) => +(self: Schema): BrandSchema => { + const out = makeBrandClass( + self, + new AST.Refinement( + self.ast, + function predicate(a: A, _: ParseOptions, ast: AST.AST): option_.Option { + const either = constructor.either(a) + return either_.isLeft(either) ? + option_.some(new ParseResult.Type(ast, a, either.left.map((v) => v.message).join(", "))) : + option_.none() + }, + toASTAnnotations({ + schemaId: BrandSchemaId, + [BrandSchemaId]: { constructor }, + ...annotations + }) + ) + ) + return out as any +} + +/** + * @category schema id + * @since 3.10.0 + */ +export const InstanceOfSchemaId: unique symbol = Symbol.for("effect/SchemaId/InstanceOf") + +/** + * @category api interface + * @since 3.10.0 + */ +export interface instanceOf extends AnnotableDeclare, A> {} + +/** + * @category constructors + * @since 3.10.0 + */ +export const instanceOf = any>( + constructor: A, + annotations?: Annotations.Schema> +): instanceOf> => + declare( + (u): u is InstanceType => u instanceof constructor, + { + title: constructor.name, + description: `an instance of ${constructor.name}`, + pretty: (): pretty_.Pretty> => String, + schemaId: InstanceOfSchemaId, + [InstanceOfSchemaId]: { constructor }, + ...annotations + } + ) + +/** + * @category primitives + * @since 3.10.0 + */ +export class Undefined extends make(AST.undefinedKeyword) {} + +/** + * @category primitives + * @since 3.10.0 + */ +export class Void extends make(AST.voidKeyword) {} + +/** + * @category primitives + * @since 3.10.0 + */ +export class Null extends make(AST.null) {} + +/** + * @category primitives + * @since 3.10.0 + */ +export class Never extends make(AST.neverKeyword) {} + +/** + * @category primitives + * @since 3.10.0 + */ +export class Unknown extends make(AST.unknownKeyword) {} + +/** + * @category primitives + * @since 3.10.0 + */ +export class Any extends make(AST.anyKeyword) {} + +/** + * @category primitives + * @since 3.10.0 + */ +export class BigIntFromSelf extends make(AST.bigIntKeyword) {} + +/** + * @category primitives + * @since 3.10.0 + */ +export class SymbolFromSelf extends make(AST.symbolKeyword) {} + +/** @ignore */ +class String$ extends make(AST.stringKeyword) {} + +/** @ignore */ +class Number$ extends make(AST.numberKeyword) {} + +/** @ignore */ +class Boolean$ extends make(AST.booleanKeyword) {} + +/** @ignore */ +class Object$ extends make(AST.objectKeyword) {} + +export { + /** + * @category primitives + * @since 3.10.0 + */ + Boolean$ as Boolean, + /** + * @category primitives + * @since 3.10.0 + */ + Number$ as Number, + /** + * @category primitives + * @since 3.10.0 + */ + Object$ as Object, + /** + * @category primitives + * @since 3.10.0 + */ + String$ as String +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Union> extends + AnnotableClass< + Union, + Schema.Type, + Schema.Encoded, + Schema.Context + > +{ + readonly members: Readonly +} + +const getDefaultUnionAST = >(members: Members): AST.AST => + AST.Union.make(members.map((m) => m.ast)) + +function makeUnionClass>( + members: Members, + ast: AST.AST = getDefaultUnionAST(members) +): Union { + return class UnionClass extends make< + Schema.Type, + Schema.Encoded, + Schema.Context + >(ast) { + static override annotations(annotations: Annotations.Schema>): Union { + return makeUnionClass(this.members, mergeSchemaAnnotations(this.ast, annotations)) + } + + static members = [...members] + } +} + +/** + * @category combinators + * @since 3.10.0 + */ +export function Union>(...members: Members): Union +export function Union(member: Member): Member +export function Union(): typeof Never +export function Union>( + ...members: Members +): Schema, Schema.Encoded, Schema.Context> +export function Union>( + ...members: Members +) { + return AST.isMembers(members) + ? makeUnionClass(members) + : array_.isNonEmptyReadonlyArray(members) + ? members[0] + : Never +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface NullOr extends Union<[S, typeof Null]> { + annotations(annotations: Annotations.Schema | null>): NullOr +} + +/** + * @category combinators + * @since 3.10.0 + */ +export const NullOr = (self: S): NullOr => Union(self, Null) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface UndefinedOr extends Union<[S, typeof Undefined]> { + annotations(annotations: Annotations.Schema | undefined>): UndefinedOr +} + +/** + * @category combinators + * @since 3.10.0 + */ +export const UndefinedOr = (self: S): UndefinedOr => Union(self, Undefined) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface NullishOr extends Union<[S, typeof Null, typeof Undefined]> { + annotations(annotations: Annotations.Schema | null | undefined>): NullishOr +} + +/** + * @category combinators + * @since 3.10.0 + */ +export const NullishOr = (self: S): NullishOr => Union(self, Null, Undefined) + +/** + * @category combinators + * @since 3.10.0 + */ +export const keyof = (self: Schema): SchemaClass => make(AST.keyof(self.ast)) + +/** + * @since 3.10.0 + */ +export declare namespace Element { + /** + * @since 3.10.0 + */ + export interface Annotations extends Annotations.Doc { + readonly missingMessage?: AST.MissingMessageAnnotation + } + + /** + * @since 3.10.0 + */ + export type Token = "" | "?" +} + +/** + * @category API interface + * @since 3.10.0 + */ +export interface Element + extends Schema.Variance, Schema.Encoded, Schema.Context> +{ + readonly _Token: Token + readonly ast: AST.OptionalType + readonly from: S + annotations(annotations: Element.Annotations>): Element +} + +/** + * @since 3.10.0 + */ +export const element = (self: S): Element => + new ElementImpl(new AST.OptionalType(self.ast, false), self) + +/** + * @since 3.10.0 + */ +export const optionalElement = (self: S): Element => + new ElementImpl(new AST.OptionalType(self.ast, true), self) + +class ElementImpl implements Element { + readonly [TypeId]!: Schema.Variance, Schema.Encoded, Schema.Context>[TypeId] + readonly _Token!: Token + constructor( + readonly ast: AST.OptionalType, + readonly from: S + ) {} + annotations( + annotations: Annotations.Schema> + ): ElementImpl { + return new ElementImpl( + new AST.OptionalType( + this.ast.type, + this.ast.isOptional, + { ...this.ast.annotations, ...toASTAnnotations(annotations) } + ), + this.from + ) + } + toString() { + return `${this.ast.type}${this.ast.isOptional ? "?" : ""}` + } +} + +/** + * @since 3.10.0 + */ +export declare namespace TupleType { + type ElementsType< + Elements, + Out extends ReadonlyArray = readonly [] + > = Elements extends readonly [infer Head, ...infer Tail] ? + Head extends Element ? ElementsType?]> + : ElementsType]> + : Out + + type ElementsEncoded< + Elements, + Out extends ReadonlyArray = readonly [] + > = Elements extends readonly [infer Head, ...infer Tail] ? + Head extends Element ? ElementsEncoded?]> + : ElementsEncoded]> + : Out + + /** + * @since 3.10.0 + */ + export type Elements = ReadonlyArray> + + /** + * @since 3.10.0 + */ + export type Rest = ReadonlyArray> + + /** + * @since 3.10.0 + */ + export type Type = Rest extends + [infer Head, ...infer Tail] ? Readonly<[ + ...ElementsType, + ...ReadonlyArray>, + ...{ readonly [K in keyof Tail]: Schema.Type } + ]> : + ElementsType + + /** + * @since 3.10.0 + */ + export type Encoded = Rest extends + [infer Head, ...infer Tail] ? Readonly<[ + ...ElementsEncoded, + ...ReadonlyArray>, + ...{ readonly [K in keyof Tail]: Schema.Encoded } + ]> : + ElementsEncoded +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface TupleType extends + AnnotableClass< + TupleType, + TupleType.Type, + TupleType.Encoded, + Schema.Context | Schema.Context + > +{ + readonly elements: Readonly + readonly rest: Readonly +} + +const getDefaultTupleTypeAST = ( + elements: Elements, + rest: Rest +) => + new AST.TupleType( + elements.map((el) => isSchema(el) ? new AST.OptionalType(el.ast, false) : el.ast), + rest.map((el) => isSchema(el) ? new AST.Type(el.ast) : el.ast), + true + ) + +function makeTupleTypeClass( + elements: Elements, + rest: Rest, + ast: AST.AST = getDefaultTupleTypeAST(elements, rest) +) { + return class TupleTypeClass extends make< + TupleType.Type, + TupleType.Encoded, + Schema.Context | Schema.Context + >(ast) { + static override annotations( + annotations: Annotations.Schema> + ): TupleType { + return makeTupleTypeClass(this.elements, this.rest, mergeSchemaAnnotations(this.ast, annotations)) + } + + static elements = [...elements] as any as Elements + + static rest = [...rest] as any as Rest + } +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Tuple extends TupleType { + annotations(annotations: Annotations.Schema>): Tuple +} + +/** + * @category api interface + * @since 3.13.3 + */ +export interface Tuple2 extends + AnnotableClass< + Tuple2, + readonly [Schema.Type, Schema.Type], + readonly [Schema.Encoded, Schema.Encoded], + Schema.Context | Schema.Context + > +{ + readonly elements: readonly [Fst, Snd] + readonly rest: readonly [] +} + +/** + * @category constructors + * @since 3.10.0 + */ +export function Tuple< + const Elements extends TupleType.Elements, + Rest extends array_.NonEmptyReadonlyArray +>(elements: Elements, ...rest: Rest): TupleType +export function Tuple(fst: Fst, snd: Snd): Tuple2 +export function Tuple(...elements: Elements): Tuple +export function Tuple(...args: ReadonlyArray): any { + return Array.isArray(args[0]) + ? makeTupleTypeClass(args[0], args.slice(1)) + : makeTupleTypeClass(args, []) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Array$ extends TupleType<[], [Value]> { + readonly value: Value + annotations(annotations: Annotations.Schema>): Array$ +} + +function makeArrayClass( + value: Value, + ast?: AST.AST +): Array$ { + return class ArrayClass extends makeTupleTypeClass<[], [Value]>([], [value], ast) { + static override annotations(annotations: Annotations.Schema>) { + return makeArrayClass(this.value, mergeSchemaAnnotations(this.ast, annotations)) + } + + static value = value + } +} + +const Array$ = (value: Value): Array$ => makeArrayClass(value) + +export { + /** + * @category constructors + * @since 3.10.0 + */ + Array$ as Array +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface NonEmptyArray extends + AnnotableClass< + NonEmptyArray, + array_.NonEmptyReadonlyArray>, + array_.NonEmptyReadonlyArray>, + Schema.Context + > +{ + readonly elements: readonly [Value] + readonly rest: readonly [Value] + readonly value: Value +} + +function makeNonEmptyArrayClass( + value: Value, + ast?: AST.AST +) { + return class NonEmptyArrayClass extends makeTupleTypeClass<[Value], [Value]>([value], [value], ast) { + static override annotations(annotations: Annotations.Schema>) { + return makeNonEmptyArrayClass(this.value, mergeSchemaAnnotations(this.ast, annotations)) + } + + static value = value + } +} + +/** + * @category constructors + * @since 3.10.0 + */ +export const NonEmptyArray = (value: Value): NonEmptyArray => + makeNonEmptyArrayClass(value) as any + +/** + * @category api interface + * @since 3.10.0 + */ +export interface ArrayEnsure + extends transform]>, Array$>>> +{} + +/** + * @category constructors + * @since 3.10.0 + */ +export function ArrayEnsure(value: Value): ArrayEnsure { + return transform(Union(value, Array$(value)), Array$(typeSchema(asSchema(value))), { + strict: true, + decode: (i) => array_.ensure(i), + encode: (a) => a.length === 1 ? a[0] : a + }) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface NonEmptyArrayEnsure + extends transform]>, NonEmptyArray>>> +{} + +/** + * @category constructors + * @since 3.10.0 + */ +export function NonEmptyArrayEnsure(value: Value): NonEmptyArrayEnsure { + return transform(Union(value, NonEmptyArray(value)), NonEmptyArray(typeSchema(asSchema(value))), { + strict: true, + decode: (i) => array_.isNonEmptyReadonlyArray(i) ? i : array_.of(i), + encode: (a) => a.length === 1 ? a[0] : a + }) +} + +/** + * @since 3.10.0 + */ +export declare namespace PropertySignature { + /** + * @since 3.10.0 + */ + export type Token = "?:" | ":" + + /** + * @since 3.10.0 + */ + export type Any = PropertySignature< + Token, + any, + Key, + Token, + any, + boolean, + unknown + > + + /** + * @since 3.10.0 + */ + export type All = + | Any + | PropertySignature + | PropertySignature + | PropertySignature + + /** + * @since 3.10.0 + */ + export type AST = + | PropertySignatureDeclaration + | PropertySignatureTransformation + + /** + * @since 3.10.0 + */ + export interface Annotations extends Annotations.Doc { + readonly missingMessage?: AST.MissingMessageAnnotation + } +} + +const formatPropertySignatureToken = (isOptional: boolean): string => isOptional ? "\"?:\"" : "\":\"" + +/** + * @category PropertySignature + * @since 3.10.0 + */ +export class PropertySignatureDeclaration extends AST.OptionalType { + /** + * @since 3.10.0 + */ + readonly _tag = "PropertySignatureDeclaration" + constructor( + type: AST.AST, + isOptional: boolean, + readonly isReadonly: boolean, + annotations: AST.Annotations, + readonly defaultValue: (() => unknown) | undefined + ) { + super(type, isOptional, annotations) + } + /** + * @since 3.10.0 + */ + toString() { + const token = formatPropertySignatureToken(this.isOptional) + const type = String(this.type) + return `PropertySignature<${token}, ${type}, never, ${token}, ${type}>` + } +} + +/** + * @category PropertySignature + * @since 3.10.0 + */ +export class FromPropertySignature extends AST.OptionalType { + constructor( + type: AST.AST, + isOptional: boolean, + readonly isReadonly: boolean, + annotations: AST.Annotations, + readonly fromKey?: PropertyKey | undefined + ) { + super(type, isOptional, annotations) + } +} + +/** + * @category PropertySignature + * @since 3.10.0 + */ +export class ToPropertySignature extends AST.OptionalType { + constructor( + type: AST.AST, + isOptional: boolean, + readonly isReadonly: boolean, + annotations: AST.Annotations, + readonly defaultValue: (() => unknown) | undefined + ) { + super(type, isOptional, annotations) + } +} + +const formatPropertyKey = (p: PropertyKey | undefined): string => { + if (p === undefined) { + return "never" + } + if (Predicate.isString(p)) { + return JSON.stringify(p) + } + return String(p) +} + +/** + * @category PropertySignature + * @since 3.10.0 + */ +export class PropertySignatureTransformation { + /** + * @since 3.10.0 + */ + readonly _tag = "PropertySignatureTransformation" + constructor( + readonly from: FromPropertySignature, + readonly to: ToPropertySignature, + readonly decode: AST.PropertySignatureTransformation["decode"], + readonly encode: AST.PropertySignatureTransformation["encode"] + ) {} + /** + * @since 3.10.0 + */ + toString() { + return `PropertySignature<${formatPropertySignatureToken(this.to.isOptional)}, ${this.to.type}, ${ + formatPropertyKey(this.from.fromKey) + }, ${formatPropertySignatureToken(this.from.isOptional)}, ${this.from.type}>` + } +} + +const mergeSignatureAnnotations = ( + ast: PropertySignature.AST, + annotations: AST.Annotations +): PropertySignature.AST => { + switch (ast._tag) { + case "PropertySignatureDeclaration": { + return new PropertySignatureDeclaration( + ast.type, + ast.isOptional, + ast.isReadonly, + { ...ast.annotations, ...annotations }, + ast.defaultValue + ) + } + case "PropertySignatureTransformation": { + return new PropertySignatureTransformation( + ast.from, + new ToPropertySignature(ast.to.type, ast.to.isOptional, ast.to.isReadonly, { + ...ast.to.annotations, + ...annotations + }, ast.to.defaultValue), + ast.decode, + ast.encode + ) + } + } +} + +/** + * @since 3.10.0 + * @category symbol + */ +export const PropertySignatureTypeId: unique symbol = Symbol.for("effect/PropertySignature") + +/** + * @since 3.10.0 + * @category symbol + */ +export type PropertySignatureTypeId = typeof PropertySignatureTypeId + +/** + * @since 3.10.0 + * @category guards + */ +export const isPropertySignature = (u: unknown): u is PropertySignature.All => + Predicate.hasProperty(u, PropertySignatureTypeId) + +/** + * @category PropertySignature + * @since 3.10.0 + */ +export interface PropertySignature< + TypeToken extends PropertySignature.Token, + Type, + Key extends PropertyKey, + EncodedToken extends PropertySignature.Token, + Encoded, + HasDefault extends boolean = false, + R = never +> extends Schema.Variance, Pipeable { + readonly [PropertySignatureTypeId]: null + readonly _TypeToken: TypeToken + readonly _EncodedToken: EncodedToken + readonly _HasDefault: HasDefault + readonly _Key: Key + readonly ast: PropertySignature.AST + + annotations( + annotations: PropertySignature.Annotations + ): PropertySignature +} + +class PropertySignatureImpl< + TypeToken extends PropertySignature.Token, + Type, + Key extends PropertyKey, + EncodedToken extends PropertySignature.Token, + Encoded, + HasDefault extends boolean = false, + R = never +> implements PropertySignature { + readonly [TypeId]!: Schema.Variance[TypeId] + readonly [PropertySignatureTypeId] = null + readonly _TypeToken!: TypeToken + readonly _Key!: Key + readonly _EncodedToken!: EncodedToken + readonly _HasDefault!: HasDefault + + constructor( + readonly ast: PropertySignature.AST + ) {} + + pipe() { + return pipeArguments(this, arguments) + } + + annotations( + annotations: PropertySignature.Annotations + ): PropertySignature { + return new PropertySignatureImpl(mergeSignatureAnnotations(this.ast, toASTAnnotations(annotations))) + } + + toString() { + return String(this.ast) + } +} + +/** + * @category PropertySignature + * @since 3.10.0 + */ +export const makePropertySignature = < + TypeToken extends PropertySignature.Token, + Type, + Key extends PropertyKey, + EncodedToken extends PropertySignature.Token, + Encoded, + HasDefault extends boolean = false, + R = never +>(ast: PropertySignature.AST) => + new PropertySignatureImpl(ast) + +class PropertySignatureWithFromImpl< + From extends Schema.All, + TypeToken extends PropertySignature.Token, + Type, + Key extends PropertyKey, + EncodedToken extends PropertySignature.Token, + Encoded, + HasDefault extends boolean = false, + R = never +> extends PropertySignatureImpl { + constructor(ast: PropertySignature.AST, readonly from: From) { + super(ast) + } + annotations( + annotations: PropertySignature.Annotations + ): PropertySignatureWithFromImpl { + return new PropertySignatureWithFromImpl( + mergeSignatureAnnotations(this.ast, toASTAnnotations(annotations)), + this.from + ) + } +} + +/** + * @category API interface + * @since 1.0.0 + */ +export interface propertySignature + extends PropertySignature<":", Schema.Type, never, ":", Schema.Encoded, false, Schema.Context> +{ + readonly from: S + annotations(annotations: PropertySignature.Annotations>): propertySignature +} + +/** + * Lifts a `Schema` into a `PropertySignature`. + * + * @category PropertySignature + * @since 3.10.0 + */ +export const propertySignature = ( + self: S +): propertySignature => + new PropertySignatureWithFromImpl( + new PropertySignatureDeclaration(self.ast, false, true, {}, undefined), + self + ) + +/** + * Enhances a property signature with a default constructor value. + * + * @category PropertySignature + * @since 3.10.0 + */ +export const withConstructorDefault: { + /** + * Enhances a property signature with a default constructor value. + * + * @category PropertySignature + * @since 3.10.0 + */ + (defaultValue: () => Types.NoInfer): < + TypeToken extends PropertySignature.Token, + Key extends PropertyKey, + EncodedToken extends PropertySignature.Token, + Encoded, + R + >( + self: PropertySignature + ) => PropertySignature + /** + * Enhances a property signature with a default constructor value. + * + * @category PropertySignature + * @since 3.10.0 + */ + < + TypeToken extends PropertySignature.Token, + Type, + Key extends PropertyKey, + EncodedToken extends PropertySignature.Token, + Encoded, + R + >( + self: PropertySignature, + defaultValue: () => Types.NoInfer + ): PropertySignature +} = dual(2, < + TypeToken extends PropertySignature.Token, + Type, + Key extends PropertyKey, + EncodedToken extends PropertySignature.Token, + Encoded, + R +>( + self: PropertySignature, + defaultValue: () => Types.NoInfer +): PropertySignature => { + const ast = self.ast + switch (ast._tag) { + case "PropertySignatureDeclaration": + return makePropertySignature( + new PropertySignatureDeclaration(ast.type, ast.isOptional, ast.isReadonly, ast.annotations, defaultValue) + ) + case "PropertySignatureTransformation": + return makePropertySignature( + new PropertySignatureTransformation( + ast.from, + new ToPropertySignature(ast.to.type, ast.to.isOptional, ast.to.isReadonly, ast.to.annotations, defaultValue), + ast.decode, + ast.encode + ) + ) + } +}) + +const applyDefaultValue = (o: option_.Option, defaultValue: () => A) => + option_.match(o, { + onNone: () => option_.some(defaultValue()), + onSome: (value) => option_.some(value === undefined ? defaultValue() : value) + }) + +const pruneUndefined = (ast: AST.AST): AST.AST | undefined => + AST.pruneUndefined(ast, pruneUndefined, (ast) => { + const pruned = pruneUndefined(ast.to) + if (pruned) { + return new AST.Transformation(ast.from, pruned, ast.transformation) + } + }) + +/** + * Enhances a property signature with a default decoding value. + * + * @category PropertySignature + * @since 3.10.0 + */ +export const withDecodingDefault: { + /** + * Enhances a property signature with a default decoding value. + * + * @category PropertySignature + * @since 3.10.0 + */ + (defaultValue: () => Types.NoInfer>): < + Key extends PropertyKey, + Encoded, + R + >( + self: PropertySignature<"?:", Type, Key, "?:", Encoded, false, R> + ) => PropertySignature<":", Exclude, Key, "?:", Encoded, false, R> + /** + * Enhances a property signature with a default decoding value. + * + * @category PropertySignature + * @since 3.10.0 + */ + < + Type, + Key extends PropertyKey, + Encoded, + R + >( + self: PropertySignature<"?:", Type, Key, "?:", Encoded, false, R>, + defaultValue: () => Types.NoInfer> + ): PropertySignature<":", Exclude, Key, "?:", Encoded, false, R> +} = dual(2, < + Type, + Key extends PropertyKey, + Encoded, + R +>( + self: PropertySignature<"?:", Type, Key, "?:", Encoded, false, R>, + defaultValue: () => Types.NoInfer> +): PropertySignature<":", Exclude, Key, "?:", Encoded, false, R> => { + const ast = self.ast + switch (ast._tag) { + case "PropertySignatureDeclaration": { + const to = AST.typeAST(ast.type) + return makePropertySignature( + new PropertySignatureTransformation( + new FromPropertySignature(ast.type, ast.isOptional, ast.isReadonly, ast.annotations), + new ToPropertySignature(pruneUndefined(to) ?? to, false, true, {}, ast.defaultValue), + (o) => applyDefaultValue(o, defaultValue), + identity + ) + ) + } + case "PropertySignatureTransformation": { + const to = ast.to.type + return makePropertySignature( + new PropertySignatureTransformation( + ast.from, + new ToPropertySignature( + pruneUndefined(to) ?? to, + false, + ast.to.isReadonly, + ast.to.annotations, + ast.to.defaultValue + ), + (o) => applyDefaultValue(ast.decode(o), defaultValue), + ast.encode + ) + ) + } + } +}) + +/** + * Enhances a property signature with a default decoding value and a default constructor value. + * + * @category PropertySignature + * @since 3.10.0 + */ +export const withDefaults: { + /** + * Enhances a property signature with a default decoding value and a default constructor value. + * + * @category PropertySignature + * @since 3.10.0 + */ + ( + defaults: { + constructor: () => Types.NoInfer> + decoding: () => Types.NoInfer> + } + ): < + Key extends PropertyKey, + Encoded, + R + >( + self: PropertySignature<"?:", Type, Key, "?:", Encoded, boolean, R> + ) => PropertySignature<":", Exclude, Key, "?:", Encoded, true, R> + /** + * Enhances a property signature with a default decoding value and a default constructor value. + * + * @category PropertySignature + * @since 3.10.0 + */ + < + Type, + Key extends PropertyKey, + Encoded, + R + >( + self: PropertySignature<"?:", Type, Key, "?:", Encoded, boolean, R>, + defaults: { + constructor: () => Types.NoInfer> + decoding: () => Types.NoInfer> + } + ): PropertySignature<":", Exclude, Key, "?:", Encoded, true, R> +} = dual(2, < + Type, + Key extends PropertyKey, + Encoded, + R +>( + self: PropertySignature<"?:", Type, Key, "?:", Encoded, false, R>, + defaults: { + constructor: () => Types.NoInfer> + decoding: () => Types.NoInfer> + } +): PropertySignature<":", Exclude, Key, "?:", Encoded, true, R> => + self.pipe(withDecodingDefault(defaults.decoding), withConstructorDefault(defaults.constructor))) + +/** + * Enhances a property signature by specifying a different key for it in the Encoded type. + * + * @category PropertySignature + * @since 3.10.0 + */ +export const fromKey: { + /** + * Enhances a property signature by specifying a different key for it in the Encoded type. + * + * @category PropertySignature + * @since 3.10.0 + */ + (key: Key): < + TypeToken extends PropertySignature.Token, + Type, + EncodedToken extends PropertySignature.Token, + Encoded, + HasDefault extends boolean, + R + >( + self: PropertySignature + ) => PropertySignature + /** + * Enhances a property signature by specifying a different key for it in the Encoded type. + * + * @category PropertySignature + * @since 3.10.0 + */ + < + Type, + TypeToken extends PropertySignature.Token, + Encoded, + EncodedToken extends PropertySignature.Token, + HasDefault extends boolean, + R, + Key extends PropertyKey + >( + self: PropertySignature, + key: Key + ): PropertySignature +} = dual(2, < + Type, + TypeToken extends PropertySignature.Token, + Encoded, + EncodedToken extends PropertySignature.Token, + HasDefault extends boolean, + R, + Key extends PropertyKey +>( + self: PropertySignature, + key: Key +): PropertySignature => { + const ast = self.ast + switch (ast._tag) { + case "PropertySignatureDeclaration": { + return makePropertySignature( + new PropertySignatureTransformation( + new FromPropertySignature( + ast.type, + ast.isOptional, + ast.isReadonly, + ast.annotations, + key + ), + new ToPropertySignature(AST.typeAST(ast.type), ast.isOptional, ast.isReadonly, {}, ast.defaultValue), + identity, + identity + ) + ) + } + case "PropertySignatureTransformation": + return makePropertySignature( + new PropertySignatureTransformation( + new FromPropertySignature( + ast.from.type, + ast.from.isOptional, + ast.from.isReadonly, + ast.from.annotations, + key + ), + ast.to, + ast.decode, + ast.encode + ) + ) + } +}) + +/** + * Converts an optional property to a required one through a transformation `Option -> Type`. + * + * - `decode`: `none` as argument means the value is missing in the input. + * - `encode`: `none` as return value means the value will be missing in the output. + * + * @category PropertySignature + * @since 3.10.0 + */ +export const optionalToRequired = ( + from: Schema, + to: Schema, + options: { + readonly decode: (o: option_.Option) => TI + readonly encode: (ti: TI) => option_.Option + } +): PropertySignature<":", TA, never, "?:", FI, false, FR | TR> => + makePropertySignature( + new PropertySignatureTransformation( + new FromPropertySignature(from.ast, true, true, {}, undefined), + new ToPropertySignature(to.ast, false, true, {}, undefined), + (o) => option_.some(options.decode(o)), + option_.flatMap(options.encode) + ) + ) + +/** + * Converts an optional property to a required one through a transformation `Type -> Option`. + * + * - `decode`: `none` as return value means the value will be missing in the output. + * - `encode`: `none` as argument means the value is missing in the input. + * + * @category PropertySignature + * @since 3.10.0 + */ +export const requiredToOptional = ( + from: Schema, + to: Schema, + options: { + readonly decode: (fa: FA) => option_.Option + readonly encode: (o: option_.Option) => FA + } +): PropertySignature<"?:", TA, never, ":", FI, false, FR | TR> => + makePropertySignature( + new PropertySignatureTransformation( + new FromPropertySignature(from.ast, false, true, {}, undefined), + new ToPropertySignature(to.ast, true, true, {}, undefined), + option_.flatMap(options.decode), + (o) => option_.some(options.encode(o)) + ) + ) + +/** + * Converts an optional property to another optional property through a transformation `Option -> Option`. + * + * - `decode`: + * - `none` as argument means the value is missing in the input. + * - `none` as return value means the value will be missing in the output. + * - `encode`: + * - `none` as argument means the value is missing in the input. + * - `none` as return value means the value will be missing in the output. + * + * @category PropertySignature + * @since 3.10.0 + */ +export const optionalToOptional = ( + from: Schema, + to: Schema, + options: { + readonly decode: (o: option_.Option) => option_.Option + readonly encode: (o: option_.Option) => option_.Option + } +): PropertySignature<"?:", TA, never, "?:", FI, false, FR | TR> => + makePropertySignature( + new PropertySignatureTransformation( + new FromPropertySignature(from.ast, true, true, {}, undefined), + new ToPropertySignature(to.ast, true, true, {}, undefined), + options.decode, + options.encode + ) + ) + +/** + * @since 3.10.0 + */ +export type OptionalOptions = { + readonly default?: never + readonly as?: never + readonly exact?: true + readonly nullable?: true +} | { + readonly default: LazyArg + readonly as?: never + readonly exact?: true + readonly nullable?: true +} | { + readonly as: "Option" + readonly default?: never + readonly exact?: never + readonly nullable?: never + readonly onNoneEncoding?: LazyArg> +} | { + readonly as: "Option" + readonly default?: never + readonly exact?: never + readonly nullable: true + readonly onNoneEncoding?: LazyArg> +} | { + readonly as: "Option" + readonly default?: never + readonly exact: true + readonly nullable?: never + readonly onNoneEncoding?: never +} | { + readonly as: "Option" + readonly default?: never + readonly exact: true + readonly nullable: true + readonly onNoneEncoding?: LazyArg> +} | undefined + +/** + * @category api interface + * @since 3.10.0 + */ +export interface optional extends + PropertySignature< + "?:", + Schema.Type | undefined, + never, + "?:", + Schema.Encoded | undefined, + false, + Schema.Context + > +{ + readonly from: S + annotations(annotations: PropertySignature.Annotations | undefined>): optional +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface optionalWith extends + PropertySignature< + Types.Has extends true ? ":" : "?:", + | (Types.Has extends true ? option_.Option> : Schema.Type) + | (Types.Has extends true ? never : undefined), + never, + "?:", + | Schema.Encoded + | (Types.Has extends true ? null : never) + | (Types.Has extends true ? never : undefined), + Types.Has, + Schema.Context + > +{ + readonly from: S + annotations( + annotations: PropertySignature.Annotations< + | (Types.Has extends true ? option_.Option> : Schema.Type) + | (Types.Has extends true ? never : undefined) + > + ): optionalWith +} + +const optionalPropertySignatureAST = ( + self: Schema, + options?: { + readonly exact?: true + readonly default?: () => A + readonly nullable?: true + readonly as?: "Option" + readonly onNoneEncoding?: () => option_.Option + } +): PropertySignature.AST => { + const isExact = options?.exact + const defaultValue = options?.default + const isNullable = options?.nullable + const asOption = options?.as == "Option" + const asOptionEncode = options?.onNoneEncoding ? option_.orElse(options.onNoneEncoding) : identity + + if (isExact) { + if (defaultValue) { + if (isNullable) { + return withConstructorDefault( + optionalToRequired( + NullOr(self), + typeSchema(self), + { + decode: option_.match({ onNone: defaultValue, onSome: (a) => a === null ? defaultValue() : a }), + encode: option_.some + } + ), + defaultValue + ).ast + } else { + return withConstructorDefault( + optionalToRequired( + self, + typeSchema(self), + { decode: option_.match({ onNone: defaultValue, onSome: identity }), encode: option_.some } + ), + defaultValue + ).ast + } + } else if (asOption) { + const to = OptionFromSelf_(typeSchema(self)) + if (isNullable) { + return optionalToRequired( + NullOr(self), + to, + { + decode: option_.filter(Predicate.isNotNull), + encode: asOptionEncode + } + ).ast + } else { + return optionalToRequired( + self, + to, + { decode: identity, encode: identity } + ).ast + } + } else { + if (isNullable) { + return optionalToOptional( + NullOr(self), + typeSchema(self), + { decode: option_.filter(Predicate.isNotNull), encode: identity } + ).ast + } else { + return new PropertySignatureDeclaration(self.ast, true, true, {}, undefined) + } + } + } else { + if (defaultValue) { + if (isNullable) { + return withConstructorDefault( + optionalToRequired( + NullishOr(self), + typeSchema(self), + { + decode: option_.match({ onNone: defaultValue, onSome: (a) => (a == null ? defaultValue() : a) }), + encode: option_.some + } + ), + defaultValue + ).ast + } else { + return withConstructorDefault( + optionalToRequired( + UndefinedOr(self), + typeSchema(self), + { + decode: option_.match({ onNone: defaultValue, onSome: (a) => (a === undefined ? defaultValue() : a) }), + encode: option_.some + } + ), + defaultValue + ).ast + } + } else if (asOption) { + const to = OptionFromSelf_(typeSchema(self)) + if (isNullable) { + return optionalToRequired( + NullishOr(self), + to, + { + decode: option_.filter((a): a is A => a != null), + encode: asOptionEncode + } + ).ast + } else { + return optionalToRequired( + UndefinedOr(self), + to, + { + decode: option_.filter(Predicate.isNotUndefined), + encode: asOptionEncode + } + ).ast + } + } else { + if (isNullable) { + return optionalToOptional( + NullishOr(self), + UndefinedOr(typeSchema(self)), + { decode: option_.filter(Predicate.isNotNull), encode: identity } + ).ast + } else { + return new PropertySignatureDeclaration(UndefinedOr(self).ast, true, true, {}, undefined) + } + } + } +} + +/** + * @category PropertySignature + * @since 3.10.0 + */ +export const optional = (self: S): optional => { + const ast = self.ast === AST.undefinedKeyword || self.ast === AST.neverKeyword + ? AST.undefinedKeyword + : UndefinedOr(self).ast + return new PropertySignatureWithFromImpl(new PropertySignatureDeclaration(ast, true, true, {}, undefined), self) +} + +/** + * @category PropertySignature + * @since 3.10.0 + */ +export const optionalWith: { + /** + * @category PropertySignature + * @since 3.10.0 + */ + >>(options: Options): (self: S) => optionalWith + /** + * @category PropertySignature + * @since 3.10.0 + */ + >>(self: S, options: Options): optionalWith +} = dual((args) => isSchema(args[0]), (self, options) => { + return new PropertySignatureWithFromImpl(optionalPropertySignatureAST(self, options), self) +}) + +/** + * @since 3.10.0 + */ +export declare namespace Struct { + /** + * Useful for creating a type that can be used to add custom constraints to the fields of a struct. + * + * ```ts + * import { Schema } from "effect" + * + * const f = >( + * schema: Schema.Struct + * ) => { + * return schema.omit("a") + * } + * + * // ┌─── Schema.Struct<{ b: typeof Schema.Number; }> + * // ▼ + * const result = f(Schema.Struct({ a: Schema.String, b: Schema.Number })) + * ``` + * @since 3.13.11 + */ + export type Field = + | Schema.All + | PropertySignature.All + + /** + * @since 3.10.0 + */ + export type Fields = { readonly [x: PropertyKey]: Field } + + type OptionalEncodedPropertySignature = + | PropertySignature + | PropertySignature + | PropertySignature + | PropertySignature + + type EncodedOptionalKeys = { + [K in keyof Fields]: Fields[K] extends OptionalEncodedPropertySignature ? K + : never + }[keyof Fields] + + type OptionalTypePropertySignature = + | PropertySignature<"?:", any, PropertyKey, PropertySignature.Token, any, boolean, unknown> + | PropertySignature<"?:", any, PropertyKey, PropertySignature.Token, never, boolean, unknown> + | PropertySignature<"?:", never, PropertyKey, PropertySignature.Token, any, boolean, unknown> + | PropertySignature<"?:", never, PropertyKey, PropertySignature.Token, never, boolean, unknown> + + // type TypeOptionalKeys = { + // [K in keyof Fields]: Fields[K] extends OptionalTypePropertySignature ? K : never + // }[keyof Fields] + + /** + * @since 3.10.0 + */ + export type Type = Types.UnionToIntersection< + { + [K in keyof F]: F[K] extends OptionalTypePropertySignature ? { readonly [H in K]?: Schema.Type } : + { readonly [h in K]: Schema.Type } + }[keyof F] + > extends infer Q ? Q : never + + type Key = [K] extends [never] ? never : + F[K] extends PropertySignature.All ? [Key] extends [never] ? K : Key : + K + + /** + * @since 3.10.0 + */ + export type Encoded = + & { readonly [K in Exclude> as Key]: Schema.Encoded } + & { readonly [K in EncodedOptionalKeys as Key]?: Schema.Encoded } + + /** + * @since 3.10.0 + */ + export type Context = Schema.Context + + type PropertySignatureWithDefault = + | PropertySignature + | PropertySignature + | PropertySignature + | PropertySignature + + /** + * @since 3.10.0 + */ + export type Constructor = Types.UnionToIntersection< + { + [K in keyof F]: F[K] extends OptionalTypePropertySignature ? { readonly [H in K]?: Schema.Type } : + F[K] extends PropertySignatureWithDefault ? { readonly [H in K]?: Schema.Type } : + { readonly [h in K]: Schema.Type } + }[keyof F] + > extends infer Q ? Q : never +} + +/** + * @since 3.10.0 + */ +export declare namespace IndexSignature { + /** + * @since 3.10.0 + */ + export type Record = { readonly key: Schema.All; readonly value: Schema.All } + + /** + * @since 3.10.0 + */ + export type Records = ReadonlyArray + + /** + * @since 3.10.0 + */ + export type NonEmptyRecords = array_.NonEmptyReadonlyArray + + type MergeTuple> = T extends readonly [infer Head, ...infer Tail] ? + Head & MergeTuple + : {} + + /** + * @since 3.10.0 + */ + export type Type = MergeTuple< + { + readonly [K in keyof Records]: { + readonly [P in Schema.Type]: Schema.Type + } + } + > + + /** + * @since 3.10.0 + */ + export type Encoded = MergeTuple< + { + readonly [K in keyof Records]: { + readonly [P in Schema.Encoded]: Schema.Encoded + } + } + > + + /** + * @since 3.10.0 + */ + export type Context = { + [K in keyof Records]: Schema.Context | Schema.Context + }[number] +} + +/** + * @since 3.10.0 + */ +export declare namespace TypeLiteral { + /** + * @since 3.10.0 + */ + export type Type = + & Struct.Type + & IndexSignature.Type + + /** + * @since 3.10.0 + */ + export type Encoded = + & Struct.Encoded + & IndexSignature.Encoded + + /** + * @since 3.10.0 + */ + export type Constructor = + & Struct.Constructor + & IndexSignature.Type +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface TypeLiteral< + Fields extends Struct.Fields, + Records extends IndexSignature.Records +> extends + AnnotableClass< + TypeLiteral, + Simplify>, + Simplify>, + | Struct.Context + | IndexSignature.Context + > +{ + readonly fields: Readonly + readonly records: Readonly + annotations( + annotations: Annotations.Schema>> + ): TypeLiteral + make( + props: RequiredKeys> extends never + ? void | Simplify> + : Simplify>, + options?: MakeOptions + ): Simplify> +} + +const preserveMissingMessageAnnotation = AST.pickAnnotations([AST.MissingMessageAnnotationId]) + +const getDefaultTypeLiteralAST = < + Fields extends Struct.Fields, + const Records extends IndexSignature.Records +>(fields: Fields, records: Records) => { + const ownKeys = Reflect.ownKeys(fields) + const pss: Array = [] + if (ownKeys.length > 0) { + const from: Array = [] + const to: Array = [] + const transformations: Array = [] + for (let i = 0; i < ownKeys.length; i++) { + const key = ownKeys[i] + const field = fields[key] + if (isPropertySignature(field)) { + const ast: PropertySignature.AST = field.ast + switch (ast._tag) { + case "PropertySignatureDeclaration": { + const type = ast.type + const isOptional = ast.isOptional + const toAnnotations = ast.annotations + from.push(new AST.PropertySignature(key, type, isOptional, true, preserveMissingMessageAnnotation(ast))) + to.push(new AST.PropertySignature(key, AST.typeAST(type), isOptional, true, toAnnotations)) + pss.push( + new AST.PropertySignature(key, type, isOptional, true, toAnnotations) + ) + break + } + case "PropertySignatureTransformation": { + const fromKey = ast.from.fromKey ?? key + from.push( + new AST.PropertySignature(fromKey, ast.from.type, ast.from.isOptional, true, ast.from.annotations) + ) + to.push( + new AST.PropertySignature(key, ast.to.type, ast.to.isOptional, true, ast.to.annotations) + ) + transformations.push(new AST.PropertySignatureTransformation(fromKey, key, ast.decode, ast.encode)) + break + } + } + } else { + from.push(new AST.PropertySignature(key, field.ast, false, true)) + to.push(new AST.PropertySignature(key, AST.typeAST(field.ast), false, true)) + pss.push(new AST.PropertySignature(key, field.ast, false, true)) + } + } + if (array_.isNonEmptyReadonlyArray(transformations)) { + const issFrom: Array = [] + const issTo: Array = [] + for (const r of records) { + const { indexSignatures, propertySignatures } = AST.record(r.key.ast, r.value.ast) + propertySignatures.forEach((ps) => { + from.push(ps) + to.push( + new AST.PropertySignature(ps.name, AST.typeAST(ps.type), ps.isOptional, ps.isReadonly, ps.annotations) + ) + }) + indexSignatures.forEach((is) => { + issFrom.push(is) + issTo.push(new AST.IndexSignature(is.parameter, AST.typeAST(is.type), is.isReadonly)) + }) + } + return new AST.Transformation( + new AST.TypeLiteral(from, issFrom, { [AST.AutoTitleAnnotationId]: "Struct (Encoded side)" }), + new AST.TypeLiteral(to, issTo, { [AST.AutoTitleAnnotationId]: "Struct (Type side)" }), + new AST.TypeLiteralTransformation(transformations) + ) + } + } + const iss: Array = [] + for (const r of records) { + const { indexSignatures, propertySignatures } = AST.record(r.key.ast, r.value.ast) + propertySignatures.forEach((ps) => pss.push(ps)) + indexSignatures.forEach((is) => iss.push(is)) + } + return new AST.TypeLiteral(pss, iss) +} + +const lazilyMergeDefaults = ( + fields: Struct.Fields, + out: Record +): { [x: string | symbol]: unknown } => { + const ownKeys = Reflect.ownKeys(fields) + for (const key of ownKeys) { + const field = fields[key] + if (out[key] === undefined && isPropertySignature(field)) { + const ast = field.ast + const defaultValue = ast._tag === "PropertySignatureDeclaration" ? ast.defaultValue : ast.to.defaultValue + if (defaultValue !== undefined) { + out[key] = defaultValue() + } + } + } + return out +} + +function makeTypeLiteralClass( + fields: Fields, + records: Records, + ast: AST.AST = getDefaultTypeLiteralAST(fields, records) +): TypeLiteral { + return class TypeLiteralClass extends make< + Simplify>, + Simplify>, + | Struct.Context + | IndexSignature.Context + >(ast) { + static override annotations( + annotations: Annotations.Schema>> + ): TypeLiteral { + return makeTypeLiteralClass(this.fields, this.records, mergeSchemaAnnotations(this.ast, annotations)) + } + + static fields = { ...fields } + + static records = [...records] as Records + + static make = ( + props: Simplify>, + options?: MakeOptions + ): Simplify> => { + const propsWithDefaults: any = lazilyMergeDefaults(fields, { ...props as any }) + return getDisableValidationMakeOption(options) + ? propsWithDefaults + : ParseResult.validateSync(this)(propsWithDefaults) + } + + static pick(...keys: Array): Struct>> { + return Struct(struct_.pick(fields, ...keys) as any) + } + + static omit(...keys: Array): Struct>> { + return Struct(struct_.omit(fields, ...keys) as any) + } + } +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Struct extends + AnnotableClass< + Struct, + Simplify>, + Simplify>, + Struct.Context + > +{ + readonly fields: Readonly + readonly records: readonly [] + make( + props: RequiredKeys> extends never ? void | Simplify> + : Simplify>, + options?: MakeOptions + ): Simplify> + + annotations(annotations: Annotations.Schema>>): Struct + pick>(...keys: Keys): Struct>> + omit>(...keys: Keys): Struct>> +} + +/** + * @category constructors + * @since 3.10.0 + */ +export function Struct( + fields: Fields, + ...records: Records +): TypeLiteral +export function Struct(fields: Fields): Struct +export function Struct( + fields: Fields, + ...records: Records +): TypeLiteral { + return makeTypeLiteralClass(fields, records) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface tag extends PropertySignature<":", Tag, never, ":", Tag, true, never> {} + +/** + * Returns a property signature that represents a tag. + * A tag is a literal value that is used to distinguish between different types of objects. + * The tag is optional when using the `make` method. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Schema } from "effect" + * + * const User = Schema.Struct({ + * _tag: Schema.tag("User"), + * name: Schema.String, + * age: Schema.Number + * }) + * + * assert.deepStrictEqual(User.make({ name: "John", age: 44 }), { _tag: "User", name: "John", age: 44 }) + * ``` + * + * @see {@link TaggedStruct} + * + * @since 3.10.0 + */ +export const tag = (tag: Tag): tag => + Literal(tag).pipe(propertySignature, withConstructorDefault(() => tag)) + +/** + * @category api interface + * @since 3.10.0 + */ +export type TaggedStruct = Struct< + { _tag: tag } & Fields +> + +/** + * A tagged struct is a struct that has a tag property that is used to distinguish between different types of objects. + * + * The tag is optional when using the `make` method. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Schema } from "effect" + * + * const User = Schema.TaggedStruct("User", { + * name: Schema.String, + * age: Schema.Number + * }) + * + * assert.deepStrictEqual(User.make({ name: "John", age: 44 }), { _tag: "User", name: "John", age: 44 }) + * ``` + * + * @category constructors + * @since 3.10.0 + */ +export const TaggedStruct = ( + value: Tag, + fields: Fields +): TaggedStruct => Struct({ _tag: tag(value), ...fields }) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Record$ extends + AnnotableClass< + Record$, + { readonly [P in Schema.Type]: Schema.Type }, + { readonly [P in Schema.Encoded]: Schema.Encoded }, + | Schema.Context + | Schema.Context + > +{ + readonly fields: {} + readonly records: readonly [{ readonly key: K; readonly value: V }] + readonly key: K + readonly value: V + make( + props: void | { readonly [P in Schema.Type]: Schema.Type }, + options?: MakeOptions + ): { readonly [P in Schema.Type]: Schema.Type } + annotations(annotations: Annotations.Schema<{ readonly [P in Schema.Type]: Schema.Type }>): Record$ +} + +function makeRecordClass( + key: K, + value: V, + ast?: AST.AST +): Record$ { + return class RecordClass extends makeTypeLiteralClass({}, [{ key, value }], ast) { + static override annotations( + annotations: Annotations.Schema<{ readonly [P in Schema.Type]: Schema.Type }> + ): Record$ { + return makeRecordClass(key, value, mergeSchemaAnnotations(this.ast, annotations)) + } + + static key = key + + static value = value + } +} + +/** + * @category constructors + * @since 3.10.0 + */ +export const Record = ( + options: { readonly key: K; readonly value: V } +): Record$ => makeRecordClass(options.key, options.value) + +/** + * @category struct transformations + * @since 3.10.0 + */ +export const pick = >(...keys: Keys) => +( + self: Schema +): SchemaClass>, Simplify>, R> => make(AST.pick(self.ast, keys)) + +/** + * @category struct transformations + * @since 3.10.0 + */ +export const omit = >(...keys: Keys) => +( + self: Schema +): SchemaClass>, Simplify>, R> => make(AST.omit(self.ast, keys)) + +/** + * Given a schema `Schema` and a key `key: K`, this function extracts a specific field from the `A` type, + * producing a new schema that represents a transformation from the `{ readonly [key]: I[K] }` type to `A[K]`. + * + * @example + * ```ts + * import * as Schema from "effect/Schema" + * + * // --------------------------------------------- + * // use case: pull out a single field from a + * // struct through a transformation + * // --------------------------------------------- + * + * const mytable = Schema.Struct({ + * column1: Schema.NumberFromString, + * column2: Schema.Number + * }) + * + * // const pullOutColumn: S.Schema + * const pullOutColumn = mytable.pipe(Schema.pluck("column1")) + * + * console.log(Schema.decodeUnknownEither(Schema.Array(pullOutColumn))([{ column1: "1", column2: 100 }, { column1: "2", column2: 300 }])) + * // Output: { _id: 'Either', _tag: 'Right', right: [ 1, 2 ] } + * ``` + * + * @category struct transformations + * @since 3.10.0 + */ +export const pluck: { + /** + * Given a schema `Schema` and a key `key: K`, this function extracts a specific field from the `A` type, + * producing a new schema that represents a transformation from the `{ readonly [key]: I[K] }` type to `A[K]`. + * + * @example + * ```ts + * import * as Schema from "effect/Schema" + * + * // --------------------------------------------- + * // use case: pull out a single field from a + * // struct through a transformation + * // --------------------------------------------- + * + * const mytable = Schema.Struct({ + * column1: Schema.NumberFromString, + * column2: Schema.Number + * }) + * + * // const pullOutColumn: S.Schema + * const pullOutColumn = mytable.pipe(Schema.pluck("column1")) + * + * console.log(Schema.decodeUnknownEither(Schema.Array(pullOutColumn))([{ column1: "1", column2: 100 }, { column1: "2", column2: 300 }])) + * // Output: { _id: 'Either', _tag: 'Right', right: [ 1, 2 ] } + * ``` + * + * @category struct transformations + * @since 3.10.0 + */ + (key: K): (schema: Schema) => SchemaClass>, R> + /** + * Given a schema `Schema` and a key `key: K`, this function extracts a specific field from the `A` type, + * producing a new schema that represents a transformation from the `{ readonly [key]: I[K] }` type to `A[K]`. + * + * @example + * ```ts + * import * as Schema from "effect/Schema" + * + * // --------------------------------------------- + * // use case: pull out a single field from a + * // struct through a transformation + * // --------------------------------------------- + * + * const mytable = Schema.Struct({ + * column1: Schema.NumberFromString, + * column2: Schema.Number + * }) + * + * // const pullOutColumn: S.Schema + * const pullOutColumn = mytable.pipe(Schema.pluck("column1")) + * + * console.log(Schema.decodeUnknownEither(Schema.Array(pullOutColumn))([{ column1: "1", column2: 100 }, { column1: "2", column2: 300 }])) + * // Output: { _id: 'Either', _tag: 'Right', right: [ 1, 2 ] } + * ``` + * + * @category struct transformations + * @since 3.10.0 + */ + (schema: Schema, key: K): SchemaClass>, R> +} = dual( + 2, + ( + schema: Schema, + key: K + ): Schema, R> => { + const ps = AST.getPropertyKeyIndexedAccess(AST.typeAST(schema.ast), key) + const value = make` and a key `key: K`, this function extracts a specific field from the `A` type, + * producing a new schema that represents a transformation from the `{ readonly [key]: I[K] }` type to `A[K]`. + * + * @example + * ```ts + * import * as Schema from "effect/Schema" + * + * // --------------------------------------------- + * // use case: pull out a single field from a + * // struct through a transformation + * // --------------------------------------------- + * + * const mytable = Schema.Struct({ + * column1: Schema.NumberFromString, + * column2: Schema.Number + * }) + * + * // const pullOutColumn: S.Schema + * const pullOutColumn = mytable.pipe(Schema.pluck("column1")) + * + * console.log(Schema.decodeUnknownEither(Schema.Array(pullOutColumn))([{ column1: "1", column2: 100 }, { column1: "2", column2: 300 }])) + * // Output: { _id: 'Either', _tag: 'Right', right: [ 1, 2 ] } + * ``` + * + * @category struct transformations + * @since 3.10.0 + */ + A[K], /** + * Given a schema `Schema` and a key `key: K`, this function extracts a specific field from the `A` type, + * producing a new schema that represents a transformation from the `{ readonly [key]: I[K] }` type to `A[K]`. + * + * @example + * ```ts + * import * as Schema from "effect/Schema" + * + * // --------------------------------------------- + * // use case: pull out a single field from a + * // struct through a transformation + * // --------------------------------------------- + * + * const mytable = Schema.Struct({ + * column1: Schema.NumberFromString, + * column2: Schema.Number + * }) + * + * // const pullOutColumn: S.Schema + * const pullOutColumn = mytable.pipe(Schema.pluck("column1")) + * + * console.log(Schema.decodeUnknownEither(Schema.Array(pullOutColumn))([{ column1: "1", column2: 100 }, { column1: "2", column2: 300 }])) + * // Output: { _id: 'Either', _tag: 'Right', right: [ 1, 2 ] } + * ``` + * + * @category struct transformations + * @since 3.10.0 + */ + A[K], /** + * Given a schema `Schema` and a key `key: K`, this function extracts a specific field from the `A` type, + * producing a new schema that represents a transformation from the `{ readonly [key]: I[K] }` type to `A[K]`. + * + * @example + * ```ts + * import * as Schema from "effect/Schema" + * + * // --------------------------------------------- + * // use case: pull out a single field from a + * // struct through a transformation + * // --------------------------------------------- + * + * const mytable = Schema.Struct({ + * column1: Schema.NumberFromString, + * column2: Schema.Number + * }) + * + * // const pullOutColumn: S.Schema + * const pullOutColumn = mytable.pipe(Schema.pluck("column1")) + * + * console.log(Schema.decodeUnknownEither(Schema.Array(pullOutColumn))([{ column1: "1", column2: 100 }, { column1: "2", column2: 300 }])) + * // Output: { _id: 'Either', _tag: 'Right', right: [ 1, 2 ] } + * ``` + * + * @category struct transformations + * @since 3.10.0 + */ + R>(ps.isOptional ? AST.orUndefined(ps.type) : ps.type) + const out = transform( + schema.pipe(pick(key)), + value, + { + strict: true, + decode: (i) => i[key], + encode: (a) => ps.isOptional && a === undefined ? {} : { [key]: a } as any + } + ) + return out + } +) + +/** + * @category branding + * @since 3.10.0 + */ +export interface BrandSchema, I = A, R = never> + extends AnnotableClass, A, I, R> +{ + make(a: Brand.Unbranded, options?: MakeOptions): A +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface brand + extends BrandSchema & Brand, Schema.Encoded, Schema.Context> +{ + readonly from: S + annotations(annotations: Annotations.Schema & Brand>): brand +} + +function makeBrandClass( + from: S, + ast: AST.AST +): brand { + return class BrandClass extends make & Brand, Schema.Encoded, Schema.Context>(ast) { + static override annotations(annotations: Annotations.Schema & Brand>): brand { + return makeBrandClass(this.from, mergeSchemaAnnotations(this.ast, annotations)) + } + + static make = (a: Brand.Unbranded & Brand>, options?: MakeOptions): Schema.Type & Brand => { + return getDisableValidationMakeOption(options) ? a : ParseResult.validateSync(this)(a) + } + + static from = from + } +} + +/** + * Returns a nominal branded schema by applying a brand to a given schema. + * + * ``` + * Schema + B -> Schema> + * ``` + * + * @example + * ```ts + * import * as Schema from "effect/Schema" + * + * const Int = Schema.Number.pipe(Schema.int(), Schema.brand("Int")) + * type Int = Schema.Schema.Type // number & Brand<"Int"> + * ``` + * + * @category branding + * @since 3.10.0 + */ +export const brand = ( + brand: B, + annotations?: Annotations.Schema & Brand> +) => +(self: S): brand => { + const annotation: AST.BrandAnnotation = option_.match(AST.getBrandAnnotation(self.ast), { + onNone: () => [brand], + onSome: (brands) => [...brands, brand] + }) + const ast = AST.annotations( + self.ast, + toASTAnnotations({ + [AST.BrandAnnotationId]: annotation, + ...annotations + }) + ) + return makeBrandClass(self, ast) +} + +/** + * @category combinators + * @since 3.10.0 + */ +export const partial = ( + self: Schema +): SchemaClass<{ [K in keyof A]?: A[K] | undefined }, { [K in keyof I]?: I[K] | undefined }, R> => + make(AST.partial(self.ast)) + +/** + * @category combinators + * @since 3.10.0 + */ +export const partialWith: { + /** + * @category combinators + * @since 3.10.0 + */ + (options: Options): ( + self: Schema + ) => SchemaClass<{ [K in keyof A]?: A[K] }, { [K in keyof I]?: I[K] }, R> + /** + * @category combinators + * @since 3.10.0 + */ + (self: Schema, options: Options): SchemaClass<{ [K in keyof A]?: A[K] }, { [K in keyof I]?: I[K] }, R> +} = dual((args) => isSchema(args[0]), ( + self: Schema, + options: { readonly exact: true } +): SchemaClass, Partial, R> => make(AST.partial(self.ast, options))) + +/** + * @category combinators + * @since 3.10.0 + */ +export const required = ( + self: Schema +): SchemaClass<{ [K in keyof A]-?: A[K] }, { [K in keyof I]-?: I[K] }, R> => make(AST.required(self.ast)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface mutable extends + AnnotableClass< + mutable, + SimplifyMutable>, + SimplifyMutable>, + Schema.Context + > +{} + +/** + * Creates a new schema with shallow mutability applied to its properties. + * + * @category combinators + * @since 3.10.0 + */ +export const mutable = (schema: S): mutable => make(AST.mutable(schema.ast)) + +const intersectTypeLiterals = ( + x: AST.AST, + y: AST.AST, + path: ReadonlyArray +): AST.TypeLiteral => { + if (AST.isTypeLiteral(x) && AST.isTypeLiteral(y)) { + const propertySignatures = [...x.propertySignatures] + for (const ps of y.propertySignatures) { + const name = ps.name + const i = propertySignatures.findIndex((ps) => ps.name === name) + if (i === -1) { + propertySignatures.push(ps) + } else { + const { isOptional, type } = propertySignatures[i] + propertySignatures[i] = new AST.PropertySignature( + name, + extendAST(type, ps.type, path.concat(name)), + isOptional, + true + ) + } + } + return new AST.TypeLiteral( + propertySignatures, + x.indexSignatures.concat(y.indexSignatures) + ) + } + throw new Error(errors_.getSchemaExtendErrorMessage(x, y, path)) +} + +const preserveRefinementAnnotations = AST.omitAnnotations([AST.IdentifierAnnotationId]) + +const addRefinementToMembers = (refinement: AST.Refinement, asts: ReadonlyArray): Array => + asts.map((ast) => new AST.Refinement(ast, refinement.filter, preserveRefinementAnnotations(refinement))) + +const extendAST = (x: AST.AST, y: AST.AST, path: ReadonlyArray): AST.AST => + AST.Union.make(intersectUnionMembers([x], [y], path)) + +const getTypes = (ast: AST.AST): ReadonlyArray => AST.isUnion(ast) ? ast.types : [ast] + +const intersectUnionMembers = ( + xs: ReadonlyArray, + ys: ReadonlyArray, + path: ReadonlyArray +): Array => + array_.flatMap(xs, (x) => + array_.flatMap(ys, (y) => { + switch (y._tag) { + case "Literal": { + if ( + (Predicate.isString(y.literal) && AST.isStringKeyword(x) || + (Predicate.isNumber(y.literal) && AST.isNumberKeyword(x)) || + (Predicate.isBoolean(y.literal) && AST.isBooleanKeyword(x))) + ) { + return [y] + } + break + } + case "StringKeyword": { + if (y === AST.stringKeyword) { + if (AST.isStringKeyword(x) || (AST.isLiteral(x) && Predicate.isString(x.literal))) { + return [x] + } else if (AST.isRefinement(x)) { + return addRefinementToMembers(x, intersectUnionMembers(getTypes(x.from), [y], path)) + } + } else if (x === AST.stringKeyword) { + return [y] + } + break + } + case "NumberKeyword": { + if (y === AST.numberKeyword) { + if (AST.isNumberKeyword(x) || (AST.isLiteral(x) && Predicate.isNumber(x.literal))) { + return [x] + } else if (AST.isRefinement(x)) { + return addRefinementToMembers(x, intersectUnionMembers(getTypes(x.from), [y], path)) + } + } else if (x === AST.numberKeyword) { + return [y] + } + break + } + case "BooleanKeyword": { + if (y === AST.booleanKeyword) { + if (AST.isBooleanKeyword(x) || (AST.isLiteral(x) && Predicate.isBoolean(x.literal))) { + return [x] + } else if (AST.isRefinement(x)) { + return addRefinementToMembers(x, intersectUnionMembers(getTypes(x.from), [y], path)) + } + } else if (x === AST.booleanKeyword) { + return [y] + } + break + } + case "Union": + return intersectUnionMembers(getTypes(x), y.types, path) + case "Suspend": + return [new AST.Suspend(() => extendAST(x, y.f(), path))] + case "Refinement": + return addRefinementToMembers(y, intersectUnionMembers(getTypes(x), getTypes(y.from), path)) + case "TypeLiteral": { + switch (x._tag) { + case "Union": + return intersectUnionMembers(x.types, [y], path) + case "Suspend": + return [new AST.Suspend(() => extendAST(x.f(), y, path))] + case "Refinement": + return addRefinementToMembers(x, intersectUnionMembers(getTypes(x.from), [y], path)) + case "TypeLiteral": + return [intersectTypeLiterals(x, y, path)] + case "Transformation": { + const transformation = x.transformation + const from = intersectTypeLiterals(x.from, y, path) + const to = intersectTypeLiterals(x.to, AST.typeAST(y), path) + switch (transformation._tag) { + case "TypeLiteralTransformation": + return [ + new AST.Transformation( + from, + to, + new AST.TypeLiteralTransformation(transformation.propertySignatureTransformations) + ) + ] + case "ComposeTransformation": + return [new AST.Transformation(from, to, AST.composeTransformation)] + case "FinalTransformation": + return [ + new AST.Transformation( + from, + to, + new AST.FinalTransformation( + (fromA, options, ast, fromI) => + ParseResult.map( + transformation.decode(fromA, options, ast, fromI), + (partial) => ({ ...fromA, ...partial }) + ), + (toI, options, ast, toA) => + ParseResult.map( + transformation.encode(toI, options, ast, toA), + (partial) => ({ ...toI, ...partial }) + ) + ) + ) + ] + } + } + } + break + } + case "Transformation": { + if (AST.isTransformation(x)) { + if ( + AST.isTypeLiteralTransformation(y.transformation) && AST.isTypeLiteralTransformation(x.transformation) + ) { + return [ + new AST.Transformation( + intersectTypeLiterals(x.from, y.from, path), + intersectTypeLiterals(x.to, y.to, path), + new AST.TypeLiteralTransformation( + y.transformation.propertySignatureTransformations.concat( + x.transformation.propertySignatureTransformations + ) + ) + ) + ] + } + } else { + return intersectUnionMembers([y], [x], path) + } + break + } + } + throw new Error(errors_.getSchemaExtendErrorMessage(x, y, path)) + })) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface extend extends + AnnotableClass< + extend, + Schema.Type & Schema.Type, + Schema.Encoded & Schema.Encoded, + Schema.Context | Schema.Context + > +{} + +/** + * Extends a schema with another schema. + * + * Not all extensions are supported, and their support depends on the nature of + * the involved schemas. + * + * Possible extensions include: + * - `Schema.String` with another `Schema.String` refinement or a string literal + * - `Schema.Number` with another `Schema.Number` refinement or a number literal + * - `Schema.Boolean` with another `Schema.Boolean` refinement or a boolean + * literal + * - A struct with another struct where overlapping fields support extension + * - A struct with in index signature + * - A struct with a union of supported schemas + * - A refinement of a struct with a supported schema + * - A suspend of a struct with a supported schema + * - A transformation between structs where the “from” and “to” sides have no + * overlapping fields with the target struct + * + * @example + * ```ts + * import * as Schema from "effect/Schema" + * + * const schema = Schema.Struct({ + * a: Schema.String, + * b: Schema.String + * }) + * + * // const extended: Schema< + * // { + * // readonly a: string + * // readonly b: string + * // } & { + * // readonly c: string + * // } & { + * // readonly [x: string]: string + * // } + * // > + * const extended = Schema.asSchema(schema.pipe( + * Schema.extend(Schema.Struct({ c: Schema.String })), // <= you can add more fields + * Schema.extend(Schema.Record({ key: Schema.String, value: Schema.String })) // <= you can add index signatures + * )) + * ``` + * + * @category combinators + * @since 3.10.0 + */ +export const extend: { + /** + * Extends a schema with another schema. + * + * Not all extensions are supported, and their support depends on the nature of + * the involved schemas. + * + * Possible extensions include: + * - `Schema.String` with another `Schema.String` refinement or a string literal + * - `Schema.Number` with another `Schema.Number` refinement or a number literal + * - `Schema.Boolean` with another `Schema.Boolean` refinement or a boolean + * literal + * - A struct with another struct where overlapping fields support extension + * - A struct with in index signature + * - A struct with a union of supported schemas + * - A refinement of a struct with a supported schema + * - A suspend of a struct with a supported schema + * - A transformation between structs where the “from” and “to” sides have no + * overlapping fields with the target struct + * + * @example + * ```ts + * import * as Schema from "effect/Schema" + * + * const schema = Schema.Struct({ + * a: Schema.String, + * b: Schema.String + * }) + * + * // const extended: Schema< + * // { + * // readonly a: string + * // readonly b: string + * // } & { + * // readonly c: string + * // } & { + * // readonly [x: string]: string + * // } + * // > + * const extended = Schema.asSchema(schema.pipe( + * Schema.extend(Schema.Struct({ c: Schema.String })), // <= you can add more fields + * Schema.extend(Schema.Record({ key: Schema.String, value: Schema.String })) // <= you can add index signatures + * )) + * ``` + * + * @category combinators + * @since 3.10.0 + */ + (that: That): (self: Self) => extend + /** + * Extends a schema with another schema. + * + * Not all extensions are supported, and their support depends on the nature of + * the involved schemas. + * + * Possible extensions include: + * - `Schema.String` with another `Schema.String` refinement or a string literal + * - `Schema.Number` with another `Schema.Number` refinement or a number literal + * - `Schema.Boolean` with another `Schema.Boolean` refinement or a boolean + * literal + * - A struct with another struct where overlapping fields support extension + * - A struct with in index signature + * - A struct with a union of supported schemas + * - A refinement of a struct with a supported schema + * - A suspend of a struct with a supported schema + * - A transformation between structs where the “from” and “to” sides have no + * overlapping fields with the target struct + * + * @example + * ```ts + * import * as Schema from "effect/Schema" + * + * const schema = Schema.Struct({ + * a: Schema.String, + * b: Schema.String + * }) + * + * // const extended: Schema< + * // { + * // readonly a: string + * // readonly b: string + * // } & { + * // readonly c: string + * // } & { + * // readonly [x: string]: string + * // } + * // > + * const extended = Schema.asSchema(schema.pipe( + * Schema.extend(Schema.Struct({ c: Schema.String })), // <= you can add more fields + * Schema.extend(Schema.Record({ key: Schema.String, value: Schema.String })) // <= you can add index signatures + * )) + * ``` + * + * @category combinators + * @since 3.10.0 + */ + (self: Self, that: That): extend +} = dual( + 2, + (self: Self, that: That) => make(extendAST(self.ast, that.ast, [])) +) + +/** + * @category combinators + * @since 3.10.0 + */ +export const compose: { + /** + * @category combinators + * @since 3.10.0 + */ + >(to: To & Schema, C, Schema.Context>): (from: From) => transform + /** + * @category combinators + * @since 3.10.0 + */ + (to: To): >( + from: From & Schema, Schema.Context> + ) => transform + /** + * @category combinators + * @since 3.10.0 + */ + (to: To, options?: { readonly strict: true }): ( + from: From & Schema, Schema.Encoded, Schema.Context> + ) => transform + /** + * @category combinators + * @since 3.10.0 + */ + (to: To, options: { readonly strict: false }): (from: From) => transform + + /** + * @category combinators + * @since 3.10.0 + */ + >(from: From, to: To & Schema, C, Schema.Context>): transform + /** + * @category combinators + * @since 3.10.0 + */ + , To extends Schema.Any>(from: From & Schema, Schema.Context>, to: To): transform + /** + * @category combinators + * @since 3.10.0 + */ + ( + from: From & Schema, Schema.Encoded, Schema.Context>, + to: To, + options?: { readonly strict: true } + ): transform + /** + * @category combinators + * @since 3.10.0 + */ + (from: From, to: To, options: { readonly strict: false }): transform +} = dual( + (args) => isSchema(args[1]), + (from: Schema, to: Schema): SchemaClass => + makeTransformationClass(from, to, AST.compose(from.ast, to.ast)) +) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface suspend extends AnnotableClass, A, I, R> {} + +/** + * @category constructors + * @since 3.10.0 + */ +export const suspend = (f: () => Schema): suspend => make(new AST.Suspend(() => f().ast)) + +/** + * @since 3.10.0 + * @category symbol + */ +export const RefineSchemaId: unique symbol = Symbol.for("effect/SchemaId/Refine") + +/** + * @since 3.10.0 + * @category symbol + */ +export type RefineSchemaId = typeof RefineSchemaId + +/** + * @category api interface + * @since 3.10.0 + */ +export interface refine + extends AnnotableClass, A, Schema.Encoded, Schema.Context> +{ + /** The following is required for {@link HasFields} to work */ + readonly [RefineSchemaId]: From + readonly from: From + readonly filter: ( + a: Schema.Type, + options: ParseOptions, + self: AST.Refinement + ) => option_.Option + make(a: Schema.Type, options?: MakeOptions): A +} + +function makeRefineClass( + from: From, + filter: (a: Schema.Type, options: ParseOptions, self: AST.Refinement) => option_.Option, + ast: AST.AST +): refine { + return class RefineClass extends make, Schema.Context>(ast) { + static override annotations(annotations: Annotations.Schema): refine { + return makeRefineClass(this.from, this.filter, mergeSchemaAnnotations(this.ast, annotations)) + } + + static [RefineSchemaId] = from + + static from = from + + static filter = filter + + static make = (a: Schema.Type, options?: MakeOptions): A => { + return getDisableValidationMakeOption(options) ? a : ParseResult.validateSync(this)(a) + } + } +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface filter extends refine, From> {} + +const fromFilterPredicateReturnTypeItem = ( + item: FilterOutput, + ast: AST.Refinement | AST.Transformation, + input: unknown +): option_.Option => { + if (Predicate.isBoolean(item)) { + return item + ? option_.none() + : option_.some(new ParseResult.Type(ast, input)) + } + if (Predicate.isString(item)) { + return option_.some(new ParseResult.Type(ast, input, item)) + } + if (item !== undefined) { + if ("_tag" in item) { + return option_.some(item) + } + const issue = new ParseResult.Type(ast, input, item.message) + return option_.some( + array_.isNonEmptyReadonlyArray(item.path) ? new ParseResult.Pointer(item.path, input, issue) : issue + ) + } + return option_.none() +} + +const toFilterParseIssue = ( + out: FilterReturnType, + ast: AST.Refinement | AST.Transformation, + input: unknown +): option_.Option => { + if (util_.isSingle(out)) { + return fromFilterPredicateReturnTypeItem(out, ast, input) + } + if (array_.isNonEmptyReadonlyArray(out)) { + const issues = array_.filterMap(out, (issue) => fromFilterPredicateReturnTypeItem(issue, ast, input)) + if (array_.isNonEmptyReadonlyArray(issues)) { + return option_.some(issues.length === 1 ? issues[0] : new ParseResult.Composite(ast, input, issues)) + } + } + return option_.none() +} + +/** + * @category filtering + * @since 3.10.0 + */ +export interface FilterIssue { + readonly path: ReadonlyArray + readonly message: string +} + +/** + * @category filtering + * @since 3.10.0 + */ +export type FilterOutput = undefined | boolean | string | ParseResult.ParseIssue | FilterIssue + +type FilterReturnType = FilterOutput | ReadonlyArray + +/** + * @category filtering + * @since 3.10.0 + */ +export function filter( + refinement: (a: A, options: ParseOptions, self: AST.Refinement) => a is B, + annotations?: Annotations.Filter +): (self: Schema) => refine> +export function filter( + refinement: (a: A, options: ParseOptions, self: AST.Refinement) => a is B, + annotations?: Annotations.Filter +): (self: Schema) => refine> +export function filter( + predicate: ( + a: Types.NoInfer>, + options: ParseOptions, + self: AST.Refinement + ) => FilterReturnType, + annotations?: Annotations.Filter>> +): (self: S) => filter +export function filter( + predicate: ( + a: A, + options: ParseOptions, + self: AST.Refinement + ) => FilterReturnType, + annotations?: Annotations.Filter +): (self: Schema) => refine> { + return (self: Schema) => { + function filter(input: A, options: AST.ParseOptions, ast: AST.Refinement) { + return toFilterParseIssue(predicate(input, options, ast), ast, input) + } + const ast = new AST.Refinement( + self.ast, + filter, + toASTAnnotations(annotations) + ) + return makeRefineClass(self, filter, ast) + } +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface filterEffect + extends transformOrFail>, FD> +{} + +/** + * @category transformations + * @since 3.10.0 + */ +export const filterEffect: { + /** + * @category transformations + * @since 3.10.0 + */ + ( + f: ( + a: Types.NoInfer>, + options: ParseOptions, + self: AST.Transformation + ) => Effect.Effect + ): (self: S) => filterEffect + /** + * @category transformations + * @since 3.10.0 + */ + ( + self: S, + f: ( + a: Types.NoInfer>, + options: ParseOptions, + self: AST.Transformation + ) => Effect.Effect + ): filterEffect +} = dual(2, ( + self: S, + f: ( + a: Types.NoInfer>, + options: ParseOptions, + self: AST.Transformation + ) => Effect.Effect +): filterEffect => + transformOrFail( + self, + typeSchema(self), + { + strict: true, + decode: (i, options, ast) => + ParseResult.flatMap( + f(i, options, ast), + (filterReturnType) => + option_.match(toFilterParseIssue(filterReturnType, ast, i), { + onNone: () => ParseResult.succeed(i), + onSome: ParseResult.fail + }) + ), + encode: (a) => ParseResult.succeed(a) + } + )) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface transformOrFail extends + AnnotableClass< + transformOrFail, + Schema.Type, + Schema.Encoded, + Schema.Context | Schema.Context | R + > +{ + readonly from: From + readonly to: To +} + +function makeTransformationClass( + from: From, + to: To, + ast: AST.AST +): transformOrFail { + return class TransformationClass + extends make, Schema.Encoded, Schema.Context | Schema.Context | R>(ast) + { + static override annotations(annotations: Annotations.Schema>) { + return makeTransformationClass( + this.from, + this.to, + mergeSchemaAnnotations(this.ast, annotations) + ) + } + + static from = from + + static to = to + } +} + +/** + * Create a new `Schema` by transforming the input and output of an existing `Schema` + * using the provided decoding functions. + * + * @category transformations + * @since 3.10.0 + */ +export const transformOrFail: { + /** + * Create a new `Schema` by transforming the input and output of an existing `Schema` + * using the provided decoding functions. + * + * @category transformations + * @since 3.10.0 + */ + ( + to: To, + options: { + readonly decode: ( + fromA: Schema.Type, + options: ParseOptions, + ast: AST.Transformation, + fromI: Schema.Encoded + ) => Effect.Effect, ParseResult.ParseIssue, RD> + readonly encode: ( + toI: Schema.Encoded, + options: ParseOptions, + ast: AST.Transformation, + toA: Schema.Type + ) => Effect.Effect, ParseResult.ParseIssue, RE> + readonly strict?: true + } | { + readonly decode: ( + fromA: Schema.Type, + options: ParseOptions, + ast: AST.Transformation, + fromI: Schema.Encoded + ) => Effect.Effect + readonly encode: ( + toI: Schema.Encoded, + options: ParseOptions, + ast: AST.Transformation, + toA: Schema.Type + ) => Effect.Effect + readonly strict: false + } + ): (from: From) => transformOrFail + /** + * Create a new `Schema` by transforming the input and output of an existing `Schema` + * using the provided decoding functions. + * + * @category transformations + * @since 3.10.0 + */ + ( + from: From, + to: To, + options: { + readonly decode: ( + fromA: Schema.Type, + options: ParseOptions, + ast: AST.Transformation, + fromI: Schema.Encoded + ) => Effect.Effect, ParseResult.ParseIssue, RD> + readonly encode: ( + toI: Schema.Encoded, + options: ParseOptions, + ast: AST.Transformation, + toA: Schema.Type + ) => Effect.Effect, ParseResult.ParseIssue, RE> + readonly strict?: true + } | { + readonly decode: ( + fromA: Schema.Type, + options: ParseOptions, + ast: AST.Transformation, + fromI: Schema.Encoded + ) => Effect.Effect + readonly encode: ( + toI: Schema.Encoded, + options: ParseOptions, + ast: AST.Transformation, + toA: Schema.Type + ) => Effect.Effect + readonly strict: false + } + ): transformOrFail +} = dual((args) => isSchema(args[0]) && isSchema(args[1]), ( + from: Schema, + to: Schema, + options: { + readonly decode: ( + fromA: FromA, + options: ParseOptions, + ast: AST.Transformation, + fromI: FromI + ) => Effect.Effect + readonly encode: ( + toI: ToI, + options: ParseOptions, + ast: AST.Transformation, + toA: ToA + ) => Effect.Effect + } +): Schema => + makeTransformationClass( + from, + to, + new AST.Transformation( + from.ast, + to.ast, + new AST.FinalTransformation(options.decode, options.encode) + ) + )) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface transform extends transformOrFail { + annotations(annotations: Annotations.Schema>): transform +} + +/** + * Create a new `Schema` by transforming the input and output of an existing `Schema` + * using the provided mapping functions. + * + * @category transformations + * @since 3.10.0 + */ +export const transform: { + /** + * Create a new `Schema` by transforming the input and output of an existing `Schema` + * using the provided mapping functions. + * + * @category transformations + * @since 3.10.0 + */ + ( + to: To, + options: { + readonly decode: (fromA: Schema.Type, fromI: Schema.Encoded) => Schema.Encoded + readonly encode: (toI: Schema.Encoded, toA: Schema.Type) => Schema.Type + readonly strict?: true + } | { + readonly decode: (fromA: Schema.Type, fromI: Schema.Encoded) => unknown + readonly encode: (toI: Schema.Encoded, toA: Schema.Type) => unknown + readonly strict: false + } + ): (from: From) => transform + /** + * Create a new `Schema` by transforming the input and output of an existing `Schema` + * using the provided mapping functions. + * + * @category transformations + * @since 3.10.0 + */ + ( + from: From, + to: To, + options: { + readonly decode: (fromA: Schema.Type, fromI: Schema.Encoded) => Schema.Encoded + readonly encode: (toI: Schema.Encoded, toA: Schema.Type) => Schema.Type + readonly strict?: true + } | { + readonly decode: (fromA: Schema.Type, fromI: Schema.Encoded) => unknown + readonly encode: (toI: Schema.Encoded, toA: Schema.Type) => unknown + readonly strict: false + } + ): transform +} = dual( + (args) => isSchema(args[0]) && isSchema(args[1]), + ( + from: Schema, + to: Schema, + options: { + readonly decode: (fromA: FromA, fromI: FromI) => ToI + readonly encode: (toI: ToI, toA: ToA) => FromA + } + ): Schema => + transformOrFail( + from, + to, + { + strict: true, + decode: (fromA, _options, _ast, toA) => ParseResult.succeed(options.decode(fromA, toA)), + encode: (toI, _options, _ast, toA) => ParseResult.succeed(options.encode(toI, toA)) + } + ) +) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface transformLiteral + extends transform, Literal<[Type]>> +{ + annotations(annotations: Annotations.Schema): transformLiteral +} + +/** + * Creates a new `Schema` which transforms literal values. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import * as S from "effect/Schema" + * + * const schema = S.transformLiteral(0, "a") + * + * assert.deepStrictEqual(S.decodeSync(schema)(0), "a") + * ``` + * + * @category constructors + * @since 3.10.0 + */ +export function transformLiteral( + from: Encoded, + to: Type +): transformLiteral { + return transform(Literal(from), Literal(to), { + strict: true, + decode: () => to, + encode: () => from + }) +} + +/** + * Creates a new `Schema` which maps between corresponding literal values. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import * as S from "effect/Schema" + * + * const Animal = S.transformLiterals( + * [0, "cat"], + * [1, "dog"], + * [2, "cow"] + * ) + * + * assert.deepStrictEqual(S.decodeSync(Animal)(1), "dog") + * ``` + * + * @category constructors + * @since 3.10.0 + */ +export function transformLiterals>( + ...pairs: A +): Union<{ -readonly [I in keyof A]: transformLiteral }> +export function transformLiterals( + pairs: [Encoded, Type] +): transformLiteral +export function transformLiterals< + const A extends ReadonlyArray +>(...pairs: A): Schema +export function transformLiterals< + const A extends ReadonlyArray +>(...pairs: A): Schema { + return Union(...pairs.map(([from, to]) => transformLiteral(from, to))) +} + +/** + * Attaches a property signature with the specified key and value to the schema. + * This API is useful when you want to add a property to your schema which doesn't describe the shape of the input, + * but rather maps to another schema, for example when you want to add a discriminant to a simple union. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import * as S from "effect/Schema" + * import { pipe } from "effect/Function" + * + * const Circle = S.Struct({ radius: S.Number }) + * const Square = S.Struct({ sideLength: S.Number }) + * const Shape = S.Union( + * Circle.pipe(S.attachPropertySignature("kind", "circle")), + * Square.pipe(S.attachPropertySignature("kind", "square")) + * ) + * + * assert.deepStrictEqual(S.decodeSync(Shape)({ radius: 10 }), { + * kind: "circle", + * radius: 10 + * }) + * ``` + * + * @category combinators + * @since 3.10.0 + */ +export const attachPropertySignature: { + /** + * Attaches a property signature with the specified key and value to the schema. + * This API is useful when you want to add a property to your schema which doesn't describe the shape of the input, + * but rather maps to another schema, for example when you want to add a discriminant to a simple union. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import * as S from "effect/Schema" + * import { pipe } from "effect/Function" + * + * const Circle = S.Struct({ radius: S.Number }) + * const Square = S.Struct({ sideLength: S.Number }) + * const Shape = S.Union( + * Circle.pipe(S.attachPropertySignature("kind", "circle")), + * Square.pipe(S.attachPropertySignature("kind", "square")) + * ) + * + * assert.deepStrictEqual(S.decodeSync(Shape)({ radius: 10 }), { + * kind: "circle", + * radius: 10 + * }) + * ``` + * + * @category combinators + * @since 3.10.0 + */ + ( + key: K, + value: V, + annotations?: Annotations.Schema + ): ( + schema: Schema + ) => SchemaClass + /** + * Attaches a property signature with the specified key and value to the schema. + * This API is useful when you want to add a property to your schema which doesn't describe the shape of the input, + * but rather maps to another schema, for example when you want to add a discriminant to a simple union. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import * as S from "effect/Schema" + * import { pipe } from "effect/Function" + * + * const Circle = S.Struct({ radius: S.Number }) + * const Square = S.Struct({ sideLength: S.Number }) + * const Shape = S.Union( + * Circle.pipe(S.attachPropertySignature("kind", "circle")), + * Square.pipe(S.attachPropertySignature("kind", "square")) + * ) + * + * assert.deepStrictEqual(S.decodeSync(Shape)({ radius: 10 }), { + * kind: "circle", + * radius: 10 + * }) + * ``` + * + * @category combinators + * @since 3.10.0 + */ + ( + schema: Schema, + key: K, + value: V, + annotations?: Annotations.Schema + ): SchemaClass +} = dual( + (args) => isSchema(args[0]), + ( + schema: Schema, + key: K, + value: V, + annotations?: Annotations.Schema + ): SchemaClass => { + const ast = extend( + typeSchema(schema), + Struct({ [key]: Predicate.isSymbol(value) ? UniqueSymbolFromSelf(value) : Literal(value) }) + ).ast + return make( + new AST.Transformation( + schema.ast, + annotations ? mergeSchemaAnnotations(ast, annotations) : ast, + new AST.TypeLiteralTransformation( + [ + new AST.PropertySignatureTransformation( + key, + key, + () => option_.some(value), + () => option_.none() + ) + ] + ) + ) + ) + } +) + +/** + * @category annotations + * @since 3.10.0 + */ +export declare namespace Annotations { + /** + * @category annotations + * @since 3.10.0 + */ + export interface Doc extends AST.Annotations { + readonly title?: AST.TitleAnnotation + readonly description?: AST.DescriptionAnnotation + readonly documentation?: AST.DocumentationAnnotation + readonly examples?: AST.ExamplesAnnotation + readonly default?: AST.DefaultAnnotation + } + + /** + * @since 3.10.0 + */ + export interface Schema = readonly []> extends Doc { + readonly typeConstructor?: AST.TypeConstructorAnnotation + readonly identifier?: AST.IdentifierAnnotation + readonly message?: AST.MessageAnnotation + readonly schemaId?: AST.SchemaIdAnnotation + readonly jsonSchema?: AST.JSONSchemaAnnotation + readonly arbitrary?: ArbitraryAnnotation + readonly pretty?: pretty_.PrettyAnnotation + readonly equivalence?: AST.EquivalenceAnnotation + readonly concurrency?: AST.ConcurrencyAnnotation + readonly batching?: AST.BatchingAnnotation + readonly parseIssueTitle?: AST.ParseIssueTitleAnnotation + readonly parseOptions?: AST.ParseOptions + readonly decodingFallback?: AST.DecodingFallbackAnnotation + } + + /** + * @since 3.11.6 + */ + export interface GenericSchema extends Schema { + readonly arbitrary?: (..._: any) => LazyArbitrary + readonly pretty?: (..._: any) => pretty_.Pretty + readonly equivalence?: (..._: any) => Equivalence.Equivalence + } + + // TODO(4.0): replace `readonly [P]` with `readonly []` + /** + * @since 3.10.0 + */ + export interface Filter extends Schema {} +} + +/** + * Merges a set of new annotations with existing ones, potentially overwriting + * any duplicates. + * + * @category annotations + * @since 3.10.0 + */ +export const annotations: { + /** + * Merges a set of new annotations with existing ones, potentially overwriting + * any duplicates. + * + * @category annotations + * @since 3.10.0 + */ + (annotations: Annotations.GenericSchema>): (self: S) => Annotable.Self + /** + * Merges a set of new annotations with existing ones, potentially overwriting + * any duplicates. + * + * @category annotations + * @since 3.10.0 + */ + (self: S, annotations: Annotations.GenericSchema>): Annotable.Self +} = dual( + 2, + (self: Schema, annotations: Annotations.GenericSchema): Schema => + self.annotations(annotations) +) + +type Rename = { + [ + K in keyof A as K extends keyof M ? M[K] extends PropertyKey ? M[K] + : never + : K + ]: A[K] +} + +/** + * @category renaming + * @since 3.10.0 + */ +export const rename: { + /** + * @category renaming + * @since 3.10.0 + */ + < + A, + const M extends + & { readonly [K in keyof A]?: PropertyKey } + & { readonly [K in Exclude]: never } + >(mapping: M): (self: Schema) => SchemaClass>, I, R> + /** + * @category renaming + * @since 3.10.0 + */ + < + A, + I, + R, + const M extends + & { readonly [K in keyof A]?: PropertyKey } + & { readonly [K in Exclude]: never } + >(self: Schema, mapping: M): SchemaClass>, I, R> +} = dual( + 2, + < + A, + I, + R, + const M extends + & { readonly [K in keyof A]?: PropertyKey } + & { readonly [K in Exclude]: never } + >( + self: Schema, + mapping: M + ): SchemaClass>, I, R> => make(AST.rename(self.ast, mapping)) +) + +/** + * @category schema id + * @since 3.10.0 + */ +export const TrimmedSchemaId: unique symbol = Symbol.for("effect/SchemaId/Trimmed") + +/** + * Verifies that a string contains no leading or trailing whitespaces. + * + * Note. This combinator does not make any transformations, it only validates. + * If what you were looking for was a combinator to trim strings, then check out the `trim` combinator. + * + * @category string filters + * @since 3.10.0 + */ +export const trimmed = ( + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a === a.trim(), { + schemaId: TrimmedSchemaId, + title: "trimmed", + description: "a string with no leading or trailing whitespace", + jsonSchema: { pattern: "^\\S[\\s\\S]*\\S$|^\\S$|^$" }, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const MaxLengthSchemaId: unique symbol = schemaId_.MaxLengthSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type MaxLengthSchemaId = typeof MaxLengthSchemaId + +/** + * @category string filters + * @since 3.10.0 + */ +export const maxLength = + (maxLength: number, annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter( + (a) => a.length <= maxLength, + { + schemaId: MaxLengthSchemaId, + title: `maxLength(${maxLength})`, + description: `a string at most ${maxLength} character(s) long`, + jsonSchema: { maxLength }, + ...annotations + } + ) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const MinLengthSchemaId: unique symbol = schemaId_.MinLengthSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type MinLengthSchemaId = typeof MinLengthSchemaId + +/** + * @category string filters + * @since 3.10.0 + */ +export const minLength = ( + minLength: number, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter( + (a) => a.length >= minLength, + { + schemaId: MinLengthSchemaId, + title: `minLength(${minLength})`, + description: `a string at least ${minLength} character(s) long`, + jsonSchema: { minLength }, + ...annotations + } + ) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const LengthSchemaId: unique symbol = schemaId_.LengthSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type LengthSchemaId = typeof LengthSchemaId + +/** + * @category string filters + * @since 3.10.0 + */ +export const length = ( + length: number | { readonly min: number; readonly max: number }, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => { + const minLength = Predicate.isObject(length) ? Math.max(0, Math.floor(length.min)) : Math.max(0, Math.floor(length)) + const maxLength = Predicate.isObject(length) ? Math.max(minLength, Math.floor(length.max)) : minLength + if (minLength !== maxLength) { + return self.pipe( + filter((a) => a.length >= minLength && a.length <= maxLength, { + schemaId: LengthSchemaId, + title: `length({ min: ${minLength}, max: ${maxLength})`, + description: `a string at least ${minLength} character(s) and at most ${maxLength} character(s) long`, + jsonSchema: { minLength, maxLength }, + ...annotations + }) + ) + } + return self.pipe( + filter((a) => a.length === minLength, { + schemaId: LengthSchemaId, + title: `length(${minLength})`, + description: minLength === 1 ? `a single character` : `a string ${minLength} character(s) long`, + jsonSchema: { minLength, maxLength: minLength }, + ...annotations + }) + ) +} + +/** + * @category schema id + * @since 3.10.0 + */ +export const PatternSchemaId: unique symbol = Symbol.for("effect/SchemaId/Pattern") + +/** + * @category string filters + * @since 3.10.0 + */ +export const pattern = ( + regex: RegExp, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => { + const source = regex.source + return self.pipe( + filter( + (a) => { + // The following line ensures that `lastIndex` is reset to `0` in case the user has specified the `g` flag + regex.lastIndex = 0 + return regex.test(a) + }, + { + schemaId: PatternSchemaId, + [PatternSchemaId]: { regex }, + // title: `pattern(/${source}/)`, // avoiding this because it can be very long + description: `a string matching the pattern ${source}`, + jsonSchema: { pattern: source }, + ...annotations + } + ) + ) +} + +/** + * @category schema id + * @since 3.10.0 + */ +export const StartsWithSchemaId: unique symbol = Symbol.for("effect/SchemaId/StartsWith") + +/** + * @category string filters + * @since 3.10.0 + */ +export const startsWith = ( + startsWith: string, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => { + const formatted = JSON.stringify(startsWith) + return self.pipe( + filter( + (a) => a.startsWith(startsWith), + { + schemaId: StartsWithSchemaId, + [StartsWithSchemaId]: { startsWith }, + title: `startsWith(${formatted})`, + description: `a string starting with ${formatted}`, + jsonSchema: { pattern: `^${startsWith}` }, + ...annotations + } + ) + ) +} + +/** + * @category schema id + * @since 3.10.0 + */ +export const EndsWithSchemaId: unique symbol = Symbol.for("effect/SchemaId/EndsWith") + +/** + * @category string filters + * @since 3.10.0 + */ +export const endsWith = ( + endsWith: string, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => { + const formatted = JSON.stringify(endsWith) + return self.pipe( + filter( + (a) => a.endsWith(endsWith), + { + schemaId: EndsWithSchemaId, + [EndsWithSchemaId]: { endsWith }, + title: `endsWith(${formatted})`, + description: `a string ending with ${formatted}`, + jsonSchema: { pattern: `^.*${endsWith}$` }, + ...annotations + } + ) + ) +} + +/** + * @category schema id + * @since 3.10.0 + */ +export const IncludesSchemaId: unique symbol = Symbol.for("effect/SchemaId/Includes") + +/** + * @category string filters + * @since 3.10.0 + */ +export const includes = ( + searchString: string, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => { + const formatted = JSON.stringify(searchString) + return self.pipe( + filter( + (a) => a.includes(searchString), + { + schemaId: IncludesSchemaId, + [IncludesSchemaId]: { includes: searchString }, + title: `includes(${formatted})`, + description: `a string including ${formatted}`, + jsonSchema: { pattern: `.*${searchString}.*` }, + ...annotations + } + ) + ) +} + +/** + * @category schema id + * @since 3.10.0 + */ +export const LowercasedSchemaId: unique symbol = Symbol.for("effect/SchemaId/Lowercased") + +/** + * Verifies that a string is lowercased. + * + * @category string filters + * @since 3.10.0 + */ +export const lowercased = + (annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a === a.toLowerCase(), { + schemaId: LowercasedSchemaId, + title: "lowercased", + description: "a lowercase string", + jsonSchema: { pattern: "^[^A-Z]*$" }, + ...annotations + }) + ) + +/** + * @category string constructors + * @since 3.10.0 + */ +export class Lowercased extends String$.pipe( + lowercased({ identifier: "Lowercased" }) +) {} + +/** + * @category schema id + * @since 3.10.0 + */ +export const UppercasedSchemaId: unique symbol = Symbol.for("effect/SchemaId/Uppercased") + +/** + * Verifies that a string is uppercased. + * + * @category string filters + * @since 3.10.0 + */ +export const uppercased = + (annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a === a.toUpperCase(), { + schemaId: UppercasedSchemaId, + title: "uppercased", + description: "an uppercase string", + jsonSchema: { pattern: "^[^a-z]*$" }, + ...annotations + }) + ) + +/** + * @category string constructors + * @since 3.10.0 + */ +export class Uppercased extends String$.pipe( + uppercased({ identifier: "Uppercased" }) +) {} + +/** + * @category schema id + * @since 3.10.0 + */ +export const CapitalizedSchemaId: unique symbol = Symbol.for("effect/SchemaId/Capitalized") + +/** + * Verifies that a string is capitalized. + * + * @category string filters + * @since 3.10.0 + */ +export const capitalized = + (annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a[0]?.toUpperCase() === a[0], { + schemaId: CapitalizedSchemaId, + title: "capitalized", + description: "a capitalized string", + jsonSchema: { pattern: "^[^a-z]?.*$" }, + ...annotations + }) + ) + +/** + * @category string constructors + * @since 3.10.0 + */ +export class Capitalized extends String$.pipe( + capitalized({ identifier: "Capitalized" }) +) {} + +/** + * @category schema id + * @since 3.10.0 + */ +export const UncapitalizedSchemaId: unique symbol = Symbol.for("effect/SchemaId/Uncapitalized") + +/** + * Verifies that a string is uncapitalized. + * + * @category string filters + * @since 3.10.0 + */ +export const uncapitalized = + (annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a[0]?.toLowerCase() === a[0], { + schemaId: UncapitalizedSchemaId, + title: "uncapitalized", + description: "a uncapitalized string", + jsonSchema: { pattern: "^[^A-Z]?.*$" }, + ...annotations + }) + ) + +/** + * @category string constructors + * @since 3.10.0 + */ +export class Uncapitalized extends String$.pipe( + uncapitalized({ identifier: "Uncapitalized" }) +) {} + +/** + * A schema representing a single character. + * + * @category string constructors + * @since 3.10.0 + */ +export class Char extends String$.pipe(length(1, { identifier: "Char" })) {} + +/** + * @category string filters + * @since 3.10.0 + */ +export const nonEmptyString = ( + annotations?: Annotations.Filter> +): (self: S & Schema, Schema.Context>) => filter => + minLength(1, { + title: "nonEmptyString", + description: "a non empty string", + ...annotations + }) + +/** + * This schema converts a string to lowercase. + * + * @category string transformations + * @since 3.10.0 + */ +export class Lowercase extends transform( + String$.annotations({ description: "a string that will be converted to lowercase" }), + Lowercased, + { + strict: true, + decode: (i) => i.toLowerCase(), + encode: identity + } +).annotations({ identifier: "Lowercase" }) {} + +/** + * This schema converts a string to uppercase. + * + * @category string transformations + * @since 3.10.0 + */ +export class Uppercase extends transform( + String$.annotations({ description: "a string that will be converted to uppercase" }), + Uppercased, + { + strict: true, + decode: (i) => i.toUpperCase(), + encode: identity + } +).annotations({ identifier: "Uppercase" }) {} + +/** + * This schema converts a string to capitalized one. + * + * @category string transformations + * @since 3.10.0 + */ +export class Capitalize extends transform( + String$.annotations({ description: "a string that will be converted to a capitalized format" }), + Capitalized, + { + strict: true, + decode: (i) => string_.capitalize(i), + encode: identity + } +).annotations({ identifier: "Capitalize" }) {} + +/** + * This schema converts a string to uncapitalized one. + * + * @category string transformations + * @since 3.10.0 + */ +export class Uncapitalize extends transform( + String$.annotations({ description: "a string that will be converted to an uncapitalized format" }), + Uncapitalized, + { + strict: true, + decode: (i) => string_.uncapitalize(i), + encode: identity + } +).annotations({ identifier: "Uncapitalize" }) {} + +/** + * @category string constructors + * @since 3.10.0 + */ +export class Trimmed extends String$.pipe( + trimmed({ identifier: "Trimmed" }) +) {} + +/** + * Useful for validating strings that must contain meaningful characters without + * leading or trailing whitespace. + * + * @example + * ```ts + * import { Schema } from "effect" + * + * console.log(Schema.decodeOption(Schema.NonEmptyTrimmedString)("")) // Option.none() + * console.log(Schema.decodeOption(Schema.NonEmptyTrimmedString)(" a ")) // Option.none() + * console.log(Schema.decodeOption(Schema.NonEmptyTrimmedString)("a")) // Option.some("a") + * ``` + * + * @category string constructors + * @since 3.10.0 + */ +export class NonEmptyTrimmedString extends Trimmed.pipe( + nonEmptyString({ identifier: "NonEmptyTrimmedString" }) +) {} + +/** + * This schema allows removing whitespaces from the beginning and end of a string. + * + * @category string transformations + * @since 3.10.0 + */ +export class Trim extends transform( + String$.annotations({ description: "a string that will be trimmed" }), + Trimmed, + { + strict: true, + decode: (i) => i.trim(), + encode: identity + } +).annotations({ identifier: "Trim" }) {} + +/** + * Returns a schema that allows splitting a string into an array of strings. + * + * @category string transformations + * @since 3.10.0 + */ +export const split = (separator: string): transform, Array$> => + transform( + String$.annotations({ description: "a string that will be split" }), + Array$(String$), + { + strict: true, + decode: (i) => i.split(separator), + encode: (a) => a.join(separator) + } + ) + +/** + * @since 3.10.0 + */ +export type ParseJsonOptions = { + readonly reviver?: Parameters[1] + readonly replacer?: Parameters[1] + readonly space?: Parameters[2] +} + +const getErrorMessage = (e: unknown): string => e instanceof Error ? e.message : String(e) + +const getParseJsonTransformation = (options?: ParseJsonOptions): SchemaClass => + transformOrFail( + String$.annotations({ description: "a string to be decoded into JSON" }), + Unknown, + { + strict: true, + decode: (i, _, ast) => + ParseResult.try({ + try: () => JSON.parse(i, options?.reviver), + catch: (e) => new ParseResult.Type(ast, i, getErrorMessage(e)) + }), + encode: (a, _, ast) => + ParseResult.try({ + try: () => JSON.stringify(a, options?.replacer, options?.space), + catch: (e) => new ParseResult.Type(ast, a, getErrorMessage(e)) + }) + } + ).annotations({ + title: "parseJson", + schemaId: AST.ParseJsonSchemaId + }) + +/** + * The `ParseJson` combinator provides a method to convert JSON strings into the `unknown` type using the underlying + * functionality of `JSON.parse`. It also utilizes `JSON.stringify` for encoding. + * + * You can optionally provide a `ParseJsonOptions` to configure both `JSON.parse` and `JSON.stringify` executions. + * + * Optionally, you can pass a schema `Schema` to obtain an `A` type instead of `unknown`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import * as Schema from "effect/Schema" + * + * assert.deepStrictEqual(Schema.decodeUnknownSync(Schema.parseJson())(`{"a":"1"}`), { a: "1" }) + * assert.deepStrictEqual(Schema.decodeUnknownSync(Schema.parseJson(Schema.Struct({ a: Schema.NumberFromString })))(`{"a":"1"}`), { a: 1 }) + * ``` + * + * @category string transformations + * @since 3.10.0 + */ +export const parseJson: { + /** + * The `ParseJson` combinator provides a method to convert JSON strings into the `unknown` type using the underlying + * functionality of `JSON.parse`. It also utilizes `JSON.stringify` for encoding. + * + * You can optionally provide a `ParseJsonOptions` to configure both `JSON.parse` and `JSON.stringify` executions. + * + * Optionally, you can pass a schema `Schema` to obtain an `A` type instead of `unknown`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import * as Schema from "effect/Schema" + * + * assert.deepStrictEqual(Schema.decodeUnknownSync(Schema.parseJson())(`{"a":"1"}`), { a: "1" }) + * assert.deepStrictEqual(Schema.decodeUnknownSync(Schema.parseJson(Schema.Struct({ a: Schema.NumberFromString })))(`{"a":"1"}`), { a: 1 }) + * ``` + * + * @category string transformations + * @since 3.10.0 + */ + (schema: S, options?: ParseJsonOptions): transform, S> + /** + * The `ParseJson` combinator provides a method to convert JSON strings into the `unknown` type using the underlying + * functionality of `JSON.parse`. It also utilizes `JSON.stringify` for encoding. + * + * You can optionally provide a `ParseJsonOptions` to configure both `JSON.parse` and `JSON.stringify` executions. + * + * Optionally, you can pass a schema `Schema` to obtain an `A` type instead of `unknown`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import * as Schema from "effect/Schema" + * + * assert.deepStrictEqual(Schema.decodeUnknownSync(Schema.parseJson())(`{"a":"1"}`), { a: "1" }) + * assert.deepStrictEqual(Schema.decodeUnknownSync(Schema.parseJson(Schema.Struct({ a: Schema.NumberFromString })))(`{"a":"1"}`), { a: 1 }) + * ``` + * + * @category string transformations + * @since 3.10.0 + */ + (options?: ParseJsonOptions): SchemaClass +} = (schemaOrOptions?: Schema | ParseJsonOptions, o?: ParseJsonOptions) => + isSchema(schemaOrOptions) + ? compose(parseJson(o), schemaOrOptions) as any + : getParseJsonTransformation(schemaOrOptions as ParseJsonOptions | undefined) + +/** + * @category string constructors + * @since 3.10.0 + */ +export class NonEmptyString extends String$.pipe( + nonEmptyString({ identifier: "NonEmptyString" }) +) {} + +/** + * @category schema id + * @since 3.10.0 + */ +export const UUIDSchemaId: unique symbol = Symbol.for("effect/SchemaId/UUID") + +const uuidRegexp = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/i + +/** + * Represents a Universally Unique Identifier (UUID). + * + * This schema ensures that the provided string adheres to the standard UUID format. + * + * @category string constructors + * @since 3.10.0 + */ +export class UUID extends String$.pipe( + pattern(uuidRegexp, { + schemaId: UUIDSchemaId, + identifier: "UUID", + jsonSchema: { + format: "uuid", + pattern: uuidRegexp.source + }, + description: "a Universally Unique Identifier", + arbitrary: (): LazyArbitrary => (fc) => fc.uuid() + }) +) {} + +/** + * @category schema id + * @since 3.10.0 + */ +export const ULIDSchemaId: unique symbol = Symbol.for("effect/SchemaId/ULID") + +const ulidRegexp = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/i + +/** + * Represents a Universally Unique Lexicographically Sortable Identifier (ULID). + * + * ULIDs are designed to be compact, URL-safe, and ordered, making them suitable for use as identifiers. + * This schema ensures that the provided string adheres to the standard ULID format. + * + * @category string constructors + * @since 3.10.0 + */ +export class ULID extends String$.pipe( + pattern(ulidRegexp, { + schemaId: ULIDSchemaId, + identifier: "ULID", + description: "a Universally Unique Lexicographically Sortable Identifier", + arbitrary: (): LazyArbitrary => (fc) => fc.ulid() + }) +) {} + +/** + * Defines a schema that represents a `URL` object. + * + * @category URL constructors + * @since 3.11.0 + */ +export class URLFromSelf extends instanceOf(URL, { + typeConstructor: { _tag: "URL" }, + identifier: "URLFromSelf", + arbitrary: (): LazyArbitrary => (fc) => fc.webUrl().map((s) => new URL(s)), + pretty: () => (url) => url.toString() +}) {} + +/** @ignore */ +class URL$ extends transformOrFail( + String$.annotations({ description: "a string to be decoded into a URL" }), + URLFromSelf, + { + strict: true, + decode: (i, _, ast) => + ParseResult.try({ + try: () => new URL(i), + catch: (e) => + new ParseResult.Type( + ast, + i, + `Unable to decode ${JSON.stringify(i)} into a URL. ${getErrorMessage(e)}` + ) + }), + encode: (a) => ParseResult.succeed(a.toString()) + } +).annotations({ + identifier: "URL", + pretty: () => (url) => url.toString() +}) {} + +export { + /** + * Defines a schema that attempts to convert a `string` to a `URL` object using + * the `new URL` constructor. + * + * @category URL transformations + * @since 3.11.0 + */ + URL$ as URL +} + +/** + * @category schema id + * @since 3.10.0 + */ +export const FiniteSchemaId: unique symbol = schemaId_.FiniteSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type FiniteSchemaId = typeof FiniteSchemaId + +/** + * Ensures that the provided value is a finite number (excluding NaN, +Infinity, and -Infinity). + * + * @category number filters + * @since 3.10.0 + */ +export const finite = + (annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter(Number.isFinite, { + schemaId: FiniteSchemaId, + title: "finite", + description: "a finite number", + jsonSchema: {}, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const GreaterThanSchemaId: unique symbol = schemaId_.GreaterThanSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type GreaterThanSchemaId = typeof GreaterThanSchemaId + +/** + * This filter checks whether the provided number is greater than the specified minimum. + * + * @category number filters + * @since 3.10.0 + */ +export const greaterThan = ( + exclusiveMinimum: number, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a > exclusiveMinimum, { + schemaId: GreaterThanSchemaId, + title: `greaterThan(${exclusiveMinimum})`, + description: exclusiveMinimum === 0 ? "a positive number" : `a number greater than ${exclusiveMinimum}`, + jsonSchema: { exclusiveMinimum }, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const GreaterThanOrEqualToSchemaId: unique symbol = schemaId_.GreaterThanOrEqualToSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type GreaterThanOrEqualToSchemaId = typeof GreaterThanOrEqualToSchemaId + +/** + * This filter checks whether the provided number is greater than or equal to the specified minimum. + * + * @category number filters + * @since 3.10.0 + */ +export const greaterThanOrEqualTo = ( + minimum: number, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a >= minimum, { + schemaId: GreaterThanOrEqualToSchemaId, + title: `greaterThanOrEqualTo(${minimum})`, + description: minimum === 0 ? "a non-negative number" : `a number greater than or equal to ${minimum}`, + jsonSchema: { minimum }, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const MultipleOfSchemaId: unique symbol = Symbol.for("effect/SchemaId/MultipleOf") + +/** + * @category number filters + * @since 3.10.0 + */ +export const multipleOf = ( + divisor: number, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => { + const positiveDivisor = Math.abs(divisor) // spec requires positive divisor + return self.pipe( + filter((a) => number_.remainder(a, divisor) === 0, { + schemaId: MultipleOfSchemaId, + title: `multipleOf(${positiveDivisor})`, + description: `a number divisible by ${positiveDivisor}`, + jsonSchema: { multipleOf: positiveDivisor }, + ...annotations + }) + ) +} + +/** + * @category schema id + * @since 3.10.0 + */ +export const IntSchemaId: unique symbol = schemaId_.IntSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type IntSchemaId = typeof IntSchemaId + +/** + * Ensures that the provided value is an integer number (excluding NaN, +Infinity, and -Infinity). + * + * @category number filters + * @since 3.10.0 + */ +export const int = + (annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => Number.isSafeInteger(a), { + schemaId: IntSchemaId, + title: "int", + description: "an integer", + jsonSchema: { type: "integer" }, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const LessThanSchemaId: unique symbol = schemaId_.LessThanSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type LessThanSchemaId = typeof LessThanSchemaId + +/** + * This filter checks whether the provided number is less than the specified maximum. + * + * @category number filters + * @since 3.10.0 + */ +export const lessThan = + (exclusiveMaximum: number, annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a < exclusiveMaximum, { + schemaId: LessThanSchemaId, + title: `lessThan(${exclusiveMaximum})`, + description: exclusiveMaximum === 0 ? "a negative number" : `a number less than ${exclusiveMaximum}`, + jsonSchema: { exclusiveMaximum }, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const LessThanOrEqualToSchemaId: unique symbol = schemaId_.LessThanOrEqualToSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type LessThanOrEqualToSchemaId = typeof LessThanOrEqualToSchemaId + +/** + * This schema checks whether the provided number is less than or equal to the specified maximum. + * + * @category number filters + * @since 3.10.0 + */ +export const lessThanOrEqualTo = ( + maximum: number, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a <= maximum, { + schemaId: LessThanOrEqualToSchemaId, + title: `lessThanOrEqualTo(${maximum})`, + description: maximum === 0 ? "a non-positive number" : `a number less than or equal to ${maximum}`, + jsonSchema: { maximum }, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const BetweenSchemaId: unique symbol = schemaId_.BetweenSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type BetweenSchemaId = typeof BetweenSchemaId + +/** + * This filter checks whether the provided number falls within the specified minimum and maximum values. + * + * @category number filters + * @since 3.10.0 + */ +export const between = ( + minimum: number, + maximum: number, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a >= minimum && a <= maximum, { + schemaId: BetweenSchemaId, + title: `between(${minimum}, ${maximum})`, + description: `a number between ${minimum} and ${maximum}`, + jsonSchema: { minimum, maximum }, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const NonNaNSchemaId: unique symbol = schemaId_.NonNaNSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type NonNaNSchemaId = typeof NonNaNSchemaId + +/** + * @category number filters + * @since 3.10.0 + */ +export const nonNaN = + (annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => !Number.isNaN(a), { + schemaId: NonNaNSchemaId, + title: "nonNaN", + description: "a number excluding NaN", + ...annotations + }) + ) + +/** + * @category number filters + * @since 3.10.0 + */ +export const positive = ( + annotations?: Annotations.Filter> +): (self: S & Schema, Schema.Context>) => filter => + greaterThan(0, { title: "positive", ...annotations }) + +/** + * @category number filters + * @since 3.10.0 + */ +export const negative = ( + annotations?: Annotations.Filter> +): (self: S & Schema, Schema.Context>) => filter => + lessThan(0, { title: "negative", ...annotations }) + +/** + * @category number filters + * @since 3.10.0 + */ +export const nonPositive = ( + annotations?: Annotations.Filter> +): (self: S & Schema, Schema.Context>) => filter => + lessThanOrEqualTo(0, { title: "nonPositive", ...annotations }) + +/** + * @category number filters + * @since 3.10.0 + */ +export const nonNegative = ( + annotations?: Annotations.Filter> +): (self: S & Schema, Schema.Context>) => filter => + greaterThanOrEqualTo(0, { title: "nonNegative", ...annotations }) + +/** + * Clamps a number between a minimum and a maximum value. + * + * @category number transformations + * @since 3.10.0 + */ +export const clamp = (minimum: number, maximum: number) => +( + self: S & Schema, Schema.Context> +): transform>> => { + return transform( + self, + typeSchema(self).pipe(between(minimum, maximum)), + { + strict: false, + decode: (i) => number_.clamp(i, { minimum, maximum }), + encode: identity + } + ) +} + +/** + * Transforms a `string` into a `number` by parsing the string using the `parse` + * function of the `effect/Number` module. + * + * It returns an error if the value can't be converted (for example when + * non-numeric characters are provided). + * + * The following special string values are supported: "NaN", "Infinity", + * "-Infinity". + * + * @category number transformations + * @since 3.10.0 + */ +export function parseNumber( + self: S & Schema, Schema.Context> +): transformOrFail { + return transformOrFail( + self, + Number$, + { + strict: false, + decode: (i, _, ast) => + ParseResult.fromOption( + number_.parse(i), + () => new ParseResult.Type(ast, i, `Unable to decode ${JSON.stringify(i)} into a number`) + ), + encode: (a) => ParseResult.succeed(String(a)) + } + ) +} + +/** + * This schema transforms a `string` into a `number` by parsing the string using the `parse` function of the `effect/Number` module. + * + * It returns an error if the value can't be converted (for example when non-numeric characters are provided). + * + * The following special string values are supported: "NaN", "Infinity", "-Infinity". + * + * @category number transformations + * @since 3.10.0 + */ +export class NumberFromString extends parseNumber(String$.annotations({ + description: "a string to be decoded into a number" +})).annotations({ identifier: "NumberFromString" }) {} + +/** + * @category number constructors + * @since 3.10.0 + */ +export class Finite extends Number$.pipe(finite({ identifier: "Finite" })) {} + +/** + * @category number constructors + * @since 3.10.0 + */ +export class Int extends Number$.pipe(int({ identifier: "Int" })) {} + +/** + * @category number constructors + * @since 3.10.0 + */ +export class NonNaN extends Number$.pipe(nonNaN({ identifier: "NonNaN" })) {} + +/** + * @category number constructors + * @since 3.10.0 + */ +export class Positive extends Number$.pipe( + positive({ identifier: "Positive" }) +) {} + +/** + * @category number constructors + * @since 3.10.0 + */ +export class Negative extends Number$.pipe( + negative({ identifier: "Negative" }) +) {} + +/** + * @category number constructors + * @since 3.10.0 + */ +export class NonPositive extends Number$.pipe( + nonPositive({ identifier: "NonPositive" }) +) {} + +/** + * @category number constructors + * @since 3.10.0 + */ +export class NonNegative extends Number$.pipe( + nonNegative({ identifier: "NonNegative" }) +) {} + +/** + * @category schema id + * @since 3.10.0 + */ +export const JsonNumberSchemaId: unique symbol = schemaId_.JsonNumberSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type JsonNumberSchemaId = typeof JsonNumberSchemaId + +/** + * The `JsonNumber` is a schema for representing JSON numbers. It ensures that the provided value is a valid + * number by filtering out `NaN` and `(+/-) Infinity`. This is useful when you want to validate and represent numbers in JSON + * format. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import * as Schema from "effect/Schema" + * + * const is = Schema.is(Schema.JsonNumber) + * + * assert.deepStrictEqual(is(42), true) + * assert.deepStrictEqual(is(Number.NaN), false) + * assert.deepStrictEqual(is(Number.POSITIVE_INFINITY), false) + * assert.deepStrictEqual(is(Number.NEGATIVE_INFINITY), false) + * ``` + * + * @category number constructors + * @since 3.10.0 + */ +export class JsonNumber extends Number$.pipe( + finite({ + schemaId: JsonNumberSchemaId, + identifier: "JsonNumber" + }) +) {} + +/** + * @category boolean transformations + * @since 3.10.0 + */ +export class Not extends transform(Boolean$.annotations({ description: "a boolean that will be negated" }), Boolean$, { + strict: true, + decode: (i) => boolean_.not(i), + encode: (a) => boolean_.not(a) +}) {} + +const encodeSymbol = (sym: symbol, ast: AST.AST) => { + const key = Symbol.keyFor(sym) + return key === undefined + ? ParseResult.fail( + new ParseResult.Type(ast, sym, `Unable to encode a unique symbol ${String(sym)} into a string`) + ) + : ParseResult.succeed(key) +} + +const decodeSymbol = (s: string) => ParseResult.succeed(Symbol.for(s)) + +/** @ignore */ +class Symbol$ extends transformOrFail( + String$.annotations({ description: "a string to be decoded into a globally shared symbol" }), + SymbolFromSelf, + { + strict: false, + decode: (i) => decodeSymbol(i), + encode: (a, _, ast) => encodeSymbol(a, ast) + } +).annotations({ identifier: "Symbol" }) {} + +export { + /** + * Converts a string key into a globally shared symbol. + * + * @category symbol transformations + * @since 3.10.0 + */ + Symbol$ as Symbol +} + +/** + * @category schema id + * @since 3.10.0 + */ +export const GreaterThanBigIntSchemaId: unique symbol = schemaId_.GreaterThanBigintSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type GreaterThanBigIntSchemaId = typeof GreaterThanBigIntSchemaId + +/** + * @category bigint filters + * @since 3.10.0 + */ +export const greaterThanBigInt = ( + min: bigint, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a > min, { + schemaId: GreaterThanBigIntSchemaId, + [GreaterThanBigIntSchemaId]: { min }, + title: `greaterThanBigInt(${min})`, + description: min === 0n ? "a positive bigint" : `a bigint greater than ${min}n`, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const GreaterThanOrEqualToBigIntSchemaId: unique symbol = schemaId_.GreaterThanOrEqualToBigIntSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type GreaterThanOrEqualToBigIntSchemaId = typeof GreaterThanOrEqualToBigIntSchemaId + +/** + * @category bigint filters + * @since 3.10.0 + */ +export const greaterThanOrEqualToBigInt = ( + min: bigint, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a >= min, { + schemaId: GreaterThanOrEqualToBigIntSchemaId, + [GreaterThanOrEqualToBigIntSchemaId]: { min }, + title: `greaterThanOrEqualToBigInt(${min})`, + description: min === 0n + ? "a non-negative bigint" + : `a bigint greater than or equal to ${min}n`, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const LessThanBigIntSchemaId: unique symbol = schemaId_.LessThanBigIntSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type LessThanBigIntSchemaId = typeof LessThanBigIntSchemaId + +/** + * @category bigint filters + * @since 3.10.0 + */ +export const lessThanBigInt = ( + max: bigint, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a < max, { + schemaId: LessThanBigIntSchemaId, + [LessThanBigIntSchemaId]: { max }, + title: `lessThanBigInt(${max})`, + description: max === 0n ? "a negative bigint" : `a bigint less than ${max}n`, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const LessThanOrEqualToBigIntSchemaId: unique symbol = schemaId_.LessThanOrEqualToBigIntSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type LessThanOrEqualToBigIntSchemaId = typeof LessThanOrEqualToBigIntSchemaId + +/** + * @category bigint filters + * @since 3.10.0 + */ +export const lessThanOrEqualToBigInt = ( + max: bigint, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a <= max, { + schemaId: LessThanOrEqualToBigIntSchemaId, + [LessThanOrEqualToBigIntSchemaId]: { max }, + title: `lessThanOrEqualToBigInt(${max})`, + description: max === 0n ? "a non-positive bigint" : `a bigint less than or equal to ${max}n`, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const BetweenBigIntSchemaId: unique symbol = schemaId_.BetweenBigintSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type BetweenBigIntSchemaId = typeof BetweenBigIntSchemaId + +/** + * @category bigint filters + * @since 3.10.0 + */ +export const betweenBigInt = ( + min: bigint, + max: bigint, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a >= min && a <= max, { + schemaId: BetweenBigIntSchemaId, + [BetweenBigIntSchemaId]: { min, max }, + title: `betweenBigInt(${min}, ${max})`, + description: `a bigint between ${min}n and ${max}n`, + ...annotations + }) + ) + +/** + * @category bigint filters + * @since 3.10.0 + */ +export const positiveBigInt = ( + annotations?: Annotations.Filter> +): (self: S & Schema, Schema.Context>) => filter => + greaterThanBigInt(0n, { title: "positiveBigInt", ...annotations }) + +/** + * @category bigint filters + * @since 3.10.0 + */ +export const negativeBigInt = ( + annotations?: Annotations.Filter> +): (self: S & Schema, Schema.Context>) => filter => + lessThanBigInt(0n, { title: "negativeBigInt", ...annotations }) + +/** + * @category bigint filters + * @since 3.10.0 + */ +export const nonNegativeBigInt = ( + annotations?: Annotations.Filter> +): (self: S & Schema, Schema.Context>) => filter => + greaterThanOrEqualToBigInt(0n, { title: "nonNegativeBigInt", ...annotations }) + +/** + * @category bigint filters + * @since 3.10.0 + */ +export const nonPositiveBigInt = ( + annotations?: Annotations.Filter> +): (self: S & Schema, Schema.Context>) => filter => + lessThanOrEqualToBigInt(0n, { title: "nonPositiveBigInt", ...annotations }) + +/** + * Clamps a bigint between a minimum and a maximum value. + * + * @category bigint transformations + * @since 3.10.0 + */ +export const clampBigInt = (minimum: bigint, maximum: bigint) => +( + self: S & Schema, Schema.Context> +): transform>> => + transform( + self, + self.pipe(typeSchema, betweenBigInt(minimum, maximum)), + { + strict: false, + decode: (i) => bigInt_.clamp(i, { minimum, maximum }), + encode: identity + } + ) + +/** @ignore */ +class BigInt$ extends transformOrFail( + String$.annotations({ description: "a string to be decoded into a bigint" }), + BigIntFromSelf, + { + strict: true, + decode: (i, _, ast) => + ParseResult.fromOption( + bigInt_.fromString(i), + () => new ParseResult.Type(ast, i, `Unable to decode ${JSON.stringify(i)} into a bigint`) + ), + encode: (a) => ParseResult.succeed(String(a)) + } +).annotations({ identifier: "BigInt" }) {} + +export { + /** + * This schema transforms a `string` into a `bigint` by parsing the string using the `BigInt` function. + * + * It returns an error if the value can't be converted (for example when non-numeric characters are provided). + * + * @category bigint transformations + * @since 3.10.0 + */ + BigInt$ as BigInt +} + +/** + * @category bigint constructors + * @since 3.10.0 + */ +export const PositiveBigIntFromSelf: filter> = BigIntFromSelf.pipe( + positiveBigInt({ identifier: "PositiveBigintFromSelf" }) +) + +/** + * @category bigint constructors + * @since 3.10.0 + */ +export const PositiveBigInt: filter> = BigInt$.pipe( + positiveBigInt({ identifier: "PositiveBigint" }) +) + +/** + * @category bigint constructors + * @since 3.10.0 + */ +export const NegativeBigIntFromSelf: filter> = BigIntFromSelf.pipe( + negativeBigInt({ identifier: "NegativeBigintFromSelf" }) +) + +/** + * @category bigint constructors + * @since 3.10.0 + */ +export const NegativeBigInt: filter> = BigInt$.pipe( + negativeBigInt({ identifier: "NegativeBigint" }) +) + +/** + * @category bigint constructors + * @since 3.10.0 + */ +export const NonPositiveBigIntFromSelf: filter> = BigIntFromSelf.pipe( + nonPositiveBigInt({ identifier: "NonPositiveBigintFromSelf" }) +) + +/** + * @category bigint constructors + * @since 3.10.0 + */ +export const NonPositiveBigInt: filter> = BigInt$.pipe( + nonPositiveBigInt({ identifier: "NonPositiveBigint" }) +) + +/** + * @category bigint constructors + * @since 3.10.0 + */ +export const NonNegativeBigIntFromSelf: filter> = BigIntFromSelf.pipe( + nonNegativeBigInt({ identifier: "NonNegativeBigintFromSelf" }) +) + +/** + * @category bigint constructors + * @since 3.10.0 + */ +export const NonNegativeBigInt: filter> = BigInt$.pipe( + nonNegativeBigInt({ identifier: "NonNegativeBigint" }) +) + +/** + * This schema transforms a `number` into a `bigint` by parsing the number using the `BigInt` function. + * + * It returns an error if the value can't be safely encoded as a `number` due to being out of range. + * + * @category bigint transformations + * @since 3.10.0 + */ +export class BigIntFromNumber extends transformOrFail( + Number$.annotations({ description: "a number to be decoded into a bigint" }), + BigIntFromSelf.pipe(betweenBigInt(BigInt(Number.MIN_SAFE_INTEGER), BigInt(Number.MAX_SAFE_INTEGER))), + { + strict: true, + decode: (i, _, ast) => + ParseResult.fromOption( + bigInt_.fromNumber(i), + () => new ParseResult.Type(ast, i, `Unable to decode ${i} into a bigint`) + ), + encode: (a, _, ast) => + ParseResult.fromOption( + bigInt_.toNumber(a), + () => new ParseResult.Type(ast, a, `Unable to encode ${a}n into a number`) + ) + } +).annotations({ identifier: "BigIntFromNumber" }) {} + +const redactedArbitrary = (value: LazyArbitrary): LazyArbitrary> => (fc) => + value(fc).map(redacted_.make) + +const toComposite = ( + eff: Effect.Effect, + onSuccess: (a: A) => B, + ast: AST.AST, + actual: unknown +): Effect.Effect => + ParseResult.mapBoth(eff, { + onFailure: (e) => new ParseResult.Composite(ast, actual, e), + onSuccess + }) + +const redactedParse = ( + decodeUnknown: ParseResult.DecodeUnknown +): ParseResult.DeclarationDecodeUnknown, R> => +(u, options, ast) => + redacted_.isRedacted(u) ? + toComposite(decodeUnknown(redacted_.value(u), options), redacted_.make, ast, u) : + ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface RedactedFromSelf extends + AnnotableDeclare< + RedactedFromSelf, + redacted_.Redacted>, + redacted_.Redacted>, + [Value] + > +{} + +/** + * @category Redacted constructors + * @since 3.10.0 + */ +export const RedactedFromSelf = (value: Value): RedactedFromSelf => + declare( + [value], + { + decode: (value) => redactedParse(ParseResult.decodeUnknown(value)), + encode: (value) => redactedParse(ParseResult.encodeUnknown(value)) + }, + { + typeConstructor: { _tag: "effect/Redacted" }, + description: "Redacted()", + pretty: () => () => "Redacted()", + arbitrary: redactedArbitrary, + equivalence: redacted_.getEquivalence + } + ) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Redacted + extends transform>>> +{} + +/** + * A transformation that transform a `Schema` into a + * `RedactedFromSelf`. + * + * @category Redacted transformations + * @since 3.10.0 + */ +export function Redacted(value: Value): Redacted { + return transform( + value, + RedactedFromSelf(typeSchema(asSchema(value))), + { + strict: true, + decode: (i) => redacted_.make(i), + encode: (a) => redacted_.value(a) + } + ) +} + +/** + * @category Duration constructors + * @since 3.10.0 + */ +export class DurationFromSelf extends declare( + duration_.isDuration, + { + typeConstructor: { _tag: "effect/Duration" }, + identifier: "DurationFromSelf", + pretty: (): pretty_.Pretty => String, + arbitrary: (): LazyArbitrary => (fc) => + fc.oneof( + fc.constant(duration_.infinity), + fc.bigInt({ min: 0n }).map((_) => duration_.nanos(_)), + fc.maxSafeNat().map((_) => duration_.millis(_)) + ), + equivalence: (): Equivalence.Equivalence => duration_.Equivalence + } +) {} + +/** + * A schema that transforms a non negative `bigint` into a `Duration`. Treats + * the value as the number of nanoseconds. + * + * @category Duration transformations + * @since 3.10.0 + */ +export class DurationFromNanos extends transformOrFail( + NonNegativeBigIntFromSelf.annotations({ description: "a bigint to be decoded into a Duration" }), + DurationFromSelf.pipe(filter((duration) => duration_.isFinite(duration), { description: "a finite duration" })), + { + strict: true, + decode: (i) => ParseResult.succeed(duration_.nanos(i)), + encode: (a, _, ast) => + option_.match(duration_.toNanos(a), { + onNone: () => ParseResult.fail(new ParseResult.Type(ast, a, `Unable to encode ${a} into a bigint`)), + onSome: (nanos) => ParseResult.succeed(nanos) + }) + } +).annotations({ identifier: "DurationFromNanos" }) {} + +/** + * A non-negative integer. +Infinity is excluded. + * + * @category number constructors + * @since 3.11.10 + */ +export const NonNegativeInt = NonNegative.pipe(int()).annotations({ identifier: "NonNegativeInt" }) + +/** + * A schema that transforms a (possibly Infinite) non negative number into a + * `Duration`. Treats the value as the number of milliseconds. + * + * @category Duration transformations + * @since 3.10.0 + */ +export class DurationFromMillis extends transform( + NonNegative.annotations({ + description: "a non-negative number to be decoded into a Duration" + }), + DurationFromSelf, + { + strict: true, + decode: (i) => duration_.millis(i), + encode: (a) => duration_.toMillis(a) + } +).annotations({ identifier: "DurationFromMillis" }) {} + +const DurationValueMillis = TaggedStruct("Millis", { millis: NonNegativeInt }) +const DurationValueNanos = TaggedStruct("Nanos", { nanos: BigInt$ }) +const DurationValueInfinity = TaggedStruct("Infinity", {}) +const durationValueInfinity = DurationValueInfinity.make({}) + +/** + * @category Duration utils + * @since 3.12.8 + */ +export type DurationEncoded = + | { + readonly _tag: "Millis" + readonly millis: number + } + | { + readonly _tag: "Nanos" + readonly nanos: string + } + | { + readonly _tag: "Infinity" + } + +const DurationValue: Schema = Union( + DurationValueMillis, + DurationValueNanos, + DurationValueInfinity +).annotations({ + identifier: "DurationValue", + description: "an JSON-compatible tagged union to be decoded into a Duration" +}) + +const FiniteHRTime = Tuple( + element(NonNegativeInt).annotations({ title: "seconds" }), + element(NonNegativeInt).annotations({ title: "nanos" }) +).annotations({ identifier: "FiniteHRTime" }) + +const InfiniteHRTime = Tuple(Literal(-1), Literal(0)).annotations({ identifier: "InfiniteHRTime" }) + +const HRTime: Schema = Union(FiniteHRTime, InfiniteHRTime).annotations({ + identifier: "HRTime", + description: "a tuple of seconds and nanos to be decoded into a Duration" +}) + +const isDurationValue = (u: duration_.DurationValue | typeof HRTime.Type): u is duration_.DurationValue => + typeof u === "object" + +// TODO(4.0): remove HRTime union member +/** + * A schema that converts a JSON-compatible tagged union into a `Duration`. + * + * @category Duration transformations + * @since 3.10.0 + */ +export class Duration extends transform( + Union(DurationValue, HRTime), + DurationFromSelf, + { + strict: true, + decode: (i) => { + if (isDurationValue(i)) { + switch (i._tag) { + case "Millis": + return duration_.millis(i.millis) + case "Nanos": + return duration_.nanos(i.nanos) + case "Infinity": + return duration_.infinity + } + } + const [seconds, nanos] = i + return seconds === -1 ? duration_.infinity : duration_.nanos(BigInt(seconds) * BigInt(1e9) + BigInt(nanos)) + }, + encode: (a) => { + switch (a.value._tag) { + case "Millis": + return DurationValueMillis.make({ millis: a.value.millis }) + case "Nanos": + return DurationValueNanos.make({ nanos: a.value.nanos }) + case "Infinity": + return durationValueInfinity + } + } + } +).annotations({ identifier: "Duration" }) {} + +/** + * Clamps a `Duration` between a minimum and a maximum value. + * + * @category Duration transformations + * @since 3.10.0 + */ +export const clampDuration = + (minimum: duration_.DurationInput, maximum: duration_.DurationInput) => + ( + self: S & Schema, Schema.Context> + ): transform>> => + transform( + self, + self.pipe(typeSchema, betweenDuration(minimum, maximum)), + { + strict: false, + decode: (i) => duration_.clamp(i, { minimum, maximum }), + encode: identity + } + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const LessThanDurationSchemaId: unique symbol = Symbol.for("effect/SchemaId/LessThanDuration") + +/** + * @category Duration filters + * @since 3.10.0 + */ +export const lessThanDuration = ( + max: duration_.DurationInput, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => duration_.lessThan(a, max), { + schemaId: LessThanDurationSchemaId, + [LessThanDurationSchemaId]: { max }, + title: `lessThanDuration(${max})`, + description: `a Duration less than ${duration_.decode(max)}`, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const LessThanOrEqualToDurationSchemaId: unique symbol = Symbol.for( + "effect/schema/LessThanOrEqualToDuration" +) + +/** + * @category Duration filters + * @since 3.10.0 + */ +export const lessThanOrEqualToDuration = ( + max: duration_.DurationInput, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => duration_.lessThanOrEqualTo(a, max), { + schemaId: LessThanDurationSchemaId, + [LessThanDurationSchemaId]: { max }, + title: `lessThanOrEqualToDuration(${max})`, + description: `a Duration less than or equal to ${duration_.decode(max)}`, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const GreaterThanDurationSchemaId: unique symbol = Symbol.for("effect/SchemaId/GreaterThanDuration") + +/** + * @category Duration filters + * @since 3.10.0 + */ +export const greaterThanDuration = ( + min: duration_.DurationInput, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => duration_.greaterThan(a, min), { + schemaId: GreaterThanDurationSchemaId, + [GreaterThanDurationSchemaId]: { min }, + title: `greaterThanDuration(${min})`, + description: `a Duration greater than ${duration_.decode(min)}`, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const GreaterThanOrEqualToDurationSchemaId: unique symbol = Symbol.for( + "effect/schema/GreaterThanOrEqualToDuration" +) + +/** + * @category Duration filters + * @since 3.10.0 + */ +export const greaterThanOrEqualToDuration = ( + min: duration_.DurationInput, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => duration_.greaterThanOrEqualTo(a, min), { + schemaId: GreaterThanOrEqualToDurationSchemaId, + [GreaterThanOrEqualToDurationSchemaId]: { min }, + title: `greaterThanOrEqualToDuration(${min})`, + description: `a Duration greater than or equal to ${duration_.decode(min)}`, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const BetweenDurationSchemaId: unique symbol = Symbol.for("effect/SchemaId/BetweenDuration") + +/** + * @category Duration filters + * @since 3.10.0 + */ +export const betweenDuration = ( + minimum: duration_.DurationInput, + maximum: duration_.DurationInput, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => duration_.between(a, { minimum, maximum }), { + schemaId: BetweenDurationSchemaId, + [BetweenDurationSchemaId]: { maximum, minimum }, + title: `betweenDuration(${minimum}, ${maximum})`, + description: `a Duration between ${duration_.decode(minimum)} and ${duration_.decode(maximum)}`, + ...annotations + }) + ) + +/** + * @category Uint8Array constructors + * @since 3.10.0 + */ +export class Uint8ArrayFromSelf extends declare( + Predicate.isUint8Array, + { + typeConstructor: { _tag: "Uint8Array" }, + identifier: "Uint8ArrayFromSelf", + pretty: (): pretty_.Pretty => (u8arr) => `new Uint8Array(${JSON.stringify(Array.from(u8arr))})`, + arbitrary: (): LazyArbitrary => (fc) => fc.uint8Array(), + equivalence: (): Equivalence.Equivalence => array_.getEquivalence(Equal.equals) as any + } +) {} + +/** + * @category number constructors + * @since 3.11.10 + */ +export class Uint8 extends Number$.pipe( + between(0, 255, { + identifier: "Uint8", + description: "a 8-bit unsigned integer" + }) +) {} + +/** @ignore */ +class Uint8Array$ extends transform( + Array$(Uint8).annotations({ + description: "an array of 8-bit unsigned integers to be decoded into a Uint8Array" + }), + Uint8ArrayFromSelf, + { + strict: true, + decode: (i) => Uint8Array.from(i), + encode: (a) => Array.from(a) + } +).annotations({ identifier: "Uint8Array" }) {} + +export { + /** + * A schema that transforms an array of numbers into a `Uint8Array`. + * + * @category Uint8Array transformations + * @since 3.10.0 + */ + Uint8Array$ as Uint8Array +} + +const makeUint8ArrayTransformation = ( + id: string, + decode: (s: string) => either_.Either, + encode: (u: Uint8Array) => string +) => + transformOrFail( + String$.annotations({ description: "a string to be decoded into a Uint8Array" }), + Uint8ArrayFromSelf, + { + strict: true, + decode: (i, _, ast) => + either_.mapLeft( + decode(i), + (decodeException) => new ParseResult.Type(ast, i, decodeException.message) + ), + encode: (a) => ParseResult.succeed(encode(a)) + } + ).annotations({ identifier: id }) + +/** + * Decodes a base64 (RFC4648) encoded string into a `Uint8Array`. + * + * @category Uint8Array transformations + * @since 3.10.0 + */ +export const Uint8ArrayFromBase64: Schema = makeUint8ArrayTransformation( + "Uint8ArrayFromBase64", + Encoding.decodeBase64, + Encoding.encodeBase64 +) + +/** + * Decodes a base64 (URL) encoded string into a `Uint8Array`. + * + * @category Uint8Array transformations + * @since 3.10.0 + */ +export const Uint8ArrayFromBase64Url: Schema = makeUint8ArrayTransformation( + "Uint8ArrayFromBase64Url", + Encoding.decodeBase64Url, + Encoding.encodeBase64Url +) + +/** + * Decodes a hex encoded string into a `Uint8Array`. + * + * @category Uint8Array transformations + * @since 3.10.0 + */ +export const Uint8ArrayFromHex: Schema = makeUint8ArrayTransformation( + "Uint8ArrayFromHex", + Encoding.decodeHex, + Encoding.encodeHex +) + +const makeEncodingTransformation = ( + id: string, + decode: (s: string) => either_.Either, + encode: (u: string) => string +) => + transformOrFail( + String$.annotations({ + description: `A string that is interpreted as being ${id}-encoded and will be decoded into a UTF-8 string` + }), + String$, + { + strict: true, + decode: (i, _, ast) => + either_.mapLeft( + decode(i), + (decodeException) => new ParseResult.Type(ast, i, decodeException.message) + ), + encode: (a) => ParseResult.succeed(encode(a)) + } + ).annotations({ identifier: `StringFrom${id}` }) + +/** + * Decodes a base64 (RFC4648) encoded string into a UTF-8 string. + * + * @category string transformations + * @since 3.10.0 + */ +export const StringFromBase64: Schema = makeEncodingTransformation( + "Base64", + Encoding.decodeBase64String, + Encoding.encodeBase64 +) + +/** + * Decodes a base64 (URL) encoded string into a UTF-8 string. + * + * @category string transformations + * @since 3.10.0 + */ +export const StringFromBase64Url: Schema = makeEncodingTransformation( + "Base64Url", + Encoding.decodeBase64UrlString, + Encoding.encodeBase64Url +) + +/** + * Decodes a hex encoded string into a UTF-8 string. + * + * @category string transformations + * @since 3.10.0 + */ +export const StringFromHex: Schema = makeEncodingTransformation( + "Hex", + Encoding.decodeHexString, + Encoding.encodeHex +) + +/** + * Decodes a URI component encoded string into a UTF-8 string. + * Can be used to store data in a URL. + * + * @example + * ```ts + * import { Schema } from "effect" + * + * const PaginationSchema = Schema.Struct({ + * maxItemPerPage: Schema.Number, + * page: Schema.Number + * }) + * + * const UrlSchema = Schema.compose(Schema.StringFromUriComponent, Schema.parseJson(PaginationSchema)) + * + * console.log(Schema.encodeSync(UrlSchema)({ maxItemPerPage: 10, page: 1 })) + * // Output: %7B%22maxItemPerPage%22%3A10%2C%22page%22%3A1%7D + * ``` + * + * @category string transformations + * @since 3.12.0 + */ +export const StringFromUriComponent = transformOrFail( + String$.annotations({ + description: `A string that is interpreted as being UriComponent-encoded and will be decoded into a UTF-8 string` + }), + String$, + { + strict: true, + decode: (i, _, ast) => + either_.mapLeft( + Encoding.decodeUriComponent(i), + (decodeException) => new ParseResult.Type(ast, i, decodeException.message) + ), + encode: (a, _, ast) => + either_.mapLeft( + Encoding.encodeUriComponent(a), + (encodeException) => new ParseResult.Type(ast, a, encodeException.message) + ) + } +).annotations({ identifier: `StringFromUriComponent` }) + +/** + * @category schema id + * @since 3.10.0 + */ +export const MinItemsSchemaId: unique symbol = schemaId_.MinItemsSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type MinItemsSchemaId = typeof MinItemsSchemaId + +/** + * @category ReadonlyArray filters + * @since 3.10.0 + */ +export const minItems = ( + n: number, + annotations?: Annotations.Filter> +) => +>(self: S & Schema, Schema.Context>): filter => { + const minItems = Math.floor(n) + if (minItems < 1) { + throw new Error( + errors_.getInvalidArgumentErrorMessage(`Expected an integer greater than or equal to 1, actual ${n}`) + ) + } + return self.pipe( + filter( + (a) => a.length >= minItems, + { + schemaId: MinItemsSchemaId, + title: `minItems(${minItems})`, + description: `an array of at least ${minItems} item(s)`, + jsonSchema: { minItems }, + [AST.StableFilterAnnotationId]: true, + ...annotations + } + ) + ) +} + +/** + * @category schema id + * @since 3.10.0 + */ +export const MaxItemsSchemaId: unique symbol = schemaId_.MaxItemsSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type MaxItemsSchemaId = typeof MaxItemsSchemaId + +/** + * @category ReadonlyArray filters + * @since 3.10.0 + */ +export const maxItems = ( + n: number, + annotations?: Annotations.Filter> +) => +>(self: S & Schema, Schema.Context>): filter => { + const maxItems = Math.floor(n) + if (maxItems < 1) { + throw new Error( + errors_.getInvalidArgumentErrorMessage(`Expected an integer greater than or equal to 1, actual ${n}`) + ) + } + return self.pipe( + filter((a) => a.length <= maxItems, { + schemaId: MaxItemsSchemaId, + title: `maxItems(${maxItems})`, + description: `an array of at most ${maxItems} item(s)`, + jsonSchema: { maxItems }, + [AST.StableFilterAnnotationId]: true, + ...annotations + }) + ) +} + +/** + * @category schema id + * @since 3.10.0 + */ +export const ItemsCountSchemaId: unique symbol = schemaId_.ItemsCountSchemaId + +/** + * @category schema id + * @since 3.10.0 + */ +export type ItemsCountSchemaId = typeof ItemsCountSchemaId + +/** + * @category ReadonlyArray filters + * @since 3.10.0 + */ +export const itemsCount = ( + n: number, + annotations?: Annotations.Filter> +) => +>(self: S & Schema, Schema.Context>): filter => { + const itemsCount = Math.floor(n) + if (itemsCount < 0) { + throw new Error( + errors_.getInvalidArgumentErrorMessage(`Expected an integer greater than or equal to 0, actual ${n}`) + ) + } + return self.pipe( + filter((a) => a.length === itemsCount, { + schemaId: ItemsCountSchemaId, + title: `itemsCount(${itemsCount})`, + description: `an array of exactly ${itemsCount} item(s)`, + jsonSchema: { minItems: itemsCount, maxItems: itemsCount }, + [AST.StableFilterAnnotationId]: true, + ...annotations + }) + ) +} + +/** + * @category ReadonlyArray transformations + * @since 3.10.0 + */ +export const getNumberIndexedAccess = , I extends ReadonlyArray, R>( + self: Schema +): SchemaClass => make(AST.getNumberIndexedAccess(self.ast)) + +/** + * Get the first element of a `ReadonlyArray`, or `None` if the array is empty. + * + * @category ReadonlyArray transformations + * @since 3.10.0 + */ +export function head>( + self: S & Schema, Schema.Context> +): transform>> { + return transform( + self, + OptionFromSelf(getNumberIndexedAccess(typeSchema(self))), + { + strict: false, + decode: (i) => array_.head(i), + encode: (a) => + option_.match(a, { + onNone: () => [], + onSome: array_.of + }) + } + ) +} + +/** + * Get the first element of a `NonEmptyReadonlyArray`. + * + * @category NonEmptyReadonlyArray transformations + * @since 3.12.0 + */ +export function headNonEmpty>( + self: S & Schema, Schema.Context> +): transform> { + return transform( + self, + getNumberIndexedAccess(typeSchema(self)), + { + strict: false, + decode: (i) => array_.headNonEmpty(i), + encode: (a) => array_.of(a) + } + ) +} + +/** + * Retrieves the first element of a `ReadonlyArray`. + * + * If the array is empty, it returns the `fallback` argument if provided; otherwise, it fails. + * + * @category ReadonlyArray transformations + * @since 3.10.0 + */ +export const headOrElse: { + /** + * Retrieves the first element of a `ReadonlyArray`. + * + * If the array is empty, it returns the `fallback` argument if provided; otherwise, it fails. + * + * @category ReadonlyArray transformations + * @since 3.10.0 + */ + >(fallback?: LazyArg): ( + self: S & Schema, Schema.Context> + ) => transform> + /** + * Retrieves the first element of a `ReadonlyArray`. + * + * If the array is empty, it returns the `fallback` argument if provided; otherwise, it fails. + * + * @category ReadonlyArray transformations + * @since 3.10.0 + */ + >( + self: S & Schema, Schema.Context>, + fallback?: LazyArg + ): transform> +} = dual( + (args) => isSchema(args[0]), + ( + self: Schema, I, R>, + fallback?: LazyArg + ): transform, I, R>, SchemaClass> => + transformOrFail( + self, + getNumberIndexedAccess(typeSchema(self)), + { + strict: true, + decode: (i, _, ast) => + i.length > 0 + ? ParseResult.succeed(i[0]) + : fallback + ? ParseResult.succeed(fallback()) + : ParseResult.fail(new ParseResult.Type(ast, i, "Unable to retrieve the first element of an empty array")), + encode: (a) => ParseResult.succeed(array_.of(a)) + } + ) +) + +/** + * @category schema id + * @since 3.10.0 + */ +export const ValidDateSchemaId: unique symbol = Symbol.for("effect/SchemaId/ValidDate") + +/** + * Defines a filter that specifically rejects invalid dates, such as `new + * Date("Invalid Date")`. This filter ensures that only properly formatted and + * valid date objects are accepted, enhancing data integrity by preventing + * erroneous date values from being processed. + * + * @category Date filters + * @since 3.10.0 + */ +export const validDate = + (annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => !Number.isNaN(a.getTime()), { + schemaId: ValidDateSchemaId, + [ValidDateSchemaId]: { noInvalidDate: true }, + title: "validDate", + description: "a valid Date", + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const LessThanDateSchemaId: unique symbol = Symbol.for("effect/SchemaId/LessThanDate") + +/** + * @category Date filters + * @since 3.10.0 + */ +export const lessThanDate = ( + max: Date, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a: Date) => a < max, { + schemaId: LessThanDateSchemaId, + [LessThanDateSchemaId]: { max }, + title: `lessThanDate(${Inspectable.formatDate(max)})`, + description: `a date before ${Inspectable.formatDate(max)}`, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const LessThanOrEqualToDateSchemaId: unique symbol = Symbol.for( + "effect/schema/LessThanOrEqualToDate" +) + +/** + * @category Date filters + * @since 3.10.0 + */ +export const lessThanOrEqualToDate = ( + max: Date, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a: Date) => a <= max, { + schemaId: LessThanOrEqualToDateSchemaId, + [LessThanOrEqualToDateSchemaId]: { max }, + title: `lessThanOrEqualToDate(${Inspectable.formatDate(max)})`, + description: `a date before or equal to ${Inspectable.formatDate(max)}`, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const GreaterThanDateSchemaId: unique symbol = Symbol.for("effect/SchemaId/GreaterThanDate") + +/** + * @category Date filters + * @since 3.10.0 + */ +export const greaterThanDate = ( + min: Date, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a: Date) => a > min, { + schemaId: GreaterThanDateSchemaId, + [GreaterThanDateSchemaId]: { min }, + title: `greaterThanDate(${Inspectable.formatDate(min)})`, + description: `a date after ${Inspectable.formatDate(min)}`, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const GreaterThanOrEqualToDateSchemaId: unique symbol = Symbol.for( + "effect/schema/GreaterThanOrEqualToDate" +) + +/** + * @category Date filters + * @since 3.10.0 + */ +export const greaterThanOrEqualToDate = ( + min: Date, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a: Date) => a >= min, { + schemaId: GreaterThanOrEqualToDateSchemaId, + [GreaterThanOrEqualToDateSchemaId]: { min }, + title: `greaterThanOrEqualToDate(${Inspectable.formatDate(min)})`, + description: `a date after or equal to ${Inspectable.formatDate(min)}`, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.10.0 + */ +export const BetweenDateSchemaId: unique symbol = Symbol.for("effect/SchemaId/BetweenDate") + +/** + * @category Date filters + * @since 3.10.0 + */ +export const betweenDate = ( + min: Date, + max: Date, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a: Date) => a <= max && a >= min, { + schemaId: BetweenDateSchemaId, + [BetweenDateSchemaId]: { max, min }, + title: `betweenDate(${Inspectable.formatDate(min)}, ${Inspectable.formatDate(max)})`, + description: `a date between ${Inspectable.formatDate(min)} and ${Inspectable.formatDate(max)}`, + ...annotations + }) + ) + +/** + * @category schema id + * @since 3.11.8 + */ +export const DateFromSelfSchemaId: unique symbol = schemaId_.DateFromSelfSchemaId + +/** + * @category schema id + * @since 3.11.8 + */ +export type DateFromSelfSchemaId = typeof DateFromSelfSchemaId + +/** + * Describes a schema that accommodates potentially invalid `Date` instances, + * such as `new Date("Invalid Date")`, without rejection. + * + * @category Date constructors + * @since 3.10.0 + */ +export class DateFromSelf extends declare( + Predicate.isDate, + { + typeConstructor: { _tag: "Date" }, + identifier: "DateFromSelf", + schemaId: DateFromSelfSchemaId, + [DateFromSelfSchemaId]: { noInvalidDate: false }, + description: "a potentially invalid Date instance", + pretty: () => (date) => `new Date(${JSON.stringify(date)})`, + arbitrary: () => (fc) => fc.date({ noInvalidDate: false }), + equivalence: () => Equivalence.Date + } +) {} + +/** + * Defines a schema that ensures only valid dates are accepted. This schema + * rejects values like `new Date("Invalid Date")`, which, despite being a `Date` + * instance, represents an invalid date. Such stringent validation ensures that + * all date objects processed through this schema are properly formed and + * represent real dates. + * + * @category Date constructors + * @since 3.10.0 + */ +export class ValidDateFromSelf extends DateFromSelf.pipe( + validDate({ + identifier: "ValidDateFromSelf", + description: "a valid Date instance" + }) +) {} + +/** + * Defines a schema that attempts to convert a `string` to a `Date` object using + * the `new Date` constructor. This conversion is lenient, meaning it does not + * reject strings that do not form valid dates (e.g., using `new Date("Invalid + * Date")` results in a `Date` object, despite being invalid). + * + * @category Date transformations + * @since 3.10.0 + */ +export class DateFromString extends transform( + String$.annotations({ description: "a string to be decoded into a Date" }), + DateFromSelf, + { + strict: true, + decode: (i) => new Date(i), + encode: (a) => Inspectable.formatDate(a) + } +).annotations({ identifier: "DateFromString" }) {} + +/** @ignore */ +class Date$ extends DateFromString.pipe( + validDate({ identifier: "Date" }) +) {} + +export { + /** + * This schema converts a `string` into a `Date` object using the `new Date` + * constructor. It ensures that only valid date strings are accepted, + * rejecting any strings that would result in an invalid date, such as `new + * Date("Invalid Date")`. + * + * @category Date transformations + * @since 3.10.0 + */ + Date$ as Date +} + +/** + * Defines a schema that converts a `number` into a `Date` object using the `new + * Date` constructor. This schema does not validate the numerical input, + * allowing potentially invalid values such as `NaN`, `Infinity`, and + * `-Infinity` to be converted into `Date` objects. During the encoding process, + * any invalid `Date` object will be encoded to `NaN`. + * + * @category Date transformations + * @since 3.10.0 + */ +export class DateFromNumber extends transform( + Number$.annotations({ description: "a number to be decoded into a Date" }), + DateFromSelf, + { + strict: true, + decode: (i) => new Date(i), + encode: (a) => a.getTime() + } +).annotations({ identifier: "DateFromNumber" }) {} + +/** + * Describes a schema that represents a `DateTime.Utc` instance. + * + * @category DateTime.Utc constructors + * @since 3.10.0 + */ +export class DateTimeUtcFromSelf extends declare( + (u) => dateTime.isDateTime(u) && dateTime.isUtc(u), + { + typeConstructor: { _tag: "effect/DateTime.Utc" }, + identifier: "DateTimeUtcFromSelf", + description: "a DateTime.Utc instance", + pretty: (): pretty_.Pretty => (dateTime) => dateTime.toString(), + arbitrary: (): LazyArbitrary => (fc) => + fc.date({ noInvalidDate: true }).map((date) => dateTime.unsafeFromDate(date)), + equivalence: () => dateTime.Equivalence + } +) {} + +const decodeDateTimeUtc = (input: A, ast: AST.AST) => + ParseResult.try({ + try: () => dateTime.unsafeMake(input), + catch: () => + new ParseResult.Type(ast, input, `Unable to decode ${Inspectable.formatUnknown(input)} into a DateTime.Utc`) + }) + +/** + * Defines a schema that attempts to convert a `number` to a `DateTime.Utc` instance using the `DateTime.unsafeMake` constructor. + * + * @category DateTime.Utc transformations + * @since 3.10.0 + */ +export class DateTimeUtcFromNumber extends transformOrFail( + Number$.annotations({ description: "a number to be decoded into a DateTime.Utc" }), + DateTimeUtcFromSelf, + { + strict: true, + decode: (i, _, ast) => decodeDateTimeUtc(i, ast), + encode: (a) => ParseResult.succeed(dateTime.toEpochMillis(a)) + } +).annotations({ identifier: "DateTimeUtcFromNumber" }) {} + +/** + * Defines a schema that attempts to convert a `Date` to a `DateTime.Utc` instance using the `DateTime.unsafeMake` constructor. + * + * @category DateTime.Utc transformations + * @since 3.12.0 + */ +export class DateTimeUtcFromDate extends transformOrFail( + DateFromSelf.annotations({ description: "a Date to be decoded into a DateTime.Utc" }), + DateTimeUtcFromSelf, + { + strict: true, + decode: (i, _, ast) => decodeDateTimeUtc(i, ast), + encode: (a) => ParseResult.succeed(dateTime.toDateUtc(a)) + } +).annotations({ identifier: "DateTimeUtcFromDate" }) {} + +/** + * Defines a schema that attempts to convert a `string` to a `DateTime.Utc` instance using the `DateTime.unsafeMake` constructor. + * + * @category DateTime.Utc transformations + * @since 3.10.0 + */ +export class DateTimeUtc extends transformOrFail( + String$.annotations({ description: "a string to be decoded into a DateTime.Utc" }), + DateTimeUtcFromSelf, + { + strict: true, + decode: (i, _, ast) => decodeDateTimeUtc(i, ast), + encode: (a) => ParseResult.succeed(dateTime.formatIso(a)) + } +).annotations({ identifier: "DateTimeUtc" }) {} + +const timeZoneOffsetArbitrary = (): LazyArbitrary => (fc) => + fc.integer({ min: -12 * 60 * 60 * 1000, max: 14 * 60 * 60 * 1000 }).map(dateTime.zoneMakeOffset) + +/** + * Describes a schema that represents a `TimeZone.Offset` instance. + * + * @category TimeZone constructors + * @since 3.10.0 + */ +export class TimeZoneOffsetFromSelf extends declare( + dateTime.isTimeZoneOffset, + { + typeConstructor: { _tag: "effect/DateTime.TimeZone.Offset" }, + identifier: "TimeZoneOffsetFromSelf", + description: "a TimeZone.Offset instance", + pretty: (): pretty_.Pretty => (zone) => zone.toString(), + arbitrary: timeZoneOffsetArbitrary + } +) {} + +/** + * Defines a schema that converts a `number` to a `TimeZone.Offset` instance using the `DateTime.zoneMakeOffset` constructor. + * + * @category TimeZone transformations + * @since 3.10.0 + */ +export class TimeZoneOffset extends transform( + Number$.annotations({ description: "a number to be decoded into a TimeZone.Offset" }), + TimeZoneOffsetFromSelf, + { + strict: true, + decode: (i) => dateTime.zoneMakeOffset(i), + encode: (a) => a.offset + } +).annotations({ identifier: "TimeZoneOffset" }) {} + +const timeZoneNamedArbitrary = (): LazyArbitrary => (fc) => + fc.constantFrom(...Intl.supportedValuesOf("timeZone")).map(dateTime.zoneUnsafeMakeNamed) + +/** + * Describes a schema that represents a `TimeZone.Named` instance. + * + * @category TimeZone constructors + * @since 3.10.0 + */ +export class TimeZoneNamedFromSelf extends declare( + dateTime.isTimeZoneNamed, + { + typeConstructor: { _tag: "effect/DateTime.TimeZone.Named" }, + identifier: "TimeZoneNamedFromSelf", + description: "a TimeZone.Named instance", + pretty: (): pretty_.Pretty => (zone) => zone.toString(), + arbitrary: timeZoneNamedArbitrary + } +) {} + +/** + * Defines a schema that attempts to convert a `string` to a `TimeZone.Named` instance using the `DateTime.zoneUnsafeMakeNamed` constructor. + * + * @category TimeZone transformations + * @since 3.10.0 + */ +export class TimeZoneNamed extends transformOrFail( + String$.annotations({ description: "a string to be decoded into a TimeZone.Named" }), + TimeZoneNamedFromSelf, + { + strict: true, + decode: (i, _, ast) => + ParseResult.try({ + try: () => dateTime.zoneUnsafeMakeNamed(i), + catch: () => new ParseResult.Type(ast, i, `Unable to decode ${JSON.stringify(i)} into a TimeZone.Named`) + }), + encode: (a) => ParseResult.succeed(a.id) + } +).annotations({ identifier: "TimeZoneNamed" }) {} + +/** + * @category TimeZone constructors + * @since 3.10.0 + */ +export class TimeZoneFromSelf extends Union(TimeZoneOffsetFromSelf, TimeZoneNamedFromSelf) {} + +/** + * Defines a schema that attempts to convert a `string` to a `TimeZone` using the `DateTime.zoneFromString` constructor. + * + * @category TimeZone transformations + * @since 3.10.0 + */ +export class TimeZone extends transformOrFail( + String$.annotations({ description: "a string to be decoded into a TimeZone" }), + TimeZoneFromSelf, + { + strict: true, + decode: (i, _, ast) => + option_.match(dateTime.zoneFromString(i), { + onNone: () => + ParseResult.fail(new ParseResult.Type(ast, i, `Unable to decode ${JSON.stringify(i)} into a TimeZone`)), + onSome: ParseResult.succeed + }), + encode: (a) => ParseResult.succeed(dateTime.zoneToString(a)) + } +).annotations({ identifier: "TimeZone" }) {} + +const timeZoneArbitrary: LazyArbitrary = (fc) => + fc.oneof( + timeZoneOffsetArbitrary()(fc), + timeZoneNamedArbitrary()(fc) + ) + +/** + * Describes a schema that represents a `DateTime.Zoned` instance. + * + * @category DateTime.Zoned constructors + * @since 3.10.0 + */ +export class DateTimeZonedFromSelf extends declare( + (u) => dateTime.isDateTime(u) && dateTime.isZoned(u), + { + typeConstructor: { _tag: "effect/DateTime.Zoned" }, + identifier: "DateTimeZonedFromSelf", + description: "a DateTime.Zoned instance", + pretty: (): pretty_.Pretty => (dateTime) => dateTime.toString(), + arbitrary: (): LazyArbitrary => (fc) => + fc.tuple( + fc.integer({ + // time zone db supports +/- 1000 years or so + min: -31536000000000, + max: 31536000000000 + }), + timeZoneArbitrary(fc) + ).map(([millis, timeZone]) => dateTime.unsafeMakeZoned(millis, { timeZone })), + equivalence: () => dateTime.Equivalence + } +) {} + +/** + * Defines a schema that attempts to convert a `string` to a `DateTime.Zoned` instance. + * + * @category DateTime.Zoned transformations + * @since 3.10.0 + */ +export class DateTimeZoned extends transformOrFail( + String$.annotations({ description: "a string to be decoded into a DateTime.Zoned" }), + DateTimeZonedFromSelf, + { + strict: true, + decode: (i, _, ast) => + option_.match(dateTime.makeZonedFromString(i), { + onNone: () => + ParseResult.fail(new ParseResult.Type(ast, i, `Unable to decode ${JSON.stringify(i)} into a DateTime.Zoned`)), + onSome: ParseResult.succeed + }), + encode: (a) => ParseResult.succeed(dateTime.formatIsoZoned(a)) + } +).annotations({ identifier: "DateTimeZoned" }) {} + +/** + * @category Option utils + * @since 3.10.0 + */ +export type OptionEncoded = + | { + readonly _tag: "None" + } + | { + readonly _tag: "Some" + readonly value: I + } + +const OptionNoneEncoded = Struct({ + _tag: Literal("None") +}).annotations({ description: "NoneEncoded" }) + +const optionSomeEncoded = (value: Value) => + Struct({ + _tag: Literal("Some"), + value + }).annotations({ description: `SomeEncoded<${format(value)}>` }) + +const optionEncoded = (value: Value) => + Union( + OptionNoneEncoded, + optionSomeEncoded(value) + ).annotations({ + description: `OptionEncoded<${format(value)}>` + }) + +const optionDecode = (input: OptionEncoded): option_.Option => + input._tag === "None" ? option_.none() : option_.some(input.value) + +const optionArbitrary = + (value: LazyArbitrary, ctx: ArbitraryGenerationContext): LazyArbitrary> => (fc) => + fc.oneof( + ctx, + fc.record({ _tag: fc.constant("None" as const) }), + fc.record({ _tag: fc.constant("Some" as const), value: value(fc) }) + ).map(optionDecode) + +const optionPretty = (value: pretty_.Pretty): pretty_.Pretty> => + option_.match({ + onNone: () => "none()", + onSome: (a) => `some(${value(a)})` + }) + +const optionParse = + (decodeUnknown: ParseResult.DecodeUnknown): ParseResult.DeclarationDecodeUnknown, R> => + (u, options, ast) => + option_.isOption(u) ? + option_.isNone(u) ? + ParseResult.succeed(option_.none()) + : toComposite(decodeUnknown(u.value, options), option_.some, ast, u) + : ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface OptionFromSelf extends + AnnotableDeclare< + OptionFromSelf, + option_.Option>, + option_.Option>, + [Value] + > +{} + +const OptionFromSelf_ = (value: Value): OptionFromSelf => { + return declare( + [value], + { + decode: (value) => optionParse(ParseResult.decodeUnknown(value)), + encode: (value) => optionParse(ParseResult.encodeUnknown(value)) + }, + { + typeConstructor: { _tag: "effect/Option" }, + pretty: optionPretty, + arbitrary: optionArbitrary, + equivalence: option_.getEquivalence + } + ) +} + +/** + * @category Option transformations + * @since 3.10.0 + */ +export const OptionFromSelf = (value: Value): OptionFromSelf => { + return OptionFromSelf_(value).annotations({ description: `Option<${format(value)}>` }) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Option extends + transform< + Union<[ + Struct<{ _tag: Literal<["None"]> }>, + Struct<{ _tag: Literal<["Some"]>; value: Value }> + ]>, + OptionFromSelf>> + > +{} + +const makeNoneEncoded = { + _tag: "None" +} as const + +const makeSomeEncoded = (value: A) => ({ + _tag: "Some", + value +} as const) + +/** + * @category Option transformations + * @since 3.10.0 + */ +export function Option(value: Value): Option { + const value_ = asSchema(value) + const out = transform( + optionEncoded(value_), + OptionFromSelf(typeSchema(value_)), + { + strict: true, + decode: (i) => optionDecode(i), + encode: (a) => + option_.match(a, { + onNone: () => makeNoneEncoded, + onSome: makeSomeEncoded + }) + } + ) + return out as any +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface OptionFromNullOr + extends transform, OptionFromSelf>>> +{} + +/** + * @category Option transformations + * @since 3.10.0 + */ +export function OptionFromNullOr(value: Value): OptionFromNullOr { + return transform(NullOr(value), OptionFromSelf(typeSchema(asSchema(value))), { + strict: true, + decode: (i) => option_.fromNullable(i), + encode: (a) => option_.getOrNull(a) + }) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface OptionFromNullishOr + extends transform, OptionFromSelf>>> +{} + +/** + * @category Option transformations + * @since 3.10.0 + */ +export function OptionFromNullishOr( + value: Value, + onNoneEncoding: null | undefined +): OptionFromNullishOr { + return transform( + NullishOr(value), + OptionFromSelf(typeSchema(asSchema(value))), + { + strict: true, + decode: (i) => option_.fromNullable(i), + encode: onNoneEncoding === null ? + (a) => option_.getOrNull(a) : + (a) => option_.getOrUndefined(a) + } + ) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface OptionFromUndefinedOr + extends transform, OptionFromSelf>>> +{} + +/** + * @category Option transformations + * @since 3.10.0 + */ +export function OptionFromUndefinedOr(value: Value): OptionFromUndefinedOr { + return transform(UndefinedOr(value), OptionFromSelf(typeSchema(asSchema(value))), { + strict: true, + decode: (i) => option_.fromNullable(i), + encode: (a) => option_.getOrUndefined(a) + }) +} + +/** + * Transforms strings into an Option type, effectively filtering out empty or + * whitespace-only strings by trimming them and checking their length. Returns + * `none` for invalid inputs and `some` for valid non-empty strings. + * + * @example + * ```ts + * import { Schema } from "effect" + * + * console.log(Schema.decodeSync(Schema.OptionFromNonEmptyTrimmedString)("")) // Option.none() + * console.log(Schema.decodeSync(Schema.OptionFromNonEmptyTrimmedString)(" a ")) // Option.some("a") + * console.log(Schema.decodeSync(Schema.OptionFromNonEmptyTrimmedString)("a")) // Option.some("a") + * ``` + * + * @category Option transformations + * @since 3.10.0 + */ +export class OptionFromNonEmptyTrimmedString extends transform(String$, OptionFromSelf(NonEmptyTrimmedString), { + strict: true, + decode: (i) => option_.filter(option_.some(i.trim()), string_.isNonEmpty), + encode: (a) => option_.getOrElse(a, () => "") +}) {} + +/** + * @category Either utils + * @since 3.10.0 + */ +export type RightEncoded = { + readonly _tag: "Right" + readonly right: IA +} + +/** + * @category Either utils + * @since 3.10.0 + */ +export type LeftEncoded = { + readonly _tag: "Left" + readonly left: IE +} + +/** + * @category Either utils + * @since 3.10.0 + */ +export type EitherEncoded = RightEncoded | LeftEncoded + +const rightEncoded = (right: Right) => + Struct({ + _tag: Literal("Right"), + right + }).annotations({ description: `RightEncoded<${format(right)}>` }) + +const leftEncoded = (left: Left) => + Struct({ + _tag: Literal("Left"), + left + }).annotations({ description: `LeftEncoded<${format(left)}>` }) + +const eitherEncoded = ( + right: Right, + left: Left +) => + Union(rightEncoded(right), leftEncoded(left)).annotations({ + description: `EitherEncoded<${format(left)}, ${format(right)}>` + }) + +const eitherDecode = (input: EitherEncoded): either_.Either => + input._tag === "Left" ? either_.left(input.left) : either_.right(input.right) + +const eitherArbitrary = ( + right: LazyArbitrary, + left: LazyArbitrary +): LazyArbitrary> => +(fc) => + fc.oneof( + fc.record({ _tag: fc.constant("Left" as const), left: left(fc) }), + fc.record({ _tag: fc.constant("Right" as const), right: right(fc) }) + ).map(eitherDecode) + +const eitherPretty = ( + right: pretty_.Pretty, + left: pretty_.Pretty +): pretty_.Pretty> => + either_.match({ + onLeft: (e) => `left(${left(e)})`, + onRight: (a) => `right(${right(a)})` + }) + +const eitherParse = ( + parseRight: ParseResult.DecodeUnknown, + decodeUnknownLeft: ParseResult.DecodeUnknown +): ParseResult.DeclarationDecodeUnknown, LR | RR> => +(u, options, ast) => + either_.isEither(u) ? + either_.match(u, { + onLeft: (left) => toComposite(decodeUnknownLeft(left, options), either_.left, ast, u), + onRight: (right) => toComposite(parseRight(right, options), either_.right, ast, u) + }) + : ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface EitherFromSelf extends + AnnotableDeclare< + EitherFromSelf, + either_.Either, Schema.Type>, + either_.Either, Schema.Encoded>, + [R, L] + > +{} + +/** + * @category Either transformations + * @since 3.10.0 + */ +export const EitherFromSelf = ({ left, right }: { + readonly left: L + readonly right: R +}): EitherFromSelf => { + return declare( + [right, left], + { + decode: (right, left) => eitherParse(ParseResult.decodeUnknown(right), ParseResult.decodeUnknown(left)), + encode: (right, left) => eitherParse(ParseResult.encodeUnknown(right), ParseResult.encodeUnknown(left)) + }, + { + typeConstructor: { _tag: "effect/Either" }, + description: `Either<${format(right)}, ${format(left)}>`, + pretty: eitherPretty, + arbitrary: eitherArbitrary, + equivalence: (right, left) => either_.getEquivalence({ left, right }) + } + ) +} + +const makeLeftEncoded = (left: E) => (({ + _tag: "Left", + left +}) as const) +const makeRightEncoded = (right: A) => (({ + _tag: "Right", + right +}) as const) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Either extends + transform< + Union<[ + Struct<{ + _tag: Literal<["Right"]> + right: Right + }>, + Struct<{ + _tag: Literal<["Left"]> + left: Left + }> + ]>, + EitherFromSelf>, SchemaClass>> + > +{} + +/** + * @category Either transformations + * @since 3.10.0 + */ +export const Either = ({ left, right }: { + readonly left: L + readonly right: R +}): Either => { + const right_ = asSchema(right) + const left_ = asSchema(left) + const out = transform( + eitherEncoded(right_, left_), + EitherFromSelf({ left: typeSchema(left_), right: typeSchema(right_) }), + { + strict: true, + decode: (i) => eitherDecode(i), + encode: (a) => + either_.match(a, { + onLeft: makeLeftEncoded, + onRight: makeRightEncoded + }) + } + ) + return out as any +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface EitherFromUnion extends + transform< + Union<[ + transform; right: SchemaClass> }>>, + transform; right: SchemaClass> }>> + ]>, + EitherFromSelf>, SchemaClass>> + > +{} + +/** + * @example + * ```ts + * import * as Schema from "effect/Schema" + * + * // Schema> + * Schema.EitherFromUnion({ left: Schema.String, right: Schema.Number }) + * ``` + * + * @category Either transformations + * @since 3.10.0 + */ +export const EitherFromUnion = ({ left, right }: { + readonly left: Left + readonly right: Right +}): EitherFromUnion => { + const right_ = asSchema(right) + const left_ = asSchema(left) + const toright = typeSchema(right_) + const toleft = typeSchema(left_) + const fromRight = transform(right_, rightEncoded(toright), { + strict: true, + decode: (i) => makeRightEncoded(i), + encode: (a) => a.right + }) + const fromLeft = transform(left_, leftEncoded(toleft), { + strict: true, + decode: (i) => makeLeftEncoded(i), + encode: (a) => a.left + }) + const out = transform( + Union(fromRight, fromLeft), + EitherFromSelf({ left: toleft, right: toright }), + { + strict: true, + decode: (i) => i._tag === "Left" ? either_.left(i.left) : either_.right(i.right), + encode: (a) => + either_.match(a, { + onLeft: makeLeftEncoded, + onRight: makeRightEncoded + }) + } + ) + return out as any +} + +const mapArbitrary = ( + key: LazyArbitrary, + value: LazyArbitrary, + ctx: ArbitraryGenerationContext +): LazyArbitrary> => { + return (fc) => { + const items = fc.array(fc.tuple(key(fc), value(fc))) + return (ctx.depthIdentifier !== undefined ? fc.oneof(ctx, fc.constant([]), items) : items).map((as) => new Map(as)) + } +} + +const readonlyMapPretty = ( + key: pretty_.Pretty, + value: pretty_.Pretty +): pretty_.Pretty> => +(map) => + `new Map([${ + Array.from(map.entries()) + .map(([k, v]) => `[${key(k)}, ${value(v)}]`) + .join(", ") + }])` + +const readonlyMapEquivalence = ( + key: Equivalence.Equivalence, + value: Equivalence.Equivalence +): Equivalence.Equivalence> => { + const arrayEquivalence = array_.getEquivalence( + Equivalence.make<[K, V]>(([ka, va], [kb, vb]) => key(ka, kb) && value(va, vb)) + ) + return Equivalence.make((a, b) => arrayEquivalence(Array.from(a.entries()), Array.from(b.entries()))) +} + +const readonlyMapParse = ( + decodeUnknown: ParseResult.DecodeUnknown, R> +): ParseResult.DeclarationDecodeUnknown, R> => +(u, options, ast) => + Predicate.isMap(u) ? + toComposite(decodeUnknown(Array.from(u.entries()), options), (as) => new Map(as), ast, u) + : ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface ReadonlyMapFromSelf extends + AnnotableDeclare< + ReadonlyMapFromSelf, + ReadonlyMap, Schema.Type>, + ReadonlyMap, Schema.Encoded>, + [K, V] + > +{} + +const mapFromSelf_ = ( + key: K, + value: V, + description: string +): ReadonlyMapFromSelf => + declare( + [key, value], + { + decode: (Key, Value) => readonlyMapParse(ParseResult.decodeUnknown(Array$(Tuple(Key, Value)))), + encode: (Key, Value) => readonlyMapParse(ParseResult.encodeUnknown(Array$(Tuple(Key, Value)))) + }, + { + typeConstructor: { _tag: "ReadonlyMap" }, + description, + pretty: readonlyMapPretty, + arbitrary: mapArbitrary, + equivalence: readonlyMapEquivalence + } + ) + +/** + * @category ReadonlyMap + * @since 3.10.0 + */ +export const ReadonlyMapFromSelf = ({ key, value }: { + readonly key: K + readonly value: V +}): ReadonlyMapFromSelf => mapFromSelf_(key, value, `ReadonlyMap<${format(key)}, ${format(value)}>`) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface MapFromSelf extends + AnnotableDeclare< + MapFromSelf, + Map, Schema.Type>, + ReadonlyMap, Schema.Encoded>, + [K, V] + > +{} + +/** + * @category Map + * @since 3.10.0 + */ +export const MapFromSelf = ({ key, value }: { + readonly key: K + readonly value: V +}): MapFromSelf => mapFromSelf_(key, value, `Map<${format(key)}, ${format(value)}>`) as any + +/** + * @category api interface + * @since 3.10.0 + */ +export interface ReadonlyMap$ + extends transform>, ReadonlyMapFromSelf>, SchemaClass>>> +{} + +/** + * @category ReadonlyMap transformations + * @since 3.10.0 + */ +export function ReadonlyMap({ key, value }: { + readonly key: K + readonly value: V +}): ReadonlyMap$ { + return transform( + Array$(Tuple(key, value)), + ReadonlyMapFromSelf({ key: typeSchema(asSchema(key)), value: typeSchema(asSchema(value)) }), + { + strict: true, + decode: (i) => new Map(i), + encode: (a) => Array.from(a.entries()) + } + ) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Map$ + extends transform>, MapFromSelf>, SchemaClass>>> +{} + +/** @ignore */ +function map({ key, value }: { + readonly key: K + readonly value: V +}): Map$ { + return transform( + Array$(Tuple(key, value)), + MapFromSelf({ key: typeSchema(asSchema(key)), value: typeSchema(asSchema(value)) }), + { + strict: true, + decode: (i) => new Map(i), + encode: (a) => Array.from(a.entries()) + } + ) +} + +export { + /** + * @category Map transformations + * @since 3.10.0 + */ + map as Map +} + +/** + * @category ReadonlyMap transformations + * @since 3.10.0 + */ +export const ReadonlyMapFromRecord = ({ key, value }: { + key: Schema + value: Schema +}): SchemaClass, { readonly [x: string]: VI }, KR | VR> => + transform( + Record({ key: encodedBoundSchema(key), value }).annotations({ + description: "a record to be decoded into a ReadonlyMap" + }), + ReadonlyMapFromSelf({ key, value: typeSchema(value) }), + { + strict: true, + decode: (i) => new Map(Object.entries(i)), + encode: (a) => Object.fromEntries(a) + } + ) + +/** + * @category Map transformations + * @since 3.10.0 + */ +export const MapFromRecord = ({ key, value }: { + key: Schema + value: Schema +}): SchemaClass, { readonly [x: string]: VI }, KR | VR> => + transform( + Record({ key: encodedBoundSchema(key), value }).annotations({ + description: "a record to be decoded into a Map" + }), + MapFromSelf({ key, value: typeSchema(value) }), + { + strict: true, + decode: (i) => new Map(Object.entries(i)), + encode: (a) => Object.fromEntries(a) + } + ) + +const setArbitrary = + (item: LazyArbitrary, ctx: ArbitraryGenerationContext): LazyArbitrary> => (fc) => { + const items = fc.array(item(fc)) + return (ctx.depthIdentifier !== undefined ? fc.oneof(ctx, fc.constant([]), items) : items).map((as) => new Set(as)) + } + +const readonlySetPretty = (item: pretty_.Pretty): pretty_.Pretty> => (set) => + `new Set([${Array.from(set.values()).map((a) => item(a)).join(", ")}])` + +const readonlySetEquivalence = ( + item: Equivalence.Equivalence +): Equivalence.Equivalence> => { + const arrayEquivalence = array_.getEquivalence(item) + return Equivalence.make((a, b) => arrayEquivalence(Array.from(a.values()), Array.from(b.values()))) +} + +const readonlySetParse = ( + decodeUnknown: ParseResult.DecodeUnknown, R> +): ParseResult.DeclarationDecodeUnknown, R> => +(u, options, ast) => + Predicate.isSet(u) ? + toComposite(decodeUnknown(Array.from(u.values()), options), (as) => new Set(as), ast, u) + : ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface ReadonlySetFromSelf extends + AnnotableDeclare< + ReadonlySetFromSelf, + ReadonlySet>, + ReadonlySet>, + [Value] + > +{} + +const setFromSelf_ = (value: Value, description: string): ReadonlySetFromSelf => + declare( + [value], + { + decode: (item) => readonlySetParse(ParseResult.decodeUnknown(Array$(item))), + encode: (item) => readonlySetParse(ParseResult.encodeUnknown(Array$(item))) + }, + { + typeConstructor: { _tag: "ReadonlySet" }, + description, + pretty: readonlySetPretty, + arbitrary: setArbitrary, + equivalence: readonlySetEquivalence + } + ) + +/** + * @category ReadonlySet + * @since 3.10.0 + */ +export const ReadonlySetFromSelf = (value: Value): ReadonlySetFromSelf => + setFromSelf_(value, `ReadonlySet<${format(value)}>`) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface SetFromSelf extends + AnnotableDeclare< + SetFromSelf, + Set>, + ReadonlySet>, + [Value] + > +{} + +/** + * @category Set + * @since 3.10.0 + */ +export const SetFromSelf = (value: Value): SetFromSelf => + setFromSelf_(value, `Set<${format(value)}>`) as any + +/** + * @category api interface + * @since 3.10.0 + */ +export interface ReadonlySet$ + extends transform, ReadonlySetFromSelf>>> +{} + +/** + * @category ReadonlySet transformations + * @since 3.10.0 + */ +export function ReadonlySet(value: Value): ReadonlySet$ { + return transform( + Array$(value), + ReadonlySetFromSelf(typeSchema(asSchema(value))), + { + strict: true, + decode: (i) => new Set(i), + encode: (a) => Array.from(a) + } + ) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Set$ + extends transform, SetFromSelf>>> +{} + +/** @ignore */ +function set(value: Value): Set$ { + return transform( + Array$(value), + SetFromSelf(typeSchema(asSchema(value))), + { + strict: true, + decode: (i) => new Set(i), + encode: (a) => Array.from(a) + } + ) +} + +export { + /** + * @category Set transformations + * @since 3.10.0 + */ + set as Set +} + +const bigDecimalPretty = (): pretty_.Pretty => (val) => + `BigDecimal(${bigDecimal_.format(bigDecimal_.normalize(val))})` + +const bigDecimalArbitrary = (): LazyArbitrary => (fc) => + fc.tuple(fc.bigInt(), fc.integer({ min: -18, max: 18 })) + .map(([value, scale]) => bigDecimal_.make(value, scale)) + +/** + * @category BigDecimal constructors + * @since 3.10.0 + */ +export class BigDecimalFromSelf extends declare( + bigDecimal_.isBigDecimal, + { + typeConstructor: { _tag: "effect/BigDecimal" }, + identifier: "BigDecimalFromSelf", + pretty: bigDecimalPretty, + arbitrary: bigDecimalArbitrary, + equivalence: () => bigDecimal_.Equivalence + } +) {} + +/** + * @category BigDecimal transformations + * @since 3.10.0 + */ +export class BigDecimal extends transformOrFail( + String$.annotations({ description: "a string to be decoded into a BigDecimal" }), + BigDecimalFromSelf, + { + strict: true, + decode: (i, _, ast) => + bigDecimal_.fromString(i).pipe(option_.match({ + onNone: () => + ParseResult.fail(new ParseResult.Type(ast, i, `Unable to decode ${JSON.stringify(i)} into a BigDecimal`)), + onSome: (val) => ParseResult.succeed(bigDecimal_.normalize(val)) + })), + encode: (a) => ParseResult.succeed(bigDecimal_.format(bigDecimal_.normalize(a))) + } +).annotations({ identifier: "BigDecimal" }) {} + +/** + * A schema that transforms a `number` into a `BigDecimal`. + * When encoding, this Schema will produce incorrect results if the BigDecimal exceeds the 64-bit range of a number. + * + * @category BigDecimal transformations + * @since 3.10.0 + */ +export class BigDecimalFromNumber extends transform( + Number$.annotations({ description: "a number to be decoded into a BigDecimal" }), + BigDecimalFromSelf, + { + strict: true, + decode: (i) => bigDecimal_.unsafeFromNumber(i), + encode: (a) => bigDecimal_.unsafeToNumber(a) + } +).annotations({ identifier: "BigDecimalFromNumber" }) {} + +/** + * @category schema id + * @since 3.10.0 + */ +export const GreaterThanBigDecimalSchemaId: unique symbol = Symbol.for("effect/SchemaId/GreaterThanBigDecimal") + +/** + * @category BigDecimal filters + * @since 3.10.0 + */ +export const greaterThanBigDecimal = + (min: bigDecimal_.BigDecimal, annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => { + const formatted = bigDecimal_.format(min) + return self.pipe( + filter((a) => bigDecimal_.greaterThan(a, min), { + schemaId: GreaterThanBigDecimalSchemaId, + [GreaterThanBigDecimalSchemaId]: { min }, + title: `greaterThanBigDecimal(${formatted})`, + description: `a BigDecimal greater than ${formatted}`, + ...annotations + }) + ) + } + +/** + * @category schema id + * @since 3.10.0 + */ +export const GreaterThanOrEqualToBigDecimalSchemaId: unique symbol = Symbol.for( + "effect/schema/GreaterThanOrEqualToBigDecimal" +) + +/** + * @category BigDecimal filters + * @since 3.10.0 + */ +export const greaterThanOrEqualToBigDecimal = + (min: bigDecimal_.BigDecimal, annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => { + const formatted = bigDecimal_.format(min) + return self.pipe( + filter((a) => bigDecimal_.greaterThanOrEqualTo(a, min), { + schemaId: GreaterThanOrEqualToBigDecimalSchemaId, + [GreaterThanOrEqualToBigDecimalSchemaId]: { min }, + title: `greaterThanOrEqualToBigDecimal(${formatted})`, + description: `a BigDecimal greater than or equal to ${formatted}`, + ...annotations + }) + ) + } + +/** + * @category schema id + * @since 3.10.0 + */ +export const LessThanBigDecimalSchemaId: unique symbol = Symbol.for("effect/SchemaId/LessThanBigDecimal") + +/** + * @category BigDecimal filters + * @since 3.10.0 + */ +export const lessThanBigDecimal = + (max: bigDecimal_.BigDecimal, annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => { + const formatted = bigDecimal_.format(max) + return self.pipe( + filter((a) => bigDecimal_.lessThan(a, max), { + schemaId: LessThanBigDecimalSchemaId, + [LessThanBigDecimalSchemaId]: { max }, + title: `lessThanBigDecimal(${formatted})`, + description: `a BigDecimal less than ${formatted}`, + ...annotations + }) + ) + } + +/** + * @category schema id + * @since 3.10.0 + */ +export const LessThanOrEqualToBigDecimalSchemaId: unique symbol = Symbol.for( + "effect/schema/LessThanOrEqualToBigDecimal" +) + +/** + * @category BigDecimal filters + * @since 3.10.0 + */ +export const lessThanOrEqualToBigDecimal = + (max: bigDecimal_.BigDecimal, annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => { + const formatted = bigDecimal_.format(max) + return self.pipe( + filter((a) => bigDecimal_.lessThanOrEqualTo(a, max), { + schemaId: LessThanOrEqualToBigDecimalSchemaId, + [LessThanOrEqualToBigDecimalSchemaId]: { max }, + title: `lessThanOrEqualToBigDecimal(${formatted})`, + description: `a BigDecimal less than or equal to ${formatted}`, + ...annotations + }) + ) + } + +/** + * @category schema id + * @since 3.10.0 + */ +export const PositiveBigDecimalSchemaId: unique symbol = Symbol.for( + "effect/schema/PositiveBigDecimal" +) + +/** + * @category BigDecimal filters + * @since 3.10.0 + */ +export const positiveBigDecimal = + (annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => bigDecimal_.isPositive(a), { + schemaId: PositiveBigDecimalSchemaId, + title: "positiveBigDecimal", + description: `a positive BigDecimal`, + ...annotations + }) + ) + +/** + * @category BigDecimal constructors + * @since 3.10.0 + */ +export const PositiveBigDecimalFromSelf: filter> = BigDecimalFromSelf.pipe( + positiveBigDecimal({ identifier: "PositiveBigDecimalFromSelf" }) +) + +/** + * @category schema id + * @since 3.10.0 + */ +export const NonNegativeBigDecimalSchemaId: unique symbol = Symbol.for( + "effect/schema/NonNegativeBigDecimal" +) + +/** + * @category BigDecimal filters + * @since 3.10.0 + */ +export const nonNegativeBigDecimal = + (annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a.value >= 0n, { + schemaId: NonNegativeBigDecimalSchemaId, + title: "nonNegativeBigDecimal", + description: `a non-negative BigDecimal`, + ...annotations + }) + ) + +/** + * @category BigDecimal constructors + * @since 3.10.0 + */ +export const NonNegativeBigDecimalFromSelf: filter> = BigDecimalFromSelf.pipe( + nonNegativeBigDecimal({ identifier: "NonNegativeBigDecimalFromSelf" }) +) + +/** + * @category schema id + * @since 3.10.0 + */ +export const NegativeBigDecimalSchemaId: unique symbol = Symbol.for( + "effect/schema/NegativeBigDecimal" +) + +/** + * @category BigDecimal filters + * @since 3.10.0 + */ +export const negativeBigDecimal = + (annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => bigDecimal_.isNegative(a), { + schemaId: NegativeBigDecimalSchemaId, + title: "negativeBigDecimal", + description: `a negative BigDecimal`, + ...annotations + }) + ) + +/** + * @category BigDecimal constructors + * @since 3.10.0 + */ +export const NegativeBigDecimalFromSelf: filter> = BigDecimalFromSelf.pipe( + negativeBigDecimal({ identifier: "NegativeBigDecimalFromSelf" }) +) + +/** + * @category schema id + * @since 3.10.0 + */ +export const NonPositiveBigDecimalSchemaId: unique symbol = Symbol.for( + "effect/schema/NonPositiveBigDecimal" +) + +/** + * @category BigDecimal filters + * @since 3.10.0 + */ +export const nonPositiveBigDecimal = + (annotations?: Annotations.Filter>) => + (self: S & Schema, Schema.Context>): filter => + self.pipe( + filter((a) => a.value <= 0n, { + schemaId: NonPositiveBigDecimalSchemaId, + title: "nonPositiveBigDecimal", + description: `a non-positive BigDecimal`, + ...annotations + }) + ) + +/** + * @category BigDecimal constructors + * @since 3.10.0 + */ +export const NonPositiveBigDecimalFromSelf: filter> = BigDecimalFromSelf.pipe( + nonPositiveBigDecimal({ identifier: "NonPositiveBigDecimalFromSelf" }) +) + +/** + * @category schema id + * @since 3.10.0 + */ +export const BetweenBigDecimalSchemaId: unique symbol = Symbol.for("effect/SchemaId/BetweenBigDecimal") + +/** + * @category BigDecimal filters + * @since 3.10.0 + */ +export const betweenBigDecimal = ( + minimum: bigDecimal_.BigDecimal, + maximum: bigDecimal_.BigDecimal, + annotations?: Annotations.Filter> +) => +(self: S & Schema, Schema.Context>): filter => { + const formattedMinimum = bigDecimal_.format(minimum) + const formattedMaximum = bigDecimal_.format(maximum) + return self.pipe( + filter((a) => bigDecimal_.between(a, { minimum, maximum }), { + schemaId: BetweenBigDecimalSchemaId, + [BetweenBigDecimalSchemaId]: { maximum, minimum }, + title: `betweenBigDecimal(${formattedMinimum}, ${formattedMaximum})`, + description: `a BigDecimal between ${formattedMinimum} and ${formattedMaximum}`, + ...annotations + }) + ) +} + +/** + * Clamps a `BigDecimal` between a minimum and a maximum value. + * + * @category BigDecimal transformations + * @since 3.10.0 + */ +export const clampBigDecimal = + (minimum: bigDecimal_.BigDecimal, maximum: bigDecimal_.BigDecimal) => + ( + self: S & Schema, Schema.Context> + ): transform>> => + transform( + self, + self.pipe(typeSchema, betweenBigDecimal(minimum, maximum)), + { + strict: false, + decode: (i) => bigDecimal_.clamp(i, { minimum, maximum }), + encode: identity + } + ) + +const chunkArbitrary = + (item: LazyArbitrary, ctx: ArbitraryGenerationContext): LazyArbitrary> => (fc) => { + const items = fc.array(item(fc)) + return (ctx.depthIdentifier !== undefined ? fc.oneof(ctx, fc.constant([]), items) : items).map(chunk_.fromIterable) + } + +const chunkPretty = (item: pretty_.Pretty): pretty_.Pretty> => (c) => + `Chunk(${chunk_.toReadonlyArray(c).map(item).join(", ")})` + +const chunkParse = ( + decodeUnknown: ParseResult.DecodeUnknown, R> +): ParseResult.DeclarationDecodeUnknown, R> => +(u, options, ast) => + chunk_.isChunk(u) ? + chunk_.isEmpty(u) ? + ParseResult.succeed(chunk_.empty()) + : toComposite(decodeUnknown(chunk_.toReadonlyArray(u), options), chunk_.fromIterable, ast, u) + : ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface ChunkFromSelf extends + AnnotableDeclare< + ChunkFromSelf, + chunk_.Chunk>, + chunk_.Chunk>, + [Value] + > +{} + +/** + * @category Chunk + * @since 3.10.0 + */ +export const ChunkFromSelf = (value: Value): ChunkFromSelf => { + return declare( + [value], + { + decode: (item) => chunkParse(ParseResult.decodeUnknown(Array$(item))), + encode: (item) => chunkParse(ParseResult.encodeUnknown(Array$(item))) + }, + { + typeConstructor: { _tag: "effect/Chunk" }, + description: `Chunk<${format(value)}>`, + pretty: chunkPretty, + arbitrary: chunkArbitrary, + equivalence: chunk_.getEquivalence + } + ) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Chunk + extends transform, ChunkFromSelf>>> +{} + +/** + * @category Chunk transformations + * @since 3.10.0 + */ +export function Chunk(value: Value): Chunk { + return transform( + Array$(value), + ChunkFromSelf(typeSchema(asSchema(value))), + { + strict: true, + decode: (i) => i.length === 0 ? chunk_.empty() : chunk_.fromIterable(i), + encode: (a) => chunk_.toReadonlyArray(a) + } + ) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface NonEmptyChunkFromSelf extends + AnnotableDeclare< + NonEmptyChunkFromSelf, + chunk_.NonEmptyChunk>, + chunk_.NonEmptyChunk>, + [Value] + > +{} + +const nonEmptyChunkArbitrary = (item: LazyArbitrary): LazyArbitrary> => (fc) => + fastCheck_.array(item(fc), { minLength: 1 }).map((as) => chunk_.unsafeFromNonEmptyArray(as as any)) + +const nonEmptyChunkPretty = (item: pretty_.Pretty): pretty_.Pretty> => (c) => + `NonEmptyChunk(${chunk_.toReadonlyArray(c).map(item).join(", ")})` + +const nonEmptyChunkParse = ( + decodeUnknown: ParseResult.DecodeUnknown, R> +): ParseResult.DeclarationDecodeUnknown, R> => +(u, options, ast) => + chunk_.isChunk(u) && chunk_.isNonEmpty(u) + ? toComposite(decodeUnknown(chunk_.toReadonlyArray(u), options), chunk_.unsafeFromNonEmptyArray, ast, u) + : ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category Chunk + * @since 3.10.0 + */ +export const NonEmptyChunkFromSelf = (value: Value): NonEmptyChunkFromSelf => { + return declare( + [value], + { + decode: (item) => nonEmptyChunkParse(ParseResult.decodeUnknown(NonEmptyArray(item))), + encode: (item) => nonEmptyChunkParse(ParseResult.encodeUnknown(NonEmptyArray(item))) + }, + { + typeConstructor: { _tag: "effect/Chunk.NonEmptyChunk" }, + description: `NonEmptyChunk<${format(value)}>`, + pretty: nonEmptyChunkPretty, + arbitrary: nonEmptyChunkArbitrary, + equivalence: chunk_.getEquivalence + } + ) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface NonEmptyChunk + extends transform, NonEmptyChunkFromSelf>>> +{} + +/** + * @category Chunk transformations + * @since 3.10.0 + */ +export function NonEmptyChunk(value: Value): NonEmptyChunk { + return transform( + NonEmptyArray(value), + NonEmptyChunkFromSelf(typeSchema(asSchema(value))), + { + strict: true, + decode: (i) => chunk_.unsafeFromNonEmptyArray(i), + encode: (a) => chunk_.toReadonlyArray(a) + } + ) +} + +const decodeData = > | ReadonlyArray>(a: A): A => + Array.isArray(a) ? data_.array(a) : data_.struct(a) + +const dataArbitrary = > | ReadonlyArray>( + item: LazyArbitrary +): LazyArbitrary => +(fc) => item(fc).map(decodeData) + +const dataPretty = > | ReadonlyArray>( + item: pretty_.Pretty +): pretty_.Pretty => +(d) => `Data(${item(d)})` + +const dataParse = > | ReadonlyArray>( + decodeUnknown: ParseResult.DecodeUnknown +): ParseResult.DeclarationDecodeUnknown => +(u, options, ast) => + Equal.isEqual(u) ? + toComposite(decodeUnknown(u, options), decodeData, ast, u) + : ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category api interface + * @since 3.13.3 + */ +export interface DataFromSelf extends + AnnotableDeclare< + DataFromSelf, + Schema.Type, + Schema.Encoded, + [Value] + > +{} + +/** + * Type and Encoded must extend `Readonly> | + * ReadonlyArray` to be compatible with this API. + * + * @category Data transformations + * @since 3.10.0 + */ +export const DataFromSelf = < + S extends Schema.Any, + A extends Readonly> | ReadonlyArray, + I extends Readonly> | ReadonlyArray +>(value: S & Schema, I & Schema.Encoded, Schema.Context>): DataFromSelf => { + return declare( + [value], + { + decode: (item) => dataParse(ParseResult.decodeUnknown(item)), + encode: (item) => dataParse(ParseResult.encodeUnknown(item)) + }, + { + description: `Data<${format(value)}>`, + pretty: dataPretty, + arbitrary: dataArbitrary + } + ) +} + +/** + * @category api interface + * @since 3.13.3 + */ +export interface Data + extends transform>>> +{} + +/** + * Type and Encoded must extend `Readonly> | + * ReadonlyArray` to be compatible with this API. + * + * @category Data transformations + * @since 3.10.0 + */ +export const Data = < + S extends Schema.Any, + A extends Readonly> | ReadonlyArray, + I extends Readonly> | ReadonlyArray +>(value: S & Schema, I & Schema.Encoded, Schema.Context>): Data => { + return transform( + value, + DataFromSelf(typeSchema(value)), + { + strict: false, + decode: (i) => decodeData(i), + encode: (a) => Array.isArray(a) ? Array.from(a) : Object.assign({}, a) + } + ) +} + +type MissingSelfGeneric = + `Missing \`Self\` generic - use \`class Self extends ${Usage}()(${Params}{ ... })\`` + +type RequiredKeys = { + [K in keyof T]-?: {} extends Pick ? never : K +}[keyof T] + +type ClassAnnotations = + | Annotations.Schema + | readonly [ + // Annotations for the "to" schema + Annotations.Schema | undefined, + // Annotations for the "transformation schema + (Annotations.Schema | undefined)?, + // Annotations for the "from" schema + Annotations.Schema? + ] + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Class + extends Schema, R> +{ + new( + props: RequiredKeys extends never ? void | Simplify : Simplify, + options?: MakeOptions + ): Struct.Type & Inherited & Proto + + /** @since 3.10.0 */ + readonly ast: AST.Transformation + + make) => any>(this: C, ...args: ConstructorParameters): InstanceType + + annotations(annotations: Annotations.Schema): SchemaClass, R> + + readonly fields: { readonly [K in keyof Fields]: Fields[K] } + + readonly identifier: string + + /** + * @example + * ```ts + * import { Schema } from "effect" + * + * class MyClass extends Schema.Class("MyClass")({ + * myField: Schema.String + * }) { + * myMethod() { + * return this.myField + "my" + * } + * } + * + * class NextClass extends MyClass.extend("NextClass")({ + * nextField: Schema.Number + * }) { + * nextMethod() { + * return this.myMethod() + this.myField + this.nextField + * } + * } + * ``` + */ + extend(identifier: string): ( + fields: NewFields | HasFields, + annotations?: ClassAnnotations>> + ) => [Extended] extends [never] ? MissingSelfGeneric<"Base.extend"> + : Class< + Extended, + Fields & NewFields, + I & Struct.Encoded, + R | Struct.Context, + C & Struct.Constructor, + Self, + Proto + > + + /** + * @example + * ```ts + * import { Effect, Schema } from "effect" + * + * class MyClass extends Schema.Class("MyClass")({ + * myField: Schema.String + * }) { + * myMethod() { + * return this.myField + "my" + * } + * } + * + * class NextClass extends MyClass.transformOrFail("NextClass")({ + * nextField: Schema.Number + * }, { + * decode: (i) => + * Effect.succeed({ + * myField: i.myField, + * nextField: i.myField.length + * }), + * encode: (a) => Effect.succeed({ myField: a.myField }) + * }) { + * nextMethod() { + * return this.myMethod() + this.myField + this.nextField + * } + * } + * ``` + */ + transformOrFail(identifier: string): < + NewFields extends Struct.Fields, + R2, + R3 + >( + fields: NewFields, + options: { + readonly decode: ( + input: Simplify>, + options: ParseOptions, + ast: AST.Transformation + ) => Effect.Effect>, ParseResult.ParseIssue, R2> + readonly encode: ( + input: Simplify>, + options: ParseOptions, + ast: AST.Transformation + ) => Effect.Effect, ParseResult.ParseIssue, R3> + }, + annotations?: ClassAnnotations>> + ) => [Transformed] extends [never] ? MissingSelfGeneric<"Base.transformOrFail"> + : Class< + Transformed, + Fields & NewFields, + I, + R | Struct.Context | R2 | R3, + C & Struct.Constructor, + Self, + Proto + > + + /** + * @example + * ```ts + * import { Effect, Schema } from "effect" + * + * class MyClass extends Schema.Class("MyClass")({ + * myField: Schema.String + * }) { + * myMethod() { + * return this.myField + "my" + * } + * } + * + * class NextClass extends MyClass.transformOrFailFrom("NextClass")({ + * nextField: Schema.Number + * }, { + * decode: (i) => + * Effect.succeed({ + * myField: i.myField, + * nextField: i.myField.length + * }), + * encode: (a) => Effect.succeed({ myField: a.myField }) + * }) { + * nextMethod() { + * return this.myMethod() + this.myField + this.nextField + * } + * } + * ``` + */ + transformOrFailFrom(identifier: string): < + NewFields extends Struct.Fields, + R2, + R3 + >( + fields: NewFields, + options: { + readonly decode: ( + input: Simplify, + options: ParseOptions, + ast: AST.Transformation + ) => Effect.Effect>, ParseResult.ParseIssue, R2> + readonly encode: ( + input: Simplify>, + options: ParseOptions, + ast: AST.Transformation + ) => Effect.Effect + }, + annotations?: ClassAnnotations>> + ) => [Transformed] extends [never] ? MissingSelfGeneric<"Base.transformOrFailFrom"> + : Class< + Transformed, + Fields & NewFields, + I, + R | Struct.Context | R2 | R3, + C & Struct.Constructor, + Self, + Proto + > +} + +type HasFields = Struct | { + readonly [RefineSchemaId]: HasFields +} + +const isField = (u: unknown) => isSchema(u) || isPropertySignature(u) + +const isFields = (fields: object): fields is Fields => + Reflect.ownKeys(fields).every((key) => isField((fields as any)[key])) + +const getFields = (hasFields: HasFields): Fields => + "fields" in hasFields ? hasFields.fields : getFields(hasFields[RefineSchemaId]) + +const getSchemaFromFieldsOr = (fieldsOr: Fields | HasFields): Schema.Any => + isFields(fieldsOr) ? Struct(fieldsOr) : isSchema(fieldsOr) ? fieldsOr : Struct(getFields(fieldsOr)) + +const getFieldsFromFieldsOr = (fieldsOr: Fields | HasFields): Fields => + isFields(fieldsOr) ? fieldsOr : getFields(fieldsOr) + +/** + * @example + * ```ts + * import { Schema } from "effect" + * + * class MyClass extends Schema.Class("MyClass")({ + * someField: Schema.String + * }) { + * someMethod() { + * return this.someField + "bar" + * } + * } + * ``` + * + * @category classes + * @since 3.10.0 + */ +export const Class = (identifier: string) => +( + fieldsOr: Fields | HasFields, + annotations?: ClassAnnotations>> +): [Self] extends [never] ? MissingSelfGeneric<"Class"> + : Class< + Self, + Fields, + Struct.Encoded, + Struct.Context, + Struct.Constructor, + {}, + {} + > => + makeClass({ + kind: "Class", + identifier, + schema: getSchemaFromFieldsOr(fieldsOr), + fields: getFieldsFromFieldsOr(fieldsOr), + Base: data_.Class, + annotations + }) + +/** @internal */ +export const getClassTag = (tag: Tag) => + withConstructorDefault(propertySignature(Literal(tag)), () => tag) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface TaggedClass extends + Class< + Self, + Fields, + Struct.Encoded, + Struct.Context, + Struct.Constructor>, + {}, + {} + > +{ + readonly _tag: Tag +} + +/** + * @example + * ```ts + * import { Schema } from "effect" + * + * class MyClass extends Schema.TaggedClass("MyClass")("MyClass", { + * a: Schema.String + * }) {} + * ``` + * + * @category classes + * @since 3.10.0 + */ +export const TaggedClass = (identifier?: string) => +( + tag: Tag, + fieldsOr: Fields | HasFields, + annotations?: ClassAnnotations } & Fields>>> +): [Self] extends [never] ? MissingSelfGeneric<"TaggedClass", `"Tag", `> + : TaggedClass } & Fields> => +{ + const fields = getFieldsFromFieldsOr(fieldsOr) + const schema = getSchemaFromFieldsOr(fieldsOr) + const newFields = { _tag: getClassTag(tag) } + const taggedFields = extendFields(newFields, fields) + return class TaggedClass extends makeClass({ + kind: "TaggedClass", + identifier: identifier ?? tag, + schema: extend(schema, Struct(newFields)), + fields: taggedFields, + Base: data_.Class, + annotations + }) { + static _tag = tag + } as any +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface TaggedErrorClass extends + Class< + Self, + Fields, + Struct.Encoded, + Struct.Context, + Struct.Constructor>, + {}, + cause_.YieldableError + > +{ + readonly _tag: Tag +} + +/** + * @example + * ```ts + * import { Schema } from "effect" + * + * class MyError extends Schema.TaggedError("MyError")( + * "MyError", + * { + * module: Schema.String, + * method: Schema.String, + * description: Schema.String + * } + * ) { + * get message(): string { + * return `${this.module}.${this.method}: ${this.description}` + * } + * } + * ``` + * @category classes + * @since 3.10.0 + */ +export const TaggedError = (identifier?: string) => +( + tag: Tag, + fieldsOr: Fields | HasFields, + annotations?: ClassAnnotations } & Fields>>> +): [Self] extends [never] ? MissingSelfGeneric<"TaggedError", `"Tag", `> + : TaggedErrorClass< + Self, + Tag, + { readonly _tag: tag } & Fields + > => +{ + class Base extends data_.Error {} + ;(Base.prototype as any).name = tag + const fields = getFieldsFromFieldsOr(fieldsOr) + const schema = getSchemaFromFieldsOr(fieldsOr) + const newFields = { _tag: getClassTag(tag) } + const taggedFields = extendFields(newFields, fields) + const hasMessageField = "message" in taggedFields + class TaggedErrorClass extends makeClass({ + kind: "TaggedError", + identifier: identifier ?? tag, + schema: extend(schema, Struct(newFields)), + fields: taggedFields, + Base, + annotations, + disableToString: true + }) { + static _tag = tag + } + + if (!hasMessageField) { + Object.defineProperty(TaggedErrorClass.prototype, "message", { + get() { + return `{ ${ + Reflect.ownKeys(fields) + .map((p: any) => `${Inspectable.formatPropertyKey(p)}: ${Inspectable.formatUnknown((this)[p])}`) + .join(", ") + } }` + }, + enumerable: false, // mirrors the built-in Error.prototype.message, whose descriptor is also non-enumerable + configurable: true + }) + } + + return TaggedErrorClass as any +} + +const extendFields = (a: Struct.Fields, b: Struct.Fields): Struct.Fields => { + const out = { ...a } + for (const key of Reflect.ownKeys(b)) { + if (key in a) { + throw new Error(errors_.getASTDuplicatePropertySignatureErrorMessage(key)) + } + out[key] = b[key] + } + return out +} + +/** + * @category Constructor utils + * @since 3.13.4 + */ +export type MakeOptions = boolean | { + readonly disableValidation?: boolean | undefined +} + +function getDisableValidationMakeOption(options: MakeOptions | undefined): boolean { + return Predicate.isBoolean(options) ? options : options?.disableValidation ?? false +} + +const astCache = globalValue("effect/Schema/astCache", () => new WeakMap()) + +const getClassAnnotations = ( + annotations: ClassAnnotations | undefined +): [Annotations.Schema?, Annotations.Schema?, Annotations.Schema?] => { + if (annotations === undefined) { + return [] + } else if (Array.isArray(annotations)) { + return annotations as any + } else { + return [annotations] as any + } +} + +const makeClass = ( + { Base, annotations, disableToString, fields, identifier, kind, schema }: { + kind: "Class" | "TaggedClass" | "TaggedError" | "TaggedRequest" + identifier: string + schema: Schema.Any + fields: Fields + Base: new(...args: ReadonlyArray) => any + annotations?: ClassAnnotations | undefined + disableToString?: boolean | undefined + } +): any => { + const classSymbol = Symbol.for(`effect/Schema/${kind}/${identifier}`) + + const [typeAnnotations, transformationAnnotations, encodedAnnotations] = getClassAnnotations(annotations) + + const typeSchema_ = typeSchema(schema) + + const declarationSurrogate = typeSchema_.annotations({ + identifier, + ...typeAnnotations + }) + + const typeSide = typeSchema_.annotations({ + [AST.AutoTitleAnnotationId]: `${identifier} (Type side)`, + ...typeAnnotations + }) + + const constructorSchema = schema.annotations({ + [AST.AutoTitleAnnotationId]: `${identifier} (Constructor)`, + ...typeAnnotations + }) + + const encodedSide = schema.annotations({ + [AST.AutoTitleAnnotationId]: `${identifier} (Encoded side)`, + ...encodedAnnotations + }) + + const transformationSurrogate = schema.annotations({ + ...encodedAnnotations, + ...typeAnnotations, + ...transformationAnnotations + }) + + const fallbackInstanceOf = (u: unknown) => Predicate.hasProperty(u, classSymbol) && ParseResult.is(typeSide)(u) + + const klass = class extends Base { + constructor( + props: { [x: string | symbol]: unknown } = {}, + options: MakeOptions = false + ) { + props = { ...props } + if (kind !== "Class") { + delete props["_tag"] + } + props = lazilyMergeDefaults(fields, props) + if (!getDisableValidationMakeOption(options)) { + props = ParseResult.validateSync(constructorSchema)(props) + } + super(props, true) + } + + // ---------------- + // Schema interface + // ---------------- + + static [TypeId] = variance + + static get ast(): AST.AST { + let out = astCache.get(this) + if (out) { + return out + } + + const declaration: Schema.Any = declare( + [schema], + { + decode: () => (input, _, ast) => + input instanceof this || fallbackInstanceOf(input) + ? ParseResult.succeed(input) + : ParseResult.fail(new ParseResult.Type(ast, input)), + encode: () => (input, options) => + input instanceof this + ? ParseResult.succeed(input) + : ParseResult.map( + ParseResult.encodeUnknown(typeSide)(input, options), + (props) => new this(props, true) + ) + }, + { + identifier, + pretty: (pretty) => (self: any) => `${identifier}(${pretty(self)})`, + // @ts-expect-error + arbitrary: (arb) => (fc) => arb(fc).map((props) => new this(props)), + equivalence: identity, + [AST.SurrogateAnnotationId]: declarationSurrogate.ast, + ...typeAnnotations + } + ) + + out = transform( + encodedSide, + declaration, + { + strict: true, + decode: (i) => new this(i, true), + encode: identity + } + ).annotations({ + [AST.SurrogateAnnotationId]: transformationSurrogate.ast, + ...transformationAnnotations + }).ast + + astCache.set(this, out) + + return out + } + + static pipe() { + return pipeArguments(this, arguments) + } + + static annotations(annotations: Annotations.Schema) { + return make(this.ast).annotations(annotations) + } + + static toString() { + return `(${String(encodedSide)} <-> ${identifier})` + } + + // ---------------- + // Class interface + // ---------------- + + static make(...args: Array) { + return new this(...args) + } + + static fields = { ...fields } + + static identifier = identifier + + static extend(identifier: string) { + return ( + newFieldsOr: NewFields | HasFields, + annotations?: ClassAnnotations>> + ) => { + const newFields = getFieldsFromFieldsOr(newFieldsOr) + const newSchema = getSchemaFromFieldsOr(newFieldsOr) + const extendedFields = extendFields(fields, newFields) + return makeClass({ + kind, + identifier, + schema: extend(schema, newSchema), + fields: extendedFields, + Base: this, + annotations + }) + } + } + + static transformOrFail(identifier: string) { + return ( + newFieldsOr: NewFields, + options: any, + annotations?: ClassAnnotations>> + ) => { + const transformedFields: Struct.Fields = extendFields(fields, newFieldsOr) + return makeClass({ + kind, + identifier, + schema: transformOrFail( + schema, + typeSchema(Struct(transformedFields)), + options + ), + fields: transformedFields, + Base: this, + annotations + }) + } + } + + static transformOrFailFrom(identifier: string) { + return ( + newFields: NewFields, + options: any, + annotations?: ClassAnnotations>> + ) => { + const transformedFields: Struct.Fields = extendFields(fields, newFields) + return makeClass({ + kind, + identifier, + schema: transformOrFail( + encodedSchema(schema), + Struct(transformedFields), + options + ), + fields: transformedFields, + Base: this, + annotations + }) + } + } + + // ---------------- + // other + // ---------------- + + get [classSymbol]() { + return classSymbol + } + } + if (disableToString !== true) { + Object.defineProperty(klass.prototype, "toString", { + value() { + return `${identifier}({ ${ + Reflect.ownKeys(fields).map((p: any) => + `${Inspectable.formatPropertyKey(p)}: ${Inspectable.formatUnknown(this[p])}` + ) + .join(", ") + } })` + }, + configurable: true, + writable: true + }) + } + return klass +} + +/** + * @category FiberId + * @since 3.10.0 + */ +export type FiberIdEncoded = + | { + readonly _tag: "Composite" + readonly left: FiberIdEncoded + readonly right: FiberIdEncoded + } + | { + readonly _tag: "None" + } + | { + readonly _tag: "Runtime" + readonly id: number + readonly startTimeMillis: number + } + +const FiberIdNoneEncoded = Struct({ + _tag: Literal("None") +}).annotations({ identifier: "FiberIdNoneEncoded" }) + +const FiberIdRuntimeEncoded = Struct({ + _tag: Literal("Runtime"), + id: Int, + startTimeMillis: Int +}).annotations({ identifier: "FiberIdRuntimeEncoded" }) + +const FiberIdCompositeEncoded = Struct({ + _tag: Literal("Composite"), + left: suspend(() => FiberIdEncoded), + right: suspend(() => FiberIdEncoded) +}).annotations({ identifier: "FiberIdCompositeEncoded" }) + +const FiberIdEncoded: Schema = Union( + FiberIdNoneEncoded, + FiberIdRuntimeEncoded, + FiberIdCompositeEncoded +).annotations({ identifier: "FiberIdEncoded" }) + +const fiberIdArbitrary: LazyArbitrary = (fc) => + fc.letrec((tie) => ({ + None: fc.record({ _tag: fc.constant("None" as const) }), + Runtime: fc.record({ _tag: fc.constant("Runtime" as const), id: fc.integer(), startTimeMillis: fc.integer() }), + Composite: fc.record({ _tag: fc.constant("Composite" as const), left: tie("FiberId"), right: tie("FiberId") }), + FiberId: fc.oneof(tie("None"), tie("Runtime"), tie("Composite")) as any as fastCheck_.Arbitrary + })).FiberId.map(fiberIdDecode) + +const fiberIdPretty: pretty_.Pretty = (fiberId) => { + switch (fiberId._tag) { + case "None": + return "FiberId.none" + case "Runtime": + return `FiberId.runtime(${fiberId.id}, ${fiberId.startTimeMillis})` + case "Composite": + return `FiberId.composite(${fiberIdPretty(fiberId.right)}, ${fiberIdPretty(fiberId.left)})` + } +} + +/** + * @category FiberId constructors + * @since 3.10.0 + */ +export class FiberIdFromSelf extends declare( + fiberId_.isFiberId, + { + typeConstructor: { _tag: "effect/FiberId" }, + identifier: "FiberIdFromSelf", + pretty: () => fiberIdPretty, + arbitrary: () => fiberIdArbitrary + } +) {} + +const fiberIdDecode = (input: FiberIdEncoded): fiberId_.FiberId => { + switch (input._tag) { + case "None": + return fiberId_.none + case "Runtime": + return fiberId_.runtime(input.id, input.startTimeMillis) + case "Composite": + return fiberId_.composite(fiberIdDecode(input.left), fiberIdDecode(input.right)) + } +} + +const fiberIdEncode = (input: fiberId_.FiberId): FiberIdEncoded => { + switch (input._tag) { + case "None": + return { _tag: "None" } + case "Runtime": + return { _tag: "Runtime", id: input.id, startTimeMillis: input.startTimeMillis } + case "Composite": + return { + _tag: "Composite", + left: fiberIdEncode(input.left), + right: fiberIdEncode(input.right) + } + } +} + +/** + * @category FiberId transformations + * @since 3.10.0 + */ +export class FiberId extends transform( + FiberIdEncoded, + FiberIdFromSelf, + { + strict: true, + decode: (i) => fiberIdDecode(i), + encode: (a) => fiberIdEncode(a) + } +).annotations({ identifier: "FiberId" }) {} + +/** + * @category Cause utils + * @since 3.10.0 + */ +export type CauseEncoded = + | { + readonly _tag: "Empty" + } + | { + readonly _tag: "Fail" + readonly error: E + } + | { + readonly _tag: "Die" + readonly defect: D + } + | { + readonly _tag: "Interrupt" + readonly fiberId: FiberIdEncoded + } + | { + readonly _tag: "Sequential" + readonly left: CauseEncoded + readonly right: CauseEncoded + } + | { + readonly _tag: "Parallel" + readonly left: CauseEncoded + readonly right: CauseEncoded + } + +const causeDieEncoded = (defect: Defect) => + Struct({ + _tag: Literal("Die"), + defect + }) + +const CauseEmptyEncoded = Struct({ + _tag: Literal("Empty") +}) + +const causeFailEncoded = (error: E) => + Struct({ + _tag: Literal("Fail"), + error + }) + +const CauseInterruptEncoded = Struct({ + _tag: Literal("Interrupt"), + fiberId: FiberIdEncoded +}) + +let causeEncodedId = 0 + +const causeEncoded = ( + error: E, + defect: D +): SchemaClass< + CauseEncoded, Schema.Type>, + CauseEncoded, Schema.Encoded>, + Schema.Context | Schema.Context +> => { + const error_ = asSchema(error) + const defect_ = asSchema(defect) + const suspended = suspend((): Schema< + CauseEncoded, Schema.Type>, + CauseEncoded, Schema.Encoded>, + Schema.Context | Schema.Context + > => out) + const out = Union( + CauseEmptyEncoded, + causeFailEncoded(error_), + causeDieEncoded(defect_), + CauseInterruptEncoded, + Struct({ + _tag: Literal("Sequential"), + left: suspended, + right: suspended + }), + Struct({ + _tag: Literal("Parallel"), + left: suspended, + right: suspended + }) + ).annotations({ + title: `CauseEncoded<${format(error)}>`, + [AST.JSONIdentifierAnnotationId]: `CauseEncoded${causeEncodedId++}` + }) + return out +} + +const causeArbitrary = ( + error: LazyArbitrary, + defect: LazyArbitrary +): LazyArbitrary> => +(fc) => + fc.letrec((tie) => ({ + Empty: fc.record({ _tag: fc.constant("Empty" as const) }), + Fail: fc.record({ _tag: fc.constant("Fail" as const), error: error(fc) }), + Die: fc.record({ _tag: fc.constant("Die" as const), defect: defect(fc) }), + Interrupt: fc.record({ _tag: fc.constant("Interrupt" as const), fiberId: fiberIdArbitrary(fc) }), + Sequential: fc.record({ _tag: fc.constant("Sequential" as const), left: tie("Cause"), right: tie("Cause") }), + Parallel: fc.record({ _tag: fc.constant("Parallel" as const), left: tie("Cause"), right: tie("Cause") }), + Cause: fc.oneof( + tie("Empty"), + tie("Fail"), + tie("Die"), + tie("Interrupt"), + tie("Sequential"), + tie("Parallel") + ) as any as fastCheck_.Arbitrary> + })).Cause.map(causeDecode) + +const causePretty = (error: pretty_.Pretty): pretty_.Pretty> => (cause) => { + const f = (cause: cause_.Cause): string => { + switch (cause._tag) { + case "Empty": + return "Cause.empty" + case "Fail": + return `Cause.fail(${error(cause.error)})` + case "Die": + return `Cause.die(${cause_.pretty(cause)})` + case "Interrupt": + return `Cause.interrupt(${fiberIdPretty(cause.fiberId)})` + case "Sequential": + return `Cause.sequential(${f(cause.left)}, ${f(cause.right)})` + case "Parallel": + return `Cause.parallel(${f(cause.left)}, ${f(cause.right)})` + } + } + return f(cause) +} + +const causeParse = ( + decodeUnknown: ParseResult.DecodeUnknown, R> +): ParseResult.DeclarationDecodeUnknown, R> => +(u, options, ast) => + cause_.isCause(u) ? + toComposite(decodeUnknown(causeEncode(u), options), causeDecode, ast, u) + : ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface CauseFromSelf extends + AnnotableDeclare< + CauseFromSelf, + cause_.Cause>, + cause_.Cause>, + [E, D] + > +{} + +/** + * @category Cause transformations + * @since 3.10.0 + */ +export const CauseFromSelf = ({ defect, error }: { + readonly error: E + readonly defect: D +}): CauseFromSelf => { + return declare( + [error, defect], + { + decode: (error, defect) => causeParse(ParseResult.decodeUnknown(causeEncoded(error, defect))), + encode: (error, defect) => causeParse(ParseResult.encodeUnknown(causeEncoded(error, defect))) + }, + { + typeConstructor: { _tag: "effect/Cause" }, + title: `Cause<${error.ast}>`, + pretty: causePretty, + arbitrary: causeArbitrary + } + ) +} + +function causeDecode(cause: CauseEncoded): cause_.Cause { + switch (cause._tag) { + case "Empty": + return cause_.empty + case "Fail": + return cause_.fail(cause.error) + case "Die": + return cause_.die(cause.defect) + case "Interrupt": + return cause_.interrupt(fiberIdDecode(cause.fiberId)) + case "Sequential": + return cause_.sequential(causeDecode(cause.left), causeDecode(cause.right)) + case "Parallel": + return cause_.parallel(causeDecode(cause.left), causeDecode(cause.right)) + } +} + +function causeEncode(cause: cause_.Cause): CauseEncoded { + switch (cause._tag) { + case "Empty": + return { _tag: "Empty" } + case "Fail": + return { _tag: "Fail", error: cause.error } + case "Die": + return { _tag: "Die", defect: cause.defect } + case "Interrupt": + return { _tag: "Interrupt", fiberId: cause.fiberId } + case "Sequential": + return { + _tag: "Sequential", + left: causeEncode(cause.left), + right: causeEncode(cause.right) + } + case "Parallel": + return { + _tag: "Parallel", + left: causeEncode(cause.left), + right: causeEncode(cause.right) + } + } +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Cause extends + transform< + SchemaClass< + CauseEncoded, Schema.Type>, + CauseEncoded, Schema.Encoded>, + Schema.Context | Schema.Context + >, + CauseFromSelf>, SchemaClass>> + > +{} + +/** + * @category Cause transformations + * @since 3.10.0 + */ +export const Cause = ({ defect, error }: { + readonly error: E + readonly defect: D +}): Cause => { + const error_ = asSchema(error) + const defect_ = asSchema(defect) + const out = transform( + causeEncoded(error_, defect_), + CauseFromSelf({ error: typeSchema(error_), defect: typeSchema(defect_) }), + { + strict: false, + decode: (i) => causeDecode(i), + encode: (a) => causeEncode(a) + } + ) + return out as any +} + +/** + * Defines a schema for handling JavaScript errors (`Error` instances) and other types of defects. + * It decodes objects into Error instances if they match the expected structure (i.e., have a `message` and optionally a `name` and `stack`), + * or converts other values to their string representations. + * + * When encoding, it converts `Error` instances back into plain objects containing only the error's name and message, + * or other values into their string forms. + * + * This is useful for serializing and deserializing errors across network boundaries where error objects do not natively serialize. + * + * @category defect + * @since 3.10.0 + */ +export class Defect extends transform( + Unknown, + Unknown, + { + strict: true, + decode: (i) => { + if (Predicate.isObject(i) && "message" in i && typeof i.message === "string") { + const err = new Error(i.message, { cause: i }) + if ("name" in i && typeof i.name === "string") { + err.name = i.name + } + err.stack = "stack" in i && typeof i.stack === "string" ? i.stack : "" + return err + } + return internalCause_.prettyErrorMessage(i) + }, + encode: (a) => { + if (a instanceof Error) { + return { + name: a.name, + message: a.message + // no stack because of security reasons + } + } + return internalCause_.prettyErrorMessage(a) + } + } +).annotations({ identifier: "Defect" }) {} + +/** + * @category Exit utils + * @since 3.10.0 + */ +export type ExitEncoded = + | { + readonly _tag: "Failure" + readonly cause: CauseEncoded + } + | { + readonly _tag: "Success" + readonly value: A + } + +const exitFailureEncoded = ( + error: E, + defect: D +) => + Struct({ + _tag: Literal("Failure"), + cause: causeEncoded(error, defect) + }) + +const exitSuccessEncoded = ( + value: A +) => + Struct({ + _tag: Literal("Success"), + value + }) + +const exitEncoded = ( + value: A, + error: E, + defect: D +) => { + return Union( + exitFailureEncoded(error, defect), + exitSuccessEncoded(value) + ).annotations({ + title: `ExitEncoded<${format(value)}, ${format(error)}, ${format(defect)}>` + }) +} + +const exitDecode = (input: ExitEncoded): exit_.Exit => { + switch (input._tag) { + case "Failure": + return exit_.failCause(causeDecode(input.cause)) + case "Success": + return exit_.succeed(input.value) + } +} + +const exitArbitrary = ( + value: LazyArbitrary, + error: LazyArbitrary, + defect: LazyArbitrary +): LazyArbitrary> => +(fc) => + fc.oneof( + fc.record({ _tag: fc.constant("Failure" as const), cause: causeArbitrary(error, defect)(fc) }), + fc.record({ _tag: fc.constant("Success" as const), value: value(fc) }) + ).map(exitDecode) + +const exitPretty = + (value: pretty_.Pretty, error: pretty_.Pretty): pretty_.Pretty> => (exit) => + exit._tag === "Failure" + ? `Exit.failCause(${causePretty(error)(exit.cause)})` + : `Exit.succeed(${value(exit.value)})` + +const exitParse = ( + decodeUnknownValue: ParseResult.DecodeUnknown, + decodeUnknownCause: ParseResult.DecodeUnknown, ER> +): ParseResult.DeclarationDecodeUnknown, ER | R> => +(u, options, ast) => + exit_.isExit(u) ? + exit_.match(u, { + onFailure: (cause) => toComposite(decodeUnknownCause(cause, options), exit_.failCause, ast, u), + onSuccess: (value) => toComposite(decodeUnknownValue(value, options), exit_.succeed, ast, u) + }) + : ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface ExitFromSelf + extends + AnnotableDeclare< + ExitFromSelf, + exit_.Exit, Schema.Type>, + exit_.Exit, Schema.Encoded>, + [A, E, D] + > +{} + +/** + * @category Exit transformations + * @since 3.10.0 + */ +export const ExitFromSelf = ( + { defect, failure, success }: { + readonly failure: E + readonly success: A + readonly defect: D + } +): ExitFromSelf => + declare( + [success, failure, defect], + { + decode: (success, failure, defect) => + exitParse( + ParseResult.decodeUnknown(success), + ParseResult.decodeUnknown(CauseFromSelf({ error: failure, defect })) + ), + encode: (success, failure, defect) => + exitParse( + ParseResult.encodeUnknown(success), + ParseResult.encodeUnknown(CauseFromSelf({ error: failure, defect })) + ) + }, + { + typeConstructor: { _tag: "effect/Exit" }, + title: `Exit<${success.ast}, ${failure.ast}>`, + pretty: exitPretty, + arbitrary: exitArbitrary + } + ) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface Exit extends + transform< + Union<[ + Struct<{ + _tag: Literal<["Failure"]> + cause: SchemaClass< + CauseEncoded, Schema.Type>, + CauseEncoded, Schema.Encoded>, + Schema.Context | Schema.Context + > + }>, + Struct<{ + _tag: Literal<["Success"]> + value: A + }> + ]>, + ExitFromSelf>, SchemaClass>, SchemaClass>> + > +{} + +/** + * @category Exit transformations + * @since 3.10.0 + */ +export const Exit = ( + { defect, failure, success }: { + readonly failure: E + readonly success: A + readonly defect: D + } +): Exit => { + const success_ = asSchema(success) + const failure_ = asSchema(failure) + const defect_ = asSchema(defect) + const out = transform( + exitEncoded(success_, failure_, defect_), + ExitFromSelf({ failure: typeSchema(failure_), success: typeSchema(success_), defect: typeSchema(defect_) }), + { + strict: false, + decode: (i) => exitDecode(i), + encode: (a) => + a._tag === "Failure" + ? { _tag: "Failure", cause: a.cause } as const + : { _tag: "Success", value: a.value } as const + } + ) + return out as any +} + +const hashSetArbitrary = + (item: LazyArbitrary, ctx: ArbitraryGenerationContext): LazyArbitrary> => (fc) => { + const items = fc.array(item(fc)) + return (ctx.depthIdentifier !== undefined ? fc.oneof(ctx, fc.constant([]), items) : items).map( + hashSet_.fromIterable + ) + } + +const hashSetPretty = (item: pretty_.Pretty): pretty_.Pretty> => (set) => + `HashSet(${Array.from(set).map((a) => item(a)).join(", ")})` + +const hashSetEquivalence = ( + item: Equivalence.Equivalence +): Equivalence.Equivalence> => { + const arrayEquivalence = array_.getEquivalence(item) + return Equivalence.make((a, b) => arrayEquivalence(Array.from(a), Array.from(b))) +} + +const hashSetParse = ( + decodeUnknown: ParseResult.DecodeUnknown, R> +): ParseResult.DeclarationDecodeUnknown, R> => +(u, options, ast) => + hashSet_.isHashSet(u) ? + toComposite(decodeUnknown(Array.from(u), options), hashSet_.fromIterable, ast, u) + : ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface HashSetFromSelf extends + AnnotableDeclare< + HashSetFromSelf, + hashSet_.HashSet>, + hashSet_.HashSet>, + [Value] + > +{} + +/** + * @category HashSet transformations + * @since 3.10.0 + */ +export const HashSetFromSelf = ( + value: Value +): HashSetFromSelf => { + return declare( + [value], + { + decode: (item) => hashSetParse(ParseResult.decodeUnknown(Array$(item))), + encode: (item) => hashSetParse(ParseResult.encodeUnknown(Array$(item))) + }, + { + typeConstructor: { _tag: "effect/HashSet" }, + description: `HashSet<${format(value)}>`, + pretty: hashSetPretty, + arbitrary: hashSetArbitrary, + equivalence: hashSetEquivalence + } + ) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface HashSet + extends transform, HashSetFromSelf>>> +{} + +/** + * @category HashSet transformations + * @since 3.10.0 + */ +export function HashSet(value: Value): HashSet { + return transform( + Array$(value), + HashSetFromSelf(typeSchema(asSchema(value))), + { + strict: true, + decode: (i) => hashSet_.fromIterable(i), + encode: (a) => Array.from(a) + } + ) +} + +const hashMapArbitrary = ( + key: LazyArbitrary, + value: LazyArbitrary, + ctx: ArbitraryGenerationContext +): LazyArbitrary> => +(fc) => { + const items = fc.array(fc.tuple(key(fc), value(fc))) + return (ctx.depthIdentifier !== undefined ? fc.oneof(ctx, fc.constant([]), items) : items).map(hashMap_.fromIterable) +} + +const hashMapPretty = ( + key: pretty_.Pretty, + value: pretty_.Pretty +): pretty_.Pretty> => +(map) => + `HashMap([${ + Array.from(map) + .map(([k, v]) => `[${key(k)}, ${value(v)}]`) + .join(", ") + }])` + +const hashMapEquivalence = ( + key: Equivalence.Equivalence, + value: Equivalence.Equivalence +): Equivalence.Equivalence> => { + const arrayEquivalence = array_.getEquivalence( + Equivalence.make<[K, V]>(([ka, va], [kb, vb]) => key(ka, kb) && value(va, vb)) + ) + return Equivalence.make((a, b) => arrayEquivalence(Array.from(a), Array.from(b))) +} + +const hashMapParse = ( + decodeUnknown: ParseResult.DecodeUnknown, R> +): ParseResult.DeclarationDecodeUnknown, R> => +(u, options, ast) => + hashMap_.isHashMap(u) ? + toComposite(decodeUnknown(Array.from(u), options), hashMap_.fromIterable, ast, u) + : ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface HashMapFromSelf extends + AnnotableDeclare< + HashMapFromSelf, + hashMap_.HashMap, Schema.Type>, + hashMap_.HashMap, Schema.Encoded>, + [K, V] + > +{} + +/** + * @category HashMap transformations + * @since 3.10.0 + */ +export const HashMapFromSelf = ({ key, value }: { + readonly key: K + readonly value: V +}): HashMapFromSelf => { + return declare( + [key, value], + { + decode: (key, value) => hashMapParse(ParseResult.decodeUnknown(Array$(Tuple(key, value)))), + encode: (key, value) => hashMapParse(ParseResult.encodeUnknown(Array$(Tuple(key, value)))) + }, + { + typeConstructor: { _tag: "effect/HashMap" }, + description: `HashMap<${format(key)}, ${format(value)}>`, + pretty: hashMapPretty, + arbitrary: hashMapArbitrary, + equivalence: hashMapEquivalence + } + ) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface HashMap + extends transform>, HashMapFromSelf>, SchemaClass>>> +{} + +/** + * @category HashMap transformations + * @since 3.10.0 + */ +export const HashMap = ({ key, value }: { + readonly key: K + readonly value: V +}): HashMap => { + return transform( + Array$(Tuple(key, value)), + HashMapFromSelf({ key: typeSchema(asSchema(key)), value: typeSchema(asSchema(value)) }), + { + strict: true, + decode: (i) => hashMap_.fromIterable(i), + encode: (a) => Array.from(a) + } + ) +} + +const listArbitrary = + (item: LazyArbitrary, ctx: ArbitraryGenerationContext): LazyArbitrary> => (fc) => { + const items = fc.array(item(fc)) + return (ctx.depthIdentifier !== undefined ? fc.oneof(ctx, fc.constant([]), items) : items).map(list_.fromIterable) + } + +const listPretty = (item: pretty_.Pretty): pretty_.Pretty> => (set) => + `List(${Array.from(set).map((a) => item(a)).join(", ")})` + +const listEquivalence = ( + item: Equivalence.Equivalence +): Equivalence.Equivalence> => { + const arrayEquivalence = array_.getEquivalence(item) + return Equivalence.make((a, b) => arrayEquivalence(Array.from(a), Array.from(b))) +} + +const listParse = ( + decodeUnknown: ParseResult.DecodeUnknown, R> +): ParseResult.DeclarationDecodeUnknown, R> => +(u, options, ast) => + list_.isList(u) ? + toComposite(decodeUnknown(Array.from(u), options), list_.fromIterable, ast, u) + : ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface ListFromSelf extends + AnnotableDeclare< + ListFromSelf, + list_.List>, + list_.List>, + [Value] + > +{} + +/** + * @category List transformations + * @since 3.10.0 + */ +export const ListFromSelf = ( + value: Value +): ListFromSelf => { + return declare( + [value], + { + decode: (item) => listParse(ParseResult.decodeUnknown(Array$(item))), + encode: (item) => listParse(ParseResult.encodeUnknown(Array$(item))) + }, + { + typeConstructor: { _tag: "effect/List" }, + description: `List<${format(value)}>`, + pretty: listPretty, + arbitrary: listArbitrary, + equivalence: listEquivalence + } + ) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface List + extends transform, ListFromSelf>>> +{} + +/** + * @category List transformations + * @since 3.10.0 + */ +export function List(value: Value): List { + return transform( + Array$(value), + ListFromSelf(typeSchema(asSchema(value))), + { + strict: true, + decode: (i) => list_.fromIterable(i), + encode: (a) => Array.from(a) + } + ) +} + +const sortedSetArbitrary = ( + item: LazyArbitrary, + ord: Order.Order, + ctx: ArbitraryGenerationContext +): LazyArbitrary> => +(fc) => { + const items = fc.array(item(fc)) + return (ctx.depthIdentifier !== undefined ? fc.oneof(ctx, fc.constant([]), items) : items).map((as) => + sortedSet_.fromIterable(as, ord) + ) +} + +const sortedSetPretty = (item: pretty_.Pretty): pretty_.Pretty> => (set) => + `new SortedSet([${Array.from(sortedSet_.values(set)).map((a) => item(a)).join(", ")}])` + +const sortedSetParse = ( + decodeUnknown: ParseResult.DecodeUnknown, R>, + ord: Order.Order +): ParseResult.DeclarationDecodeUnknown, R> => +(u, options, ast) => + sortedSet_.isSortedSet(u) ? + toComposite( + decodeUnknown(Array.from(sortedSet_.values(u)), options), + (as): sortedSet_.SortedSet => sortedSet_.fromIterable(as, ord), + ast, + u + ) + : ParseResult.fail(new ParseResult.Type(ast, u)) + +/** + * @category api interface + * @since 3.10.0 + */ +export interface SortedSetFromSelf extends + AnnotableDeclare< + SortedSetFromSelf, + sortedSet_.SortedSet>, + sortedSet_.SortedSet>, + [Value] + > +{} + +/** + * @category SortedSet transformations + * @since 3.10.0 + */ +export const SortedSetFromSelf = ( + value: Value, + ordA: Order.Order>, + ordI: Order.Order> +): SortedSetFromSelf => { + return declare( + [value], + { + decode: (item) => sortedSetParse(ParseResult.decodeUnknown(Array$(item)), ordA), + encode: (item) => sortedSetParse(ParseResult.encodeUnknown(Array$(item)), ordI) + }, + { + typeConstructor: { _tag: "effect/SortedSet" }, + description: `SortedSet<${format(value)}>`, + pretty: sortedSetPretty, + arbitrary: (arb, ctx) => sortedSetArbitrary(arb, ordA, ctx), + equivalence: () => sortedSet_.getEquivalence>() + } + ) +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface SortedSet + extends transform, SortedSetFromSelf>>> +{} + +/** + * @category SortedSet transformations + * @since 3.10.0 + */ +export function SortedSet( + value: Value, + ordA: Order.Order> +): SortedSet { + const to = typeSchema(asSchema(value)) + return transform( + Array$(value), + SortedSetFromSelf(to, ordA, ordA), + { + strict: true, + decode: (i) => sortedSet_.fromIterable(i, ordA), + encode: (a) => Array.from(sortedSet_.values(a)) + } + ) +} + +/** + * Converts an arbitrary value to a `boolean` by testing whether it is truthy. + * Uses `!!val` to coerce the value to a `boolean`. + * + * @see https://developer.mozilla.org/docs/Glossary/Truthy + * + * @category boolean constructors + * @since 3.10.0 + */ +export class BooleanFromUnknown extends transform( + Unknown, + Boolean$, + { + strict: true, + decode: (i) => Predicate.isTruthy(i), + encode: identity + } +).annotations({ identifier: "BooleanFromUnknown" }) {} + +/** + * Converts an `string` value into its corresponding `boolean` + * ("true" as `true` and "false" as `false`). + * + * @category boolean transformations + * @since 3.11.0 + */ +export class BooleanFromString extends transform( + Literal("true", "false").annotations({ description: "a string to be decoded into a boolean" }), + Boolean$, + { + strict: true, + decode: (i) => i === "true", + encode: (a) => a ? "true" : "false" + } +).annotations({ identifier: "BooleanFromString" }) {} + +/** + * @category Config validations + * @since 3.10.0 + */ +export const Config = (name: string, schema: Schema): config_.Config => { + const decodeUnknownEither = ParseResult.decodeUnknownEither(schema) + return config_.string(name).pipe( + config_.mapOrFail((s) => + decodeUnknownEither(s).pipe( + either_.mapLeft((error) => configError_.InvalidData([], ParseResult.TreeFormatter.formatIssueSync(error))) + ) + ) + ) +} + +// --------------------------------------------- +// Serializable +// --------------------------------------------- + +/** + * @since 3.10.0 + * @category symbol + */ +export const symbolSerializable: unique symbol = Symbol.for( + "effect/Schema/Serializable/symbol" +) + +/** + * The `Serializable` trait allows objects to define their own schema for + * serialization. + * + * @since 3.10.0 + * @category model + */ +export interface Serializable { + readonly [symbolSerializable]: Schema +} + +/** + * @since 3.10.0 + * @category model + */ +export declare namespace Serializable { + /** + * @since 3.10.0 + */ + export type Type = T extends Serializable ? A : never + /** + * @since 3.10.0 + */ + export type Encoded = T extends Serializable ? I : never + /** + * @since 3.10.0 + */ + export type Context = T extends Serializable ? R : never + /** + * @since 3.10.0 + */ + export type Any = Serializable + /** + * @since 3.10.0 + */ + export type All = + | Any + | Serializable + | Serializable + | Serializable +} + +/** + * @since 3.10.0 + */ +export const asSerializable = ( + serializable: S +): Serializable, Serializable.Encoded, Serializable.Context> => serializable as any + +/** + * @since 3.10.0 + * @category accessor + */ +export const serializableSchema = (self: Serializable): Schema => self[symbolSerializable] + +/** + * @since 3.10.0 + * @category encoding + */ +export const serialize = (self: Serializable): Effect.Effect => + encodeUnknown(self[symbolSerializable])(self) + +/** + * @since 3.10.0 + * @category decoding + */ +export const deserialize: { + /** + * @since 3.10.0 + * @category decoding + */ + (value: unknown): (self: Serializable) => Effect.Effect + /** + * @since 3.10.0 + * @category decoding + */ + (self: Serializable, value: unknown): Effect.Effect +} = dual( + 2, + (self: Serializable, value: unknown): Effect.Effect => + decodeUnknown(self[symbolSerializable])(value) +) + +/** + * @since 3.10.0 + * @category symbol + */ +export const symbolWithResult: unique symbol = Symbol.for( + "effect/Schema/Serializable/symbolResult" +) + +/** + * The `WithResult` trait is designed to encapsulate the outcome of an + * operation, distinguishing between success and failure cases. Each case is + * associated with a schema that defines the structure and types of the success + * or failure data. + * + * @since 3.10.0 + * @category model + */ +export interface WithResult { + readonly [symbolWithResult]: { + readonly success: Schema + readonly failure: Schema + } +} + +/** + * @since 3.10.0 + * @category model + */ +export declare namespace WithResult { + /** + * @since 3.10.0 + */ + export type Success = T extends WithResult ? _A : never + /** + * @since 3.10.0 + */ + export type SuccessEncoded = T extends WithResult ? _I : never + /** + * @since 3.10.0 + */ + export type Failure = T extends WithResult ? _E : never + /** + * @since 3.10.0 + */ + export type FailureEncoded = T extends WithResult ? _EI : never + + /** + * @since 3.10.0 + */ + export type Context = T extends WithResult ? R : never + /** + * @since 3.10.0 + */ + export type Any = WithResult + /** + * @since 3.10.0 + */ + export type All = + | Any + | WithResult +} + +/** + * @since 3.10.0 + */ +export const asWithResult = ( + withExit: WR +): WithResult< + WithResult.Success, + WithResult.SuccessEncoded, + WithResult.Failure, + WithResult.FailureEncoded, + WithResult.Context +> => withExit as any + +/** + * @since 3.10.0 + * @category accessor + */ +export const failureSchema = (self: WithResult): Schema => + self[symbolWithResult].failure + +/** + * @since 3.10.0 + * @category accessor + */ +export const successSchema = (self: WithResult): Schema => + self[symbolWithResult].success + +const exitSchemaCache = globalValue( + "effect/Schema/Serializable/exitSchemaCache", + () => new WeakMap>() +) + +/** + * @since 3.10.0 + * @category accessor + */ +export const exitSchema = (self: WithResult): Schema< + exit_.Exit, + ExitEncoded, + R +> => { + const proto = Object.getPrototypeOf(self) + if (!(symbolWithResult in proto)) { + return Exit({ + failure: failureSchema(self), + success: successSchema(self), + defect: Defect + }) + } + let schema = exitSchemaCache.get(proto) + if (schema === undefined) { + schema = Exit({ + failure: failureSchema(self), + success: successSchema(self), + defect: Defect + }) + exitSchemaCache.set(proto, schema) + } + return schema +} + +/** + * @since 3.10.0 + * @category encoding + */ +export const serializeFailure: { + /** + * @since 3.10.0 + * @category encoding + */ + (value: FA): ( + self: WithResult + ) => Effect.Effect + /** + * @since 3.10.0 + * @category encoding + */ + (self: WithResult, value: FA): Effect.Effect +} = dual( + 2, + (self: WithResult, value: FA): Effect.Effect => + encode(self[symbolWithResult].failure)(value) +) + +/** + * @since 3.10.0 + * @category decoding + */ +export const deserializeFailure: { + /** + * @since 3.10.0 + * @category decoding + */ + (value: unknown): (self: WithResult) => Effect.Effect + /** + * @since 3.10.0 + * @category decoding + */ + (self: WithResult, value: unknown): Effect.Effect +} = dual( + 2, + ( + self: WithResult, + value: unknown + ): Effect.Effect => decodeUnknown(self[symbolWithResult].failure)(value) +) + +/** + * @since 3.10.0 + * @category encoding + */ +export const serializeSuccess: { + /** + * @since 3.10.0 + * @category encoding + */ + (value: SA): ( + self: WithResult + ) => Effect.Effect + /** + * @since 3.10.0 + * @category encoding + */ + (self: WithResult, value: SA): Effect.Effect +} = dual( + 2, + (self: WithResult, value: SA): Effect.Effect => + encode(self[symbolWithResult].success)(value) +) + +/** + * @since 3.10.0 + * @category decoding + */ +export const deserializeSuccess: { + /** + * @since 3.10.0 + * @category decoding + */ + (value: unknown): ( + self: WithResult + ) => Effect.Effect + /** + * @since 3.10.0 + * @category decoding + */ + (self: WithResult, value: unknown): Effect.Effect +} = dual( + 2, + ( + self: WithResult, + value: unknown + ): Effect.Effect => decodeUnknown(self[symbolWithResult].success)(value) +) + +/** + * @since 3.10.0 + * @category encoding + */ +export const serializeExit: { + /** + * @since 3.10.0 + * @category encoding + */ + (value: exit_.Exit): ( + self: WithResult + ) => Effect.Effect, ParseResult.ParseError, R> + /** + * @since 3.10.0 + * @category encoding + */ + (self: WithResult, value: exit_.Exit): Effect.Effect, ParseResult.ParseError, R> +} = dual(2, ( + self: WithResult, + value: exit_.Exit +): Effect.Effect, ParseResult.ParseError, R> => encode(exitSchema(self))(value)) + +/** + * @since 3.10.0 + * @category decoding + */ +export const deserializeExit: { + /** + * @since 3.10.0 + * @category decoding + */ + (value: unknown): ( + self: WithResult + ) => Effect.Effect, ParseResult.ParseError, R> + /** + * @since 3.10.0 + * @category decoding + */ + (self: WithResult, value: unknown): Effect.Effect, ParseResult.ParseError, R> +} = dual(2, ( + self: WithResult, + value: unknown +): Effect.Effect, ParseResult.ParseError, R> => decodeUnknown(exitSchema(self))(value)) + +// --------------------------------------------- +// SerializableWithResult +// --------------------------------------------- + +/** + * The `SerializableWithResult` trait is specifically designed to model remote + * procedures that require serialization of their input and output, managing + * both successful and failed outcomes. + * + * This trait combines functionality from both the `Serializable` and `WithResult` + * traits to handle data serialization and the bifurcation of operation results + * into success or failure categories. + * + * @since 3.10.0 + * @category model + */ +export interface SerializableWithResult< + A, + I, + R, + Success, + SuccessEncoded, + Failure, + FailureEncoded, + ResultR +> extends Serializable, WithResult {} + +/** + * @since 3.10.0 + * @category model + */ +export declare namespace SerializableWithResult { + /** + * @since 3.10.0 + */ + export type Context

= P extends + SerializableWithResult ? SR | RR + : never + /** + * @since 3.10.0 + */ + export type Any = SerializableWithResult + /** + * @since 3.10.0 + */ + export type All = + | Any + | SerializableWithResult +} + +/** + * @since 3.10.0 + */ +export const asSerializableWithResult = ( + procedure: SWR +): SerializableWithResult< + Serializable.Type, + Serializable.Encoded, + Serializable.Context, + WithResult.Success, + WithResult.SuccessEncoded, + WithResult.Failure, + WithResult.FailureEncoded, + WithResult.Context +> => procedure as any + +/** + * @since 3.10.0 + */ +export interface TaggedRequest< + Tag extends string, + A, + I, + R, + SuccessType, + SuccessEncoded, + FailureType, + FailureEncoded, + ResultR +> extends + Request.Request, + SerializableWithResult< + A, + I, + R, + SuccessType, + SuccessEncoded, + FailureType, + FailureEncoded, + ResultR + > +{ + readonly _tag: Tag +} + +/** + * @since 3.10.0 + */ +export declare namespace TaggedRequest { + /** + * @since 3.10.0 + */ + export type Any = TaggedRequest + /** + * @since 3.10.0 + */ + export type All = + | Any + | TaggedRequest +} + +/** + * @category api interface + * @since 3.10.0 + */ +export interface TaggedRequestClass< + Self, + Tag extends string, + Payload extends Struct.Fields, + Success extends Schema.All, + Failure extends Schema.All +> extends + Class< + Self, + Payload, + Struct.Encoded, + Struct.Context, + Struct.Constructor>, + TaggedRequest< + Tag, + Self, + Struct.Encoded, + Struct.Context, + Schema.Type, + Schema.Encoded, + Schema.Type, + Schema.Encoded, + Schema.Context | Schema.Context + >, + {} + > +{ + readonly _tag: Tag + readonly success: Success + readonly failure: Failure +} + +/** + * @example + * ```ts + * import { Schema } from "effect" + * + * class MyRequest extends Schema.TaggedRequest("MyRequest")("MyRequest", { + * failure: Schema.String, + * success: Schema.Number, + * payload: { id: Schema.String } + * }) {} + * ``` + * + * @category classes + * @since 3.10.0 + */ +export const TaggedRequest = + (identifier?: string) => + ( + tag: Tag, + options: { + failure: Failure + success: Success + payload: Payload + }, + annotations?: ClassAnnotations } & Payload>>> + ): [Self] extends [never] ? MissingSelfGeneric<"TaggedRequest", `"Tag", SuccessSchema, FailureSchema, `> + : TaggedRequestClass< + Self, + Tag, + { readonly _tag: tag } & Payload, + Success, + Failure + > => + { + const taggedFields = extendFields({ _tag: getClassTag(tag) }, options.payload) + return class TaggedRequestClass extends makeClass({ + kind: "TaggedRequest", + identifier: identifier ?? tag, + schema: Struct(taggedFields), + fields: taggedFields, + Base: Request.Class, + annotations + }) { + static _tag = tag + static success = options.success + static failure = options.failure + get [symbolSerializable]() { + return this.constructor + } + get [symbolWithResult]() { + return { + failure: options.failure, + success: options.success + } + } + } as any + } + +// ------------------------------------------------------------------------------------------------- +// Equivalence compiler +// ------------------------------------------------------------------------------------------------- + +/** + * Given a schema `Schema`, returns an `Equivalence` instance for `A`. + * + * @category Equivalence + * @since 3.10.0 + */ +export const equivalence = (schema: Schema): Equivalence.Equivalence => go(schema.ast, []) + +const getEquivalenceAnnotation = AST.getAnnotation>(AST.EquivalenceAnnotationId) + +const go = (ast: AST.AST, path: ReadonlyArray): Equivalence.Equivalence => { + const hook = getEquivalenceAnnotation(ast) + if (option_.isSome(hook)) { + switch (ast._tag) { + case "Declaration": + return hook.value(...ast.typeParameters.map((tp) => go(tp, path))) + case "Refinement": + return hook.value(go(ast.from, path)) + default: + return hook.value() + } + } + switch (ast._tag) { + case "NeverKeyword": + throw new Error(errors_.getEquivalenceUnsupportedErrorMessage(ast, path)) + case "Transformation": + return go(ast.to, path) + case "Declaration": + case "Literal": + case "StringKeyword": + case "TemplateLiteral": + case "UniqueSymbol": + case "SymbolKeyword": + case "UnknownKeyword": + case "AnyKeyword": + case "NumberKeyword": + case "BooleanKeyword": + case "BigIntKeyword": + case "UndefinedKeyword": + case "VoidKeyword": + case "Enums": + case "ObjectKeyword": + return Equal.equals + case "Refinement": + return go(ast.from, path) + case "Suspend": { + const get = util_.memoizeThunk(() => go(ast.f(), path)) + return (a, b) => get()(a, b) + } + case "TupleType": { + const elements = ast.elements.map((element, i) => go(element.type, path.concat(i))) + const rest = ast.rest.map((annotatedAST) => go(annotatedAST.type, path)) + return Equivalence.make((a, b) => { + if (!Array.isArray(a) || !Array.isArray(b)) { + return false + } + const len = a.length + if (len !== b.length) { + return false + } + // --------------------------------------------- + // handle elements + // --------------------------------------------- + let i = 0 + for (; i < Math.min(len, ast.elements.length); i++) { + if (!elements[i](a[i], b[i])) { + return false + } + } + // --------------------------------------------- + // handle rest element + // --------------------------------------------- + if (array_.isNonEmptyReadonlyArray(rest)) { + const [head, ...tail] = rest + for (; i < len - tail.length; i++) { + if (!head(a[i], b[i])) { + return false + } + } + // --------------------------------------------- + // handle post rest elements + // --------------------------------------------- + for (let j = 0; j < tail.length; j++) { + i += j + if (!tail[j](a[i], b[i])) { + return false + } + } + } + return true + }) + } + case "TypeLiteral": { + if (ast.propertySignatures.length === 0 && ast.indexSignatures.length === 0) { + return Equal.equals + } + const propertySignatures = ast.propertySignatures.map((ps) => go(ps.type, path.concat(ps.name))) + const indexSignatures = ast.indexSignatures.map((is) => go(is.type, path)) + return Equivalence.make((a, b) => { + if (!Predicate.isRecord(a) || !Predicate.isRecord(b)) { + return false + } + const aStringKeys = Object.keys(a) + const aSymbolKeys = Object.getOwnPropertySymbols(a) + // --------------------------------------------- + // handle property signatures + // --------------------------------------------- + for (let i = 0; i < propertySignatures.length; i++) { + const ps = ast.propertySignatures[i] + const name = ps.name + const aHas = Object.prototype.hasOwnProperty.call(a, name) + const bHas = Object.prototype.hasOwnProperty.call(b, name) + if (ps.isOptional) { + if (aHas !== bHas) { + return false + } + } + if (aHas && bHas && !propertySignatures[i](a[name], b[name])) { + return false + } + } + // --------------------------------------------- + // handle index signatures + // --------------------------------------------- + let bSymbolKeys: Array | undefined + let bStringKeys: Array | undefined + for (let i = 0; i < indexSignatures.length; i++) { + const is = ast.indexSignatures[i] + const encodedParameter = AST.getEncodedParameter(is.parameter) + const isSymbol = AST.isSymbolKeyword(encodedParameter) + if (isSymbol) { + bSymbolKeys = bSymbolKeys || Object.getOwnPropertySymbols(b) + if (aSymbolKeys.length !== bSymbolKeys.length) { + return false + } + } else { + bStringKeys = bStringKeys || Object.keys(b) + if (aStringKeys.length !== bStringKeys.length) { + return false + } + } + const aKeys = isSymbol ? aSymbolKeys : aStringKeys + for (let j = 0; j < aKeys.length; j++) { + const key = aKeys[j] + if ( + !Object.prototype.hasOwnProperty.call(b, key) || !indexSignatures[i](a[key], b[key]) + ) { + return false + } + } + } + return true + }) + } + case "Union": { + const searchTree = ParseResult.getSearchTree(ast.types, true) + const ownKeys = Reflect.ownKeys(searchTree.keys) + const len = ownKeys.length + return Equivalence.make((a, b) => { + let candidates: Array = [] + if (len > 0 && Predicate.isRecordOrArray(a)) { + for (let i = 0; i < len; i++) { + const name = ownKeys[i] + const buckets = searchTree.keys[name].buckets + if (Object.prototype.hasOwnProperty.call(a, name)) { + const literal = String(a[name]) + if (Object.prototype.hasOwnProperty.call(buckets, literal)) { + candidates = candidates.concat(buckets[literal]) + } + } + } + } + if (searchTree.otherwise.length > 0) { + candidates = candidates.concat(searchTree.otherwise) + } + const tuples = candidates.map((ast) => [go(ast, path), ParseResult.is({ ast } as any)] as const) + for (let i = 0; i < tuples.length; i++) { + const [equivalence, is] = tuples[i] + if (is(a) && is(b)) { + if (equivalence(a, b)) { + return true + } + } + } + return false + }) + } + } +} + +const SymbolStruct = TaggedStruct("symbol", { + key: String$ +}).annotations({ description: "an object to be decoded into a globally shared symbol" }) + +const SymbolFromStruct = transformOrFail( + SymbolStruct, + SymbolFromSelf, + { + strict: true, + decode: (i) => decodeSymbol(i.key), + encode: (a, _, ast) => ParseResult.map(encodeSymbol(a, ast), (key) => SymbolStruct.make({ key })) + } +) + +/** @ignore */ +class PropertyKey$ extends Union(String$, Number$, SymbolFromStruct).annotations({ identifier: "PropertyKey" }) {} + +export { + /** + * @since 3.12.5 + */ + PropertyKey$ as PropertyKey +} + +/** + * @category ArrayFormatter + * @since 3.12.5 + */ +export class ArrayFormatterIssue extends Struct({ + _tag: propertySignature(Literal( + "Pointer", + "Unexpected", + "Missing", + "Composite", + "Refinement", + "Transformation", + "Type", + "Forbidden" + )).annotations({ description: "The tag identifying the type of parse issue" }), + path: propertySignature(Array$(PropertyKey$)).annotations({ + description: "The path to the property where the issue occurred" + }), + message: propertySignature(String$).annotations({ description: "A descriptive message explaining the issue" }) +}).annotations({ + identifier: "ArrayFormatterIssue", + description: "Represents an issue returned by the ArrayFormatter formatter" +}) {} diff --git a/backend/node_modules/effect/src/Scope.ts b/backend/node_modules/effect/src/Scope.ts new file mode 100644 index 0000000000000000000000000000000000000000..1964eaf774245916501ebfb5ce70c4433012f166 --- /dev/null +++ b/backend/node_modules/effect/src/Scope.ts @@ -0,0 +1,240 @@ +/** + * @since 2.0.0 + */ + +import type * as Context from "./Context.js" +import type * as Effect from "./Effect.js" +import type * as ExecutionStrategy from "./ExecutionStrategy.js" +import type * as Exit from "./Exit.js" +import * as core from "./internal/core.js" +import * as fiberRuntime from "./internal/fiberRuntime.js" +import type { Pipeable } from "./Pipeable.js" + +/** + * A unique identifier for the `Scope` type. + * + * @since 2.0.0 + * @category symbols + */ +export const ScopeTypeId: unique symbol = core.ScopeTypeId + +/** + * The type of the unique identifier for `Scope`. + * + * @since 2.0.0 + * @category symbols + */ +export type ScopeTypeId = typeof ScopeTypeId + +/** + * A unique identifier for the `CloseableScope` type. + * + * @since 2.0.0 + * @category symbols + */ +export const CloseableScopeTypeId: unique symbol = core.CloseableScopeTypeId + +/** + * The type of the unique identifier for `CloseableScope`. + * + * @since 2.0.0 + * @category symbols + */ +export type CloseableScopeTypeId = typeof CloseableScopeTypeId + +/** + * Represents a scope that manages finalizers and can fork child scopes. + * + * @since 2.0.0 + * @category models + */ +export interface Scope extends Pipeable { + readonly [ScopeTypeId]: ScopeTypeId + /** + * The execution strategy for running finalizers in this scope. + */ + readonly strategy: ExecutionStrategy.ExecutionStrategy + /** + * Forks a new child scope with the specified execution strategy. The child scope + * will automatically be closed when this scope is closed. + * + * @internal + */ + fork(strategy: ExecutionStrategy.ExecutionStrategy): Effect.Effect + /** + * Adds a finalizer to this scope. The finalizer will be run when the scope is closed. + * + * @internal + */ + addFinalizer(finalizer: Scope.Finalizer): Effect.Effect +} + +/** + * A scope that can be explicitly closed with a specified exit value. + * + * @since 2.0.0 + * @category models + */ +export interface CloseableScope extends Scope, Pipeable { + readonly [CloseableScopeTypeId]: CloseableScopeTypeId + + /** + * Closes this scope with the given exit value, running all finalizers. + * + * @internal + */ + close(exit: Exit.Exit): Effect.Effect +} + +/** + * A tag representing the current `Scope` in the environment. + * + * @since 2.0.0 + * @category context + */ +export const Scope: Context.Tag = fiberRuntime.scopeTag + +/** + * @since 2.0.0 + */ +export declare namespace Scope { + /** + * A finalizer function that takes an `Exit` value and returns an `Effect`. + * + * @since 2.0.0 + * @category model + */ + export type Finalizer = (exit: Exit.Exit) => Effect.Effect + /** + * A closeable scope that can be explicitly closed. + * + * @since 2.0.0 + * @category model + */ + export type Closeable = CloseableScope +} + +/** + * Adds a finalizer to this scope. The finalizer is guaranteed to be run when + * the scope is closed. Use this when the finalizer does not need to know the + * `Exit` value that the scope is closed with. + * + * @see {@link addFinalizerExit} + * + * @since 2.0.0 + * @category utils + */ +export const addFinalizer: ( + self: Scope, + finalizer: Effect.Effect +) => Effect.Effect = core.scopeAddFinalizer + +/** + * Adds a finalizer to this scope. The finalizer receives the `Exit` value + * when the scope is closed, allowing it to perform different actions based + * on the exit status. + * + * @see {@link addFinalizer} + * + * @since 2.0.0 + * @category utils + */ +export const addFinalizerExit: (self: Scope, finalizer: Scope.Finalizer) => Effect.Effect = + core.scopeAddFinalizerExit + +/** + * Closes this scope with the specified exit value, running all finalizers that + * have been added to the scope. + * + * @since 2.0.0 + * @category destructors + */ +export const close: (self: CloseableScope, exit: Exit.Exit) => Effect.Effect = core.scopeClose + +/** + * Extends the scope of an `Effect` that requires a scope into this scope. + * It provides this scope to the effect but does not close the scope when the + * effect completes execution. This allows extending a scoped value into a + * larger scope. + * + * @since 2.0.0 + * @category utils + */ +export const extend: { + /** + * Extends the scope of an `Effect` that requires a scope into this scope. + * It provides this scope to the effect but does not close the scope when the + * effect completes execution. This allows extending a scoped value into a + * larger scope. + * + * @since 2.0.0 + * @category utils + */ + (scope: Scope): (effect: Effect.Effect) => Effect.Effect> + /** + * Extends the scope of an `Effect` that requires a scope into this scope. + * It provides this scope to the effect but does not close the scope when the + * effect completes execution. This allows extending a scoped value into a + * larger scope. + * + * @since 2.0.0 + * @category utils + */ + (effect: Effect.Effect, scope: Scope): Effect.Effect> +} = fiberRuntime.scopeExtend + +/** + * Forks a new child scope with the specified execution strategy. The child scope + * will automatically be closed when this scope is closed. + * + * @since 2.0.0 + * @category utils + */ +export const fork: ( + self: Scope, + strategy: ExecutionStrategy.ExecutionStrategy +) => Effect.Effect = core.scopeFork + +/** + * Provides this closeable scope to an `Effect` that requires a scope, + * guaranteeing that the scope is closed with the result of that effect as + * soon as the effect completes execution, whether by success, failure, or + * interruption. + * + * @since 2.0.0 + * @category destructors + */ +export const use: { + /** + * Provides this closeable scope to an `Effect` that requires a scope, + * guaranteeing that the scope is closed with the result of that effect as + * soon as the effect completes execution, whether by success, failure, or + * interruption. + * + * @since 2.0.0 + * @category destructors + */ + (scope: CloseableScope): (effect: Effect.Effect) => Effect.Effect> + /** + * Provides this closeable scope to an `Effect` that requires a scope, + * guaranteeing that the scope is closed with the result of that effect as + * soon as the effect completes execution, whether by success, failure, or + * interruption. + * + * @since 2.0.0 + * @category destructors + */ + (effect: Effect.Effect, scope: CloseableScope): Effect.Effect> +} = fiberRuntime.scopeUse + +/** + * Creates a new closeable scope where finalizers will run according to the + * specified `ExecutionStrategy`. If no execution strategy is provided, `sequential` + * will be used by default. + * + * @since 2.0.0 + * @category constructors + */ +export const make: ( + executionStrategy?: ExecutionStrategy.ExecutionStrategy +) => Effect.Effect = fiberRuntime.scopeMake diff --git a/backend/node_modules/effect/src/ScopedCache.ts b/backend/node_modules/effect/src/ScopedCache.ts new file mode 100644 index 0000000000000000000000000000000000000000..19cf996b20d21576bedcc8476b46eaa2643f901f --- /dev/null +++ b/backend/node_modules/effect/src/ScopedCache.ts @@ -0,0 +1,151 @@ +/** + * @since 2.0.0 + */ +import type * as Cache from "./Cache.js" +import type * as Duration from "./Duration.js" +import type * as Effect from "./Effect.js" +import type * as Exit from "./Exit.js" +import * as internal from "./internal/scopedCache.js" +import type * as Option from "./Option.js" +import type { Pipeable } from "./Pipeable.js" +import type * as Scope from "./Scope.js" +import type * as Types from "./Types.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const ScopedCacheTypeId: unique symbol = internal.ScopedCacheTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type ScopedCacheTypeId = typeof ScopedCacheTypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface ScopedCache + extends ScopedCache.Variance, Pipeable +{ + /** + * Retrieves the value associated with the specified key if it exists. + * Otherwise returns `Option.none`. + */ + getOption(key: Key): Effect.Effect, Error, Scope.Scope> + + /** + * Retrieves the value associated with the specified key if it exists and the + * lookup function has completed. Otherwise returns `Option.none`. + */ + getOptionComplete(key: Key): Effect.Effect, never, Scope.Scope> + + /** + * Returns statistics for this cache. + */ + readonly cacheStats: Effect.Effect + + /** + * Return whether a resource associated with the specified key exists in the + * cache. Sometime `contains` can return true if the resource is currently + * being created but not yet totally created. + */ + contains(key: Key): Effect.Effect + + /** + * Return statistics for the specified entry. + */ + entryStats(key: Key): Effect.Effect> + + /** + * Gets the value from the cache if it exists or otherwise computes it, the + * release action signals to the cache that the value is no longer being used + * and can potentially be finalized subject to the policies of the cache. + */ + get(key: Key): Effect.Effect + + /** + * Invalidates the resource associated with the specified key. + */ + invalidate(key: Key): Effect.Effect + + /** + * Invalidates all values in the cache. + */ + readonly invalidateAll: Effect.Effect + + /** + * Force the reuse of the lookup function to compute the returned scoped + * effect associated with the specified key immediately. Once the new resource + * is recomputed, the old resource associated to the key is cleaned (once all + * fiber using it are done with it). During the time the new resource is + * computed, concurrent call the .get will use the old resource if this one is + * not expired. + */ + refresh(key: Key): Effect.Effect + + /** + * Returns the approximate number of values in the cache. + */ + readonly size: Effect.Effect +} + +/** + * @since 2.0.0 + */ +export declare namespace ScopedCache { + /** + * @since 2.0.0 + * @category models + */ + export interface Variance { + readonly [ScopedCacheTypeId]: { + _Key: Types.Contravariant + _Error: Types.Covariant + _Value: Types.Covariant + } + } +} + +/** + * Constructs a new cache with the specified capacity, time to live, and + * lookup function. + * + * @since 2.0.0 + * @category constructors + */ +export const make: ( + options: { + readonly lookup: Lookup + readonly capacity: number + readonly timeToLive: Duration.DurationInput + } +) => Effect.Effect, never, Scope.Scope | Environment> = internal.make + +/** + * Constructs a new cache with the specified capacity, time to live, and + * lookup function, where the time to live can depend on the `Exit` value + * returned by the lookup function. + * + * @since 2.0.0 + * @category constructors + */ +export const makeWith: ( + options: { + readonly capacity: number + readonly lookup: Lookup + readonly timeToLive: (exit: Exit.Exit) => Duration.DurationInput + } +) => Effect.Effect, never, Scope.Scope | Environment> = internal.makeWith + +/** + * Similar to `Cache.Lookup`, but executes the lookup function within a `Scope`. + * + * @since 2.0.0 + * @category models + */ +export type Lookup = ( + key: Key +) => Effect.Effect diff --git a/backend/node_modules/effect/src/ScopedRef.ts b/backend/node_modules/effect/src/ScopedRef.ts new file mode 100644 index 0000000000000000000000000000000000000000..ea60b6aa9ea58fc68bfe8219e1f838db3db1a0cf --- /dev/null +++ b/backend/node_modules/effect/src/ScopedRef.ts @@ -0,0 +1,139 @@ +/** + * @since 2.0.0 + */ +import type * as Effect from "./Effect.js" +import type { LazyArg } from "./Function.js" +import * as internal from "./internal/scopedRef.js" +import type { Pipeable } from "./Pipeable.js" +import type * as Scope from "./Scope.js" +import type * as Synchronized from "./SynchronizedRef.js" +import type * as Types from "./Types.js" +import type * as Unify from "./Unify.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const ScopedRefTypeId: unique symbol = internal.ScopedRefTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type ScopedRefTypeId = typeof ScopedRefTypeId + +/** + * A `ScopedRef` is a reference whose value is associated with resources, + * which must be released properly. You can both get the current value of any + * `ScopedRef`, as well as set it to a new value (which may require new + * resources). The reference itself takes care of properly releasing resources + * for the old value whenever a new value is obtained. + * + * @since 2.0.0 + * @category models + */ +export interface ScopedRef extends Effect.Effect, ScopedRef.Variance, Pipeable { + /** @internal */ + readonly ref: Synchronized.SynchronizedRef + + readonly [Unify.typeSymbol]?: unknown + readonly [Unify.unifySymbol]?: ScopedRefUnify + readonly [Unify.ignoreSymbol]?: ScopedRefUnifyIgnore +} + +/** + * @category models + * @since 3.9.0 + */ +export interface ScopedRefUnify extends Effect.EffectUnify { + ScopedRef?: () => Extract> +} + +/** + * @category models + * @since 3.9.0 + */ +export interface ScopedRefUnifyIgnore extends Effect.EffectUnifyIgnore { + Effect?: true +} + +/** + * @since 2.0.0 + */ +export declare namespace ScopedRef { + /** + * @since 2.0.0 + * @category models + */ + export interface Variance { + readonly [ScopedRefTypeId]: { + readonly _A: Types.Invariant + } + } +} + +/** + * Creates a new `ScopedRef` from an effect that resourcefully produces a + * value. + * + * @since 2.0.0 + * @category constructors + */ +export const fromAcquire: ( + acquire: Effect.Effect +) => Effect.Effect, E, Scope.Scope | R> = internal.fromAcquire + +/** + * Retrieves the current value of the scoped reference. + * + * @since 2.0.0 + * @category getters + */ +export const get: (self: ScopedRef) => Effect.Effect = internal.get + +/** + * Creates a new `ScopedRef` from the specified value. This method should + * not be used for values whose creation require the acquisition of resources. + * + * @since 2.0.0 + * @category constructors + */ +export const make: (evaluate: LazyArg) => Effect.Effect, never, Scope.Scope> = internal.make + +/** + * Sets the value of this reference to the specified resourcefully-created + * value. Any resources associated with the old value will be released. + * + * This method will not return until either the reference is successfully + * changed to the new value, with old resources released, or until the attempt + * to acquire a new value fails. + * + * @since 2.0.0 + * @category getters + */ +export const set: { + /** + * Sets the value of this reference to the specified resourcefully-created + * value. Any resources associated with the old value will be released. + * + * This method will not return until either the reference is successfully + * changed to the new value, with old resources released, or until the attempt + * to acquire a new value fails. + * + * @since 2.0.0 + * @category getters + */ + (acquire: Effect.Effect): (self: ScopedRef) => Effect.Effect> + /** + * Sets the value of this reference to the specified resourcefully-created + * value. Any resources associated with the old value will be released. + * + * This method will not return until either the reference is successfully + * changed to the new value, with old resources released, or until the attempt + * to acquire a new value fails. + * + * @since 2.0.0 + * @category getters + */ + (self: ScopedRef, acquire: Effect.Effect): Effect.Effect> +} = internal.set diff --git a/backend/node_modules/effect/src/SingleProducerAsyncInput.ts b/backend/node_modules/effect/src/SingleProducerAsyncInput.ts new file mode 100644 index 0000000000000000000000000000000000000000..43e07dd290c243e6b14cb1880c378abc4a92ba85 --- /dev/null +++ b/backend/node_modules/effect/src/SingleProducerAsyncInput.ts @@ -0,0 +1,67 @@ +/** + * @since 2.0.0 + */ +import type * as Cause from "./Cause.js" +import type * as Effect from "./Effect.js" +import type * as Either from "./Either.js" +import type * as Exit from "./Exit.js" +import * as internal from "./internal/channel/singleProducerAsyncInput.js" + +/** + * An MVar-like abstraction for sending data to channels asynchronously which is + * designed for one producer and multiple consumers. + * + * Features the following semantics: + * - Buffer of size 1. + * - When emitting, the producer waits for a consumer to pick up the value to + * prevent "reading ahead" too much. + * - Once an emitted element is read by a consumer, it is cleared from the + * buffer, so that at most one consumer sees every emitted element. + * - When sending a done or error signal, the producer does not wait for a + * consumer to pick up the signal. The signal stays in the buffer after + * being read by a consumer, so it can be propagated to multiple consumers. + * - Trying to publish another emit/error/done after an error/done have + * already been published results in an interruption. + * + * @since 2.0.0 + * @category models + */ +export interface SingleProducerAsyncInput + extends AsyncInputProducer, AsyncInputConsumer +{ + readonly close: Effect.Effect + readonly take: Effect.Effect>> +} + +/** + * Producer-side view of `SingleProducerAsyncInput` for variance purposes. + * + * @since 2.0.0 + * @category models + */ +export interface AsyncInputProducer { + awaitRead(): Effect.Effect + done(value: Done): Effect.Effect + emit(element: Elem): Effect.Effect + error(cause: Cause.Cause): Effect.Effect +} + +/** + * Consumer-side view of `SingleProducerAsyncInput` for variance purposes. + * + * @since 2.0.0 + * @category models + */ +export interface AsyncInputConsumer { + takeWith( + onError: (cause: Cause.Cause) => A, + onElement: (element: Elem) => A, + onDone: (value: Done) => A + ): Effect.Effect +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const make: () => Effect.Effect> = internal.make diff --git a/backend/node_modules/effect/src/SortedMap.ts b/backend/node_modules/effect/src/SortedMap.ts new file mode 100644 index 0000000000000000000000000000000000000000..d0ef6ac176ec621f1ba3b9a448d9e3da886b62d5 --- /dev/null +++ b/backend/node_modules/effect/src/SortedMap.ts @@ -0,0 +1,361 @@ +/** + * @since 2.0.0 + */ +import * as Equal from "./Equal.js" +import * as Dual from "./Function.js" +import { pipe } from "./Function.js" +import * as Hash from "./Hash.js" +import { format, type Inspectable, NodeInspectSymbol, toJSON } from "./Inspectable.js" +import * as Option from "./Option.js" +import type { Order } from "./Order.js" +import type { Pipeable } from "./Pipeable.js" +import { pipeArguments } from "./Pipeable.js" +import { hasProperty } from "./Predicate.js" +import * as RBT from "./RedBlackTree.js" +import type * as Types from "./Types.js" + +const TypeId: unique symbol = Symbol.for("effect/SortedMap") + +/** + * @since 2.0.0 + * @category symbol + */ +export type TypeId = typeof TypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface SortedMap extends Iterable<[K, V]>, Equal.Equal, Pipeable, Inspectable { + readonly [TypeId]: { + readonly _K: Types.Invariant + readonly _V: Types.Covariant + } + /** @internal */ + readonly tree: RBT.RedBlackTree +} + +const SortedMapProto: Omit, "tree"> = { + [TypeId]: { + _K: (_: any) => _, + _V: (_: never) => _ + }, + [Hash.symbol](this: SortedMap): number { + return pipe( + Hash.hash(this.tree), + Hash.combine(Hash.hash("effect/SortedMap")), + Hash.cached(this) + ) + }, + [Equal.symbol](this: SortedMap, that: unknown): boolean { + return isSortedMap(that) && Equal.equals(this.tree, that.tree) + }, + [Symbol.iterator](this: SortedMap): Iterator<[K, V]> { + return this.tree[Symbol.iterator]() + }, + toString() { + return format(this.toJSON()) + }, + toJSON() { + return { + _id: "SortedMap", + values: Array.from(this).map(toJSON) + } + }, + [NodeInspectSymbol]() { + return this.toJSON() + }, + pipe() { + return pipeArguments(this, arguments) + } +} + +const makeImpl = (tree: RBT.RedBlackTree): SortedMap => { + const self = Object.create(SortedMapProto) + self.tree = tree + return self +} + +/** + * @since 2.0.0 + * @category refinements + */ +export const isSortedMap: { + /** + * @since 2.0.0 + * @category refinements + */ + (u: Iterable): u is SortedMap + /** + * @since 2.0.0 + * @category refinements + */ + (u: unknown): u is SortedMap +} = (u: unknown): u is SortedMap => hasProperty(u, TypeId) + +/** + * @since 2.0.0 + * @category constructors + */ +export const empty = (ord: Order): SortedMap => makeImpl(RBT.empty(ord)) + +/** + * Creates a new `SortedMap` from an iterable collection of key/value pairs. + * + * @since 2.0.0 + * @category constructors + */ +export const fromIterable: { + /** + * Creates a new `SortedMap` from an iterable collection of key/value pairs. + * + * @since 2.0.0 + * @category constructors + */ + (ord: Order): (iterable: Iterable) => SortedMap + /** + * Creates a new `SortedMap` from an iterable collection of key/value pairs. + * + * @since 2.0.0 + * @category constructors + */ + (iterable: Iterable, ord: Order): SortedMap +} = Dual.dual( + 2, + (iterable: Iterable, ord: Order): SortedMap => + makeImpl(RBT.fromIterable(iterable, ord)) +) + +/** + * @since 2.0.0 + * @category constructors + */ +export const make = + (ord: Order) => + >(...entries: Entries): SortedMap< + K, + Entries[number] extends (readonly [any, infer V]) ? V : never + > => fromIterable(ord)(entries) + +/** + * @since 2.0.0 + * @category predicates + */ +export const isEmpty = (self: SortedMap): boolean => size(self) === 0 + +/** + * @since 2.0.0 + * @category predicates + */ +export const isNonEmpty = (self: SortedMap): boolean => size(self) > 0 + +/** + * @since 2.0.0 + * @category elements + */ +export const get: { + /** + * @since 2.0.0 + * @category elements + */ + (key: K): (self: SortedMap) => Option.Option + /** + * @since 2.0.0 + * @category elements + */ + (self: SortedMap, key: K): Option.Option +} = Dual.dual< + (key: K) => (self: SortedMap) => Option.Option, + (self: SortedMap, key: K) => Option.Option +>(2, (self, key) => RBT.findFirst(self.tree, key)) + +/** + * Gets the `Order` that the `SortedMap` is using. + * + * @since 2.0.0 + * @category getters + */ +export const getOrder = (self: SortedMap): Order => RBT.getOrder(self.tree) + +/** + * @since 2.0.0 + * @category elements + */ +export const has: { + /** + * @since 2.0.0 + * @category elements + */ + (key: K): (self: SortedMap) => boolean + /** + * @since 2.0.0 + * @category elements + */ + (self: SortedMap, key: K): boolean +} = Dual.dual< + (key: K) => (self: SortedMap) => boolean, + (self: SortedMap, key: K) => boolean +>(2, (self, key) => Option.isSome(get(self, key))) + +/** + * @since 2.0.0 + * @category elements + */ +export const headOption = (self: SortedMap): Option.Option<[K, V]> => RBT.first(self.tree) + +/** + * @since 2.0.0 + * @category mapping + */ +export const map: { + /** + * @since 2.0.0 + * @category mapping + */ + (f: (a: A, k: K) => B): (self: SortedMap) => SortedMap + /** + * @since 2.0.0 + * @category mapping + */ + (self: SortedMap, f: (a: A, k: K) => B): SortedMap +} = Dual.dual< + (f: (a: A, k: K) => B) => (self: SortedMap) => SortedMap, + (self: SortedMap, f: (a: A, k: K) => B) => SortedMap +>(2, (self: SortedMap, f: (a: A, k: K) => B) => + reduce( + self, + empty(RBT.getOrder(self.tree)), + (acc, v, k) => set(acc, k, f(v, k)) + )) + +/** + * @since 2.0.0 + * @category folding + */ +export const reduce: { + /** + * @since 2.0.0 + * @category folding + */ + (zero: B, f: (acc: B, value: A, key: K) => B): (self: SortedMap) => B + /** + * @since 2.0.0 + * @category folding + */ + (self: SortedMap, zero: B, f: (acc: B, value: A, key: K) => B): B +} = Dual.dual< + (zero: B, f: (acc: B, value: A, key: K) => B) => (self: SortedMap) => B, + (self: SortedMap, zero: B, f: (acc: B, value: A, key: K) => B) => B +>(3, (self, zero, f) => RBT.reduce(self.tree, zero, f)) + +/** + * @since 2.0.0 + * @category elements + */ +export const remove: { + /** + * @since 2.0.0 + * @category elements + */ + (key: K): (self: SortedMap) => SortedMap + /** + * @since 2.0.0 + * @category elements + */ + (self: SortedMap, key: K): SortedMap +} = Dual.dual< + (key: K) => (self: SortedMap) => SortedMap, + (self: SortedMap, key: K) => SortedMap +>(2, (self, key) => makeImpl(RBT.removeFirst(self.tree, key))) + +/** + * @since 2.0.0 + * @category elements + */ +export const set: { + /** + * @since 2.0.0 + * @category elements + */ + (key: K, value: V): (self: SortedMap) => SortedMap + /** + * @since 2.0.0 + * @category elements + */ + (self: SortedMap, key: K, value: V): SortedMap +} = Dual.dual< + (key: K, value: V) => (self: SortedMap) => SortedMap, + (self: SortedMap, key: K, value: V) => SortedMap +>(3, (self, key, value) => + RBT.has(self.tree, key) + ? makeImpl(RBT.insert(RBT.removeFirst(self.tree, key), key, value)) + : makeImpl(RBT.insert(self.tree, key, value))) + +/** + * @since 2.0.0 + * @category getters + */ +export const size = (self: SortedMap): number => RBT.size(self.tree) + +/** + * @since 2.0.0 + * @category getters + */ +export const keys = (self: SortedMap): IterableIterator => RBT.keys(self.tree) + +/** + * @since 2.0.0 + * @category getters + */ +export const values = (self: SortedMap): IterableIterator => RBT.values(self.tree) + +/** + * @since 2.0.0 + * @category getters + */ +export const entries = (self: SortedMap): IterableIterator<[K, V]> => { + const iterator: any = self.tree[Symbol.iterator]() + iterator[Symbol.iterator] = () => entries(self) + return iterator +} + +/** + * @since 3.1.0 + * @category elements + */ +export const lastOption = (self: SortedMap): Option.Option<[K, V]> => RBT.last(self.tree) + +/** + * @since 3.1.0 + * @category filtering + */ +export const partition: { + /** + * @since 3.1.0 + * @category filtering + */ + (predicate: (a: Types.NoInfer) => boolean): (self: SortedMap) => [excluded: SortedMap, satisfying: SortedMap] + /** + * @since 3.1.0 + * @category filtering + */ + (self: SortedMap, predicate: (a: K) => boolean): [excluded: SortedMap, satisfying: SortedMap] +} = Dual.dual( + 2, + ( + self: SortedMap, + predicate: (a: K) => boolean + ): [excluded: SortedMap, satisfying: SortedMap] => { + const ord = RBT.getOrder(self.tree) + let right = empty(ord) + let left = empty(ord) + for (const value of self) { + if (predicate(value[0])) { + right = set(right, value[0], value[1]) + } else { + left = set(left, value[0], value[1]) + } + } + return [left, right] + } +) diff --git a/backend/node_modules/effect/src/StreamEmit.ts b/backend/node_modules/effect/src/StreamEmit.ts new file mode 100644 index 0000000000000000000000000000000000000000..fdb935d1e44ebbdc4d9c7dd3f05098dc6e0d3fb7 --- /dev/null +++ b/backend/node_modules/effect/src/StreamEmit.ts @@ -0,0 +1,136 @@ +/** + * @since 2.0.0 + */ +import type * as Cause from "./Cause.js" +import type * as Chunk from "./Chunk.js" +import type * as Effect from "./Effect.js" +import type * as Exit from "./Exit.js" +import type * as Option from "./Option.js" + +/** + * An `Emit` represents an asynchronous callback that can be + * called multiple times. The callback can be called with a value of type + * `Effect, Option, R>`, where succeeding with a `Chunk` + * indicates to emit those elements, failing with `Some` indicates to + * terminate with that error, and failing with `None` indicates to terminate + * with an end of stream signal. + * + * @since 2.0.0 + * @category models + */ +export interface Emit extends EmitOps { + (f: Effect.Effect, Option.Option, R>): Promise +} + +/** + * @since 2.0.0 + * @category models + */ +export interface EmitOps { + /** + * Emits a chunk containing the specified values. + */ + chunk(chunk: Chunk.Chunk): Promise + + /** + * Terminates with a cause that dies with the specified defect. + */ + die(defect: Err): Promise + + /** + * Terminates with a cause that dies with a `Throwable` with the specified + * message. + */ + dieMessage(message: string): Promise + + /** + * Either emits the specified value if this `Exit` is a `Success` or else + * terminates with the specified cause if this `Exit` is a `Failure`. + */ + done(exit: Exit.Exit): Promise + + /** + * Terminates with an end of stream signal. + */ + end(): Promise + + /** + * Terminates with the specified error. + */ + fail(error: E): Promise + + /** + * Either emits the success value of this effect or terminates the stream + * with the failure value of this effect. + */ + fromEffect(effect: Effect.Effect): Promise + + /** + * Either emits the success value of this effect or terminates the stream + * with the failure value of this effect. + */ + fromEffectChunk(effect: Effect.Effect, E, R>): Promise + + /** + * Terminates the stream with the specified cause. + */ + halt(cause: Cause.Cause): Promise + + /** + * Emits a chunk containing the specified value. + */ + single(value: A): Promise +} + +/** + * @since 3.6.0 + * @category models + */ +export interface EmitOpsPush { + /** + * Emits a chunk containing the specified values. + */ + chunk(chunk: Chunk.Chunk): boolean + + /** + * Emits a chunk containing the specified values. + */ + array(chunk: ReadonlyArray): boolean + + /** + * Terminates with a cause that dies with the specified defect. + */ + die(defect: Err): void + + /** + * Terminates with a cause that dies with a `Throwable` with the specified + * message. + */ + dieMessage(message: string): void + + /** + * Either emits the specified value if this `Exit` is a `Success` or else + * terminates with the specified cause if this `Exit` is a `Failure`. + */ + done(exit: Exit.Exit): void + + /** + * Terminates with an end of stream signal. + */ + end(): void + + /** + * Terminates with the specified error. + */ + fail(error: E): void + + /** + * Terminates the stream with the specified cause. + */ + halt(cause: Cause.Cause): void + + /** + * Emits a chunk containing the specified value. + */ + single(value: A): boolean +} diff --git a/backend/node_modules/effect/src/StreamHaltStrategy.ts b/backend/node_modules/effect/src/StreamHaltStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..30d1ada9607adc8651aad05cf54b897845f46865 --- /dev/null +++ b/backend/node_modules/effect/src/StreamHaltStrategy.ts @@ -0,0 +1,140 @@ +/** + * @since 2.0.0 + */ +import * as internal from "./internal/stream/haltStrategy.js" + +/** + * @since 2.0.0 + * @category models + */ +export type HaltStrategy = Left | Right | Both | Either + +/** + * @since 2.0.0 + * @category models + */ +export type HaltStrategyInput = HaltStrategy | "left" | "right" | "both" | "either" + +/** + * @since 2.0.0 + * @category models + */ +export interface Left { + readonly _tag: "Left" +} + +/** + * @since 2.0.0 + * @category models + */ +export interface Right { + readonly _tag: "Right" +} + +/** + * @since 2.0.0 + * @category models + */ +export interface Both { + readonly _tag: "Both" +} + +/** + * @since 2.0.0 + * @category models + */ +export interface Either { + readonly _tag: "Either" +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const Left: HaltStrategy = internal.Left + +/** + * @since 2.0.0 + * @category constructors + */ +export const Right: HaltStrategy = internal.Right + +/** + * @since 2.0.0 + * @category constructors + */ +export const Both: HaltStrategy = internal.Both + +/** + * @since 2.0.0 + * @category constructors + */ +export const Either: HaltStrategy = internal.Either + +/** + * @since 2.0.0 + * @category constructors + */ +export const fromInput: (input: HaltStrategyInput) => HaltStrategy = internal.fromInput + +/** + * @since 2.0.0 + * @category refinements + */ +export const isLeft: (self: HaltStrategy) => self is Left = internal.isLeft + +/** + * @since 2.0.0 + * @category refinements + */ +export const isRight: (self: HaltStrategy) => self is Right = internal.isRight + +/** + * @since 2.0.0 + * @category refinements + */ +export const isBoth: (self: HaltStrategy) => self is Both = internal.isBoth + +/** + * @since 2.0.0 + * @category refinements + */ +export const isEither: (self: HaltStrategy) => self is Either = internal.isEither + +/** + * Folds over the specified `HaltStrategy` using the provided case functions. + * + * @since 2.0.0 + * @category folding + */ +export const match: { + /** + * Folds over the specified `HaltStrategy` using the provided case functions. + * + * @since 2.0.0 + * @category folding + */ + ( + options: { + readonly onLeft: () => Z + readonly onRight: () => Z + readonly onBoth: () => Z + readonly onEither: () => Z + } + ): (self: HaltStrategy) => Z + /** + * Folds over the specified `HaltStrategy` using the provided case functions. + * + * @since 2.0.0 + * @category folding + */ + ( + self: HaltStrategy, + options: { + readonly onLeft: () => Z + readonly onRight: () => Z + readonly onBoth: () => Z + readonly onEither: () => Z + } + ): Z +} = internal.match diff --git a/backend/node_modules/effect/src/String.ts b/backend/node_modules/effect/src/String.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad1cbfe3ff77f1730b30177e96e539be0aa64f3a --- /dev/null +++ b/backend/node_modules/effect/src/String.ts @@ -0,0 +1,1026 @@ +/** + * This module provides utility functions and type class instances for working with the `string` type in TypeScript. + * It includes functions for basic string manipulation, as well as type class instances for + * `Equivalence` and `Order`. + * + * @since 2.0.0 + */ + +import type { NonEmptyArray } from "./Array.js" +import * as equivalence from "./Equivalence.js" +import { dual } from "./Function.js" +import * as readonlyArray from "./internal/array.js" +import * as number from "./Number.js" +import * as Option from "./Option.js" +import * as order from "./Order.js" +import type * as Ordering from "./Ordering.js" +import type { Refinement } from "./Predicate.js" +import * as predicate from "./Predicate.js" + +/** + * Tests if a value is a `string`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { String } from "effect" + * + * assert.deepStrictEqual(String.isString("a"), true) + * assert.deepStrictEqual(String.isString(1), false) + * ``` + * + * @category guards + * @since 2.0.0 + */ +export const isString: Refinement = predicate.isString + +/** + * @category instances + * @since 2.0.0 + */ +export const Equivalence: equivalence.Equivalence = equivalence.string + +/** + * @category instances + * @since 2.0.0 + */ +export const Order: order.Order = order.string + +/** + * The empty string `""`. + * + * @since 2.0.0 + */ +export const empty: "" = "" as const + +/** + * Concatenates two strings at the type level. + * + * @since 2.0.0 + */ +export type Concat = `${A}${B}` + +/** + * Concatenates two strings at runtime. + * + * @since 2.0.0 + */ +export const concat: { + /** + * Concatenates two strings at runtime. + * + * @since 2.0.0 + */ + (that: B): (self: A) => Concat + /** + * Concatenates two strings at runtime. + * + * @since 2.0.0 + */ + (self: A, that: B): Concat +} = dual(2, (self: string, that: string): string => self + that) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe('a', String.toUpperCase), 'A') + * ``` + * + * @since 2.0.0 + */ +export const toUpperCase = (self: S): Uppercase => self.toUpperCase() as Uppercase + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe('A', String.toLowerCase), 'a') + * ``` + * + * @since 2.0.0 + */ +export const toLowerCase = (self: T): Lowercase => self.toLowerCase() as Lowercase + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe('abc', String.capitalize), 'Abc') + * ``` + * + * @since 2.0.0 + */ +export const capitalize = (self: T): Capitalize => { + if (self.length === 0) return self as Capitalize + + return (toUpperCase(self[0]) + self.slice(1)) as Capitalize +} + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe('ABC', String.uncapitalize), 'aBC') + * ``` + * + * @since 2.0.0 + */ +export const uncapitalize = (self: T): Uncapitalize => { + if (self.length === 0) return self as Uncapitalize + + return (toLowerCase(self[0]) + self.slice(1)) as Uncapitalize +} + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe('abc', String.replace('b', 'd')), 'adc') + * ``` + * + * @since 2.0.0 + */ +export const replace = (searchValue: string | RegExp, replaceValue: string) => (self: string): string => + self.replace(searchValue, replaceValue) + +/** + * @since 2.0.0 + */ +export type Trim = TrimEnd> + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { String } from "effect" + * + * assert.deepStrictEqual(String.trim(' a '), 'a') + * ``` + * + * @since 2.0.0 + */ +export const trim = (self: A): Trim => self.trim() as Trim + +/** + * @since 2.0.0 + */ +export type TrimStart = A extends `${" " | "\n" | "\t" | "\r"}${infer B}` ? TrimStart : A + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { String } from "effect" + * + * assert.deepStrictEqual(String.trimStart(' a '), 'a ') + * ``` + * + * @since 2.0.0 + */ +export const trimStart = (self: A): TrimStart => self.trimStart() as TrimStart + +/** + * @since 2.0.0 + */ +export type TrimEnd = A extends `${infer B}${" " | "\n" | "\t" | "\r"}` ? TrimEnd : A + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { String } from "effect" + * + * assert.deepStrictEqual(String.trimEnd(' a '), ' a') + * ``` + * + * @since 2.0.0 + */ +export const trimEnd = (self: A): TrimEnd => self.trimEnd() as TrimEnd + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe('abcd', String.slice(1, 3)), 'bc') + * ``` + * + * @since 2.0.0 + */ +export const slice = (start?: number, end?: number) => (self: string): string => self.slice(start, end) + +/** + * Test whether a `string` is empty. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { String } from "effect" + * + * assert.deepStrictEqual(String.isEmpty(''), true) + * assert.deepStrictEqual(String.isEmpty('a'), false) + * ``` + * + * @since 2.0.0 + */ +export const isEmpty = (self: string): self is "" => self.length === 0 + +/** + * Test whether a `string` is non empty. + * + * @since 2.0.0 + */ +export const isNonEmpty = (self: string): boolean => self.length > 0 + +/** + * Calculate the number of characters in a `string`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { String } from "effect" + * + * assert.deepStrictEqual(String.length('abc'), 3) + * ``` + * + * @since 2.0.0 + */ +export const length = (self: string): number => self.length + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe('abc', String.split('')), ['a', 'b', 'c']) + * assert.deepStrictEqual(pipe('', String.split('')), ['']) + * ``` + * + * @since 2.0.0 + */ +export const split: { + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe('abc', String.split('')), ['a', 'b', 'c']) + * assert.deepStrictEqual(pipe('', String.split('')), ['']) + * ``` + * + * @since 2.0.0 + */ + (separator: string | RegExp): (self: string) => NonEmptyArray + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe('abc', String.split('')), ['a', 'b', 'c']) + * assert.deepStrictEqual(pipe('', String.split('')), ['']) + * ``` + * + * @since 2.0.0 + */ + (self: string, separator: string | RegExp): NonEmptyArray +} = dual(2, (self: string, separator: string | RegExp): NonEmptyArray => { + const out = self.split(separator) + return readonlyArray.isNonEmptyArray(out) ? out : [self] +}) + +/** + * Returns `true` if `searchString` appears as a substring of `self`, at one or more positions that are + * greater than or equal to `position`; otherwise, returns `false`. + * + * @since 2.0.0 + */ +export const includes = (searchString: string, position?: number) => (self: string): boolean => + self.includes(searchString, position) + +/** + * @since 2.0.0 + */ +export const startsWith = (searchString: string, position?: number) => (self: string): boolean => + self.startsWith(searchString, position) + +/** + * @since 2.0.0 + */ +export const endsWith = (searchString: string, position?: number) => (self: string): boolean => + self.endsWith(searchString, position) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abc", String.charCodeAt(1)), Option.some(98)) + * assert.deepStrictEqual(pipe("abc", String.charCodeAt(4)), Option.none()) + * ``` + * + * @since 2.0.0 + */ +export const charCodeAt: { + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abc", String.charCodeAt(1)), Option.some(98)) + * assert.deepStrictEqual(pipe("abc", String.charCodeAt(4)), Option.none()) + * ``` + * + * @since 2.0.0 + */ + (index: number): (self: string) => Option.Option + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abc", String.charCodeAt(1)), Option.some(98)) + * assert.deepStrictEqual(pipe("abc", String.charCodeAt(4)), Option.none()) + * ``` + * + * @since 2.0.0 + */ + (self: string, index: number): Option.Option +} = dual( + 2, + (self: string, index: number): Option.Option => + Option.filter(Option.some(self.charCodeAt(index)), (charCode) => !isNaN(charCode)) +) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abcd", String.substring(1)), "bcd") + * assert.deepStrictEqual(pipe("abcd", String.substring(1, 3)), "bc") + * ``` + * + * @since 2.0.0 + */ +export const substring = (start: number, end?: number) => (self: string): string => self.substring(start, end) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abc", String.at(1)), Option.some("b")) + * assert.deepStrictEqual(pipe("abc", String.at(4)), Option.none()) + * ``` + * + * @since 2.0.0 + */ +export const at: { + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abc", String.at(1)), Option.some("b")) + * assert.deepStrictEqual(pipe("abc", String.at(4)), Option.none()) + * ``` + * + * @since 2.0.0 + */ + (index: number): (self: string) => Option.Option + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abc", String.at(1)), Option.some("b")) + * assert.deepStrictEqual(pipe("abc", String.at(4)), Option.none()) + * ``` + * + * @since 2.0.0 + */ + (self: string, index: number): Option.Option +} = dual(2, (self: string, index: number): Option.Option => Option.fromNullable(self.at(index))) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abc", String.charAt(1)), Option.some("b")) + * assert.deepStrictEqual(pipe("abc", String.charAt(4)), Option.none()) + * ``` + * + * @since 2.0.0 + */ +export const charAt: { + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abc", String.charAt(1)), Option.some("b")) + * assert.deepStrictEqual(pipe("abc", String.charAt(4)), Option.none()) + * ``` + * + * @since 2.0.0 + */ + (index: number): (self: string) => Option.Option + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abc", String.charAt(1)), Option.some("b")) + * assert.deepStrictEqual(pipe("abc", String.charAt(4)), Option.none()) + * ``` + * + * @since 2.0.0 + */ + (self: string, index: number): Option.Option +} = dual( + 2, + (self: string, index: number): Option.Option => Option.filter(Option.some(self.charAt(index)), isNonEmpty) +) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abc", String.codePointAt(1)), Option.some(98)) + * ``` + * + * @since 2.0.0 + */ +export const codePointAt: { + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abc", String.codePointAt(1)), Option.some(98)) + * ``` + * + * @since 2.0.0 + */ + (index: number): (self: string) => Option.Option + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abc", String.codePointAt(1)), Option.some(98)) + * ``` + * + * @since 2.0.0 + */ + (self: string, index: number): Option.Option +} = dual(2, (self: string, index: number): Option.Option => Option.fromNullable(self.codePointAt(index))) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abbbc", String.indexOf("b")), Option.some(1)) + * ``` + * + * @since 2.0.0 + */ +export const indexOf = (searchString: string) => (self: string): Option.Option => + Option.filter(Option.some(self.indexOf(searchString)), number.greaterThanOrEqualTo(0)) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("abbbc", String.lastIndexOf("b")), Option.some(3)) + * assert.deepStrictEqual(pipe("abbbc", String.lastIndexOf("d")), Option.none()) + * ``` + * + * @since 2.0.0 + */ +export const lastIndexOf = (searchString: string) => (self: string): Option.Option => + Option.filter(Option.some(self.lastIndexOf(searchString)), number.greaterThanOrEqualTo(0)) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe("a", String.localeCompare("b")), -1) + * assert.deepStrictEqual(pipe("b", String.localeCompare("a")), 1) + * assert.deepStrictEqual(pipe("a", String.localeCompare("a")), 0) + * ``` + * + * @since 2.0.0 + */ +export const localeCompare = + (that: string, locales?: Intl.LocalesArgument, options?: Intl.CollatorOptions) => (self: string): Ordering.Ordering => + number.sign(self.localeCompare(that, locales, options)) + +/** + * It is the `pipe`-able version of the native `match` method. + * + * @since 2.0.0 + */ +export const match = (regexp: RegExp | string) => (self: string): Option.Option => + Option.fromNullable(self.match(regexp)) + +/** + * It is the `pipe`-able version of the native `matchAll` method. + * + * @since 2.0.0 + */ +export const matchAll = (regexp: RegExp) => (self: string): IterableIterator => self.matchAll(regexp) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * const str = "\u1E9B\u0323"; + * assert.deepStrictEqual(pipe(str, String.normalize()), "\u1E9B\u0323") + * assert.deepStrictEqual(pipe(str, String.normalize("NFC")), "\u1E9B\u0323") + * assert.deepStrictEqual(pipe(str, String.normalize("NFD")), "\u017F\u0323\u0307") + * assert.deepStrictEqual(pipe(str, String.normalize("NFKC")), "\u1E69") + * assert.deepStrictEqual(pipe(str, String.normalize("NFKD")), "\u0073\u0323\u0307") + * ``` + * + * @since 2.0.0 + */ +export const normalize = (form?: "NFC" | "NFD" | "NFKC" | "NFKD") => (self: string): string => self.normalize(form) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe("a", String.padEnd(5)), "a ") + * assert.deepStrictEqual(pipe("a", String.padEnd(5, "_")), "a____") + * ``` + * + * @since 2.0.0 + */ +export const padEnd = (maxLength: number, fillString?: string) => (self: string): string => + self.padEnd(maxLength, fillString) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe("a", String.padStart(5)), " a") + * assert.deepStrictEqual(pipe("a", String.padStart(5, "_")), "____a") + * ``` + * + * @since 2.0.0 + */ +export const padStart = (maxLength: number, fillString?: string) => (self: string): string => + self.padStart(maxLength, fillString) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe("a", String.repeat(5)), "aaaaa") + * ``` + * + * @since 2.0.0 + */ +export const repeat = (count: number) => (self: string): string => self.repeat(count) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * assert.deepStrictEqual(pipe("ababb", String.replaceAll("b", "c")), "acacc") + * assert.deepStrictEqual(pipe("ababb", String.replaceAll(/ba/g, "cc")), "accbb") + * ``` + * + * @since 2.0.0 + */ +export const replaceAll = (searchValue: string | RegExp, replaceValue: string) => (self: string): string => + self.replaceAll(searchValue, replaceValue) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("ababb", String.search("b")), Option.some(1)) + * assert.deepStrictEqual(pipe("ababb", String.search(/abb/)), Option.some(2)) + * assert.deepStrictEqual(pipe("ababb", String.search("d")), Option.none()) + * ``` + * + * @since 2.0.0 + */ +export const search: { + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("ababb", String.search("b")), Option.some(1)) + * assert.deepStrictEqual(pipe("ababb", String.search(/abb/)), Option.some(2)) + * assert.deepStrictEqual(pipe("ababb", String.search("d")), Option.none()) + * ``` + * + * @since 2.0.0 + */ + (regexp: RegExp | string): (self: string) => Option.Option + /** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String, Option } from "effect" + * + * assert.deepStrictEqual(pipe("ababb", String.search("b")), Option.some(1)) + * assert.deepStrictEqual(pipe("ababb", String.search(/abb/)), Option.some(2)) + * assert.deepStrictEqual(pipe("ababb", String.search("d")), Option.none()) + * ``` + * + * @since 2.0.0 + */ + (self: string, regexp: RegExp | string): Option.Option +} = dual( + 2, + (self: string, regexp: RegExp | string): Option.Option => + Option.filter(Option.some(self.search(regexp)), number.greaterThanOrEqualTo(0)) +) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * const str = "\u0130" + * assert.deepStrictEqual(pipe(str, String.toLocaleLowerCase("tr")), "i") + * ``` + * + * @since 2.0.0 + */ +export const toLocaleLowerCase = (locale?: Intl.LocalesArgument) => (self: string): string => + self.toLocaleLowerCase(locale) + +/** + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, String } from "effect" + * + * const str = "i\u0307" + * assert.deepStrictEqual(pipe(str, String.toLocaleUpperCase("lt-LT")), "I") + * ``` + * + * @since 2.0.0 + */ +export const toLocaleUpperCase = (locale?: Intl.LocalesArgument) => (self: string): string => + self.toLocaleUpperCase(locale) + +/** + * Keep the specified number of characters from the start of a string. + * + * If `n` is larger than the available number of characters, the string will + * be returned whole. + * + * If `n` is not a positive number, an empty string will be returned. + * + * If `n` is a float, it will be rounded down to the nearest integer. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { String } from "effect" + * + * assert.deepStrictEqual(String.takeLeft("Hello World", 5), "Hello") + * ``` + * + * @since 2.0.0 + */ +export const takeLeft: { + /** + * Keep the specified number of characters from the start of a string. + * + * If `n` is larger than the available number of characters, the string will + * be returned whole. + * + * If `n` is not a positive number, an empty string will be returned. + * + * If `n` is a float, it will be rounded down to the nearest integer. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { String } from "effect" + * + * assert.deepStrictEqual(String.takeLeft("Hello World", 5), "Hello") + * ``` + * + * @since 2.0.0 + */ + (n: number): (self: string) => string + /** + * Keep the specified number of characters from the start of a string. + * + * If `n` is larger than the available number of characters, the string will + * be returned whole. + * + * If `n` is not a positive number, an empty string will be returned. + * + * If `n` is a float, it will be rounded down to the nearest integer. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { String } from "effect" + * + * assert.deepStrictEqual(String.takeLeft("Hello World", 5), "Hello") + * ``` + * + * @since 2.0.0 + */ + (self: string, n: number): string +} = dual(2, (self: string, n: number): string => self.slice(0, Math.max(n, 0))) + +/** + * Keep the specified number of characters from the end of a string. + * + * If `n` is larger than the available number of characters, the string will + * be returned whole. + * + * If `n` is not a positive number, an empty string will be returned. + * + * If `n` is a float, it will be rounded down to the nearest integer. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { String } from "effect" + * + * assert.deepStrictEqual(String.takeRight("Hello World", 5), "World") + * ``` + * + * @since 2.0.0 + */ +export const takeRight: { + /** + * Keep the specified number of characters from the end of a string. + * + * If `n` is larger than the available number of characters, the string will + * be returned whole. + * + * If `n` is not a positive number, an empty string will be returned. + * + * If `n` is a float, it will be rounded down to the nearest integer. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { String } from "effect" + * + * assert.deepStrictEqual(String.takeRight("Hello World", 5), "World") + * ``` + * + * @since 2.0.0 + */ + (n: number): (self: string) => string + /** + * Keep the specified number of characters from the end of a string. + * + * If `n` is larger than the available number of characters, the string will + * be returned whole. + * + * If `n` is not a positive number, an empty string will be returned. + * + * If `n` is a float, it will be rounded down to the nearest integer. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { String } from "effect" + * + * assert.deepStrictEqual(String.takeRight("Hello World", 5), "World") + * ``` + * + * @since 2.0.0 + */ + (self: string, n: number): string +} = dual( + 2, + (self: string, n: number): string => self.slice(Math.max(0, self.length - Math.floor(n)), Infinity) +) + +const CR = 0x0d +const LF = 0x0a + +/** + * Returns an `IterableIterator` which yields each line contained within the + * string, trimming off the trailing newline character. + * + * @since 2.0.0 + */ +export const linesIterator = (self: string): LinesIterator => linesSeparated(self, true) + +/** + * Returns an `IterableIterator` which yields each line contained within the + * string as well as the trailing newline character. + * + * @since 2.0.0 + */ +export const linesWithSeparators = (s: string): LinesIterator => linesSeparated(s, false) + +/** + * For every line in this string, strip a leading prefix consisting of blanks + * or control characters followed by the character specified by `marginChar` + * from the line. + * + * @since 2.0.0 + */ +export const stripMarginWith: { + /** + * For every line in this string, strip a leading prefix consisting of blanks + * or control characters followed by the character specified by `marginChar` + * from the line. + * + * @since 2.0.0 + */ + (marginChar: string): (self: string) => string + /** + * For every line in this string, strip a leading prefix consisting of blanks + * or control characters followed by the character specified by `marginChar` + * from the line. + * + * @since 2.0.0 + */ + (self: string, marginChar: string): string +} = dual(2, (self: string, marginChar: string): string => { + let out = "" + + for (const line of linesWithSeparators(self)) { + let index = 0 + + while (index < line.length && line.charAt(index) <= " ") { + index = index + 1 + } + + const stripped = index < line.length && line.charAt(index) === marginChar + ? line.substring(index + 1) + : line + + out = out + stripped + } + + return out +}) + +/** + * For every line in this string, strip a leading prefix consisting of blanks + * or control characters followed by the `"|"` character from the line. + * + * @since 2.0.0 + */ +export const stripMargin = (self: string): string => stripMarginWith(self, "|") + +/** + * @since 2.0.0 + */ +export const snakeToCamel = (self: string): string => { + let str = self[0] + for (let i = 1; i < self.length; i++) { + str += self[i] === "_" ? self[++i].toUpperCase() : self[i] + } + return str +} + +/** + * @since 2.0.0 + */ +export const snakeToPascal = (self: string): string => { + let str = self[0].toUpperCase() + for (let i = 1; i < self.length; i++) { + str += self[i] === "_" ? self[++i].toUpperCase() : self[i] + } + return str +} + +/** + * @since 2.0.0 + */ +export const snakeToKebab = (self: string): string => self.replace(/_/g, "-") + +/** + * @since 2.0.0 + */ +export const camelToSnake = (self: string): string => self.replace(/([A-Z])/g, "_$1").toLowerCase() + +/** + * @since 2.0.0 + */ +export const pascalToSnake = (self: string): string => + (self.slice(0, 1) + self.slice(1).replace(/([A-Z])/g, "_$1")).toLowerCase() + +/** + * @since 2.0.0 + */ +export const kebabToSnake = (self: string): string => self.replace(/-/g, "_") + +class LinesIterator implements IterableIterator { + private index: number + private readonly length: number + + constructor(readonly s: string, readonly stripped: boolean = false) { + this.index = 0 + this.length = s.length + } + + next(): IteratorResult { + if (this.done) { + return { done: true, value: undefined } + } + const start = this.index + while (!this.done && !isLineBreak(this.s[this.index]!)) { + this.index = this.index + 1 + } + let end = this.index + if (!this.done) { + const char = this.s[this.index]! + this.index = this.index + 1 + if (!this.done && isLineBreak2(char, this.s[this.index]!)) { + this.index = this.index + 1 + } + if (!this.stripped) { + end = this.index + } + } + return { done: false, value: this.s.substring(start, end) } + } + + [Symbol.iterator](): IterableIterator { + return new LinesIterator(this.s, this.stripped) + } + + private get done(): boolean { + return this.index >= this.length + } +} + +/** + * Test if the provided character is a line break character (i.e. either `"\r"` + * or `"\n"`). + */ +const isLineBreak = (char: string): boolean => { + const code = char.charCodeAt(0) + return code === CR || code === LF +} + +/** + * Test if the provided characters combine to form a carriage return/line-feed + * (i.e. `"\r\n"`). + */ +const isLineBreak2 = (char0: string, char1: string): boolean => char0.charCodeAt(0) === CR && char1.charCodeAt(0) === LF + +const linesSeparated = (self: string, stripped: boolean): LinesIterator => new LinesIterator(self, stripped) diff --git a/backend/node_modules/effect/src/Struct.ts b/backend/node_modules/effect/src/Struct.ts new file mode 100644 index 0000000000000000000000000000000000000000..a4cd7612cb7935198db6392959f98c56d28c2b76 --- /dev/null +++ b/backend/node_modules/effect/src/Struct.ts @@ -0,0 +1,335 @@ +/** + * This module provides utility functions for working with structs in TypeScript. + * + * @since 2.0.0 + */ + +import * as Equivalence from "./Equivalence.js" +import { dual } from "./Function.js" +import * as order from "./Order.js" +import * as Predicate from "./Predicate.js" +import type { MatchRecord, Simplify } from "./Types.js" + +/** + * Create a new object by picking properties of an existing object. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Struct } from "effect" + * + * assert.deepStrictEqual(pipe({ a: "a", b: 1, c: true }, Struct.pick("a", "b")), { a: "a", b: 1 }) + * assert.deepStrictEqual(Struct.pick({ a: "a", b: 1, c: true }, "a", "b"), { a: "a", b: 1 }) + * ``` + * + * @since 2.0.0 + */ +export const pick: { + /** + * Create a new object by picking properties of an existing object. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Struct } from "effect" + * + * assert.deepStrictEqual(pipe({ a: "a", b: 1, c: true }, Struct.pick("a", "b")), { a: "a", b: 1 }) + * assert.deepStrictEqual(Struct.pick({ a: "a", b: 1, c: true }, "a", "b"), { a: "a", b: 1 }) + * ``` + * + * @since 2.0.0 + */ + >(...keys: Keys): ( + s: S + ) => MatchRecord>> + /** + * Create a new object by picking properties of an existing object. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Struct } from "effect" + * + * assert.deepStrictEqual(pipe({ a: "a", b: 1, c: true }, Struct.pick("a", "b")), { a: "a", b: 1 }) + * assert.deepStrictEqual(Struct.pick({ a: "a", b: 1, c: true }, "a", "b"), { a: "a", b: 1 }) + * ``` + * + * @since 2.0.0 + */ + >(s: S, ...keys: Keys): MatchRecord>> +} = dual( + (args) => Predicate.isObject(args[0]), + >(s: S, ...keys: Keys) => { + const out: any = {} + for (const k of keys) { + if (k in s) { + out[k] = (s as any)[k] + } + } + return out + } +) + +/** + * Create a new object by omitting properties of an existing object. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Struct } from "effect" + * + * assert.deepStrictEqual(pipe({ a: "a", b: 1, c: true }, Struct.omit("c")), { a: "a", b: 1 }) + * assert.deepStrictEqual(Struct.omit({ a: "a", b: 1, c: true }, "c"), { a: "a", b: 1 }) + * ``` + * + * @since 2.0.0 + */ +export const omit: { + /** + * Create a new object by omitting properties of an existing object. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Struct } from "effect" + * + * assert.deepStrictEqual(pipe({ a: "a", b: 1, c: true }, Struct.omit("c")), { a: "a", b: 1 }) + * assert.deepStrictEqual(Struct.omit({ a: "a", b: 1, c: true }, "c"), { a: "a", b: 1 }) + * ``` + * + * @since 2.0.0 + */ + >(...keys: Keys): (s: S) => Simplify> + /** + * Create a new object by omitting properties of an existing object. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Struct } from "effect" + * + * assert.deepStrictEqual(pipe({ a: "a", b: 1, c: true }, Struct.omit("c")), { a: "a", b: 1 }) + * assert.deepStrictEqual(Struct.omit({ a: "a", b: 1, c: true }, "c"), { a: "a", b: 1 }) + * ``` + * + * @since 2.0.0 + */ + >(s: S, ...keys: Keys): Simplify> +} = dual( + (args) => Predicate.isObject(args[0]), + >(s: S, ...keys: Keys) => { + const out: any = { ...s } + for (const k of keys) { + delete out[k] + } + return out + } +) + +/** + * Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct + * by applying each `Equivalence` to the corresponding property of the struct. + * + * Alias of {@link Equivalence.struct}. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Struct, String, Number } from "effect" + * + * const PersonEquivalence = Struct.getEquivalence({ + * name: String.Equivalence, + * age: Number.Equivalence + * }) + * + * assert.deepStrictEqual( + * PersonEquivalence({ name: "John", age: 25 }, { name: "John", age: 25 }), + * true + * ) + * assert.deepStrictEqual( + * PersonEquivalence({ name: "John", age: 25 }, { name: "John", age: 40 }), + * false + * ) + * ``` + * + * @category combinators + * @since 2.0.0 + */ +export const getEquivalence: >>( + isEquivalents: R +) => Equivalence.Equivalence< + { readonly [K in keyof R]: [R[K]] extends [Equivalence.Equivalence] ? A : never } +> = Equivalence.struct + +/** + * This function creates and returns a new `Order` for a struct of values based on the given `Order`s + * for each property in the struct. + * + * Alias of {@link order.struct}. + * + * @category combinators + * @since 2.0.0 + */ +export const getOrder: }>( + fields: R +) => order.Order<{ [K in keyof R]: [R[K]] extends [order.Order] ? A : never }> = order.struct + +type Transformed = + & unknown + & { + [K in keyof O]: K extends keyof T ? (T[K] extends (...a: any) => any ? ReturnType : O[K]) : O[K] + } +type PartialTransform = { + [K in keyof T]: T[K] extends (a: O[K & keyof O]) => any ? T[K] : (a: O[K & keyof O]) => unknown +} +/** + * Transforms the values of a Struct provided a transformation function for each key. + * If no transformation function is provided for a key, it will return the original value for that key. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Struct } from "effect" + * + * assert.deepStrictEqual( + * pipe( + * { a: 'a', b: 1, c: 3 }, + * Struct.evolve({ + * a: (a) => a.length, + * b: (b) => b * 2 + * }) + * ), + * { a: 1, b: 2, c: 3 } + * ) + * ``` + * + * @since 2.0.0 + */ +export const evolve: { + /** + * Transforms the values of a Struct provided a transformation function for each key. + * If no transformation function is provided for a key, it will return the original value for that key. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Struct } from "effect" + * + * assert.deepStrictEqual( + * pipe( + * { a: 'a', b: 1, c: 3 }, + * Struct.evolve({ + * a: (a) => a.length, + * b: (b) => b * 2 + * }) + * ), + * { a: 1, b: 2, c: 3 } + * ) + * ``` + * + * @since 2.0.0 + */ + (t: PartialTransform): (obj: O) => Transformed + /** + * Transforms the values of a Struct provided a transformation function for each key. + * If no transformation function is provided for a key, it will return the original value for that key. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Struct } from "effect" + * + * assert.deepStrictEqual( + * pipe( + * { a: 'a', b: 1, c: 3 }, + * Struct.evolve({ + * a: (a) => a.length, + * b: (b) => b * 2 + * }) + * ), + * { a: 1, b: 2, c: 3 } + * ) + * ``` + * + * @since 2.0.0 + */ + (obj: O, t: PartialTransform): Transformed +} = dual( + 2, + (obj: O, t: PartialTransform): Transformed => { + const out = { ...obj } + for (const k in t) { + if (Object.prototype.hasOwnProperty.call(obj, k)) { + // @ts-expect-error + out[k] = t[k](obj[k]) + } + } + return out as any + } +) + +/** + * Retrieves the value associated with the specified key from a struct. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Struct } from "effect" + * + * const value = pipe({ a: 1, b: 2 }, Struct.get("a")) + * + * assert.deepStrictEqual(value, 1) + * ``` + * + * @since 2.0.0 + */ +export const get = + (key: K) => (s: S): MatchRecord => + s[key] + +/** + * Retrieves the object keys that are strings in a typed manner + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Struct } from "effect" + * + * const symbol: unique symbol = Symbol() + * + * const value = { + * a: 1, + * b: 2, + * [symbol]: 3 + * } + * + * const keys: Array<"a" | "b"> = Struct.keys(value) + * + * assert.deepStrictEqual(keys, ["a", "b"]) + * ``` + * + * @since 3.6.0 + */ +export const keys = (o: T): Array<(keyof T) & string> => Object.keys(o) as Array<(keyof T) & string> + +/** + * Retrieves the entries (key-value pairs) of an object, where keys are strings, + * in a type-safe manner. Symbol keys are excluded from the result. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Struct } from "effect" + * + * const c = Symbol("c") + * const value = { a: "foo", b: 1, [c]: true } + * + * const entries: Array<["a" | "b", string | number]> = Struct.entries(value) + * + * assert.deepStrictEqual(entries, [["a", "foo"], ["b", 1]]) + * ``` + * + * @since 3.17.0 + */ +export const entries = (obj: R): Array<[keyof R & string, R[keyof R & string]]> => + Object.entries(obj as any) as any diff --git a/backend/node_modules/effect/src/TMap.ts b/backend/node_modules/effect/src/TMap.ts new file mode 100644 index 0000000000000000000000000000000000000000..9d81192daf67389a91d64046ce4ad81a06101d94 --- /dev/null +++ b/backend/node_modules/effect/src/TMap.ts @@ -0,0 +1,875 @@ +/** + * @since 2.0.0 + */ +import type * as Chunk from "./Chunk.js" +import type { LazyArg } from "./Function.js" +import type * as HashMap from "./HashMap.js" +import * as internal from "./internal/stm/tMap.js" +import type * as Option from "./Option.js" +import type * as STM from "./STM.js" +import type * as TArray from "./TArray.js" +import type * as TRef from "./TRef.js" +import type * as Types from "./Types.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const TMapTypeId: unique symbol = internal.TMapTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type TMapTypeId = typeof TMapTypeId + +/** + * Transactional map implemented on top of `TRef` and `TArray`. Resolves + * conflicts via chaining. + * + * @since 2.0.0 + * @category models + */ +export interface TMap extends TMap.Variance {} +/** + * @internal + * @since 2.0.0 + */ +export interface TMap { + /** @internal */ + readonly tBuckets: TRef.TRef>> + /** @internal */ + readonly tSize: TRef.TRef +} + +/** + * @since 2.0.0 + */ +export declare namespace TMap { + /** + * @since 2.0.0 + * @category models + */ + export interface Variance { + readonly [TMapTypeId]: { + readonly _K: Types.Invariant + readonly _V: Types.Invariant + } + } +} + +/** + * Makes an empty `TMap`. + * + * @since 2.0.0 + * @category constructors + */ +export const empty: () => STM.STM> = internal.empty + +/** + * Finds the key/value pair matching the specified predicate, and uses the + * provided function to extract a value out of it. + * + * @since 2.0.0 + * @category elements + */ +export const find: { + /** + * Finds the key/value pair matching the specified predicate, and uses the + * provided function to extract a value out of it. + * + * @since 2.0.0 + * @category elements + */ + (pf: (key: K, value: V) => Option.Option): (self: TMap) => STM.STM> + /** + * Finds the key/value pair matching the specified predicate, and uses the + * provided function to extract a value out of it. + * + * @since 2.0.0 + * @category elements + */ + (self: TMap, pf: (key: K, value: V) => Option.Option): STM.STM> +} = internal.find + +/** + * Finds the key/value pair matching the specified predicate, and uses the + * provided effectful function to extract a value out of it. + * + * @since 2.0.0 + * @category elements + */ +export const findSTM: { + /** + * Finds the key/value pair matching the specified predicate, and uses the + * provided effectful function to extract a value out of it. + * + * @since 2.0.0 + * @category elements + */ + (f: (key: K, value: V) => STM.STM, R>): (self: TMap) => STM.STM, E, R> + /** + * Finds the key/value pair matching the specified predicate, and uses the + * provided effectful function to extract a value out of it. + * + * @since 2.0.0 + * @category elements + */ + (self: TMap, f: (key: K, value: V) => STM.STM, R>): STM.STM, E, R> +} = internal.findSTM + +/** + * Finds all the key/value pairs matching the specified predicate, and uses + * the provided function to extract values out them. + * + * @since 2.0.0 + * @category elements + */ +export const findAll: { + /** + * Finds all the key/value pairs matching the specified predicate, and uses + * the provided function to extract values out them. + * + * @since 2.0.0 + * @category elements + */ + (pf: (key: K, value: V) => Option.Option): (self: TMap) => STM.STM> + /** + * Finds all the key/value pairs matching the specified predicate, and uses + * the provided function to extract values out them. + * + * @since 2.0.0 + * @category elements + */ + (self: TMap, pf: (key: K, value: V) => Option.Option): STM.STM> +} = internal.findAll + +/** + * Finds all the key/value pairs matching the specified predicate, and uses + * the provided effectful function to extract values out of them.. + * + * @since 2.0.0 + * @category elements + */ +export const findAllSTM: { + /** + * Finds all the key/value pairs matching the specified predicate, and uses + * the provided effectful function to extract values out of them.. + * + * @since 2.0.0 + * @category elements + */ + (pf: (key: K, value: V) => STM.STM, R>): (self: TMap) => STM.STM, E, R> + /** + * Finds all the key/value pairs matching the specified predicate, and uses + * the provided effectful function to extract values out of them.. + * + * @since 2.0.0 + * @category elements + */ + ( + self: TMap, + pf: (key: K, value: V) => STM.STM, R> + ): STM.STM, E, R> +} = internal.findAllSTM + +/** + * Atomically performs transactional-effect for each binding present in map. + * + * @since 2.0.0 + * @category elements + */ +export const forEach: { + /** + * Atomically performs transactional-effect for each binding present in map. + * + * @since 2.0.0 + * @category elements + */ + (f: (key: K, value: V) => STM.STM): (self: TMap) => STM.STM + /** + * Atomically performs transactional-effect for each binding present in map. + * + * @since 2.0.0 + * @category elements + */ + (self: TMap, f: (key: K, value: V) => STM.STM): STM.STM +} = internal.forEach + +/** + * Creates a new `TMap` from an iterable collection of key/value pairs. + * + * @since 2.0.0 + * @category constructors + */ +export const fromIterable: ( + iterable: Iterable +) => STM.STM> = internal.fromIterable + +/** + * Retrieves value associated with given key. + * + * @since 2.0.0 + * @category elements + */ +export const get: { + /** + * Retrieves value associated with given key. + * + * @since 2.0.0 + * @category elements + */ + (key: K): (self: TMap) => STM.STM> + /** + * Retrieves value associated with given key. + * + * @since 2.0.0 + * @category elements + */ + (self: TMap, key: K): STM.STM> +} = internal.get + +/** + * Retrieves value associated with given key or default value, in case the key + * isn't present. + * + * @since 2.0.0 + * @category elements + */ +export const getOrElse: { + /** + * Retrieves value associated with given key or default value, in case the key + * isn't present. + * + * @since 2.0.0 + * @category elements + */ + (key: K, fallback: LazyArg): (self: TMap) => STM.STM + /** + * Retrieves value associated with given key or default value, in case the key + * isn't present. + * + * @since 2.0.0 + * @category elements + */ + (self: TMap, key: K, fallback: LazyArg): STM.STM +} = internal.getOrElse + +/** + * Tests whether or not map contains a key. + * + * @since 2.0.0 + * @category elements + */ +export const has: { + /** + * Tests whether or not map contains a key. + * + * @since 2.0.0 + * @category elements + */ + (key: K): (self: TMap) => STM.STM + /** + * Tests whether or not map contains a key. + * + * @since 2.0.0 + * @category elements + */ + (self: TMap, key: K): STM.STM +} = internal.has + +/** + * Tests if the map is empty or not. + * + * @since 2.0.0 + * @category getters + */ +export const isEmpty: (self: TMap) => STM.STM = internal.isEmpty + +/** + * Collects all keys stored in map. + * + * @since 2.0.0 + * @category elements + */ +export const keys: (self: TMap) => STM.STM> = internal.keys + +/** + * Makes a new `TMap` that is initialized with specified values. + * + * @since 2.0.0 + * @category constructors + */ +export const make: (...entries: Array) => STM.STM> = internal.make + +/** + * If the key is not already associated with a value, stores the provided value, + * otherwise merge the existing value with the new one using function `f` and + * store the result. + * + * @since 2.0.0 + * @category mutations + */ +export const merge: { + /** + * If the key is not already associated with a value, stores the provided value, + * otherwise merge the existing value with the new one using function `f` and + * store the result. + * + * @since 2.0.0 + * @category mutations + */ + (key: K, value: V, f: (x: V, y: V) => V): (self: TMap) => STM.STM + /** + * If the key is not already associated with a value, stores the provided value, + * otherwise merge the existing value with the new one using function `f` and + * store the result. + * + * @since 2.0.0 + * @category mutations + */ + (self: TMap, key: K, value: V, f: (x: V, y: V) => V): STM.STM +} = internal.merge + +/** + * Atomically folds using a pure function. + * + * @since 2.0.0 + * @category folding + */ +export const reduce: { + /** + * Atomically folds using a pure function. + * + * @since 2.0.0 + * @category folding + */ + (zero: Z, f: (acc: Z, value: V, key: K) => Z): (self: TMap) => STM.STM + /** + * Atomically folds using a pure function. + * + * @since 2.0.0 + * @category folding + */ + (self: TMap, zero: Z, f: (acc: Z, value: V, key: K) => Z): STM.STM +} = internal.reduce + +/** + * Atomically folds using a transactional function. + * + * @since 2.0.0 + * @category folding + */ +export const reduceSTM: { + /** + * Atomically folds using a transactional function. + * + * @since 2.0.0 + * @category folding + */ + (zero: Z, f: (acc: Z, value: V, key: K) => STM.STM): (self: TMap) => STM.STM + /** + * Atomically folds using a transactional function. + * + * @since 2.0.0 + * @category folding + */ + ( + self: TMap, + zero: Z, + f: (acc: Z, value: V, key: K) => STM.STM + ): STM.STM +} = internal.reduceSTM + +/** + * Removes binding for given key. + * + * @since 2.0.0 + * @category mutations + */ +export const remove: { + /** + * Removes binding for given key. + * + * @since 2.0.0 + * @category mutations + */ + (key: K): (self: TMap) => STM.STM + /** + * Removes binding for given key. + * + * @since 2.0.0 + * @category mutations + */ + (self: TMap, key: K): STM.STM +} = internal.remove + +/** + * Deletes all entries associated with the specified keys. + * + * @since 2.0.0 + * @category mutations + */ +export const removeAll: { + /** + * Deletes all entries associated with the specified keys. + * + * @since 2.0.0 + * @category mutations + */ + (keys: Iterable): (self: TMap) => STM.STM + /** + * Deletes all entries associated with the specified keys. + * + * @since 2.0.0 + * @category mutations + */ + (self: TMap, keys: Iterable): STM.STM +} = internal.removeAll + +/** + * Removes entries from a `TMap` that satisfy the specified predicate and returns the removed entries + * (or `void` if `discard = true`). + * + * @since 2.0.0 + * @category mutations + */ +export const removeIf: { + /** + * Removes entries from a `TMap` that satisfy the specified predicate and returns the removed entries + * (or `void` if `discard = true`). + * + * @since 2.0.0 + * @category mutations + */ + ( + predicate: (key: K, value: V) => boolean, + options: { + readonly discard: true + } + ): (self: TMap) => STM.STM + /** + * Removes entries from a `TMap` that satisfy the specified predicate and returns the removed entries + * (or `void` if `discard = true`). + * + * @since 2.0.0 + * @category mutations + */ + ( + predicate: (key: K, value: V) => boolean, + options?: { + readonly discard: false + } + ): (self: TMap) => STM.STM> + /** + * Removes entries from a `TMap` that satisfy the specified predicate and returns the removed entries + * (or `void` if `discard = true`). + * + * @since 2.0.0 + * @category mutations + */ + ( + self: TMap, + predicate: (key: K, value: V) => boolean, + options: { + readonly discard: true + } + ): STM.STM + /** + * Removes entries from a `TMap` that satisfy the specified predicate and returns the removed entries + * (or `void` if `discard = true`). + * + * @since 2.0.0 + * @category mutations + */ + ( + self: TMap, + predicate: (key: K, value: V) => boolean, + options?: { + readonly discard: false + } + ): STM.STM> +} = internal.removeIf + +/** + * Retains entries in a `TMap` that satisfy the specified predicate and returns the removed entries + * (or `void` if `discard = true`). + * + * @since 2.0.0 + * @category mutations + */ +export const retainIf: { + /** + * Retains entries in a `TMap` that satisfy the specified predicate and returns the removed entries + * (or `void` if `discard = true`). + * + * @since 2.0.0 + * @category mutations + */ + ( + predicate: (key: K, value: V) => boolean, + options: { + readonly discard: true + } + ): (self: TMap) => STM.STM + /** + * Retains entries in a `TMap` that satisfy the specified predicate and returns the removed entries + * (or `void` if `discard = true`). + * + * @since 2.0.0 + * @category mutations + */ + ( + predicate: (key: K, value: V) => boolean, + options?: { + readonly discard: false + } + ): (self: TMap) => STM.STM> + /** + * Retains entries in a `TMap` that satisfy the specified predicate and returns the removed entries + * (or `void` if `discard = true`). + * + * @since 2.0.0 + * @category mutations + */ + ( + self: TMap, + predicate: (key: K, value: V) => boolean, + options: { + readonly discard: true + } + ): STM.STM + /** + * Retains entries in a `TMap` that satisfy the specified predicate and returns the removed entries + * (or `void` if `discard = true`). + * + * @since 2.0.0 + * @category mutations + */ + ( + self: TMap, + predicate: (key: K, value: V) => boolean, + options?: { + readonly discard: false + } + ): STM.STM> +} = internal.retainIf + +/** + * Stores new binding into the map. + * + * @since 2.0.0 + * @category mutations + */ +export const set: { + /** + * Stores new binding into the map. + * + * @since 2.0.0 + * @category mutations + */ + (key: K, value: V): (self: TMap) => STM.STM + /** + * Stores new binding into the map. + * + * @since 2.0.0 + * @category mutations + */ + (self: TMap, key: K, value: V): STM.STM +} = internal.set + +/** + * Stores new binding in the map if it does not already exist. + * + * @since 2.0.0 + * @category mutations + */ +export const setIfAbsent: { + /** + * Stores new binding in the map if it does not already exist. + * + * @since 2.0.0 + * @category mutations + */ + (key: K, value: V): (self: TMap) => STM.STM + /** + * Stores new binding in the map if it does not already exist. + * + * @since 2.0.0 + * @category mutations + */ + (self: TMap, key: K, value: V): STM.STM +} = internal.setIfAbsent + +/** + * Returns the number of bindings. + * + * @since 2.0.0 + * @category getters + */ +export const size: (self: TMap) => STM.STM = internal.size + +/** + * Takes the first matching value, or retries until there is one. + * + * @since 2.0.0 + * @category mutations + */ +export const takeFirst: { + /** + * Takes the first matching value, or retries until there is one. + * + * @since 2.0.0 + * @category mutations + */ + (pf: (key: K, value: V) => Option.Option): (self: TMap) => STM.STM + /** + * Takes the first matching value, or retries until there is one. + * + * @since 2.0.0 + * @category mutations + */ + (self: TMap, pf: (key: K, value: V) => Option.Option): STM.STM +} = internal.takeFirst + +/** + * Takes the first matching value, or retries until there is one. + * + * @since 2.0.0 + * @category mutations + */ +export const takeFirstSTM: { + /** + * Takes the first matching value, or retries until there is one. + * + * @since 2.0.0 + * @category mutations + */ + (pf: (key: K, value: V) => STM.STM, R>): (self: TMap) => STM.STM + /** + * Takes the first matching value, or retries until there is one. + * + * @since 2.0.0 + * @category mutations + */ + ( + self: TMap, + pf: (key: K, value: V) => STM.STM, R> + ): STM.STM +} = internal.takeFirstSTM + +/** + * Takes all matching values, or retries until there is at least one. + * + * @since 2.0.0 + * @category mutations + */ +export const takeSome: { + /** + * Takes all matching values, or retries until there is at least one. + * + * @since 2.0.0 + * @category mutations + */ + (pf: (key: K, value: V) => Option.Option): (self: TMap) => STM.STM<[A, ...Array]> + /** + * Takes all matching values, or retries until there is at least one. + * + * @since 2.0.0 + * @category mutations + */ + (self: TMap, pf: (key: K, value: V) => Option.Option): STM.STM<[A, ...Array]> +} = internal.takeSome + +/** + * Takes all matching values, or retries until there is at least one. + * + * @since 2.0.0 + * @category mutations + */ +export const takeSomeSTM: { + /** + * Takes all matching values, or retries until there is at least one. + * + * @since 2.0.0 + * @category mutations + */ + (pf: (key: K, value: V) => STM.STM, R>): (self: TMap) => STM.STM<[A, ...Array], E, R> + /** + * Takes all matching values, or retries until there is at least one. + * + * @since 2.0.0 + * @category mutations + */ + ( + self: TMap, + pf: (key: K, value: V) => STM.STM, R> + ): STM.STM<[A, ...Array], E, R> +} = internal.takeSomeSTM + +/** + * Collects all bindings into a `Chunk`. + * + * @since 2.0.0 + * @category destructors + */ +export const toChunk: (self: TMap) => STM.STM> = internal.toChunk + +/** + * Collects all bindings into a `HashMap`. + * + * @since 2.0.0 + * @category destructors + */ +export const toHashMap: (self: TMap) => STM.STM> = internal.toHashMap + +/** + * Collects all bindings into an `Array`. + * + * @since 2.0.0 + * @category destructors + */ +export const toArray: (self: TMap) => STM.STM> = internal.toArray + +/** + * Collects all bindings into a `Map`. + * + * @since 2.0.0 + * @category destructors + */ +export const toMap: (self: TMap) => STM.STM> = internal.toMap + +/** + * Atomically updates all bindings using a pure function. + * + * @since 2.0.0 + * @category mutations + */ +export const transform: { + /** + * Atomically updates all bindings using a pure function. + * + * @since 2.0.0 + * @category mutations + */ + (f: (key: K, value: V) => readonly [K, V]): (self: TMap) => STM.STM + /** + * Atomically updates all bindings using a pure function. + * + * @since 2.0.0 + * @category mutations + */ + (self: TMap, f: (key: K, value: V) => readonly [K, V]): STM.STM +} = internal.transform + +/** + * Atomically updates all bindings using a transactional function. + * + * @since 2.0.0 + * @category mutations + */ +export const transformSTM: { + /** + * Atomically updates all bindings using a transactional function. + * + * @since 2.0.0 + * @category mutations + */ + (f: (key: K, value: V) => STM.STM): (self: TMap) => STM.STM + /** + * Atomically updates all bindings using a transactional function. + * + * @since 2.0.0 + * @category mutations + */ + (self: TMap, f: (key: K, value: V) => STM.STM): STM.STM +} = internal.transformSTM + +/** + * Atomically updates all values using a pure function. + * + * @since 2.0.0 + * @category mutations + */ +export const transformValues: { + /** + * Atomically updates all values using a pure function. + * + * @since 2.0.0 + * @category mutations + */ + (f: (value: V) => V): (self: TMap) => STM.STM + /** + * Atomically updates all values using a pure function. + * + * @since 2.0.0 + * @category mutations + */ + (self: TMap, f: (value: V) => V): STM.STM +} = internal.transformValues + +/** + * Atomically updates all values using a transactional function. + * + * @since 2.0.0 + * @category mutations + */ +export const transformValuesSTM: { + /** + * Atomically updates all values using a transactional function. + * + * @since 2.0.0 + * @category mutations + */ + (f: (value: V) => STM.STM): (self: TMap) => STM.STM + /** + * Atomically updates all values using a transactional function. + * + * @since 2.0.0 + * @category mutations + */ + (self: TMap, f: (value: V) => STM.STM): STM.STM +} = internal.transformValuesSTM + +/** + * Updates the mapping for the specified key with the specified function, + * which takes the current value of the key as an input, if it exists, and + * either returns `Some` with a new value to indicate to update the value in + * the map or `None` to remove the value from the map. Returns `Some` with the + * updated value or `None` if the value was removed from the map. + * + * @since 2.0.0 + * @category mutations + */ +export const updateWith: { + /** + * Updates the mapping for the specified key with the specified function, + * which takes the current value of the key as an input, if it exists, and + * either returns `Some` with a new value to indicate to update the value in + * the map or `None` to remove the value from the map. Returns `Some` with the + * updated value or `None` if the value was removed from the map. + * + * @since 2.0.0 + * @category mutations + */ + (key: K, f: (value: Option.Option) => Option.Option): (self: TMap) => STM.STM> + /** + * Updates the mapping for the specified key with the specified function, + * which takes the current value of the key as an input, if it exists, and + * either returns `Some` with a new value to indicate to update the value in + * the map or `None` to remove the value from the map. Returns `Some` with the + * updated value or `None` if the value was removed from the map. + * + * @since 2.0.0 + * @category mutations + */ + (self: TMap, key: K, f: (value: Option.Option) => Option.Option): STM.STM> +} = internal.updateWith + +/** + * Collects all values stored in map. + * + * @since 2.0.0 + * @category elements + */ +export const values: (self: TMap) => STM.STM> = internal.values diff --git a/backend/node_modules/effect/src/TPubSub.ts b/backend/node_modules/effect/src/TPubSub.ts new file mode 100644 index 0000000000000000000000000000000000000000..1eee7b2e0bd6a72c385377e22dbd148285a43df7 --- /dev/null +++ b/backend/node_modules/effect/src/TPubSub.ts @@ -0,0 +1,228 @@ +/** + * @since 2.0.0 + */ +import type * as Effect from "./Effect.js" +import type * as HashSet from "./HashSet.js" +import * as internal from "./internal/stm/tPubSub.js" +import type * as tQueue from "./internal/stm/tQueue.js" +import type * as Scope from "./Scope.js" +import type * as STM from "./STM.js" +import type * as TQueue from "./TQueue.js" +import type * as TRef from "./TRef.js" +import type * as Types from "./Types.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const TPubSubTypeId: unique symbol = internal.TPubSubTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type TPubSubTypeId = typeof TPubSubTypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface TPubSub extends TQueue.TEnqueue { + readonly [TPubSubTypeId]: { + readonly _A: Types.Invariant + } +} +/** + * @internal + * @since 2.0.0 + */ +export interface TPubSub { + /** @internal */ + readonly pubsubSize: TRef.TRef + /** @internal */ + readonly publisherHead: TRef.TRef | undefined>> + /** @internal */ + readonly publisherTail: TRef.TRef | undefined> | undefined> + /** @internal */ + readonly requestedCapacity: number + /** @internal */ + readonly strategy: tQueue.TQueueStrategy + /** @internal */ + readonly subscriberCount: TRef.TRef + /** @internal */ + readonly subscribers: TRef.TRef> | undefined>>> +} + +/** + * Waits until the `TPubSub` is shutdown. The `STM` returned by this method will + * not resume until the queue has been shutdown. If the `TPubSub` is already + * shutdown, the `STM` will resume right away. + * + * @since 2.0.0 + * @category mutations + */ +export const awaitShutdown: (self: TPubSub) => STM.STM = internal.awaitShutdown + +/** + * Creates a bounded `TPubSub` with the back pressure strategy. The `TPubSub` will retain + * messages until they have been taken by all subscribers, applying back + * pressure to publishers if the `TPubSub` is at capacity. + * + * @since 2.0.0 + * @category constructors + */ +export const bounded: (requestedCapacity: number) => STM.STM> = internal.bounded + +/** + * Returns the number of elements the `TPubSub` can hold. + * + * @since 2.0.0 + * @category getters + */ +export const capacity: (self: TPubSub) => number = internal.capacity + +/** + * Creates a bounded `TPubSub` with the dropping strategy. The `TPubSub` will drop new + * messages if the `TPubSub` is at capacity. + * + * @since 2.0.0 + * @category constructors + */ +export const dropping: (requestedCapacity: number) => STM.STM> = internal.dropping + +/** + * Returns `true` if the `TPubSub` contains zero elements, `false` otherwise. + * + * @since 2.0.0 + * @category getters + */ +export const isEmpty: (self: TPubSub) => STM.STM = internal.isEmpty + +/** + * Returns `true` if the `TPubSub` contains at least one element, `false` + * otherwise. + * + * @since 2.0.0 + * @category getters + */ +export const isFull: (self: TPubSub) => STM.STM = internal.isFull + +/** + * Interrupts any fibers that are suspended on `offer` or `take`. Future calls + * to `offer*` and `take*` will be interrupted immediately. + * + * @since 2.0.0 + * @category utils + */ +export const shutdown: (self: TPubSub) => STM.STM = internal.shutdown + +/** + * Returns `true` if `shutdown` has been called, otherwise returns `false`. + * + * @since 2.0.0 + * @category getters + */ +export const isShutdown: (self: TPubSub) => STM.STM = internal.isShutdown + +/** + * Publishes a message to the `TPubSub`, returning whether the message was published + * to the `TPubSub`. + * + * @since 2.0.0 + * @category mutations + */ +export const publish: { + /** + * Publishes a message to the `TPubSub`, returning whether the message was published + * to the `TPubSub`. + * + * @since 2.0.0 + * @category mutations + */ + (value: A): (self: TPubSub) => STM.STM + /** + * Publishes a message to the `TPubSub`, returning whether the message was published + * to the `TPubSub`. + * + * @since 2.0.0 + * @category mutations + */ + (self: TPubSub, value: A): STM.STM +} = internal.publish + +/** + * Publishes all of the specified messages to the `TPubSub`, returning whether they + * were published to the `TPubSub`. + * + * @since 2.0.0 + * @category mutations + */ +export const publishAll: { + /** + * Publishes all of the specified messages to the `TPubSub`, returning whether they + * were published to the `TPubSub`. + * + * @since 2.0.0 + * @category mutations + */ + (iterable: Iterable): (self: TPubSub) => STM.STM + /** + * Publishes all of the specified messages to the `TPubSub`, returning whether they + * were published to the `TPubSub`. + * + * @since 2.0.0 + * @category mutations + */ + (self: TPubSub, iterable: Iterable): STM.STM +} = internal.publishAll + +/** + * Retrieves the size of the `TPubSub`, which is equal to the number of elements + * in the `TPubSub`. This may be negative if fibers are suspended waiting for + * elements to be added to the `TPubSub`. + * + * @since 2.0.0 + * @category getters + */ +export const size: (self: TPubSub) => STM.STM = internal.size + +/** + * Creates a bounded `TPubSub` with the sliding strategy. The `TPubSub` will add new + * messages and drop old messages if the `TPubSub` is at capacity. + * + * For best performance use capacities that are powers of two. + * + * @since 2.0.0 + * @category constructors + */ +export const sliding: (requestedCapacity: number) => STM.STM> = internal.sliding + +/** + * Subscribes to receive messages from the `TPubSub`. The resulting subscription can + * be evaluated multiple times to take a message from the `TPubSub` each time. The + * caller is responsible for unsubscribing from the `TPubSub` by shutting down the + * queue. + * + * @since 2.0.0 + * @category mutations + */ +export const subscribe: (self: TPubSub) => STM.STM> = internal.subscribe + +/** + * Subscribes to receive messages from the `TPubSub`. The resulting subscription can + * be evaluated multiple times within the scope to take a message from the `TPubSub` + * each time. + * + * @since 2.0.0 + * @category mutations + */ +export const subscribeScoped: (self: TPubSub) => Effect.Effect, never, Scope.Scope> = + internal.subscribeScoped + +/** + * Creates an unbounded `TPubSub`. + * + * @since 2.0.0 + * @category constructors + */ +export const unbounded: () => STM.STM> = internal.unbounded diff --git a/backend/node_modules/effect/src/TQueue.ts b/backend/node_modules/effect/src/TQueue.ts new file mode 100644 index 0000000000000000000000000000000000000000..648cfab11f7b80db454307624fffb0f8b14a4d2e --- /dev/null +++ b/backend/node_modules/effect/src/TQueue.ts @@ -0,0 +1,540 @@ +/** + * @since 2.0.0 + */ +import * as internal from "./internal/stm/tQueue.js" +import type * as Option from "./Option.js" +import type { Predicate } from "./Predicate.js" +import type * as STM from "./STM.js" +import type * as Types from "./Types.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const TDequeueTypeId: unique symbol = internal.TDequeueTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type TDequeueTypeId = typeof TDequeueTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export const TEnqueueTypeId: unique symbol = internal.TEnqueueTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type TEnqueueTypeId = typeof TEnqueueTypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface TQueue extends TEnqueue, TDequeue {} + +/** + * @since 2.0.0 + * @category models + */ +export interface TEnqueue extends TQueue.TEnqueueVariance, BaseTQueue { + /** + * Places one value in the queue. + */ + offer(value: A): STM.STM + + /** + * For Bounded TQueue: uses the `BackPressure` Strategy, places the values in + * the queue and always returns true. If the queue has reached capacity, then + * the fiber performing the `offerAll` will be suspended until there is room + * in the queue. + * + * For Unbounded TQueue: Places all values in the queue and returns true. + * + * For Sliding TQueue: uses `Sliding` Strategy If there is room in the queue, + * it places the values otherwise it removes the old elements and enqueues the + * new ones. Always returns true. + * + * For Dropping TQueue: uses `Dropping` Strategy, It places the values in the + * queue but if there is no room it will not enqueue them and return false. + */ + offerAll(iterable: Iterable): STM.STM +} + +/** + * @since 2.0.0 + * @category models + */ +export interface TDequeue extends TQueue.TDequeueVariance, BaseTQueue { + /** + * Views the next element in the queue without removing it, retrying if the + * queue is empty. + */ + readonly peek: STM.STM + + /** + * Views the next element in the queue without removing it, returning `None` + * if the queue is empty. + */ + readonly peekOption: STM.STM> + + /** + * Takes the oldest value in the queue. If the queue is empty, this will return + * a computation that resumes when an item has been added to the queue. + */ + readonly take: STM.STM + + /** + * Takes all the values in the queue and returns the values. If the queue is + * empty returns an empty collection. + */ + readonly takeAll: STM.STM> + + /** + * Takes up to max number of values from the queue. + */ + takeUpTo(max: number): STM.STM> +} + +/** + * The base interface that all `TQueue`s must implement. + * + * @since 2.0.0 + * @category models + */ +export interface BaseTQueue { + /** + * Returns the number of elements the queue can hold. + */ + capacity(): number + + /** + * Retrieves the size of the queue, which is equal to the number of elements + * in the queue. This may be negative if fibers are suspended waiting for + * elements to be added to the queue. + */ + readonly size: STM.STM + + /** + * Returns `true` if the `TQueue` contains at least one element, `false` + * otherwise. + */ + readonly isFull: STM.STM + + /** + * Returns `true` if the `TQueue` contains zero elements, `false` otherwise. + */ + readonly isEmpty: STM.STM + + /** + * Interrupts any fibers that are suspended on `offer` or `take`. Future calls + * to `offer*` and `take*` will be interrupted immediately. + */ + readonly shutdown: STM.STM + + /** + * Returns `true` if `shutdown` has been called, otherwise returns `false`. + */ + readonly isShutdown: STM.STM + + /** + * Waits until the queue is shutdown. The `STM` returned by this method will + * not resume until the queue has been shutdown. If the queue is already + * shutdown, the `STM` will resume right away. + */ + readonly awaitShutdown: STM.STM +} + +/** + * @since 2.0.0 + */ +export declare namespace TQueue { + /** + * @since 2.0.0 + * @category models + */ + export interface TEnqueueVariance { + readonly [TEnqueueTypeId]: { + readonly _In: Types.Contravariant + } + } + + /** + * @since 2.0.0 + * @category models + */ + export interface TDequeueVariance { + readonly [TDequeueTypeId]: { + readonly _Out: Types.Covariant + } + } +} + +/** + * Returns `true` if the specified value is a `TQueue`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isTQueue: (u: unknown) => u is TQueue = internal.isTQueue + +/** + * Returns `true` if the specified value is a `TDequeue`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isTDequeue: (u: unknown) => u is TDequeue = internal.isTDequeue + +/** + * Returns `true` if the specified value is a `TEnqueue`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isTEnqueue: (u: unknown) => u is TEnqueue = internal.isTEnqueue + +/** + * Waits until the queue is shutdown. The `STM` returned by this method will + * not resume until the queue has been shutdown. If the queue is already + * shutdown, the `STM` will resume right away. + * + * @since 2.0.0 + * @category mutations + */ +export const awaitShutdown: (self: TDequeue | TEnqueue) => STM.STM = internal.awaitShutdown + +/** + * Creates a bounded queue with the back pressure strategy. The queue will + * retain values until they have been taken, applying back pressure to + * offerors if the queue is at capacity. + * + * For best performance use capacities that are powers of two. + * + * @since 2.0.0 + * @category constructors + */ +export const bounded: (requestedCapacity: number) => STM.STM> = internal.bounded + +/** + * Returns the number of elements the queue can hold. + * + * @since 2.0.0 + * @category getters + */ +export const capacity: (self: TDequeue | TEnqueue) => number = internal.capacity + +/** + * Creates a bounded queue with the dropping strategy. The queue will drop new + * values if the queue is at capacity. + * + * For best performance use capacities that are powers of two. + * + * @since 2.0.0 + * @category constructors + */ +export const dropping: (requestedCapacity: number) => STM.STM> = internal.dropping + +/** + * Returns `true` if the `TQueue` contains zero elements, `false` otherwise. + * + * @since 2.0.0 + * @category getters + */ +export const isEmpty: (self: TDequeue | TEnqueue) => STM.STM = internal.isEmpty + +/** + * Returns `true` if the `TQueue` contains at least one element, `false` + * otherwise. + * + * @since 2.0.0 + * @category getters + */ +export const isFull: (self: TDequeue | TEnqueue) => STM.STM = internal.isFull + +/** + * Returns `true` if `shutdown` has been called, otherwise returns `false`. + * + * @since 2.0.0 + * @category getters + */ +export const isShutdown: (self: TDequeue | TEnqueue) => STM.STM = internal.isShutdown + +/** + * Places one value in the queue. + * + * @since 2.0.0 + * @category mutations + */ +export const offer: { + /** + * Places one value in the queue. + * + * @since 2.0.0 + * @category mutations + */ + (value: A): (self: TEnqueue) => STM.STM + /** + * Places one value in the queue. + * + * @since 2.0.0 + * @category mutations + */ + (self: TEnqueue, value: A): STM.STM +} = internal.offer + +/** + * For Bounded TQueue: uses the `BackPressure` Strategy, places the values in + * the queue and always returns true. If the queue has reached capacity, then + * the fiber performing the `offerAll` will be suspended until there is room + * in the queue. + * + * For Unbounded TQueue: Places all values in the queue and returns true. + * + * For Sliding TQueue: uses `Sliding` Strategy If there is room in the queue, + * it places the values otherwise it removes the old elements and enqueues the + * new ones. Always returns true. + * + * For Dropping TQueue: uses `Dropping` Strategy, It places the values in the + * queue but if there is no room it will not enqueue them and return false. + * + * @since 2.0.0 + * @category mutations + */ +export const offerAll: { + /** + * For Bounded TQueue: uses the `BackPressure` Strategy, places the values in + * the queue and always returns true. If the queue has reached capacity, then + * the fiber performing the `offerAll` will be suspended until there is room + * in the queue. + * + * For Unbounded TQueue: Places all values in the queue and returns true. + * + * For Sliding TQueue: uses `Sliding` Strategy If there is room in the queue, + * it places the values otherwise it removes the old elements and enqueues the + * new ones. Always returns true. + * + * For Dropping TQueue: uses `Dropping` Strategy, It places the values in the + * queue but if there is no room it will not enqueue them and return false. + * + * @since 2.0.0 + * @category mutations + */ + (iterable: Iterable): (self: TEnqueue) => STM.STM + /** + * For Bounded TQueue: uses the `BackPressure` Strategy, places the values in + * the queue and always returns true. If the queue has reached capacity, then + * the fiber performing the `offerAll` will be suspended until there is room + * in the queue. + * + * For Unbounded TQueue: Places all values in the queue and returns true. + * + * For Sliding TQueue: uses `Sliding` Strategy If there is room in the queue, + * it places the values otherwise it removes the old elements and enqueues the + * new ones. Always returns true. + * + * For Dropping TQueue: uses `Dropping` Strategy, It places the values in the + * queue but if there is no room it will not enqueue them and return false. + * + * @since 2.0.0 + * @category mutations + */ + (self: TEnqueue, iterable: Iterable): STM.STM +} = internal.offerAll + +/** + * Views the next element in the queue without removing it, retrying if the + * queue is empty. + * + * @since 2.0.0 + * @category getters + */ +export const peek: (self: TDequeue) => STM.STM = internal.peek + +/** + * Views the next element in the queue without removing it, returning `None` + * if the queue is empty. + * + * @since 2.0.0 + * @category getters + */ +export const peekOption: (self: TDequeue) => STM.STM> = internal.peekOption + +/** + * Takes a single element from the queue, returning `None` if the queue is + * empty. + * + * @since 2.0.0 + * @category getters + */ +export const poll: (self: TDequeue) => STM.STM> = internal.poll + +/** + * Drops elements from the queue while they do not satisfy the predicate, + * taking and returning the first element that does satisfy the predicate. + * Retries if no elements satisfy the predicate. + * + * @since 2.0.0 + * @category mutations + */ +export const seek: { + /** + * Drops elements from the queue while they do not satisfy the predicate, + * taking and returning the first element that does satisfy the predicate. + * Retries if no elements satisfy the predicate. + * + * @since 2.0.0 + * @category mutations + */ + (predicate: Predicate): (self: TDequeue) => STM.STM + /** + * Drops elements from the queue while they do not satisfy the predicate, + * taking and returning the first element that does satisfy the predicate. + * Retries if no elements satisfy the predicate. + * + * @since 2.0.0 + * @category mutations + */ + (self: TDequeue, predicate: Predicate): STM.STM +} = internal.seek + +/** + * Interrupts any fibers that are suspended on `offer` or `take`. Future calls + * to `offer*` and `take*` will be interrupted immediately. + * + * @since 2.0.0 + * @category mutations + */ +export const shutdown: (self: TDequeue | TEnqueue) => STM.STM = internal.shutdown + +/** + * Retrieves the size of the queue, which is equal to the number of elements + * in the queue. This may be negative if fibers are suspended waiting for + * elements to be added to the queue. + * + * @since 2.0.0 + * @category getters + */ +export const size: (self: TDequeue | TEnqueue) => STM.STM = internal.size + +/** + * Creates a bounded queue with the sliding strategy. The queue will add new + * values and drop old values if the queue is at capacity. + * + * For best performance use capacities that are powers of two. + * + * @since 2.0.0 + * @category constructors + */ +export const sliding: (requestedCapacity: number) => STM.STM> = internal.sliding + +/** + * Takes the oldest value in the queue. If the queue is empty, this will return + * a computation that resumes when an item has been added to the queue. + * + * @since 2.0.0 + * @category mutations + */ +export const take: (self: TDequeue) => STM.STM = internal.take + +/** + * Takes all the values in the queue and returns the values. If the queue is + * empty returns an empty collection. + * + * @since 2.0.0 + * @category mutations + */ +export const takeAll: (self: TDequeue) => STM.STM> = internal.takeAll + +/** + * Takes a number of elements from the queue between the specified minimum and + * maximum. If there are fewer than the minimum number of elements available, + * retries until at least the minimum number of elements have been collected. + * + * @since 2.0.0 + * @category mutations + */ +export const takeBetween: { + /** + * Takes a number of elements from the queue between the specified minimum and + * maximum. If there are fewer than the minimum number of elements available, + * retries until at least the minimum number of elements have been collected. + * + * @since 2.0.0 + * @category mutations + */ + (min: number, max: number): (self: TDequeue) => STM.STM> + /** + * Takes a number of elements from the queue between the specified minimum and + * maximum. If there are fewer than the minimum number of elements available, + * retries until at least the minimum number of elements have been collected. + * + * @since 2.0.0 + * @category mutations + */ + (self: TDequeue, min: number, max: number): STM.STM> +} = internal.takeBetween + +/** + * Takes the specified number of elements from the queue. If there are fewer + * than the specified number of elements available, it retries until they + * become available. + * + * @since 2.0.0 + * @category mutations + */ +export const takeN: { + /** + * Takes the specified number of elements from the queue. If there are fewer + * than the specified number of elements available, it retries until they + * become available. + * + * @since 2.0.0 + * @category mutations + */ + (n: number): (self: TDequeue) => STM.STM> + /** + * Takes the specified number of elements from the queue. If there are fewer + * than the specified number of elements available, it retries until they + * become available. + * + * @since 2.0.0 + * @category mutations + */ + (self: TDequeue, n: number): STM.STM> +} = internal.takeN + +/** + * Takes up to max number of values from the queue. + * + * @since 2.0.0 + * @category mutations + */ +export const takeUpTo: { + /** + * Takes up to max number of values from the queue. + * + * @since 2.0.0 + * @category mutations + */ + (max: number): (self: TDequeue) => STM.STM> + /** + * Takes up to max number of values from the queue. + * + * @since 2.0.0 + * @category mutations + */ + (self: TDequeue, max: number): STM.STM> +} = internal.takeUpTo + +/** + * Creates an unbounded queue. + * + * @since 2.0.0 + * @category constructors + */ +export const unbounded: () => STM.STM> = internal.unbounded diff --git a/backend/node_modules/effect/src/TRandom.ts b/backend/node_modules/effect/src/TRandom.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb9e4bfbea77dd49dc5d00f227a0abfe4b0c8809 --- /dev/null +++ b/backend/node_modules/effect/src/TRandom.ts @@ -0,0 +1,129 @@ +/** + * @since 2.0.0 + */ +import type * as Context from "./Context.js" +import * as internal from "./internal/stm/tRandom.js" +import type * as Layer from "./Layer.js" +import type * as STM from "./STM.js" +import type * as TRef from "./TRef.js" +import type * as Random from "./Utils.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const TRandomTypeId: unique symbol = internal.TRandomTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type TRandomTypeId = typeof TRandomTypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface TRandom { + readonly [TRandomTypeId]: TRandomTypeId + /** + * Returns the next numeric value from the pseudo-random number generator. + */ + readonly next: STM.STM + /** + * Returns the next boolean value from the pseudo-random number generator. + */ + readonly nextBoolean: STM.STM + /** + * Returns the next integer value from the pseudo-random number generator. + */ + readonly nextInt: STM.STM + /** + * Returns the next numeric value in the specified range from the + * pseudo-random number generator. + */ + nextRange(min: number, max: number): STM.STM + /** + * Returns the next integer value in the specified range from the + * pseudo-random number generator. + */ + nextIntBetween(min: number, max: number): STM.STM + /** + * Uses the pseudo-random number generator to shuffle the specified iterable. + */ + shuffle(elements: Iterable): STM.STM> +} +/** + * @internal + * @since 2.0.0 + */ +export interface TRandom { + /** @internal */ + readonly state: TRef.TRef +} + +/** + * The service tag used to access `TRandom` in the environment of an effect. + * + * @since 2.0.0 + * @category context + */ +export const Tag: Context.Tag = internal.Tag + +/** + * The "live" `TRandom` service wrapped into a `Layer`. + * + * @since 2.0.0 + * @category context + */ +export const live: Layer.Layer = internal.live + +/** + * Returns the next number from the pseudo-random number generator. + * + * @since 2.0.0 + * @category random + */ +export const next: STM.STM = internal.next + +/** + * Returns the next boolean value from the pseudo-random number generator. + * + * @since 2.0.0 + * @category random + */ +export const nextBoolean: STM.STM = internal.nextBoolean + +/** + * Returns the next integer from the pseudo-random number generator. + * + * @since 2.0.0 + * @category random + */ +export const nextInt: STM.STM = internal.nextInt + +/** + * Returns the next integer in the specified range from the pseudo-random number + * generator. + * + * @since 2.0.0 + * @category random + */ +export const nextIntBetween: (low: number, high: number) => STM.STM = internal.nextIntBetween + +/** + * Returns the next number in the specified range from the pseudo-random number + * generator. + * + * @since 2.0.0 + * @category random + */ +export const nextRange: (min: number, max: number) => STM.STM = internal.nextRange + +/** + * Uses the pseudo-random number generator to shuffle the specified iterable. + * + * @since 2.0.0 + * @category random + */ +export const shuffle: (elements: Iterable) => STM.STM, never, TRandom> = internal.shuffle diff --git a/backend/node_modules/effect/src/TRef.ts b/backend/node_modules/effect/src/TRef.ts new file mode 100644 index 0000000000000000000000000000000000000000..f82261bfbda10fbd364ecf7657bc2e9e37486ff3 --- /dev/null +++ b/backend/node_modules/effect/src/TRef.ts @@ -0,0 +1,266 @@ +/** + * @since 2.0.0 + */ + +import type * as Journal from "./internal/stm/journal.js" +import * as internal from "./internal/stm/tRef.js" +import type * as TxnId from "./internal/stm/txnId.js" +import type * as Versioned from "./internal/stm/versioned.js" +import type * as Option from "./Option.js" +import type { Pipeable } from "./Pipeable.js" +import type * as STM from "./STM.js" +import type * as Types from "./Types.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const TRefTypeId: unique symbol = internal.TRefTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type TRefTypeId = typeof TRefTypeId + +/** + * A `TRef` is a purely functional description of a mutable reference that can + * be modified as part of a transactional effect. The fundamental operations of + * a `TRef` are `set` and `get`. `set` transactionally sets the reference to a + * new value. `get` gets the current value of the reference. + * + * NOTE: While `TRef` provides the transactional equivalent of a mutable + * reference, the value inside the `TRef` should be immutable. + * + * @since 2.0.0 + * @category models + */ +export interface TRef extends TRef.Variance, Pipeable { + /** + * Note: the method is unbound, exposed only for potential extensions. + */ + modify(f: (a: A) => readonly [B, A]): STM.STM +} +/** + * @internal + * @since 2.0.0 + */ +export interface TRef { + /** @internal */ + todos: Map + /** @internal */ + versioned: Versioned.Versioned +} + +/** + * @since 2.0.0 + */ +export declare namespace TRef { + /** + * @since 2.0.0 + */ + export interface Variance { + readonly [TRefTypeId]: { + readonly _A: Types.Invariant + } + } +} + +/** + * @since 2.0.0 + * @category mutations + */ +export const get: (self: TRef) => STM.STM = internal.get + +/** + * @since 2.0.0 + * @category mutations + */ +export const getAndSet: { + /** + * @since 2.0.0 + * @category mutations + */ + (value: A): (self: TRef) => STM.STM + /** + * @since 2.0.0 + * @category mutations + */ + (self: TRef, value: A): STM.STM +} = internal.getAndSet + +/** + * @since 2.0.0 + * @category mutations + */ +export const getAndUpdate: { + /** + * @since 2.0.0 + * @category mutations + */ + (f: (a: A) => A): (self: TRef) => STM.STM + /** + * @since 2.0.0 + * @category mutations + */ + (self: TRef, f: (a: A) => A): STM.STM +} = internal.getAndUpdate + +/** + * @since 2.0.0 + * @category mutations + */ +export const getAndUpdateSome: { + /** + * @since 2.0.0 + * @category mutations + */ + (f: (a: A) => Option.Option): (self: TRef) => STM.STM + /** + * @since 2.0.0 + * @category mutations + */ + (self: TRef, f: (a: A) => Option.Option): STM.STM +} = internal.getAndUpdateSome + +/** + * @since 2.0.0 + * @category constructors + */ +export const make: (value: A) => STM.STM> = internal.make + +/** + * @since 2.0.0 + * @category mutations + */ +export const modify: { + /** + * @since 2.0.0 + * @category mutations + */ + (f: (a: A) => readonly [B, A]): (self: TRef) => STM.STM + /** + * @since 2.0.0 + * @category mutations + */ + (self: TRef, f: (a: A) => readonly [B, A]): STM.STM +} = internal.modify + +/** + * @since 2.0.0 + * @category mutations + */ +export const modifySome: { + /** + * @since 2.0.0 + * @category mutations + */ + (fallback: B, f: (a: A) => Option.Option): (self: TRef) => STM.STM + /** + * @since 2.0.0 + * @category mutations + */ + (self: TRef, fallback: B, f: (a: A) => Option.Option): STM.STM +} = internal.modifySome + +/** + * @since 2.0.0 + * @category mutations + */ +export const set: { + /** + * @since 2.0.0 + * @category mutations + */ + (value: A): (self: TRef) => STM.STM + /** + * @since 2.0.0 + * @category mutations + */ + (self: TRef, value: A): STM.STM +} = internal.set + +/** + * @since 2.0.0 + * @category mutations + */ +export const setAndGet: { + /** + * @since 2.0.0 + * @category mutations + */ + (value: A): (self: TRef) => STM.STM + /** + * @since 2.0.0 + * @category mutations + */ + (self: TRef, value: A): STM.STM +} = internal.setAndGet + +/** + * @since 2.0.0 + * @category mutations + */ +export const update: { + /** + * @since 2.0.0 + * @category mutations + */ + (f: (a: A) => A): (self: TRef) => STM.STM + /** + * @since 2.0.0 + * @category mutations + */ + (self: TRef, f: (a: A) => A): STM.STM +} = internal.update + +/** + * @since 2.0.0 + * @category mutations + */ +export const updateAndGet: { + /** + * @since 2.0.0 + * @category mutations + */ + (f: (a: A) => A): (self: TRef) => STM.STM + /** + * @since 2.0.0 + * @category mutations + */ + (self: TRef, f: (a: A) => A): STM.STM +} = internal.updateAndGet + +/** + * @since 2.0.0 + * @category mutations + */ +export const updateSome: { + /** + * @since 2.0.0 + * @category mutations + */ + (f: (a: A) => Option.Option): (self: TRef) => STM.STM + /** + * @since 2.0.0 + * @category mutations + */ + (self: TRef, f: (a: A) => Option.Option): STM.STM +} = internal.updateSome + +/** + * @since 2.0.0 + * @category mutations + */ +export const updateSomeAndGet: { + /** + * @since 2.0.0 + * @category mutations + */ + (f: (a: A) => Option.Option): (self: TRef) => STM.STM + /** + * @since 2.0.0 + * @category mutations + */ + (self: TRef, f: (a: A) => Option.Option): STM.STM +} = internal.updateSomeAndGet diff --git a/backend/node_modules/effect/src/TSubscriptionRef.ts b/backend/node_modules/effect/src/TSubscriptionRef.ts new file mode 100644 index 0000000000000000000000000000000000000000..7aff89016209b6a5d8370dc509f08e45d077b879 --- /dev/null +++ b/backend/node_modules/effect/src/TSubscriptionRef.ts @@ -0,0 +1,284 @@ +/** + * @since 3.10.0 + */ +import type * as Effect from "./Effect.js" +import * as internal from "./internal/stm/tSubscriptionRef.js" +import type * as Option from "./Option.js" +import type * as Scope from "./Scope.js" +import type * as STM from "./STM.js" +import type * as Stream from "./Stream.js" +import type * as TPubSub from "./TPubSub.js" +import type * as TQueue from "./TQueue.js" +import type * as TRef from "./TRef.js" +import type * as Types from "./Types.js" + +/** + * @since 3.10.0 + * @category symbols + */ +export const TSubscriptionRefTypeId: unique symbol = internal.TSubscriptionRefTypeId + +/** + * @since 3.10.0 + * @category symbols + */ +export type TSubscriptionRefTypeId = typeof TSubscriptionRefTypeId + +/** + * A `TSubscriptionRef` is a `TRef` that can be subscribed to in order to + * receive a `TDequeue` of the current value and all committed changes to the value. + * + * @since 3.10.0 + * @category models + */ +export interface TSubscriptionRef extends TSubscriptionRef.Variance, TRef.TRef { + /** @internal */ + readonly ref: TRef.TRef + /** @internal */ + readonly pubsub: TPubSub.TPubSub + /** @internal */ + modify(f: (a: A) => readonly [B, A]): STM.STM + + /** + * A TDequeue containing the current value of the `Ref` as well as all changes + * to that value. + */ + readonly changes: STM.STM> +} + +/** + * @since 3.10.0 + */ +export declare namespace TSubscriptionRef { + /** + * @since 3.10.0 + * @category models + */ + export interface Variance { + readonly [TSubscriptionRefTypeId]: { + readonly _A: Types.Invariant + } + } +} + +/** + * @since 3.10.0 + * @category mutations + */ +export const get: (self: TSubscriptionRef) => STM.STM = internal.get + +/** + * @since 3.10.0 + * @category mutations + */ +export const getAndSet: { + /** + * @since 3.10.0 + * @category mutations + */ + (value: A): (self: TSubscriptionRef) => STM.STM + /** + * @since 3.10.0 + * @category mutations + */ + (self: TSubscriptionRef, value: A): STM.STM +} = internal.getAndSet + +/** + * @since 3.10.0 + * @category mutations + */ +export const getAndUpdate: { + /** + * @since 3.10.0 + * @category mutations + */ + (f: (a: A) => A): (self: TSubscriptionRef) => STM.STM + /** + * @since 3.10.0 + * @category mutations + */ + (self: TSubscriptionRef, f: (a: A) => A): STM.STM +} = internal.getAndUpdate + +/** + * @since 3.10.0 + * @category mutations + */ +export const getAndUpdateSome: { + /** + * @since 3.10.0 + * @category mutations + */ + (f: (a: A) => Option.Option): (self: TSubscriptionRef) => STM.STM + /** + * @since 3.10.0 + * @category mutations + */ + (self: TSubscriptionRef, f: (a: A) => Option.Option): STM.STM +} = internal.getAndUpdateSome + +/** + * @since 3.10.0 + * @category constructors + */ +export const make: (value: A) => STM.STM> = internal.make + +/** + * @since 3.10.0 + * @category mutations + */ +export const modify: { + /** + * @since 3.10.0 + * @category mutations + */ + (f: (a: A) => readonly [B, A]): (self: TSubscriptionRef) => STM.STM + /** + * @since 3.10.0 + * @category mutations + */ + (self: TSubscriptionRef, f: (a: A) => readonly [B, A]): STM.STM +} = internal.modify + +/** + * @since 3.10.0 + * @category mutations + */ +export const modifySome: { + /** + * @since 3.10.0 + * @category mutations + */ + (fallback: B, f: (a: A) => Option.Option): (self: TSubscriptionRef) => STM.STM + /** + * @since 3.10.0 + * @category mutations + */ + ( + self: TSubscriptionRef, + fallback: B, + f: (a: A) => Option.Option + ): STM.STM +} = internal.modifySome + +/** + * @since 3.10.0 + * @category mutations + */ +export const set: { + /** + * @since 3.10.0 + * @category mutations + */ + (value: A): (self: TSubscriptionRef) => STM.STM + /** + * @since 3.10.0 + * @category mutations + */ + (self: TSubscriptionRef, value: A): STM.STM +} = internal.set + +/** + * @since 3.10.0 + * @category mutations + */ +export const setAndGet: { + /** + * @since 3.10.0 + * @category mutations + */ + (value: A): (self: TSubscriptionRef) => STM.STM + /** + * @since 3.10.0 + * @category mutations + */ + (self: TSubscriptionRef, value: A): STM.STM +} = internal.setAndGet + +/** + * @since 3.10.0 + * @category mutations + */ +export const update: { + /** + * @since 3.10.0 + * @category mutations + */ + (f: (a: A) => A): (self: TSubscriptionRef) => STM.STM + /** + * @since 3.10.0 + * @category mutations + */ + (self: TSubscriptionRef, f: (a: A) => A): STM.STM +} = internal.update + +/** + * @since 3.10.0 + * @category mutations + */ +export const updateAndGet: { + /** + * @since 3.10.0 + * @category mutations + */ + (f: (a: A) => A): (self: TSubscriptionRef) => STM.STM + /** + * @since 3.10.0 + * @category mutations + */ + (self: TSubscriptionRef, f: (a: A) => A): STM.STM +} = internal.updateAndGet + +/** + * @since 3.10.0 + * @category mutations + */ +export const updateSome: { + /** + * @since 3.10.0 + * @category mutations + */ + (f: (a: A) => Option.Option): (self: TSubscriptionRef) => STM.STM + /** + * @since 3.10.0 + * @category mutations + */ + (self: TSubscriptionRef, f: (a: A) => Option.Option): STM.STM +} = internal.updateSome + +/** + * @since 3.10.0 + * @category mutations + */ +export const updateSomeAndGet: { + /** + * @since 3.10.0 + * @category mutations + */ + (f: (a: A) => Option.Option): (self: TSubscriptionRef) => STM.STM + /** + * @since 3.10.0 + * @category mutations + */ + (self: TSubscriptionRef, f: (a: A) => Option.Option): STM.STM +} = internal.updateSomeAndGet + +/** + * @since 3.10.0 + * @category mutations + */ +export const changesScoped: (self: TSubscriptionRef) => Effect.Effect, never, Scope.Scope> = + internal.changesScoped + +/** + * @since 3.10.0 + * @category mutations + */ +export const changesStream: (self: TSubscriptionRef) => Stream.Stream = internal.changesStream + +/** + * @since 3.10.0 + * @category mutations + */ +export const changes: (self: TSubscriptionRef) => STM.STM> = (self) => self.changes diff --git a/backend/node_modules/effect/src/TestAnnotation.ts b/backend/node_modules/effect/src/TestAnnotation.ts new file mode 100644 index 0000000000000000000000000000000000000000..76be7f6623a171a49bf093144d5f367e20045529 --- /dev/null +++ b/backend/node_modules/effect/src/TestAnnotation.ts @@ -0,0 +1,158 @@ +/** + * @since 2.0.0 + */ +import * as Chunk from "./Chunk.js" +import * as Either from "./Either.js" +import * as Equal from "./Equal.js" +import type * as Fiber from "./Fiber.js" +import { pipe } from "./Function.js" +import * as Hash from "./Hash.js" +import * as HashSet from "./HashSet.js" +import { getBugErrorMessage } from "./internal/errors.js" +import type * as MutableRef from "./MutableRef.js" +import { hasProperty } from "./Predicate.js" +import type * as SortedSet from "./SortedSet.js" +import type * as Types from "./Types.js" + +/** @internal */ +const TestAnnotationSymbolKey = "effect/TestAnnotation" + +/** + * @since 2.0.0 + */ +export const TestAnnotationTypeId: unique symbol = Symbol.for(TestAnnotationSymbolKey) + +/** + * @since 2.0.0 + */ +export type TestAnnotationTypeId = typeof TestAnnotationTypeId + +/** + * @since 2.0.0 + */ +export interface TestAnnotation extends Equal.Equal { + readonly [TestAnnotationTypeId]: { + readonly _A: Types.Invariant + } + readonly identifier: string + readonly initial: A + combine(a: A, b: A): A +} + +/** @internal */ +class TestAnnotationImpl implements Equal.Equal { + readonly [TestAnnotationTypeId] = { + _A: (_: any) => _ + } + constructor( + readonly identifier: string, + readonly initial: A, + readonly combine: (a: A, b: A) => A + ) {} + [Hash.symbol](): number { + return pipe( + Hash.hash(TestAnnotationSymbolKey), + Hash.combine(Hash.hash(this.identifier)), + Hash.cached(this) + ) + } + [Equal.symbol](that: unknown): boolean { + return isTestAnnotation(that) && + this.identifier === that.identifier + } +} + +/** + * @since 2.0.0 + */ +export const isTestAnnotation = (u: unknown): u is TestAnnotation => hasProperty(u, TestAnnotationTypeId) + +/** + * @since 2.0.0 + */ +export const make = ( + identifier: string, + initial: A, + combine: (a: A, b: A) => A +): TestAnnotation => { + return new TestAnnotationImpl(identifier, initial, combine) +} + +/** + * @since 2.0.0 + */ +export const compose = ( + left: Either.Either, number>, + right: Either.Either, number> +): Either.Either, number> => { + if (Either.isLeft(left) && Either.isLeft(right)) { + return Either.left(left.left + right.left) + } + if (Either.isRight(left) && Either.isRight(right)) { + return Either.right(pipe(left.right, Chunk.appendAll(right.right))) + } + if (Either.isRight(left) && Either.isLeft(right)) { + return right + } + if (Either.isLeft(left) && Either.isRight(right)) { + return right + } + throw new Error(getBugErrorMessage("TestAnnotation.compose")) +} + +/** + * @since 2.0.0 + */ +export const fibers: TestAnnotation< + Either.Either>>>, number> +> = make< + Either.Either>>>, number> +>( + "fibers", + Either.left(0), + compose +) + +/** + * An annotation which counts ignored tests. + * + * @since 2.0.0 + */ +export const ignored: TestAnnotation = make( + "ignored", + 0, + (a, b) => a + b +) + +/** + * An annotation which counts repeated tests. + * + * @since 2.0.0 + */ +export const repeated: TestAnnotation = make( + "repeated", + 0, + (a, b) => a + b +) + +/** + * An annotation which counts retried tests. + * + * @since 2.0.0 + */ +export const retried: TestAnnotation = make( + "retried", + 0, + (a, b) => a + b +) + +/** + * An annotation which tags tests with strings. + * + * @since 2.0.0 + */ +export const tagged: TestAnnotation> = make( + "tagged", + HashSet.empty(), + (a, b) => pipe(a, HashSet.union(b)) +) diff --git a/backend/node_modules/effect/src/TestConfig.ts b/backend/node_modules/effect/src/TestConfig.ts new file mode 100644 index 0000000000000000000000000000000000000000..fae217223226442136200a327f749f1d0120bbcf --- /dev/null +++ b/backend/node_modules/effect/src/TestConfig.ts @@ -0,0 +1,47 @@ +/** + * @since 2.0.0 + */ +import * as Context from "./Context.js" + +/** + * The `TestConfig` service provides access to default configuration settings + * used by tests, including the number of times to repeat tests to ensure + * they are stable, the number of times to retry flaky tests, the sufficient + * number of samples to check from a random variable, and the maximum number of + * shrinkings to minimize large failures. + * + * @since 2.0.0 + */ +export interface TestConfig { + /** + * The number of times to repeat tests to ensure they are stable. + */ + readonly repeats: number + /** + * The number of times to retry flaky tests. + */ + readonly retries: number + /** + * The number of sufficient samples to check for a random variable. + */ + readonly samples: number + /** + * The maximum number of shrinkings to minimize large failures + */ + readonly shrinks: number +} + +/** + * @since 2.0.0 + */ +export const TestConfig: Context.Tag = Context.GenericTag("effect/TestConfig") + +/** + * @since 2.0.0 + */ +export const make = (params: { + readonly repeats: number + readonly retries: number + readonly samples: number + readonly shrinks: number +}): TestConfig => params diff --git a/backend/node_modules/effect/src/TestContext.ts b/backend/node_modules/effect/src/TestContext.ts new file mode 100644 index 0000000000000000000000000000000000000000..01e7853134f6e9087c9c1c2ae7a1e042d3d299e5 --- /dev/null +++ b/backend/node_modules/effect/src/TestContext.ts @@ -0,0 +1,36 @@ +/** + * @since 2.0.0 + */ +import type * as DefaultServices from "./DefaultServices.js" +import { pipe } from "./Function.js" +import * as defaultServices from "./internal/defaultServices.js" +import * as layer from "./internal/layer.js" +import type * as Layer from "./Layer.js" +import * as TestClock from "./TestClock.js" +import * as TestServices from "./TestServices.js" + +/** @internal */ +export const live: Layer.Layer = pipe( + TestServices.annotationsLayer(), + layer.merge(TestServices.liveLayer()), + layer.merge(TestServices.sizedLayer(100)), + layer.merge(pipe( + TestClock.defaultTestClock, + layer.provideMerge( + layer.merge(TestServices.liveLayer(), TestServices.annotationsLayer()) + ) + )), + layer.merge(TestServices.testConfigLayer({ repeats: 100, retries: 100, samples: 200, shrinks: 1000 })) +) + +/** + * @since 2.0.0 + */ +export const LiveContext: Layer.Layer = layer.syncContext(() => + defaultServices.liveServices +) + +/** + * @since 2.0.0 + */ +export const TestContext: Layer.Layer = layer.provideMerge(live, LiveContext) diff --git a/backend/node_modules/effect/src/TestSized.ts b/backend/node_modules/effect/src/TestSized.ts new file mode 100644 index 0000000000000000000000000000000000000000..21ab3872e600088d8d1e1e8fe3cbae2542be82fe --- /dev/null +++ b/backend/node_modules/effect/src/TestSized.ts @@ -0,0 +1,55 @@ +/** + * @since 2.0.0 + */ +import * as Context from "./Context.js" +import type * as Effect from "./Effect.js" +import type * as FiberRef from "./FiberRef.js" +import * as core from "./internal/core.js" + +/** + * @since 2.0.0 + */ +export const TestSizedTypeId: unique symbol = Symbol.for("effect/TestSized") + +/** + * @since 2.0.0 + */ +export type TestSizedTypeId = typeof TestSizedTypeId + +/** + * @since 2.0.0 + */ +export interface TestSized { + readonly [TestSizedTypeId]: TestSizedTypeId + readonly fiberRef: FiberRef.FiberRef + readonly size: Effect.Effect + withSize(size: number): (effect: Effect.Effect) => Effect.Effect +} + +/** + * @since 2.0.0 + */ +export const TestSized: Context.Tag = Context.GenericTag("effect/TestSized") + +/** @internal */ +class SizedImpl implements TestSized { + readonly [TestSizedTypeId]: TestSizedTypeId = TestSizedTypeId + constructor(readonly fiberRef: FiberRef.FiberRef) {} + get size(): Effect.Effect { + return core.fiberRefGet(this.fiberRef) + } + withSize(size: number) { + return (effect: Effect.Effect): Effect.Effect => + core.fiberRefLocally(this.fiberRef, size)(effect) + } +} + +/** + * @since 2.0.0 + */ +export const make = (size: number): TestSized => new SizedImpl(core.fiberRefUnsafeMake(size)) + +/** + * @since 2.0.0 + */ +export const fromFiberRef = (fiberRef: FiberRef.FiberRef): TestSized => new SizedImpl(fiberRef) diff --git a/backend/node_modules/effect/src/Tracer.ts b/backend/node_modules/effect/src/Tracer.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8c27ef7aeb5e821d455478efb1dc5f83e0d6c08 --- /dev/null +++ b/backend/node_modules/effect/src/Tracer.ts @@ -0,0 +1,182 @@ +/** + * @since 2.0.0 + */ +import type * as Context from "./Context.js" +import type * as Effect from "./Effect.js" +import type * as Exit from "./Exit.js" +import type * as Fiber from "./Fiber.js" +import type { LazyArg } from "./Function.js" +import * as defaultServices from "./internal/defaultServices.js" +import * as internal from "./internal/tracer.js" +import type * as Option from "./Option.js" + +/** + * @since 2.0.0 + */ +export const TracerTypeId: unique symbol = internal.TracerTypeId + +/** + * @since 2.0.0 + */ +export type TracerTypeId = typeof TracerTypeId + +/** + * @since 2.0.0 + */ +export interface Tracer { + readonly [TracerTypeId]: TracerTypeId + span( + name: string, + parent: Option.Option, + context: Context.Context, + links: ReadonlyArray, + startTime: bigint, + kind: SpanKind, + options?: SpanOptions + ): Span + context(f: () => X, fiber: Fiber.RuntimeFiber): X +} + +/** + * @since 2.0.0 + * @category models + */ +export type SpanStatus = { + _tag: "Started" + startTime: bigint +} | { + _tag: "Ended" + startTime: bigint + endTime: bigint + exit: Exit.Exit +} + +/** + * @since 2.0.0 + * @category models + */ +export type AnySpan = Span | ExternalSpan + +/** + * @since 2.0.0 + * @category tags + */ +export interface ParentSpan { + readonly _: unique symbol +} + +/** + * @since 2.0.0 + * @category tags + */ +export const ParentSpan: Context.Tag = internal.spanTag + +/** + * @since 2.0.0 + * @category models + */ +export interface ExternalSpan { + readonly _tag: "ExternalSpan" + readonly spanId: string + readonly traceId: string + readonly sampled: boolean + readonly context: Context.Context +} + +/** + * @since 3.1.0 + * @category models + */ +export interface SpanOptions { + readonly attributes?: Record | undefined + readonly links?: ReadonlyArray | undefined + readonly parent?: AnySpan | undefined + readonly root?: boolean | undefined + readonly context?: Context.Context | undefined + readonly kind?: SpanKind | undefined + readonly captureStackTrace?: boolean | LazyArg | undefined +} + +/** + * @since 3.1.0 + * @category models + */ +export type SpanKind = "internal" | "server" | "client" | "producer" | "consumer" + +/** + * @since 2.0.0 + * @category models + */ +export interface Span { + readonly _tag: "Span" + readonly name: string + readonly spanId: string + readonly traceId: string + readonly parent: Option.Option + readonly context: Context.Context + readonly status: SpanStatus + readonly attributes: ReadonlyMap + readonly links: ReadonlyArray + readonly sampled: boolean + readonly kind: SpanKind + end(endTime: bigint, exit: Exit.Exit): void + attribute(key: string, value: unknown): void + event(name: string, startTime: bigint, attributes?: Record): void + addLinks(links: ReadonlyArray): void +} + +/** + * @since 2.0.0 + * @category models + */ +export interface SpanLink { + readonly _tag: "SpanLink" + readonly span: AnySpan + readonly attributes: Readonly> +} + +/** + * @since 2.0.0 + * @category tags + */ +export const Tracer: Context.Tag = internal.tracerTag + +/** + * @since 2.0.0 + * @category constructors + */ +export const make: (options: Omit) => Tracer = internal.make + +/** + * @since 2.0.0 + * @category constructors + */ +export const externalSpan: ( + options: { + readonly spanId: string + readonly traceId: string + readonly sampled?: boolean | undefined + readonly context?: Context.Context | undefined + } +) => ExternalSpan = internal.externalSpan + +/** + * @since 2.0.0 + * @category constructors + */ +export const tracerWith: (f: (tracer: Tracer) => Effect.Effect) => Effect.Effect = + defaultServices.tracerWith + +/** + * @since 3.12.0 + * @category annotations + */ +export interface DisablePropagation { + readonly _: unique symbol +} + +/** + * @since 3.12.0 + * @category annotations + */ +export const DisablePropagation: Context.Reference = internal.DisablePropagation diff --git a/backend/node_modules/effect/src/Trie.ts b/backend/node_modules/effect/src/Trie.ts new file mode 100644 index 0000000000000000000000000000000000000000..92b2f79915a0518b09835c6b78c71e2ac6a12da5 --- /dev/null +++ b/backend/node_modules/effect/src/Trie.ts @@ -0,0 +1,1860 @@ +/** + * A `Trie` is used for locating specific `string` keys from within a set. + * + * It works similar to `HashMap`, but with keys required to be `string`. + * This constraint unlocks some performance optimizations and new methods to get string prefixes (e.g. `keysWithPrefix`, `longestPrefixOf`). + * + * Prefix search is also the main feature that makes a `Trie` more suited than `HashMap` for certain usecases. + * + * A `Trie` is often used to store a dictionary (list of words) that can be searched + * in a manner that allows for efficient generation of completion lists + * (e.g. predict the rest of a word a user is typing). + * + * A `Trie` has O(n) lookup time where `n` is the size of the key, + * or even less than `n` on search misses. + * + * @since 2.0.0 + */ +import type { Equal } from "./Equal.js" +import type { Inspectable } from "./Inspectable.js" +import * as TR from "./internal/trie.js" +import type { Option } from "./Option.js" +import type { Pipeable } from "./Pipeable.js" +import type { Covariant, NoInfer } from "./Types.js" + +const TypeId: unique symbol = TR.TrieTypeId as TypeId + +/** + * @since 2.0.0 + * @category symbol + */ +export type TypeId = typeof TypeId + +/** + * @since 2.0.0 + * @category models + */ +export interface Trie extends Iterable<[string, Value]>, Equal, Pipeable, Inspectable { + readonly [TypeId]: { + readonly _Value: Covariant + } +} + +/** + * Creates an empty `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty() + * + * assert.equal(Trie.size(trie), 0) + * assert.deepStrictEqual(Array.from(trie), []) + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export const empty: () => Trie = TR.empty + +/** + * Creates a new `Trie` from an iterable collection of key/value pairs (e.g. `Array<[string, V]>`). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const iterable: Array = [["call", 0], ["me", 1], ["mind", 2], ["mid", 3]] + * const trie = Trie.fromIterable(iterable) + * + * // The entries in the `Trie` are extracted in alphabetical order, regardless of the insertion order + * assert.deepStrictEqual(Array.from(trie), [["call", 0], ["me", 1], ["mid", 3], ["mind", 2]]) + * assert.equal(Equal.equals(Trie.make(["call", 0], ["me", 1], ["mind", 2], ["mid", 3]), trie), true) + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export const fromIterable: (entries: Iterable) => Trie = TR.fromIterable + +/** + * Constructs a new `Trie` from the specified entries (`[string, V]`). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.make(["ca", 0], ["me", 1]) + * + * assert.deepStrictEqual(Array.from(trie), [["ca", 0], ["me", 1]]) + * assert.equal(Equal.equals(Trie.fromIterable([["ca", 0], ["me", 1]]), trie), true) + * ``` + * + * @since 2.0.0 + * @category constructors + */ +export const make: >( + ...entries: Entries +) => Trie = TR.make + +/** + * Insert a new entry in the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie1 = Trie.empty().pipe( + * Trie.insert("call", 0) + * ) + * const trie2 = trie1.pipe(Trie.insert("me", 1)) + * const trie3 = trie2.pipe(Trie.insert("mind", 2)) + * const trie4 = trie3.pipe(Trie.insert("mid", 3)) + * + * assert.deepStrictEqual(Array.from(trie1), [["call", 0]]) + * assert.deepStrictEqual(Array.from(trie2), [["call", 0], ["me", 1]]) + * assert.deepStrictEqual(Array.from(trie3), [["call", 0], ["me", 1], ["mind", 2]]) + * assert.deepStrictEqual(Array.from(trie4), [["call", 0], ["me", 1], ["mid", 3], ["mind", 2]]) + * ``` + * + * @since 2.0.0 + * @category mutations + */ +export const insert: { + /** + * Insert a new entry in the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie1 = Trie.empty().pipe( + * Trie.insert("call", 0) + * ) + * const trie2 = trie1.pipe(Trie.insert("me", 1)) + * const trie3 = trie2.pipe(Trie.insert("mind", 2)) + * const trie4 = trie3.pipe(Trie.insert("mid", 3)) + * + * assert.deepStrictEqual(Array.from(trie1), [["call", 0]]) + * assert.deepStrictEqual(Array.from(trie2), [["call", 0], ["me", 1]]) + * assert.deepStrictEqual(Array.from(trie3), [["call", 0], ["me", 1], ["mind", 2]]) + * assert.deepStrictEqual(Array.from(trie4), [["call", 0], ["me", 1], ["mid", 3], ["mind", 2]]) + * ``` + * + * @since 2.0.0 + * @category mutations + */ + (key: string, value: V1): (self: Trie) => Trie + /** + * Insert a new entry in the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie1 = Trie.empty().pipe( + * Trie.insert("call", 0) + * ) + * const trie2 = trie1.pipe(Trie.insert("me", 1)) + * const trie3 = trie2.pipe(Trie.insert("mind", 2)) + * const trie4 = trie3.pipe(Trie.insert("mid", 3)) + * + * assert.deepStrictEqual(Array.from(trie1), [["call", 0]]) + * assert.deepStrictEqual(Array.from(trie2), [["call", 0], ["me", 1]]) + * assert.deepStrictEqual(Array.from(trie3), [["call", 0], ["me", 1], ["mind", 2]]) + * assert.deepStrictEqual(Array.from(trie4), [["call", 0], ["me", 1], ["mid", 3], ["mind", 2]]) + * ``` + * + * @since 2.0.0 + * @category mutations + */ + (self: Trie, key: string, value: V1): Trie +} = TR.insert + +/** + * Returns an `IterableIterator` of the keys within the `Trie`. + * + * The keys are returned in alphabetical order, regardless of insertion order. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("cab", 0), + * Trie.insert("abc", 1), + * Trie.insert("bca", 2) + * ) + * + * const result = Array.from(Trie.keys(trie)) + * assert.deepStrictEqual(result, ["abc", "bca", "cab"]) + * ``` + * + * @since 2.0.0 + * @category getters + */ +export const keys: (self: Trie) => IterableIterator = TR.keys + +/** + * Returns an `IterableIterator` of the values within the `Trie`. + * + * Values are ordered based on their key in alphabetical order, regardless of insertion order. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1), + * Trie.insert("and", 2) + * ) + * + * const result = Array.from(Trie.values(trie)) + * assert.deepStrictEqual(result, [2, 0, 1]) + * ``` + * + * @since 2.0.0 + * @category getters + */ +export const values: (self: Trie) => IterableIterator = TR.values + +/** + * Returns an `IterableIterator` of the entries within the `Trie`. + * + * The entries are returned by keys in alphabetical order, regardless of insertion order. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1) + * ) + * + * const result = Array.from(Trie.entries(trie)) + * assert.deepStrictEqual(result, [["call", 0], ["me", 1]]) + * ``` + * + * @since 2.0.0 + * @category getters + */ +export const entries: (self: Trie) => IterableIterator<[string, V]> = TR.entries + +/** + * Returns an `Array<[K, V]>` of the entries within the `Trie`. + * + * Equivalent to `Array.from(Trie.entries(trie))`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1) + * ) + * const result = Trie.toEntries(trie) + * + * assert.deepStrictEqual(result, [["call", 0], ["me", 1]]) + * ``` + * + * @since 2.0.0 + * @category getters + */ +export const toEntries = (self: Trie): Array<[string, V]> => Array.from(entries(self)) + +/** + * Returns an `IterableIterator` of the keys within the `Trie` + * that have `prefix` as prefix (`prefix` included if it exists). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("she", 0), + * Trie.insert("shells", 1), + * Trie.insert("sea", 2), + * Trie.insert("shore", 3) + * ) + * + * const result = Array.from(Trie.keysWithPrefix(trie, "she")) + * assert.deepStrictEqual(result, ["she", "shells"]) + * ``` + * + * @since 2.0.0 + * @category getters + */ +export const keysWithPrefix: { + /** + * Returns an `IterableIterator` of the keys within the `Trie` + * that have `prefix` as prefix (`prefix` included if it exists). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("she", 0), + * Trie.insert("shells", 1), + * Trie.insert("sea", 2), + * Trie.insert("shore", 3) + * ) + * + * const result = Array.from(Trie.keysWithPrefix(trie, "she")) + * assert.deepStrictEqual(result, ["she", "shells"]) + * ``` + * + * @since 2.0.0 + * @category getters + */ + (prefix: string): (self: Trie) => IterableIterator + /** + * Returns an `IterableIterator` of the keys within the `Trie` + * that have `prefix` as prefix (`prefix` included if it exists). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("she", 0), + * Trie.insert("shells", 1), + * Trie.insert("sea", 2), + * Trie.insert("shore", 3) + * ) + * + * const result = Array.from(Trie.keysWithPrefix(trie, "she")) + * assert.deepStrictEqual(result, ["she", "shells"]) + * ``` + * + * @since 2.0.0 + * @category getters + */ + (self: Trie, prefix: string): IterableIterator +} = TR.keysWithPrefix + +/** + * Returns an `IterableIterator` of the values within the `Trie` + * that have `prefix` as prefix (`prefix` included if it exists). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("she", 0), + * Trie.insert("shells", 1), + * Trie.insert("sea", 2), + * Trie.insert("shore", 3) + * ) + * + * const result = Array.from(Trie.valuesWithPrefix(trie, "she")) + * + * // 0: "she", 1: "shells" + * assert.deepStrictEqual(result, [0, 1]) + * ``` + * + * @since 2.0.0 + * @category getters + */ +export const valuesWithPrefix: { + /** + * Returns an `IterableIterator` of the values within the `Trie` + * that have `prefix` as prefix (`prefix` included if it exists). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("she", 0), + * Trie.insert("shells", 1), + * Trie.insert("sea", 2), + * Trie.insert("shore", 3) + * ) + * + * const result = Array.from(Trie.valuesWithPrefix(trie, "she")) + * + * // 0: "she", 1: "shells" + * assert.deepStrictEqual(result, [0, 1]) + * ``` + * + * @since 2.0.0 + * @category getters + */ + (prefix: string): (self: Trie) => IterableIterator + /** + * Returns an `IterableIterator` of the values within the `Trie` + * that have `prefix` as prefix (`prefix` included if it exists). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("she", 0), + * Trie.insert("shells", 1), + * Trie.insert("sea", 2), + * Trie.insert("shore", 3) + * ) + * + * const result = Array.from(Trie.valuesWithPrefix(trie, "she")) + * + * // 0: "she", 1: "shells" + * assert.deepStrictEqual(result, [0, 1]) + * ``` + * + * @since 2.0.0 + * @category getters + */ + (self: Trie, prefix: string): IterableIterator +} = TR.valuesWithPrefix + +/** + * Returns an `IterableIterator` of the entries within the `Trie` + * that have `prefix` as prefix (`prefix` included if it exists). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("she", 0), + * Trie.insert("shells", 1), + * Trie.insert("sea", 2), + * Trie.insert("shore", 3) + * ) + * + * const result = Array.from(Trie.entriesWithPrefix(trie, "she")) + * assert.deepStrictEqual(result, [["she", 0], ["shells", 1]]) + * ``` + * + * @since 2.0.0 + * @category getters + */ +export const entriesWithPrefix: { + /** + * Returns an `IterableIterator` of the entries within the `Trie` + * that have `prefix` as prefix (`prefix` included if it exists). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("she", 0), + * Trie.insert("shells", 1), + * Trie.insert("sea", 2), + * Trie.insert("shore", 3) + * ) + * + * const result = Array.from(Trie.entriesWithPrefix(trie, "she")) + * assert.deepStrictEqual(result, [["she", 0], ["shells", 1]]) + * ``` + * + * @since 2.0.0 + * @category getters + */ + (prefix: string): (self: Trie) => IterableIterator<[string, V]> + /** + * Returns an `IterableIterator` of the entries within the `Trie` + * that have `prefix` as prefix (`prefix` included if it exists). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("she", 0), + * Trie.insert("shells", 1), + * Trie.insert("sea", 2), + * Trie.insert("shore", 3) + * ) + * + * const result = Array.from(Trie.entriesWithPrefix(trie, "she")) + * assert.deepStrictEqual(result, [["she", 0], ["shells", 1]]) + * ``` + * + * @since 2.0.0 + * @category getters + */ + (self: Trie, prefix: string): IterableIterator<[string, V]> +} = TR.entriesWithPrefix + +/** + * Returns `Array<[K, V]>` of the entries within the `Trie` + * that have `prefix` as prefix (`prefix` included if it exists). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("sea", 2), + * Trie.insert("she", 3) + * ) + * + * const result = Trie.toEntriesWithPrefix(trie, "she") + * assert.deepStrictEqual(result, [["she", 3], ["shells", 0]]) + * ``` + * + * @since 2.0.0 + * @category getters + */ +export const toEntriesWithPrefix: { + /** + * Returns `Array<[K, V]>` of the entries within the `Trie` + * that have `prefix` as prefix (`prefix` included if it exists). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("sea", 2), + * Trie.insert("she", 3) + * ) + * + * const result = Trie.toEntriesWithPrefix(trie, "she") + * assert.deepStrictEqual(result, [["she", 3], ["shells", 0]]) + * ``` + * + * @since 2.0.0 + * @category getters + */ + (prefix: string): (self: Trie) => Array<[string, V]> + /** + * Returns `Array<[K, V]>` of the entries within the `Trie` + * that have `prefix` as prefix (`prefix` included if it exists). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("sea", 2), + * Trie.insert("she", 3) + * ) + * + * const result = Trie.toEntriesWithPrefix(trie, "she") + * assert.deepStrictEqual(result, [["she", 3], ["shells", 0]]) + * ``` + * + * @since 2.0.0 + * @category getters + */ + (self: Trie, prefix: string): Array<[string, V]> +} = TR.toEntriesWithPrefix + +/** + * Returns the longest key/value in the `Trie` + * that is a prefix of that `key` if it exists, `None` otherwise. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * assert.deepStrictEqual(Trie.longestPrefixOf(trie, "sell"), Option.none()) + * assert.deepStrictEqual(Trie.longestPrefixOf(trie, "sells"), Option.some(["sells", 1])) + * assert.deepStrictEqual(Trie.longestPrefixOf(trie, "shell"), Option.some(["she", 2])) + * assert.deepStrictEqual(Trie.longestPrefixOf(trie, "shellsort"), Option.some(["shells", 0])) + * ``` + * + * @since 2.0.0 + * @category getters + */ +export const longestPrefixOf: { + /** + * Returns the longest key/value in the `Trie` + * that is a prefix of that `key` if it exists, `None` otherwise. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * assert.deepStrictEqual(Trie.longestPrefixOf(trie, "sell"), Option.none()) + * assert.deepStrictEqual(Trie.longestPrefixOf(trie, "sells"), Option.some(["sells", 1])) + * assert.deepStrictEqual(Trie.longestPrefixOf(trie, "shell"), Option.some(["she", 2])) + * assert.deepStrictEqual(Trie.longestPrefixOf(trie, "shellsort"), Option.some(["shells", 0])) + * ``` + * + * @since 2.0.0 + * @category getters + */ + (key: string): (self: Trie) => Option<[string, V]> + /** + * Returns the longest key/value in the `Trie` + * that is a prefix of that `key` if it exists, `None` otherwise. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * assert.deepStrictEqual(Trie.longestPrefixOf(trie, "sell"), Option.none()) + * assert.deepStrictEqual(Trie.longestPrefixOf(trie, "sells"), Option.some(["sells", 1])) + * assert.deepStrictEqual(Trie.longestPrefixOf(trie, "shell"), Option.some(["she", 2])) + * assert.deepStrictEqual(Trie.longestPrefixOf(trie, "shellsort"), Option.some(["shells", 0])) + * ``` + * + * @since 2.0.0 + * @category getters + */ + (self: Trie, key: string): Option<[string, V]> +} = TR.longestPrefixOf + +/** + * Returns the size of the `Trie` (number of entries in the `Trie`). + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("a", 0), + * Trie.insert("b", 1) + * ) + * + * assert.equal(Trie.size(trie), 2) + * ``` + * + * @since 2.0.0 + * @category getters + */ +export const size: (self: Trie) => number = TR.size + +/** + * Safely lookup the value for the specified key in the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1), + * Trie.insert("mind", 2), + * Trie.insert("mid", 3) + * ) + * + * assert.deepStrictEqual(Trie.get(trie, "call"), Option.some(0)) + * assert.deepStrictEqual(Trie.get(trie, "me"), Option.some(1)) + * assert.deepStrictEqual(Trie.get(trie, "mind"), Option.some(2)) + * assert.deepStrictEqual(Trie.get(trie, "mid"), Option.some(3)) + * assert.deepStrictEqual(Trie.get(trie, "cale"), Option.none()) + * assert.deepStrictEqual(Trie.get(trie, "ma"), Option.none()) + * assert.deepStrictEqual(Trie.get(trie, "midn"), Option.none()) + * assert.deepStrictEqual(Trie.get(trie, "mea"), Option.none()) + * ``` + * + * @since 2.0.0 + * @category elements + */ +export const get: { + /** + * Safely lookup the value for the specified key in the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1), + * Trie.insert("mind", 2), + * Trie.insert("mid", 3) + * ) + * + * assert.deepStrictEqual(Trie.get(trie, "call"), Option.some(0)) + * assert.deepStrictEqual(Trie.get(trie, "me"), Option.some(1)) + * assert.deepStrictEqual(Trie.get(trie, "mind"), Option.some(2)) + * assert.deepStrictEqual(Trie.get(trie, "mid"), Option.some(3)) + * assert.deepStrictEqual(Trie.get(trie, "cale"), Option.none()) + * assert.deepStrictEqual(Trie.get(trie, "ma"), Option.none()) + * assert.deepStrictEqual(Trie.get(trie, "midn"), Option.none()) + * assert.deepStrictEqual(Trie.get(trie, "mea"), Option.none()) + * ``` + * + * @since 2.0.0 + * @category elements + */ + (key: string): (self: Trie) => Option + /** + * Safely lookup the value for the specified key in the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1), + * Trie.insert("mind", 2), + * Trie.insert("mid", 3) + * ) + * + * assert.deepStrictEqual(Trie.get(trie, "call"), Option.some(0)) + * assert.deepStrictEqual(Trie.get(trie, "me"), Option.some(1)) + * assert.deepStrictEqual(Trie.get(trie, "mind"), Option.some(2)) + * assert.deepStrictEqual(Trie.get(trie, "mid"), Option.some(3)) + * assert.deepStrictEqual(Trie.get(trie, "cale"), Option.none()) + * assert.deepStrictEqual(Trie.get(trie, "ma"), Option.none()) + * assert.deepStrictEqual(Trie.get(trie, "midn"), Option.none()) + * assert.deepStrictEqual(Trie.get(trie, "mea"), Option.none()) + * ``` + * + * @since 2.0.0 + * @category elements + */ + (self: Trie, key: string): Option +} = TR.get + +/** + * Check if the given key exists in the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1), + * Trie.insert("mind", 2), + * Trie.insert("mid", 3) + * ) + * + * assert.equal(Trie.has(trie, "call"), true) + * assert.equal(Trie.has(trie, "me"), true) + * assert.equal(Trie.has(trie, "mind"), true) + * assert.equal(Trie.has(trie, "mid"), true) + * assert.equal(Trie.has(trie, "cale"), false) + * assert.equal(Trie.has(trie, "ma"), false) + * assert.equal(Trie.has(trie, "midn"), false) + * assert.equal(Trie.has(trie, "mea"), false) + * ``` + * + * @since 2.0.0 + * @category elements + */ +export const has: { + /** + * Check if the given key exists in the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1), + * Trie.insert("mind", 2), + * Trie.insert("mid", 3) + * ) + * + * assert.equal(Trie.has(trie, "call"), true) + * assert.equal(Trie.has(trie, "me"), true) + * assert.equal(Trie.has(trie, "mind"), true) + * assert.equal(Trie.has(trie, "mid"), true) + * assert.equal(Trie.has(trie, "cale"), false) + * assert.equal(Trie.has(trie, "ma"), false) + * assert.equal(Trie.has(trie, "midn"), false) + * assert.equal(Trie.has(trie, "mea"), false) + * ``` + * + * @since 2.0.0 + * @category elements + */ + (key: string): (self: Trie) => boolean + /** + * Check if the given key exists in the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1), + * Trie.insert("mind", 2), + * Trie.insert("mid", 3) + * ) + * + * assert.equal(Trie.has(trie, "call"), true) + * assert.equal(Trie.has(trie, "me"), true) + * assert.equal(Trie.has(trie, "mind"), true) + * assert.equal(Trie.has(trie, "mid"), true) + * assert.equal(Trie.has(trie, "cale"), false) + * assert.equal(Trie.has(trie, "ma"), false) + * assert.equal(Trie.has(trie, "midn"), false) + * assert.equal(Trie.has(trie, "mea"), false) + * ``` + * + * @since 2.0.0 + * @category elements + */ + (self: Trie, key: string): boolean +} = TR.has + +/** + * Checks if the `Trie` contains any entries. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty() + * const trie1 = trie.pipe(Trie.insert("ma", 0)) + * + * assert.equal(Trie.isEmpty(trie), true) + * assert.equal(Trie.isEmpty(trie1), false) + * ``` + * + * @since 2.0.0 + * @category elements + */ +export const isEmpty: (self: Trie) => boolean = TR.isEmpty + +/** + * Unsafely lookup the value for the specified key in the `Trie`. + * + * `unsafeGet` will throw if the key is not found. Use `get` instead to safely + * get a value from the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1) + * ) + * + * assert.throws(() => Trie.unsafeGet(trie, "mae")) + * ``` + * + * @since 2.0.0 + * @category unsafe + */ +export const unsafeGet: { + /** + * Unsafely lookup the value for the specified key in the `Trie`. + * + * `unsafeGet` will throw if the key is not found. Use `get` instead to safely + * get a value from the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1) + * ) + * + * assert.throws(() => Trie.unsafeGet(trie, "mae")) + * ``` + * + * @since 2.0.0 + * @category unsafe + */ + (key: string): (self: Trie) => V + /** + * Unsafely lookup the value for the specified key in the `Trie`. + * + * `unsafeGet` will throw if the key is not found. Use `get` instead to safely + * get a value from the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1) + * ) + * + * assert.throws(() => Trie.unsafeGet(trie, "mae")) + * ``` + * + * @since 2.0.0 + * @category unsafe + */ + (self: Trie, key: string): V +} = TR.unsafeGet + +/** + * Remove the entry for the specified key in the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1), + * Trie.insert("mind", 2), + * Trie.insert("mid", 3) + * ) + * + * const trie1 = trie.pipe(Trie.remove("call")) + * const trie2 = trie1.pipe(Trie.remove("mea")) + * + * assert.deepStrictEqual(Trie.get(trie, "call"), Option.some(0)) + * assert.deepStrictEqual(Trie.get(trie1, "call"), Option.none()) + * assert.deepStrictEqual(Trie.get(trie2, "call"), Option.none()) + * ``` + * + * @since 2.0.0 + * @category mutations + */ +export const remove: { + /** + * Remove the entry for the specified key in the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1), + * Trie.insert("mind", 2), + * Trie.insert("mid", 3) + * ) + * + * const trie1 = trie.pipe(Trie.remove("call")) + * const trie2 = trie1.pipe(Trie.remove("mea")) + * + * assert.deepStrictEqual(Trie.get(trie, "call"), Option.some(0)) + * assert.deepStrictEqual(Trie.get(trie1, "call"), Option.none()) + * assert.deepStrictEqual(Trie.get(trie2, "call"), Option.none()) + * ``` + * + * @since 2.0.0 + * @category mutations + */ + (key: string): (self: Trie) => Trie + /** + * Remove the entry for the specified key in the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("call", 0), + * Trie.insert("me", 1), + * Trie.insert("mind", 2), + * Trie.insert("mid", 3) + * ) + * + * const trie1 = trie.pipe(Trie.remove("call")) + * const trie2 = trie1.pipe(Trie.remove("mea")) + * + * assert.deepStrictEqual(Trie.get(trie, "call"), Option.some(0)) + * assert.deepStrictEqual(Trie.get(trie1, "call"), Option.none()) + * assert.deepStrictEqual(Trie.get(trie2, "call"), Option.none()) + * ``` + * + * @since 2.0.0 + * @category mutations + */ + (self: Trie, key: string): Trie +} = TR.remove + +/** + * Reduce a state over the entries of the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * assert.equal( + * trie.pipe( + * Trie.reduce(0, (acc, n) => acc + n) + * ), + * 3 + * ) + * assert.equal( + * trie.pipe( + * Trie.reduce(10, (acc, n) => acc + n) + * ), + * 13 + * ) + * assert.equal( + * trie.pipe( + * Trie.reduce("", (acc, _, key) => acc + key) + * ), + * "sellssheshells" + * ) + * ``` + * + * @since 2.0.0 + * @category folding + */ +export const reduce: { + /** + * Reduce a state over the entries of the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * assert.equal( + * trie.pipe( + * Trie.reduce(0, (acc, n) => acc + n) + * ), + * 3 + * ) + * assert.equal( + * trie.pipe( + * Trie.reduce(10, (acc, n) => acc + n) + * ), + * 13 + * ) + * assert.equal( + * trie.pipe( + * Trie.reduce("", (acc, _, key) => acc + key) + * ), + * "sellssheshells" + * ) + * ``` + * + * @since 2.0.0 + * @category folding + */ + (zero: Z, f: (accumulator: Z, value: V, key: string) => Z): (self: Trie) => Z + /** + * Reduce a state over the entries of the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * assert.equal( + * trie.pipe( + * Trie.reduce(0, (acc, n) => acc + n) + * ), + * 3 + * ) + * assert.equal( + * trie.pipe( + * Trie.reduce(10, (acc, n) => acc + n) + * ), + * 13 + * ) + * assert.equal( + * trie.pipe( + * Trie.reduce("", (acc, _, key) => acc + key) + * ), + * "sellssheshells" + * ) + * ``` + * + * @since 2.0.0 + * @category folding + */ + (self: Trie, zero: Z, f: (accumulator: Z, value: V, key: string) => Z): Z +} = TR.reduce + +/** + * Maps over the entries of the `Trie` using the specified function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieMapV = Trie.empty().pipe( + * Trie.insert("shells", 1), + * Trie.insert("sells", 2), + * Trie.insert("she", 3) + * ) + * + * const trieMapK = Trie.empty().pipe( + * Trie.insert("shells", 6), + * Trie.insert("sells", 5), + * Trie.insert("she", 3) + * ) + * + * assert.equal(Equal.equals(Trie.map(trie, (v) => v + 1), trieMapV), true) + * assert.equal(Equal.equals(Trie.map(trie, (_, k) => k.length), trieMapK), true) + * ``` + * + * @since 2.0.0 + * @category folding + */ +export const map: { + /** + * Maps over the entries of the `Trie` using the specified function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieMapV = Trie.empty().pipe( + * Trie.insert("shells", 1), + * Trie.insert("sells", 2), + * Trie.insert("she", 3) + * ) + * + * const trieMapK = Trie.empty().pipe( + * Trie.insert("shells", 6), + * Trie.insert("sells", 5), + * Trie.insert("she", 3) + * ) + * + * assert.equal(Equal.equals(Trie.map(trie, (v) => v + 1), trieMapV), true) + * assert.equal(Equal.equals(Trie.map(trie, (_, k) => k.length), trieMapK), true) + * ``` + * + * @since 2.0.0 + * @category folding + */ + (f: (value: V, key: string) => A): (self: Trie) => Trie + /** + * Maps over the entries of the `Trie` using the specified function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieMapV = Trie.empty().pipe( + * Trie.insert("shells", 1), + * Trie.insert("sells", 2), + * Trie.insert("she", 3) + * ) + * + * const trieMapK = Trie.empty().pipe( + * Trie.insert("shells", 6), + * Trie.insert("sells", 5), + * Trie.insert("she", 3) + * ) + * + * assert.equal(Equal.equals(Trie.map(trie, (v) => v + 1), trieMapV), true) + * assert.equal(Equal.equals(Trie.map(trie, (_, k) => k.length), trieMapK), true) + * ``` + * + * @since 2.0.0 + * @category folding + */ + (self: Trie, f: (value: V, key: string) => A): Trie +} = TR.map + +/** + * Filters entries out of a `Trie` using the specified predicate. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieMapV = Trie.empty().pipe( + * Trie.insert("she", 2) + * ) + * + * const trieMapK = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1) + * ) + * + * assert.equal(Equal.equals(Trie.filter(trie, (v) => v > 1), trieMapV), true) + * assert.equal(Equal.equals(Trie.filter(trie, (_, k) => k.length > 3), trieMapK), true) + * ``` + * + * @since 2.0.0 + * @category filtering + */ +export const filter: { + /** + * Filters entries out of a `Trie` using the specified predicate. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieMapV = Trie.empty().pipe( + * Trie.insert("she", 2) + * ) + * + * const trieMapK = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1) + * ) + * + * assert.equal(Equal.equals(Trie.filter(trie, (v) => v > 1), trieMapV), true) + * assert.equal(Equal.equals(Trie.filter(trie, (_, k) => k.length > 3), trieMapK), true) + * ``` + * + * @since 2.0.0 + * @category filtering + */ + (f: (a: NoInfer, k: string) => a is B): (self: Trie) => Trie + /** + * Filters entries out of a `Trie` using the specified predicate. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieMapV = Trie.empty().pipe( + * Trie.insert("she", 2) + * ) + * + * const trieMapK = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1) + * ) + * + * assert.equal(Equal.equals(Trie.filter(trie, (v) => v > 1), trieMapV), true) + * assert.equal(Equal.equals(Trie.filter(trie, (_, k) => k.length > 3), trieMapK), true) + * ``` + * + * @since 2.0.0 + * @category filtering + */ + (f: (a: NoInfer, k: string) => boolean): (self: Trie) => Trie + /** + * Filters entries out of a `Trie` using the specified predicate. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieMapV = Trie.empty().pipe( + * Trie.insert("she", 2) + * ) + * + * const trieMapK = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1) + * ) + * + * assert.equal(Equal.equals(Trie.filter(trie, (v) => v > 1), trieMapV), true) + * assert.equal(Equal.equals(Trie.filter(trie, (_, k) => k.length > 3), trieMapK), true) + * ``` + * + * @since 2.0.0 + * @category filtering + */ + (self: Trie, f: (a: A, k: string) => a is B): Trie + /** + * Filters entries out of a `Trie` using the specified predicate. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieMapV = Trie.empty().pipe( + * Trie.insert("she", 2) + * ) + * + * const trieMapK = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1) + * ) + * + * assert.equal(Equal.equals(Trie.filter(trie, (v) => v > 1), trieMapV), true) + * assert.equal(Equal.equals(Trie.filter(trie, (_, k) => k.length > 3), trieMapK), true) + * ``` + * + * @since 2.0.0 + * @category filtering + */ + (self: Trie, f: (a: A, k: string) => boolean): Trie +} = TR.filter + +/** + * Maps over the entries of the `Trie` using the specified partial function + * and filters out `None` values. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieMapV = Trie.empty().pipe( + * Trie.insert("she", 2) + * ) + * + * const trieMapK = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1) + * ) + * + * assert.equal(Equal.equals(Trie.filterMap(trie, (v) => v > 1 ? Option.some(v) : Option.none()), trieMapV), true) + * assert.equal( + * Equal.equals(Trie.filterMap(trie, (v, k) => k.length > 3 ? Option.some(v) : Option.none()), trieMapK), + * true + * ) + * ``` + * + * @since 2.0.0 + * @category filtering + */ +export const filterMap: { + /** + * Maps over the entries of the `Trie` using the specified partial function + * and filters out `None` values. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieMapV = Trie.empty().pipe( + * Trie.insert("she", 2) + * ) + * + * const trieMapK = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1) + * ) + * + * assert.equal(Equal.equals(Trie.filterMap(trie, (v) => v > 1 ? Option.some(v) : Option.none()), trieMapV), true) + * assert.equal( + * Equal.equals(Trie.filterMap(trie, (v, k) => k.length > 3 ? Option.some(v) : Option.none()), trieMapK), + * true + * ) + * ``` + * + * @since 2.0.0 + * @category filtering + */ + (f: (value: A, key: string) => Option): (self: Trie) => Trie + /** + * Maps over the entries of the `Trie` using the specified partial function + * and filters out `None` values. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieMapV = Trie.empty().pipe( + * Trie.insert("she", 2) + * ) + * + * const trieMapK = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1) + * ) + * + * assert.equal(Equal.equals(Trie.filterMap(trie, (v) => v > 1 ? Option.some(v) : Option.none()), trieMapV), true) + * assert.equal( + * Equal.equals(Trie.filterMap(trie, (v, k) => k.length > 3 ? Option.some(v) : Option.none()), trieMapK), + * true + * ) + * ``` + * + * @since 2.0.0 + * @category filtering + */ + (self: Trie, f: (value: A, key: string) => Option): Trie +} = TR.filterMap + +/** + * Filters out `None` values from a `Trie` of `Options`s. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal, Option } from "effect" + * + * const trie = Trie.empty>().pipe( + * Trie.insert("shells", Option.some(0)), + * Trie.insert("sells", Option.none()), + * Trie.insert("she", Option.some(2)) + * ) + * + * const trieMapV = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("she", 2) + * ) + * + * assert.equal(Equal.equals(Trie.compact(trie), trieMapV), true) + * ``` + * + * @since 2.0.0 + * @category filtering + */ +export const compact: (self: Trie>) => Trie = TR.compact + +/** + * Applies the specified function to the entries of the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * let value = 0 + * + * Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2), + * Trie.forEach((n, key) => { + * value += n + key.length + * }) + * ) + * + * assert.equal(value, 17) + * ``` + * + * @since 2.0.0 + * @category traversing + */ +export const forEach: { + /** + * Applies the specified function to the entries of the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * let value = 0 + * + * Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2), + * Trie.forEach((n, key) => { + * value += n + key.length + * }) + * ) + * + * assert.equal(value, 17) + * ``` + * + * @since 2.0.0 + * @category traversing + */ + (f: (value: V, key: string) => void): (self: Trie) => void + /** + * Applies the specified function to the entries of the `Trie`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie } from "effect" + * + * let value = 0 + * + * Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2), + * Trie.forEach((n, key) => { + * value += n + key.length + * }) + * ) + * + * assert.equal(value, 17) + * ``` + * + * @since 2.0.0 + * @category traversing + */ + (self: Trie, f: (value: V, key: string) => void): void +} = TR.forEach + +/** + * Updates the value of the specified key within the `Trie` if it exists. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * assert.deepStrictEqual(trie.pipe(Trie.modify("she", (v) => v + 10), Trie.get("she")), Option.some(12)) + * + * assert.equal(Equal.equals(trie.pipe(Trie.modify("me", (v) => v)), trie), true) + * ``` + * + * @since 2.0.0 + * @category mutations + */ +export const modify: { + /** + * Updates the value of the specified key within the `Trie` if it exists. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * assert.deepStrictEqual(trie.pipe(Trie.modify("she", (v) => v + 10), Trie.get("she")), Option.some(12)) + * + * assert.equal(Equal.equals(trie.pipe(Trie.modify("me", (v) => v)), trie), true) + * ``` + * + * @since 2.0.0 + * @category mutations + */ + (key: string, f: (v: V) => V1): (self: Trie) => Trie + /** + * Updates the value of the specified key within the `Trie` if it exists. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal, Option } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * assert.deepStrictEqual(trie.pipe(Trie.modify("she", (v) => v + 10), Trie.get("she")), Option.some(12)) + * + * assert.equal(Equal.equals(trie.pipe(Trie.modify("me", (v) => v)), trie), true) + * ``` + * + * @since 2.0.0 + * @category mutations + */ + (self: Trie, key: string, f: (v: V) => V1): Trie +} = TR.modify + +/** + * Removes all entries in the `Trie` which have the specified keys. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * assert.equal( + * Equal.equals(trie.pipe(Trie.removeMany(["she", "sells"])), Trie.empty().pipe(Trie.insert("shells", 0))), + * true + * ) + * ``` + * + * @since 2.0.0 + * @category mutations + */ +export const removeMany: { + /** + * Removes all entries in the `Trie` which have the specified keys. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * assert.equal( + * Equal.equals(trie.pipe(Trie.removeMany(["she", "sells"])), Trie.empty().pipe(Trie.insert("shells", 0))), + * true + * ) + * ``` + * + * @since 2.0.0 + * @category mutations + */ + (keys: Iterable): (self: Trie) => Trie + /** + * Removes all entries in the `Trie` which have the specified keys. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * assert.equal( + * Equal.equals(trie.pipe(Trie.removeMany(["she", "sells"])), Trie.empty().pipe(Trie.insert("shells", 0))), + * true + * ) + * ``` + * + * @since 2.0.0 + * @category mutations + */ + (self: Trie, keys: Iterable): Trie +} = TR.removeMany + +/** + * Insert multiple entries in the `Trie` at once. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieInsert = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insertMany( + * [["sells", 1], ["she", 2]] + * ) + * ) + * + * assert.equal( + * Equal.equals(trie, trieInsert), + * true + * ) + * ``` + * + * @since 2.0.0 + * @category mutations + */ +export const insertMany: { + /** + * Insert multiple entries in the `Trie` at once. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieInsert = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insertMany( + * [["sells", 1], ["she", 2]] + * ) + * ) + * + * assert.equal( + * Equal.equals(trie, trieInsert), + * true + * ) + * ``` + * + * @since 2.0.0 + * @category mutations + */ + (iter: Iterable<[string, V1]>): (self: Trie) => Trie + /** + * Insert multiple entries in the `Trie` at once. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Trie, Equal } from "effect" + * + * const trie = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insert("sells", 1), + * Trie.insert("she", 2) + * ) + * + * const trieInsert = Trie.empty().pipe( + * Trie.insert("shells", 0), + * Trie.insertMany( + * [["sells", 1], ["she", 2]] + * ) + * ) + * + * assert.equal( + * Equal.equals(trie, trieInsert), + * true + * ) + * ``` + * + * @since 2.0.0 + * @category mutations + */ + (self: Trie, iter: Iterable<[string, V1]>): Trie +} = TR.insertMany diff --git a/backend/node_modules/effect/src/Tuple.ts b/backend/node_modules/effect/src/Tuple.ts new file mode 100644 index 0000000000000000000000000000000000000000..51bd72bc4c3515977bb159842b2032a58a64e458 --- /dev/null +++ b/backend/node_modules/effect/src/Tuple.ts @@ -0,0 +1,483 @@ +/** + * This module provides utility functions for working with tuples in TypeScript. + * + * @since 2.0.0 + */ +import * as Equivalence from "./Equivalence.js" +import { dual } from "./Function.js" +import type { TypeLambda } from "./HKT.js" +import * as order from "./Order.js" +import type { TupleOf } from "./Types.js" + +/** + * @category type lambdas + * @since 2.0.0 + */ +export interface TupleTypeLambda extends TypeLambda { + readonly type: [this["Out1"], this["Target"]] +} + +/** + * Constructs a new tuple from the provided values. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { make } from "effect/Tuple" + * + * assert.deepStrictEqual(make(1, 'hello', true), [1, 'hello', true]) + * ``` + * + * @category constructors + * @since 2.0.0 + */ +export const make = >(...elements: A): A => elements + +/** + * Return the first element from a tuple with two elements. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { getFirst } from "effect/Tuple" + * + * assert.deepStrictEqual(getFirst(["hello", 42]), "hello") + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const getFirst = (self: readonly [L, R]): L => self[0] + +/** + * Return the second element from a tuple with two elements. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { getSecond } from "effect/Tuple" + * + * assert.deepStrictEqual(getSecond(["hello", 42]), 42) + * ``` + * + * @category getters + * @since 2.0.0 + */ +export const getSecond = (self: readonly [L, R]): R => self[1] + +/** + * Transforms each element of tuple using the given function, treating tuple homomorphically + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Tuple } from "effect" + * + * const result = pipe( + * ["a", 1, false] as const, + * Tuple.map((el) => el.toString().toUpperCase()) + * ) + * assert.deepStrictEqual(result, ['A', '1', 'FALSE']) + * ``` + * + * @category mapping + * @since 3.9.0 + */ +export const map: { + /** + * Transforms each element of tuple using the given function, treating tuple homomorphically + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Tuple } from "effect" + * + * const result = pipe( + * ["a", 1, false] as const, + * Tuple.map((el) => el.toString().toUpperCase()) + * ) + * assert.deepStrictEqual(result, ['A', '1', 'FALSE']) + * ``` + * + * @category mapping + * @since 3.9.0 + */ + | [], B>(fn: (element: T[number]) => B): (self: T) => TupleOf + /** + * Transforms each element of tuple using the given function, treating tuple homomorphically + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { pipe, Tuple } from "effect" + * + * const result = pipe( + * ["a", 1, false] as const, + * Tuple.map((el) => el.toString().toUpperCase()) + * ) + * assert.deepStrictEqual(result, ['A', '1', 'FALSE']) + * ``` + * + * @category mapping + * @since 3.9.0 + */ + | []>(self: T, fn: (element: T[number]) => B): TupleOf +} = dual( + 2, + ( + self: TupleOf, + fn: (element: A) => B + ): TupleOf => self.map((element) => fn(element)) as TupleOf +) + +/** + * Transforms both elements of a tuple with two elements using the given functions. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { mapBoth } from "effect/Tuple" + * + * assert.deepStrictEqual( + * mapBoth(["hello", 42], { onFirst: s => s.toUpperCase(), onSecond: n => n.toString() }), + * ["HELLO", "42"] + * ) + * ``` + * + * @category mapping + * @since 2.0.0 + */ +export const mapBoth: { + /** + * Transforms both elements of a tuple with two elements using the given functions. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { mapBoth } from "effect/Tuple" + * + * assert.deepStrictEqual( + * mapBoth(["hello", 42], { onFirst: s => s.toUpperCase(), onSecond: n => n.toString() }), + * ["HELLO", "42"] + * ) + * ``` + * + * @category mapping + * @since 2.0.0 + */ + ( + options: { + readonly onFirst: (e: L1) => L2 + readonly onSecond: (a: R1) => R2 + } + ): (self: readonly [L1, R1]) => [L2, R2] + /** + * Transforms both elements of a tuple with two elements using the given functions. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { mapBoth } from "effect/Tuple" + * + * assert.deepStrictEqual( + * mapBoth(["hello", 42], { onFirst: s => s.toUpperCase(), onSecond: n => n.toString() }), + * ["HELLO", "42"] + * ) + * ``` + * + * @category mapping + * @since 2.0.0 + */ + ( + self: readonly [L1, R1], + options: { + readonly onFirst: (e: L1) => L2 + readonly onSecond: (a: R1) => R2 + } + ): [L2, R2] +} = dual( + 2, + ( + self: readonly [L1, R1], + { onFirst, onSecond }: { + readonly onFirst: (e: L1) => L2 + readonly onSecond: (a: R1) => R2 + } + ): [L2, R2] => [onFirst(self[0]), onSecond(self[1])] +) + +/** + * Transforms the first component of a tuple with two elements using a given function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { mapFirst } from "effect/Tuple" + * + * assert.deepStrictEqual( + * mapFirst(["hello", 42], s => s.toUpperCase()), + * ["HELLO", 42] + * ) + * ``` + * + * @category mapping + * @since 2.0.0 + */ +export const mapFirst: { + /** + * Transforms the first component of a tuple with two elements using a given function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { mapFirst } from "effect/Tuple" + * + * assert.deepStrictEqual( + * mapFirst(["hello", 42], s => s.toUpperCase()), + * ["HELLO", 42] + * ) + * ``` + * + * @category mapping + * @since 2.0.0 + */ + (f: (left: L1) => L2): (self: readonly [L1, R]) => [L2, R] + /** + * Transforms the first component of a tuple with two elements using a given function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { mapFirst } from "effect/Tuple" + * + * assert.deepStrictEqual( + * mapFirst(["hello", 42], s => s.toUpperCase()), + * ["HELLO", 42] + * ) + * ``` + * + * @category mapping + * @since 2.0.0 + */ + (self: readonly [L1, R], f: (left: L1) => L2): [L2, R] +} = dual(2, (self: readonly [L1, R], f: (left: L1) => L2): [L2, R] => [f(self[0]), self[1]]) + +/** + * Transforms the second component of a tuple with two elements using a given function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { mapSecond } from "effect/Tuple" + * + * assert.deepStrictEqual( + * mapSecond(["hello", 42], n => n.toString()), + * ["hello", "42"] + * ) + * ``` + * + * @category mapping + * @since 2.0.0 + */ +export const mapSecond: { + /** + * Transforms the second component of a tuple with two elements using a given function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { mapSecond } from "effect/Tuple" + * + * assert.deepStrictEqual( + * mapSecond(["hello", 42], n => n.toString()), + * ["hello", "42"] + * ) + * ``` + * + * @category mapping + * @since 2.0.0 + */ + (f: (right: R1) => R2): (self: readonly [L, R1]) => [L, R2] + /** + * Transforms the second component of a tuple with two elements using a given function. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { mapSecond } from "effect/Tuple" + * + * assert.deepStrictEqual( + * mapSecond(["hello", 42], n => n.toString()), + * ["hello", "42"] + * ) + * ``` + * + * @category mapping + * @since 2.0.0 + */ + (self: readonly [L, R1], f: (right: R1) => R2): [L, R2] +} = dual(2, (self: readonly [L, R1], f: (right: R1) => R2): [L, R2] => [self[0], f(self[1])]) + +/** + * Swaps the elements of a tuple with two elements. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { swap } from "effect/Tuple" + * + * assert.deepStrictEqual(swap(["hello", 42]), [42, "hello"]) + * ``` + * + * @since 2.0.0 + */ +export const swap = (self: readonly [L, R]): [R, L] => [self[1], self[0]] + +/** + * Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple + * by applying each `Equivalence` to the corresponding element of the tuple. + * + * @category combinators + * @since 2.0.0 + */ +export const getEquivalence: >>( + ...isEquivalents: T +) => Equivalence.Equivalence< + Readonly<{ [I in keyof T]: [T[I]] extends [Equivalence.Equivalence] ? A : never }> +> = Equivalence.tuple + +/** + * This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. + * The returned `Order` compares two tuples of the same type by applying the corresponding `Order` to each element in the tuple. + * It is useful when you need to compare two tuples of the same type and you have a specific way of comparing each element + * of the tuple. + * + * @category combinators + * @since 2.0.0 + */ +export const getOrder: >>( + ...elements: T +) => order.Order<{ [I in keyof T]: [T[I]] extends [order.Order] ? A : never }> = order.tuple + +/** + * Appends an element to the end of a tuple. + * + * @category concatenating + * @since 2.0.0 + */ +export const appendElement: { + /** + * Appends an element to the end of a tuple. + * + * @category concatenating + * @since 2.0.0 + */ + (that: B): >(self: A) => [...A, B] + /** + * Appends an element to the end of a tuple. + * + * @category concatenating + * @since 2.0.0 + */ + , B>(self: A, that: B): [...A, B] +} = dual(2, , B>(self: A, that: B): [...A, B] => [...self, that]) + +/** + * Retrieves the element at a specified index from a tuple. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Tuple } from "effect" + * + * assert.deepStrictEqual(Tuple.at([1, 'hello', true], 1), 'hello') + * ``` + * + * @category getters + * @since 3.4.0 + */ +export const at: { + /** + * Retrieves the element at a specified index from a tuple. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Tuple } from "effect" + * + * assert.deepStrictEqual(Tuple.at([1, 'hello', true], 1), 'hello') + * ``` + * + * @category getters + * @since 3.4.0 + */ + (index: N): >(self: A) => A[N] + /** + * Retrieves the element at a specified index from a tuple. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { Tuple } from "effect" + * + * assert.deepStrictEqual(Tuple.at([1, 'hello', true], 1), 'hello') + * ``` + * + * @category getters + * @since 3.4.0 + */ + , N extends number>(self: A, index: N): A[N] +} = dual(2, , N extends number>(self: A, index: N): A[N] => self[index]) + +export { + /** + * Determine if an `Array` is a tuple with exactly `N` elements, narrowing down the type to `TupleOf`. + * + * An `Array` is considered to be a `TupleOf` if its length is exactly `N`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { isTupleOf } from "effect/Tuple" + * + * assert.deepStrictEqual(isTupleOf([1, 2, 3], 3), true); + * assert.deepStrictEqual(isTupleOf([1, 2, 3], 2), false); + * assert.deepStrictEqual(isTupleOf([1, 2, 3], 4), false); + * + * const arr: number[] = [1, 2, 3]; + * if (isTupleOf(arr, 3)) { + * console.log(arr); + * // ^? [number, number, number] + * } + * + * ``` + * @category guards + * @since 3.3.0 + */ + isTupleOf, + /** + * Determine if an `Array` is a tuple with at least `N` elements, narrowing down the type to `TupleOfAtLeast`. + * + * An `Array` is considered to be a `TupleOfAtLeast` if its length is at least `N`. + * + * @example + * ```ts + * import * as assert from "node:assert" + * import { isTupleOfAtLeast } from "effect/Tuple" + * + * assert.deepStrictEqual(isTupleOfAtLeast([1, 2, 3], 3), true); + * assert.deepStrictEqual(isTupleOfAtLeast([1, 2, 3], 2), true); + * assert.deepStrictEqual(isTupleOfAtLeast([1, 2, 3], 4), false); + * + * const arr: number[] = [1, 2, 3, 4]; + * if (isTupleOfAtLeast(arr, 3)) { + * console.log(arr); + * // ^? [number, number, number, ...number[]] + * } + * + * ``` + * @category guards + * @since 3.3.0 + */ + isTupleOfAtLeast +} from "./Predicate.js" diff --git a/backend/node_modules/effect/src/UpstreamPullRequest.ts b/backend/node_modules/effect/src/UpstreamPullRequest.ts new file mode 100644 index 0000000000000000000000000000000000000000..37aae68f42e1a79750832f3de739673222cedd50 --- /dev/null +++ b/backend/node_modules/effect/src/UpstreamPullRequest.ts @@ -0,0 +1,129 @@ +/** + * @since 2.0.0 + */ +import * as internal from "./internal/channel/upstreamPullRequest.js" +import type * as Types from "./Types.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const UpstreamPullRequestTypeId: unique symbol = internal.UpstreamPullRequestTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type UpstreamPullRequestTypeId = typeof UpstreamPullRequestTypeId + +/** + * @since 2.0.0 + * @category models + */ +export type UpstreamPullRequest = Pulled | NoUpstream + +/** + * @since 2.0.0 + */ +export declare namespace UpstreamPullRequest { + /** + * @since 2.0.0 + * @category models + */ + export interface Variance { + readonly [UpstreamPullRequestTypeId]: { + readonly _A: Types.Covariant + } + } +} + +/** + * @since 2.0.0 + * @category models + */ +export interface Pulled extends UpstreamPullRequest.Variance { + readonly _tag: "Pulled" + readonly value: A +} + +/** + * @since 2.0.0 + * @category models + */ +export interface NoUpstream extends UpstreamPullRequest.Variance { + readonly _tag: "NoUpstream" + readonly activeDownstreamCount: number +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const Pulled: (value: A) => UpstreamPullRequest = internal.Pulled + +/** + * @since 2.0.0 + * @category constructors + */ +export const NoUpstream: (activeDownstreamCount: number) => UpstreamPullRequest = internal.NoUpstream + +/** + * Returns `true` if the specified value is an `UpstreamPullRequest`, `false` + * otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isUpstreamPullRequest: (u: unknown) => u is UpstreamPullRequest = internal.isUpstreamPullRequest + +/** + * Returns `true` if the specified `UpstreamPullRequest` is a `Pulled`, `false` + * otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isPulled: (self: UpstreamPullRequest) => self is Pulled = internal.isPulled + +/** + * Returns `true` if the specified `UpstreamPullRequest` is a `NoUpstream`, + * `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isNoUpstream: (self: UpstreamPullRequest) => self is NoUpstream = internal.isNoUpstream + +/** + * Folds an `UpstreamPullRequest` into a value of type `Z`. + * + * @since 2.0.0 + * @category folding + */ +export const match: { + /** + * Folds an `UpstreamPullRequest` into a value of type `Z`. + * + * @since 2.0.0 + * @category folding + */ + ( + options: { + readonly onPulled: (value: A) => Z + readonly onNoUpstream: (activeDownstreamCount: number) => Z + } + ): (self: UpstreamPullRequest) => Z + /** + * Folds an `UpstreamPullRequest` into a value of type `Z`. + * + * @since 2.0.0 + * @category folding + */ + ( + self: UpstreamPullRequest, + options: { + readonly onPulled: (value: A) => Z + readonly onNoUpstream: (activeDownstreamCount: number) => Z + } + ): Z +} = internal.match diff --git a/backend/node_modules/effect/src/UpstreamPullStrategy.ts b/backend/node_modules/effect/src/UpstreamPullStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..b5932ef0ddc7ee277deaba5857ff7929e93990d9 --- /dev/null +++ b/backend/node_modules/effect/src/UpstreamPullStrategy.ts @@ -0,0 +1,133 @@ +/** + * @since 2.0.0 + */ +import * as internal from "./internal/channel/upstreamPullStrategy.js" +import type * as Option from "./Option.js" +import type * as Types from "./Types.js" + +/** + * @since 2.0.0 + * @category symbols + */ +export const UpstreamPullStrategyTypeId: unique symbol = internal.UpstreamPullStrategyTypeId + +/** + * @since 2.0.0 + * @category symbols + */ +export type UpstreamPullStrategyTypeId = typeof UpstreamPullStrategyTypeId + +/** + * @since 2.0.0 + * @category models + */ +export type UpstreamPullStrategy = PullAfterNext | PullAfterAllEnqueued + +/** + * @since 2.0.0 + */ +export declare namespace UpstreamPullStrategy { + /** + * @since 2.0.0 + * @category models + */ + export interface Variance { + readonly [UpstreamPullStrategyTypeId]: { + readonly _A: Types.Covariant + } + } +} + +/** + * @since 2.0.0 + * @category models + */ +export interface PullAfterNext extends UpstreamPullStrategy.Variance { + readonly _tag: "PullAfterNext" + readonly emitSeparator: Option.Option +} + +/** + * @since 2.0.0 + * @category models + */ +export interface PullAfterAllEnqueued extends UpstreamPullStrategy.Variance { + readonly _tag: "PullAfterAllEnqueued" + readonly emitSeparator: Option.Option +} + +/** + * @since 2.0.0 + * @category constructors + */ +export const PullAfterNext: (emitSeparator: Option.Option) => UpstreamPullStrategy = internal.PullAfterNext + +/** + * @since 2.0.0 + * @category constructors + */ +export const PullAfterAllEnqueued: (emitSeparator: Option.Option) => UpstreamPullStrategy = + internal.PullAfterAllEnqueued + +/** + * Returns `true` if the specified value is an `UpstreamPullStrategy`, `false` + * otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isUpstreamPullStrategy: (u: unknown) => u is UpstreamPullStrategy = + internal.isUpstreamPullStrategy + +/** + * Returns `true` if the specified `UpstreamPullStrategy` is a `PullAfterNext`, + * `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isPullAfterNext: (self: UpstreamPullStrategy) => self is PullAfterNext = internal.isPullAfterNext + +/** + * Returns `true` if the specified `UpstreamPullStrategy` is a + * `PullAfterAllEnqueued`, `false` otherwise. + * + * @since 2.0.0 + * @category refinements + */ +export const isPullAfterAllEnqueued: (self: UpstreamPullStrategy) => self is PullAfterAllEnqueued = + internal.isPullAfterAllEnqueued + +/** + * Folds an `UpstreamPullStrategy` into a value of type `Z`. + * + * @since 2.0.0 + * @category folding + */ +export const match: { + /** + * Folds an `UpstreamPullStrategy` into a value of type `Z`. + * + * @since 2.0.0 + * @category folding + */ + ( + options: { + readonly onNext: (emitSeparator: Option.Option) => Z + readonly onAllEnqueued: (emitSeparator: Option.Option) => Z + } + ): (self: UpstreamPullStrategy) => Z + /** + * Folds an `UpstreamPullStrategy` into a value of type `Z`. + * + * @since 2.0.0 + * @category folding + */ + ( + self: UpstreamPullStrategy, + options: { + readonly onNext: (emitSeparator: Option.Option) => Z + readonly onAllEnqueued: (emitSeparator: Option.Option) => Z + } + ): Z +} = internal.match diff --git a/backend/node_modules/effect/src/internal/completedRequestMap.ts b/backend/node_modules/effect/src/internal/completedRequestMap.ts new file mode 100644 index 0000000000000000000000000000000000000000..76cd0bf0ecd354ebb623a38142766e01397c746d --- /dev/null +++ b/backend/node_modules/effect/src/internal/completedRequestMap.ts @@ -0,0 +1,9 @@ +import { globalValue } from "../GlobalValue.js" +import type * as Request from "../Request.js" +import { fiberRefUnsafeMake } from "./core.js" + +/** @internal */ +export const currentRequestMap = globalValue( + Symbol.for("effect/FiberRef/currentRequestMap"), + () => fiberRefUnsafeMake(new Map>()) +) diff --git a/backend/node_modules/effect/src/internal/fiber.ts b/backend/node_modules/effect/src/internal/fiber.ts new file mode 100644 index 0000000000000000000000000000000000000000..c5a71b1838b9248dbdfbef123ec2e98d0c3b3869 --- /dev/null +++ b/backend/node_modules/effect/src/internal/fiber.ts @@ -0,0 +1,388 @@ +import type * as Cause from "../Cause.js" +import * as Clock from "../Clock.js" +import type * as Effect from "../Effect.js" +import * as Either from "../Either.js" +import * as Exit from "../Exit.js" +import type * as Fiber from "../Fiber.js" +import * as FiberId from "../FiberId.js" +import * as FiberStatus from "../FiberStatus.js" +import { dual, pipe } from "../Function.js" +import * as HashSet from "../HashSet.js" +import * as number from "../Number.js" +import * as Option from "../Option.js" +import * as order from "../Order.js" +import { pipeArguments } from "../Pipeable.js" +import { hasProperty } from "../Predicate.js" +import * as core from "./core.js" +import * as effectable from "./effectable.js" +import * as fiberScope from "./fiberScope.js" +import * as runtimeFlags from "./runtimeFlags.js" + +/** @internal */ +const FiberSymbolKey = "effect/Fiber" + +/** @internal */ +export const FiberTypeId: Fiber.FiberTypeId = Symbol.for( + FiberSymbolKey +) as Fiber.FiberTypeId + +/** @internal */ +export const fiberVariance = { + /* c8 ignore next */ + _E: (_: never) => _, + /* c8 ignore next */ + _A: (_: never) => _ +} + +/** @internal */ +const fiberProto = { + [FiberTypeId]: fiberVariance, + pipe() { + return pipeArguments(this, arguments) + } +} + +/** @internal */ +const RuntimeFiberSymbolKey = "effect/Fiber" + +/** @internal */ +export const RuntimeFiberTypeId: Fiber.RuntimeFiberTypeId = Symbol.for( + RuntimeFiberSymbolKey +) as Fiber.RuntimeFiberTypeId + +/** @internal */ +export const Order: order.Order> = pipe( + order.tuple(number.Order, number.Order), + order.mapInput((fiber: Fiber.RuntimeFiber) => + [ + (fiber.id() as FiberId.Runtime).startTimeMillis, + (fiber.id() as FiberId.Runtime).id + ] as const + ) +) + +/** @internal */ +export const isFiber = (u: unknown): u is Fiber.Fiber => hasProperty(u, FiberTypeId) + +/** @internal */ +export const isRuntimeFiber = (self: Fiber.Fiber): self is Fiber.RuntimeFiber => + RuntimeFiberTypeId in self + +/** @internal */ +export const _await = (self: Fiber.Fiber): Effect.Effect> => self.await + +/** @internal */ +export const children = ( + self: Fiber.Fiber +): Effect.Effect>> => self.children + +/** @internal */ +export const done = (exit: Exit.Exit): Fiber.Fiber => { + const _fiber = { + ...effectable.CommitPrototype, + commit() { + return join(this) + }, + ...fiberProto, + id: () => FiberId.none, + await: core.succeed(exit), + children: core.succeed([]), + inheritAll: core.void, + poll: core.succeed(Option.some(exit)), + interruptAsFork: () => core.void + } + + return _fiber +} + +/** @internal */ +export const dump = (self: Fiber.RuntimeFiber): Effect.Effect => + core.map(self.status, (status) => ({ id: self.id(), status })) + +/** @internal */ +export const dumpAll = ( + fibers: Iterable> +): Effect.Effect> => core.forEachSequential(fibers, dump) + +/** @internal */ +export const fail = (error: E): Fiber.Fiber => done(Exit.fail(error)) + +/** @internal */ +export const failCause = (cause: Cause.Cause): Fiber.Fiber => done(Exit.failCause(cause)) + +/** @internal */ +export const fromEffect = (effect: Effect.Effect): Effect.Effect> => + core.map(core.exit(effect), done) + +/** @internal */ +export const id = (self: Fiber.Fiber): FiberId.FiberId => self.id() + +/** @internal */ +export const inheritAll = (self: Fiber.Fiber): Effect.Effect => self.inheritAll + +/** @internal */ +export const interrupted = (fiberId: FiberId.FiberId): Fiber.Fiber => done(Exit.interrupt(fiberId)) + +/** @internal */ +export const interruptAll = (fibers: Iterable>): Effect.Effect => + core.flatMap(core.fiberId, (fiberId) => pipe(fibers, interruptAllAs(fiberId))) + +/** @internal */ +export const interruptAllAs = dual< + (fiberId: FiberId.FiberId) => (fibers: Iterable>) => Effect.Effect, + (fibers: Iterable>, fiberId: FiberId.FiberId) => Effect.Effect +>( + 2, + core.fnUntraced(function*(fibers, fiberId) { + for (const fiber of fibers) { + if (isRuntimeFiber(fiber)) { + fiber.unsafeInterruptAsFork(fiberId) + continue + } + yield* fiber.interruptAsFork(fiberId) + } + for (const fiber of fibers) { + if (isRuntimeFiber(fiber) && fiber.unsafePoll()) { + continue + } + yield* fiber.await + } + }) +) + +/** @internal */ +export const interruptAsFork = dual< + (fiberId: FiberId.FiberId) => (self: Fiber.Fiber) => Effect.Effect, + (self: Fiber.Fiber, fiberId: FiberId.FiberId) => Effect.Effect +>(2, (self, fiberId) => self.interruptAsFork(fiberId)) + +/** @internal */ +export const join = (self: Fiber.Fiber): Effect.Effect => + core.zipLeft(core.flatten(self.await), self.inheritAll) + +/** @internal */ +export const map = dual< + (f: (a: A) => B) => (self: Fiber.Fiber) => Fiber.Fiber, + (self: Fiber.Fiber, f: (a: A) => B) => Fiber.Fiber +>(2, (self, f) => mapEffect(self, (a) => core.sync(() => f(a)))) + +/** @internal */ +export const mapEffect = dual< + (f: (a: A) => Effect.Effect) => (self: Fiber.Fiber) => Fiber.Fiber, + (self: Fiber.Fiber, f: (a: A) => Effect.Effect) => Fiber.Fiber +>(2, (self, f) => { + const _fiber = { + ...effectable.CommitPrototype, + commit() { + return join(this) + }, + ...fiberProto, + id: () => self.id(), + await: core.flatMap(self.await, Exit.forEachEffect(f)), + children: self.children, + inheritAll: self.inheritAll, + poll: core.flatMap(self.poll, (result) => { + switch (result._tag) { + case "None": + return core.succeed(Option.none()) + case "Some": + return pipe( + Exit.forEachEffect(result.value, f), + core.map(Option.some) + ) + } + }), + interruptAsFork: (id: FiberId.FiberId) => self.interruptAsFork(id) + } + return _fiber +}) + +/** @internal */ +export const mapFiber = dual< + ( + f: (a: A) => Fiber.Fiber + ) => (self: Fiber.Fiber) => Effect.Effect>, + ( + self: Fiber.Fiber, + f: (a: A) => Fiber.Fiber + ) => Effect.Effect> +>(2, ( + self: Fiber.Fiber, + f: (a: A) => Fiber.Fiber +) => + core.map( + self.await, + Exit.match({ + onFailure: (cause): Fiber.Fiber => failCause(cause), + onSuccess: (a) => f(a) + }) + )) + +/** @internal */ +export const match = dual< + ( + options: { + readonly onFiber: (fiber: Fiber.Fiber) => Z + readonly onRuntimeFiber: (fiber: Fiber.RuntimeFiber) => Z + } + ) => (self: Fiber.Fiber) => Z, + ( + self: Fiber.Fiber, + options: { + readonly onFiber: (fiber: Fiber.Fiber) => Z + readonly onRuntimeFiber: (fiber: Fiber.RuntimeFiber) => Z + } + ) => Z +>(2, (self, { onFiber, onRuntimeFiber }) => { + if (isRuntimeFiber(self)) { + return onRuntimeFiber(self) + } + return onFiber(self) +}) + +/** @internal */ +const _never = { + ...effectable.CommitPrototype, + commit() { + return join(this) + }, + ...fiberProto, + id: () => FiberId.none, + await: core.never, + children: core.succeed([]), + inheritAll: core.never, + poll: core.succeed(Option.none()), + interruptAsFork: () => core.never +} + +/** @internal */ +export const never: Fiber.Fiber = _never + +/** @internal */ +export const orElse = dual< + (that: Fiber.Fiber) => (self: Fiber.Fiber) => Fiber.Fiber, + (self: Fiber.Fiber, that: Fiber.Fiber) => Fiber.Fiber +>(2, (self, that) => ({ + ...effectable.CommitPrototype, + commit() { + return join(this) + }, + ...fiberProto, + id: () => FiberId.getOrElse(self.id(), that.id()), + await: core.zipWith( + self.await, + that.await, + (exit1, exit2) => (Exit.isSuccess(exit1) ? exit1 : exit2) + ), + children: self.children, + inheritAll: core.zipRight(that.inheritAll, self.inheritAll), + poll: core.zipWith( + self.poll, + that.poll, + (option1, option2) => { + switch (option1._tag) { + case "None": { + return Option.none() + } + case "Some": { + return Exit.isSuccess(option1.value) ? option1 : option2 + } + } + } + ), + interruptAsFork: (id) => + pipe( + core.interruptAsFiber(self, id), + core.zipRight(pipe(that, core.interruptAsFiber(id))), + core.asVoid + ) +})) + +/** @internal */ +export const orElseEither = dual< + (that: Fiber.Fiber) => (self: Fiber.Fiber) => Fiber.Fiber, E | E2>, + (self: Fiber.Fiber, that: Fiber.Fiber) => Fiber.Fiber, E | E2> +>(2, (self, that) => orElse(map(self, Either.left), map(that, Either.right))) + +/** @internal */ +export const poll = (self: Fiber.Fiber): Effect.Effect>> => self.poll + +// forked from https://github.com/sindresorhus/parse-ms/blob/4da2ffbdba02c6e288c08236695bdece0adca173/index.js +// MIT License +// Copyright (c) Sindre Sorhus (sindresorhus.com) +/** @internal */ +const parseMs = (milliseconds: number) => { + const roundTowardsZero = milliseconds > 0 ? Math.floor : Math.ceil + return { + days: roundTowardsZero(milliseconds / 86400000), + hours: roundTowardsZero(milliseconds / 3600000) % 24, + minutes: roundTowardsZero(milliseconds / 60000) % 60, + seconds: roundTowardsZero(milliseconds / 1000) % 60, + milliseconds: roundTowardsZero(milliseconds) % 1000, + microseconds: roundTowardsZero(milliseconds * 1000) % 1000, + nanoseconds: roundTowardsZero(milliseconds * 1e6) % 1000 + } +} + +/** @internal */ +const renderStatus = (status: FiberStatus.FiberStatus): string => { + if (FiberStatus.isDone(status)) { + return "Done" + } + if (FiberStatus.isRunning(status)) { + return "Running" + } + + const isInterruptible = runtimeFlags.interruptible(status.runtimeFlags) ? + "interruptible" : + "uninterruptible" + return `Suspended(${isInterruptible})` +} + +/** @internal */ +export const pretty = (self: Fiber.RuntimeFiber): Effect.Effect => + core.flatMap(Clock.currentTimeMillis, (now) => + core.map(dump(self), (dump) => { + const time = now - dump.id.startTimeMillis + const { days, hours, milliseconds, minutes, seconds } = parseMs(time) + const lifeMsg = (days === 0 ? "" : `${days}d`) + + (days === 0 && hours === 0 ? "" : `${hours}h`) + + (days === 0 && hours === 0 && minutes === 0 ? "" : `${minutes}m`) + + (days === 0 && hours === 0 && minutes === 0 && seconds === 0 ? "" : `${seconds}s`) + + `${milliseconds}ms` + const waitMsg = FiberStatus.isSuspended(dump.status) ? + (() => { + const ids = FiberId.ids(dump.status.blockingOn) + return HashSet.size(ids) > 0 + ? `waiting on ` + Array.from(ids).map((id) => `${id}`).join(", ") + : "" + })() : + "" + const statusMsg = renderStatus(dump.status) + return `[Fiber](#${dump.id.id}) (${lifeMsg}) ${waitMsg}\n Status: ${statusMsg}` + })) + +/** @internal */ +export const unsafeRoots = (): Array> => Array.from(fiberScope.globalScope.roots) + +/** @internal */ +export const roots: Effect.Effect>> = core.sync(unsafeRoots) + +/** @internal */ +export const status = (self: Fiber.RuntimeFiber): Effect.Effect => self.status + +/** @internal */ +export const succeed = (value: A): Fiber.Fiber => done(Exit.succeed(value)) + +const void_: Fiber.Fiber = succeed(void 0) +export { + /** @internal */ + void_ as void +} + +/** @internal */ +export const currentFiberURI = "effect/FiberCurrent" + +/** @internal */ +export const getCurrentFiber = (): Option.Option> => + Option.fromNullable((globalThis as any)[currentFiberURI]) diff --git a/backend/node_modules/effect/src/internal/hashMap.ts b/backend/node_modules/effect/src/internal/hashMap.ts new file mode 100644 index 0000000000000000000000000000000000000000..75efbc5f8933c065cd7b9993d9a69ecd341710ec --- /dev/null +++ b/backend/node_modules/effect/src/internal/hashMap.ts @@ -0,0 +1,586 @@ +import * as Equal from "../Equal.js" +import * as Dual from "../Function.js" +import { identity, pipe } from "../Function.js" +import * as Hash from "../Hash.js" +import type * as HM from "../HashMap.js" +import { format, NodeInspectSymbol, toJSON } from "../Inspectable.js" +import * as Option from "../Option.js" +import { pipeArguments } from "../Pipeable.js" +import { hasProperty } from "../Predicate.js" +import type { NoInfer } from "../Types.js" +import { fromBitmap, hashFragment, toBitmap } from "./hashMap/bitwise.js" +import { SIZE } from "./hashMap/config.js" +import * as Node from "./hashMap/node.js" + +const HashMapSymbolKey = "effect/HashMap" + +/** @internal */ +export const HashMapTypeId: HM.TypeId = Symbol.for(HashMapSymbolKey) as HM.TypeId + +type TraversalFn = (k: K, v: V) => A + +type Cont = + | [ + len: number, + children: Array>, + i: number, + f: TraversalFn, + cont: Cont + ] + | undefined + +interface VisitResult { + value: A + cont: Cont +} + +/** @internal */ +export interface HashMapImpl extends HM.HashMap { + _editable: boolean // mutable by design + _edit: number // mutable by design + _root: Node.Node // mutable by design + _size: number // mutable by design +} + +const HashMapProto: HM.HashMap = { + [HashMapTypeId]: HashMapTypeId, + [Symbol.iterator](this: HashMapImpl): Iterator<[K, V]> { + return new HashMapIterator(this, (k, v) => [k, v]) + }, + [Hash.symbol](this: HM.HashMap): number { + let hash = Hash.hash(HashMapSymbolKey) + for (const item of this) { + hash ^= pipe(Hash.hash(item[0]), Hash.combine(Hash.hash(item[1]))) + } + return Hash.cached(this, hash) + }, + [Equal.symbol](this: HashMapImpl, that: unknown): boolean { + if (isHashMap(that)) { + if ((that as HashMapImpl)._size !== this._size) { + return false + } + for (const item of this) { + const elem = pipe( + that as HM.HashMap, + getHash(item[0], Hash.hash(item[0])) + ) + if (Option.isNone(elem)) { + return false + } else { + if (!Equal.equals(item[1], elem.value)) { + return false + } + } + } + return true + } + return false + }, + toString(this: HashMapImpl) { + return format(this.toJSON()) + }, + toJSON() { + return { + _id: "HashMap", + values: Array.from(this).map(toJSON) + } + }, + [NodeInspectSymbol]() { + return this.toJSON() + }, + pipe() { + return pipeArguments(this, arguments) + } +} + +const makeImpl = ( + editable: boolean, + edit: number, + root: Node.Node, + size: number +): HashMapImpl => { + const map = Object.create(HashMapProto) + map._editable = editable + map._edit = edit + map._root = root + map._size = size + return map +} + +class HashMapIterator implements IterableIterator { + v: Option.Option> + + constructor(readonly map: HashMapImpl, readonly f: TraversalFn) { + this.v = visitLazy(this.map._root, this.f, undefined) + } + + next(): IteratorResult { + if (Option.isNone(this.v)) { + return { done: true, value: undefined } + } + const v0 = this.v.value + this.v = applyCont(v0.cont) + return { done: false, value: v0.value } + } + + [Symbol.iterator](): IterableIterator { + return new HashMapIterator(this.map, this.f) + } +} + +const applyCont = (cont: Cont): Option.Option> => + cont + ? visitLazyChildren(cont[0], cont[1], cont[2], cont[3], cont[4]) + : Option.none() + +const visitLazy = ( + node: Node.Node, + f: TraversalFn, + cont: Cont = undefined +): Option.Option> => { + switch (node._tag) { + case "LeafNode": { + if (Option.isSome(node.value)) { + return Option.some({ + value: f(node.key, node.value.value), + cont + }) + } + return applyCont(cont) + } + case "CollisionNode": + case "ArrayNode": + case "IndexedNode": { + const children = node.children + return visitLazyChildren(children.length, children, 0, f, cont) + } + default: { + return applyCont(cont) + } + } +} + +const visitLazyChildren = ( + len: number, + children: Array>, + i: number, + f: TraversalFn, + cont: Cont +): Option.Option> => { + while (i < len) { + const child = children[i++] + if (child && !Node.isEmptyNode(child)) { + return visitLazy(child, f, [len, children, i, f, cont]) + } + } + return applyCont(cont) +} + +const _empty = makeImpl(false, 0, new Node.EmptyNode(), 0) + +/** @internal */ +export const empty = (): HM.HashMap => _empty + +/** @internal */ +export const make = >( + ...entries: Entries +): HM.HashMap< + Entries[number] extends readonly [infer K, any] ? K : never, + Entries[number] extends readonly [any, infer V] ? V : never +> => fromIterable(entries) + +/** @internal */ +export const fromIterable = (entries: Iterable): HM.HashMap => { + const map = beginMutation(empty()) + for (const entry of entries) { + set(map, entry[0], entry[1]) + } + return endMutation(map) +} + +/** @internal */ +export const isHashMap: { + (u: Iterable): u is HM.HashMap + (u: unknown): u is HM.HashMap +} = (u: unknown): u is HM.HashMap => hasProperty(u, HashMapTypeId) + +/** @internal */ +export const isEmpty = (self: HM.HashMap): boolean => + self && Node.isEmptyNode((self as HashMapImpl)._root) + +/** @internal */ +export const get = Dual.dual< + (key: K1) => (self: HM.HashMap) => Option.Option, + (self: HM.HashMap, key: K1) => Option.Option +>(2, (self, key) => getHash(self, key, Hash.hash(key))) + +/** @internal */ +export const getHash = Dual.dual< + (key: K1, hash: number) => (self: HM.HashMap) => Option.Option, + (self: HM.HashMap, key: K1, hash: number) => Option.Option +>(3, (self: HM.HashMap, key: K1, hash: number) => { + let node = (self as HashMapImpl)._root + let shift = 0 + + while (true) { + switch (node._tag) { + case "LeafNode": { + return Equal.equals(key, node.key) ? node.value : Option.none() + } + case "CollisionNode": { + if (hash === node.hash) { + const children = node.children + for (let i = 0, len = children.length; i < len; ++i) { + const child = children[i]! + if ("key" in child && Equal.equals(key, child.key)) { + return child.value + } + } + } + return Option.none() + } + case "IndexedNode": { + const frag = hashFragment(shift, hash) + const bit = toBitmap(frag) + if (node.mask & bit) { + node = node.children[fromBitmap(node.mask, bit)]! + shift += SIZE + break + } + return Option.none() + } + case "ArrayNode": { + node = node.children[hashFragment(shift, hash)]! + if (node) { + shift += SIZE + break + } + return Option.none() + } + default: + return Option.none() + } + } +}) + +/** @internal */ +export const unsafeGet = Dual.dual< + (key: K1) => (self: HM.HashMap) => V, + (self: HM.HashMap, key: K1) => V +>(2, (self, key) => { + const element = getHash(self, key, Hash.hash(key)) + if (Option.isNone(element)) { + throw new Error("Expected map to contain key") + } + return element.value +}) + +/** @internal */ +export const has = Dual.dual< + (key: K1) => (self: HM.HashMap) => boolean, + (self: HM.HashMap, key: K1) => boolean +>(2, (self, key) => Option.isSome(getHash(self, key, Hash.hash(key)))) + +/** @internal */ +export const hasHash = Dual.dual< + (key: K1, hash: number) => (self: HM.HashMap) => boolean, + (self: HM.HashMap, key: K1, hash: number) => boolean +>(3, (self, key, hash) => Option.isSome(getHash(self, key, hash))) + +/** @internal */ +export const hasBy = Dual.dual< + (predicate: (value: NoInfer, key: NoInfer) => boolean) => (self: HM.HashMap) => boolean, + (self: HM.HashMap, predicate: (value: NoInfer, key: NoInfer) => boolean) => boolean +>(2, (self, predicate) => Option.isSome(findFirst(self, predicate))) + +/** @internal */ +export const set = Dual.dual< + (key: K, value: V) => (self: HM.HashMap) => HM.HashMap, + (self: HM.HashMap, key: K, value: V) => HM.HashMap +>(3, (self, key, value) => modifyAt(self, key, () => Option.some(value))) + +/** @internal */ +export const setTree = Dual.dual< + (newRoot: Node.Node, newSize: number) => (self: HM.HashMap) => HM.HashMap, + (self: HM.HashMap, newRoot: Node.Node, newSize: number) => HM.HashMap +>(3, (self: HM.HashMap, newRoot: Node.Node, newSize: number) => { + if ((self as HashMapImpl)._editable) { + ;(self as HashMapImpl)._root = newRoot + ;(self as HashMapImpl)._size = newSize + return self + } + return newRoot === (self as HashMapImpl)._root + ? self + : makeImpl( + (self as HashMapImpl)._editable, + (self as HashMapImpl)._edit, + newRoot, + newSize + ) +}) + +/** @internal */ +export const keys = (self: HM.HashMap): IterableIterator => + new HashMapIterator(self as HashMapImpl, (key) => key) + +/** @internal */ +export const values = (self: HM.HashMap): IterableIterator => + new HashMapIterator(self as HashMapImpl, (_, value) => value) + +/** @internal */ +export const entries = (self: HM.HashMap): IterableIterator<[K, V]> => + new HashMapIterator(self as HashMapImpl, (key, value) => [key, value]) + +/** @internal */ +export const size = (self: HM.HashMap): number => (self as HashMapImpl)._size + +/** @internal */ +export const countBy = Dual.dual< + (predicate: (value: NoInfer, key: NoInfer) => boolean) => (self: HM.HashMap) => number, + (self: HM.HashMap, predicate: (value: NoInfer, key: NoInfer) => boolean) => number +>(2, (self, f) => { + let count = 0 + for (const [k, a] of self) { + if (f(a, k)) { + count++ + } + } + return count +}) + +/** @internal */ +export const beginMutation = (self: HM.HashMap): HM.HashMap => + makeImpl( + true, + (self as HashMapImpl)._edit + 1, + (self as HashMapImpl)._root, + (self as HashMapImpl)._size + ) + +/** @internal */ +export const endMutation = (self: HM.HashMap): HM.HashMap => { + ;(self as HashMapImpl)._editable = false + return self +} + +/** @internal */ +export const mutate = Dual.dual< + (f: (self: HM.HashMap) => void) => (self: HM.HashMap) => HM.HashMap, + (self: HM.HashMap, f: (self: HM.HashMap) => void) => HM.HashMap +>(2, (self, f) => { + const transient = beginMutation(self) + f(transient) + return endMutation(transient) +}) + +/** @internal */ +export const modifyAt = Dual.dual< + (key: K, f: HM.HashMap.UpdateFn) => (self: HM.HashMap) => HM.HashMap, + (self: HM.HashMap, key: K, f: HM.HashMap.UpdateFn) => HM.HashMap +>(3, (self, key, f) => modifyHash(self, key, Hash.hash(key), f)) + +/** @internal */ +export const modifyHash = Dual.dual< + (key: K, hash: number, f: HM.HashMap.UpdateFn) => (self: HM.HashMap) => HM.HashMap, + (self: HM.HashMap, key: K, hash: number, f: HM.HashMap.UpdateFn) => HM.HashMap +>(4, (self: HM.HashMap, key: K, hash: number, f: HM.HashMap.UpdateFn) => { + const size = { value: (self as HashMapImpl)._size } + const newRoot = (self as HashMapImpl)._root.modify( + (self as HashMapImpl)._editable ? + (self as HashMapImpl)._edit : + NaN, + 0, + f, + hash, + key, + size + ) + return pipe(self, setTree(newRoot, size.value)) +}) + +/** @internal */ +export const modify = Dual.dual< + (key: K, f: (v: V) => V) => (self: HM.HashMap) => HM.HashMap, + (self: HM.HashMap, key: K, f: (v: V) => V) => HM.HashMap +>(3, (self, key, f) => modifyAt(self, key, Option.map(f))) + +/** @internal */ +export const union = Dual.dual< + ( + that: HM.HashMap + ) => (self: HM.HashMap) => HM.HashMap, + ( + self: HM.HashMap, + that: HM.HashMap + ) => HM.HashMap +>(2, (self: HM.HashMap, that: HM.HashMap) => { + const result: HM.HashMap = beginMutation(self) + forEach(that, (v, k) => set(result, k, v)) + return endMutation(result) +}) + +/** @internal */ +export const remove = Dual.dual< + (key: K) => (self: HM.HashMap) => HM.HashMap, + (self: HM.HashMap, key: K) => HM.HashMap +>(2, (self, key) => modifyAt(self, key, Option.none)) + +/** @internal */ +export const removeMany = Dual.dual< + (keys: Iterable) => (self: HM.HashMap) => HM.HashMap, + (self: HM.HashMap, keys: Iterable) => HM.HashMap +>(2, (self, keys) => + mutate(self, (map) => { + for (const key of keys) { + remove(key)(map) + } + })) + +/** + * Maps over the entries of the `HashMap` using the specified function. + * + * @since 2.0.0 + * @category mapping + */ +export const map = Dual.dual< + (f: (value: V, key: K) => A) => (self: HM.HashMap) => HM.HashMap, + (self: HM.HashMap, f: (value: V, key: K) => A) => HM.HashMap +>(2, (self, f) => + reduce( + self, + empty(), + (map, value, key) => set(map, key, f(value, key)) + )) + +/** @internal */ +export const flatMap = Dual.dual< + ( + f: (value: A, key: K) => HM.HashMap + ) => (self: HM.HashMap) => HM.HashMap, + (self: HM.HashMap, f: (value: A, key: K) => HM.HashMap) => HM.HashMap +>( + 2, + (self, f) => + reduce(self, empty(), (zero, value, key) => + mutate( + zero, + (map) => forEach(f(value, key), (value, key) => set(map, key, value)) + )) +) + +/** @internal */ +export const forEach = Dual.dual< + (f: (value: V, key: K) => void) => (self: HM.HashMap) => void, + (self: HM.HashMap, f: (value: V, key: K) => void) => void +>(2, (self, f) => reduce(self, void 0 as void, (_, value, key) => f(value, key))) + +/** @internal */ +export const reduce = Dual.dual< + (zero: Z, f: (accumulator: Z, value: V, key: K) => Z) => (self: HM.HashMap) => Z, + (self: HM.HashMap, zero: Z, f: (accumulator: Z, value: V, key: K) => Z) => Z +>(3, (self: HM.HashMap, zero: Z, f: (accumulator: Z, value: V, key: K) => Z) => { + const root = (self as HashMapImpl)._root + if (root._tag === "LeafNode") { + return Option.isSome(root.value) ? f(zero, root.value.value, root.key) : zero + } + if (root._tag === "EmptyNode") { + return zero + } + const toVisit = [root.children] + let children + while ((children = toVisit.pop())) { + for (let i = 0, len = children.length; i < len;) { + const child = children[i++] + if (child && !Node.isEmptyNode(child)) { + if (child._tag === "LeafNode") { + if (Option.isSome(child.value)) { + zero = f(zero, child.value.value, child.key) + } + } else { + toVisit.push(child.children) + } + } + } + } + return zero +}) + +/** @internal */ +export const filter: { + (f: (a: NoInfer, k: K) => a is B): (self: HM.HashMap) => HM.HashMap + (f: (a: NoInfer, k: K) => boolean): (self: HM.HashMap) => HM.HashMap + (self: HM.HashMap, f: (a: A, k: K) => a is B): HM.HashMap + (self: HM.HashMap, f: (a: A, k: K) => boolean): HM.HashMap +} = Dual.dual( + 2, + (self: HM.HashMap, f: (a: A, k: K) => boolean): HM.HashMap => + mutate(empty(), (map) => { + for (const [k, a] of self) { + if (f(a, k)) { + set(map, k, a) + } + } + }) +) + +/** @internal */ +export const compact = (self: HM.HashMap>) => filterMap(self, identity) + +/** @internal */ +export const filterMap = Dual.dual< + ( + f: (value: A, key: K) => Option.Option + ) => (self: HM.HashMap) => HM.HashMap, + (self: HM.HashMap, f: (value: A, key: K) => Option.Option) => HM.HashMap +>(2, (self, f) => + mutate(empty(), (map) => { + for (const [k, a] of self) { + const option = f(a, k) + if (Option.isSome(option)) { + set(map, k, option.value) + } + } + })) + +/** @internal */ +export const findFirst: { + (predicate: (a: NoInfer, k: K) => a is B): (self: HM.HashMap) => Option.Option<[K, B]> + (predicate: (a: NoInfer, k: K) => boolean): (self: HM.HashMap) => Option.Option<[K, A]> + (self: HM.HashMap, predicate: (a: A, k: K) => a is B): Option.Option<[K, B]> + (self: HM.HashMap, predicate: (a: A, k: K) => boolean): Option.Option<[K, A]> +} = Dual.dual( + 2, + (self: HM.HashMap, predicate: (a: A, k: K) => boolean): Option.Option<[K, A]> => { + for (const ka of self) { + if (predicate(ka[1], ka[0])) { + return Option.some(ka) + } + } + return Option.none() + } +) + +/** @internal */ +export const some: { + (predicate: (a: NoInfer, k: K) => boolean): (self: HM.HashMap) => boolean + (self: HM.HashMap, predicate: (a: A, k: K) => boolean): boolean +} = Dual.dual( + 2, + (self: HM.HashMap, predicate: (a: A, k: K) => boolean): boolean => { + for (const ka of self) { + if (predicate(ka[1], ka[0])) { + return true + } + } + return false + } +) + +/** @internal */ +export const every: { + (predicate: (a: NoInfer, k: K) => boolean): (self: HM.HashMap) => boolean + (self: HM.HashMap, predicate: (a: A, k: K) => boolean): boolean +} = Dual.dual( + 2, + (self: HM.HashMap, predicate: (a: A, k: K) => boolean): boolean => !some(self, (a, k) => !predicate(a, k)) +) diff --git a/backend/node_modules/giget/dist/cli.mjs b/backend/node_modules/giget/dist/cli.mjs new file mode 100644 index 0000000000000000000000000000000000000000..13632c3d813bd929b5b814bdfa7eb4c809e73714 --- /dev/null +++ b/backend/node_modules/giget/dist/cli.mjs @@ -0,0 +1,112 @@ +#!/usr/bin/env node +import { relative } from 'node:path'; +import { defineCommand, runMain } from 'citty'; +import { consola } from 'consola'; +import { d as downloadTemplate, s as startShell } from './shared/giget.OCaTp9b-.mjs'; +import 'node:fs/promises'; +import 'node:fs'; +import 'assert'; +import 'path'; +import 'events'; +import 'stream'; +import 'string_decoder'; +import 'buffer'; +import 'zlib'; +import 'process'; +import 'fs'; +import 'util'; +import 'crypto'; +import 'pathe'; +import 'defu'; +import 'nypm'; +import 'node:stream'; +import 'node:child_process'; +import 'node:os'; +import 'node:util'; +import 'node-fetch-native/proxy'; + +const name = "giget"; +const version = "2.0.0"; +const description = "Download templates and git repositories with pleasure!"; +const pkg = { + name: name, + version: version, + description: description}; + +const mainCommand = defineCommand({ + meta: { + name: pkg.name, + version: pkg.version, + description: pkg.description + }, + args: { + // TODO: Make it `-t` in the next major version + template: { + type: "positional", + description: "Template name or a a URI describing provider, repository, subdir, and branch/ref" + }, + dir: { + type: "positional", + description: "A relative or absolute path where to extract the template", + required: false + }, + auth: { + type: "string", + description: "Custom Authorization token to use for downloading template. (Can be overriden with `GIGET_AUTH` environment variable)" + }, + cwd: { + type: "string", + description: "Set current working directory to resolve dirs relative to it" + }, + force: { + type: "boolean", + description: "Clone to existing directory even if exists" + }, + forceClean: { + type: "boolean", + description: "Remove any existing directory or file recusively before cloning" + }, + offline: { + type: "boolean", + description: "o not attempt to download and use cached version" + }, + preferOffline: { + type: "boolean", + description: "Use cache if exists otherwise try to download" + }, + shell: { + type: "boolean", + description: "Open a new shell with current working " + }, + install: { + type: "boolean", + description: "Install dependencies after cloning" + }, + verbose: { + type: "boolean", + description: "Show verbose debugging info" + } + }, + run: async ({ args }) => { + if (args.verbose) { + process.env.DEBUG = process.env.DEBUG || "true"; + } + const r = await downloadTemplate(args.template, { + dir: args.dir, + force: args.force, + forceClean: args.forceClean, + offline: args.offline, + preferOffline: args.preferOffline, + auth: args.auth, + install: args.install + }); + const _from = r.name || r.url; + const _to = relative(process.cwd(), r.dir) || "./"; + consola.log(`\u2728 Successfully cloned \`${_from}\` to \`${_to}\` +`); + if (args.shell) { + startShell(r.dir); + } + } +}); +runMain(mainCommand); diff --git a/backend/node_modules/giget/dist/index.d.mts b/backend/node_modules/giget/dist/index.d.mts new file mode 100644 index 0000000000000000000000000000000000000000..7320179a10bbad0a5cd73a307b7f877f68a93fd1 --- /dev/null +++ b/backend/node_modules/giget/dist/index.d.mts @@ -0,0 +1,49 @@ +interface GitInfo { + provider: "github" | "gitlab" | "bitbucket" | "sourcehut"; + repo: string; + subdir: string; + ref: string; +} +interface TemplateInfo { + name: string; + tar: string; + version?: string; + subdir?: string; + url?: string; + defaultDir?: string; + headers?: Record; + source?: never; + dir?: never; + [key: string]: any; +} +type TemplateProvider = (input: string, options: { + auth?: string; +}) => TemplateInfo | Promise | null; + +interface DownloadTemplateOptions { + provider?: string; + force?: boolean; + forceClean?: boolean; + offline?: boolean; + preferOffline?: boolean; + providers?: Record; + dir?: string; + registry?: false | string; + cwd?: string; + auth?: string; + install?: boolean; + silent?: boolean; +} +type DownloadTemplateResult = Omit & { + dir: string; + source: string; +}; +declare function downloadTemplate(input: string, options?: DownloadTemplateOptions): Promise; + +declare const registryProvider: (registryEndpoint?: string, options?: { + auth?: string; +}) => TemplateProvider; + +declare function startShell(cwd: string): void; + +export { type DownloadTemplateOptions, type DownloadTemplateResult, type GitInfo, type TemplateInfo, type TemplateProvider, downloadTemplate, registryProvider, startShell }; diff --git a/backend/node_modules/giget/dist/index.mjs b/backend/node_modules/giget/dist/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..ff38b5e4f5682dab52dd09899f118042ae0a1b36 --- /dev/null +++ b/backend/node_modules/giget/dist/index.mjs @@ -0,0 +1,22 @@ +export { d as downloadTemplate, r as registryProvider, s as startShell } from './shared/giget.OCaTp9b-.mjs'; +import 'node:fs/promises'; +import 'node:fs'; +import 'assert'; +import 'path'; +import 'events'; +import 'stream'; +import 'string_decoder'; +import 'buffer'; +import 'zlib'; +import 'process'; +import 'fs'; +import 'util'; +import 'crypto'; +import 'pathe'; +import 'defu'; +import 'nypm'; +import 'node:stream'; +import 'node:child_process'; +import 'node:os'; +import 'node:util'; +import 'node-fetch-native/proxy'; diff --git a/backend/node_modules/giget/dist/shared/giget.OCaTp9b-.mjs b/backend/node_modules/giget/dist/shared/giget.OCaTp9b-.mjs new file mode 100644 index 0000000000000000000000000000000000000000..0f909d38f599397cd2a14b6b399399ef93ebd2e6 --- /dev/null +++ b/backend/node_modules/giget/dist/shared/giget.OCaTp9b-.mjs @@ -0,0 +1,468 @@ +import { readFile, writeFile, mkdir, rm } from 'node:fs/promises'; +import { existsSync, renameSync, createWriteStream, readdirSync } from 'node:fs'; +import j$1 from 'assert'; +import H$2 from 'path'; +import nt from 'events'; +import ot from 'stream'; +import ht from 'string_decoder'; +import P from 'buffer'; +import O$2 from 'zlib'; +import nt$1 from 'process'; +import V from 'fs'; +import a$a from 'util'; +import Ds from 'crypto'; +import { resolve, relative, basename, dirname } from 'pathe'; +import { defu } from 'defu'; +import { installDependencies } from 'nypm'; +import { pipeline } from 'node:stream'; +import { spawnSync } from 'node:child_process'; +import { homedir, tmpdir } from 'node:os'; +import { promisify } from 'node:util'; +import { fetch } from 'node-fetch-native/proxy'; + +var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + +function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; +} + +var i$6,t$5;function s$6(){if(t$5)return i$6;t$5=1;const n=new Map([["C","cwd"],["f","file"],["z","gzip"],["P","preservePaths"],["U","unlink"],["strip-components","strip"],["stripComponents","strip"],["keep-newer","newer"],["keepNewer","newer"],["keep-newer-files","newer"],["keepNewerFiles","newer"],["k","keep"],["keep-existing","keep"],["keepExisting","keep"],["m","noMtime"],["no-mtime","noMtime"],["p","preserveOwner"],["L","follow"],["h","follow"]]);return i$6=r=>r?Object.keys(r).map(e=>[n.has(e)?n.get(e):e,r[e]]).reduce((e,p)=>(e[p[0]]=p[1],e),Object.create(null)):{},i$6} + +var e$5,t$4;function c$4(){return t$4||(t$4=1,e$5=o=>class extends o{warn(n,i,r={}){this.file&&(r.file=this.file),this.cwd&&(r.cwd=this.cwd),r.code=i instanceof Error&&i.code||n,r.tarCode=n,!this.strict&&r.recoverable!==false?(i instanceof Error&&(r=Object.assign(i,r),i=i.message),this.emit("warn",r.tarCode,i,r)):i instanceof Error?this.emit("error",Object.assign(i,r)):this.emit("error",Object.assign(new Error(`${n}: ${i}`),r));}}),e$5} + +var e$4={}; + +var a$9;function n$3(){return a$9?e$4:(a$9=1,function(e){e.name=new Map([["0","File"],["","OldFile"],["1","Link"],["2","SymbolicLink"],["3","CharacterDevice"],["4","BlockDevice"],["5","Directory"],["6","FIFO"],["7","ContiguousFile"],["g","GlobalExtendedHeader"],["x","ExtendedHeader"],["A","SolarisACL"],["D","GNUDumpDir"],["I","Inode"],["K","NextFileHasLongLinkpath"],["L","NextFileHasLongPath"],["M","ContinuationFile"],["N","OldGnuLongPath"],["S","SparseFile"],["V","TapeVolumeHeader"],["X","OldExtendedHeader"]]),e.code=new Map(Array.from(e.name).map(i=>[i[1],i[0]]));}(e$4),e$4)} + +var f$3,i$5;function w$1(){if(i$5)return f$3;i$5=1;const v=(e,r)=>{if(Number.isSafeInteger(e))e<0?g(e,r):p(e,r);else throw Error("cannot encode number outside of javascript safe integer range");return r},p=(e,r)=>{r[0]=128;for(var o=r.length;o>1;o--)r[o-1]=e&255,e=Math.floor(e/256);},g=(e,r)=>{r[0]=255;var o=false;e=e*-1;for(var s=r.length;s>1;s--){var a=e&255;e=Math.floor(e/256),o?r[s-1]=l(a):a===0?r[s-1]=0:(o=true,r[s-1]=c(a));}},h=e=>{const r=e[0],o=r===128?d(e.slice(1,e.length)):r===255?x(e):null;if(o===null)throw Error("invalid base256 encoding");if(!Number.isSafeInteger(o))throw Error("parsed number outside of javascript safe integer range");return o},x=e=>{for(var r=e.length,o=0,s=false,a=r-1;a>-1;a--){var n=e[a],t;s?t=l(n):n===0?t=n:(s=true,t=c(n)),t!==0&&(o-=t*Math.pow(256,r-a-1));}return o},d=e=>{for(var r=e.length,o=0,s=r-1;s>-1;s--){var a=e[s];a!==0&&(o+=a*Math.pow(256,r-s-1));}return o},l=e=>(255^e)&255,c=e=>(255^e)+1&255;return f$3={encode:v,parse:h},f$3} + +var k,w;function E(){if(w)return k;w=1;const u=n$3(),x=H$2.posix,y=w$1(),P=Symbol("slurp"),a=Symbol("type");class B{constructor(e,t,i,h){this.cksumValid=false,this.needPax=false,this.nullBlock=false,this.block=null,this.path=null,this.mode=null,this.uid=null,this.gid=null,this.size=null,this.mtime=null,this.cksum=null,this[a]="0",this.linkpath=null,this.uname=null,this.gname=null,this.devmaj=0,this.devmin=0,this.atime=null,this.ctime=null,Buffer.isBuffer(e)?this.decode(e,t||0,i,h):e&&this.set(e);}decode(e,t,i,h){if(t||(t=0),!e||!(e.length>=t+512))throw new Error("need 512 bytes for header");if(this.path=d(e,t,100),this.mode=r(e,t+100,8),this.uid=r(e,t+108,8),this.gid=r(e,t+116,8),this.size=r(e,t+124,12),this.mtime=o(e,t+136,12),this.cksum=r(e,t+148,12),this[P](i),this[P](h,true),this[a]=d(e,t+156,1),this[a]===""&&(this[a]="0"),this[a]==="0"&&this.path.slice(-1)==="/"&&(this[a]="5"),this[a]==="5"&&(this.size=0),this.linkpath=d(e,t+157,100),e.slice(t+257,t+265).toString()==="ustar\x0000")if(this.uname=d(e,t+265,32),this.gname=d(e,t+297,32),this.devmaj=r(e,t+329,8),this.devmin=r(e,t+337,8),e[t+475]!==0){const n=d(e,t+345,155);this.path=n+"/"+this.path;}else {const n=d(e,t+345,130);n&&(this.path=n+"/"+this.path),this.atime=o(e,t+476,12),this.ctime=o(e,t+488,12);}let l=8*32;for(let n=t;n=t+512))throw new Error("need 512 bytes for header");const i=this.ctime||this.atime?130:155,h=L(this.path||"",i),l=h[0],n=h[1];this.needPax=h[2],this.needPax=m(e,t,100,l)||this.needPax,this.needPax=c(e,t+100,8,this.mode)||this.needPax,this.needPax=c(e,t+108,8,this.uid)||this.needPax,this.needPax=c(e,t+116,8,this.gid)||this.needPax,this.needPax=c(e,t+124,12,this.size)||this.needPax,this.needPax=g(e,t+136,12,this.mtime)||this.needPax,e[t+156]=this[a].charCodeAt(0),this.needPax=m(e,t+157,100,this.linkpath)||this.needPax,e.write("ustar\x0000",t+257,8),this.needPax=m(e,t+265,32,this.uname)||this.needPax,this.needPax=m(e,t+297,32,this.gname)||this.needPax,this.needPax=c(e,t+329,8,this.devmaj)||this.needPax,this.needPax=c(e,t+337,8,this.devmin)||this.needPax,this.needPax=m(e,t+345,i,n)||this.needPax,e[t+475]!==0?this.needPax=m(e,t+345,155,n)||this.needPax:(this.needPax=m(e,t+345,130,n)||this.needPax,this.needPax=g(e,t+476,12,this.atime)||this.needPax,this.needPax=g(e,t+488,12,this.ctime)||this.needPax);let S=8*32;for(let p=t;p{let i=s,h="",l;const n=x.parse(s).root||".";if(Buffer.byteLength(i)<100)l=[i,h,false];else {h=x.dirname(i),i=x.basename(i);do Buffer.byteLength(i)<=100&&Buffer.byteLength(h)<=e?l=[i,h,false]:Buffer.byteLength(i)>100&&Buffer.byteLength(h)<=e?l=[i.slice(0,99),h,true]:(i=x.join(x.basename(h),i),h=x.dirname(h));while(h!==n&&!l);l||(l=[s.slice(0,99),"",true]);}return l},d=(s,e,t)=>s.slice(e,e+t).toString("utf8").replace(/\0.*/,""),o=(s,e,t)=>N(r(s,e,t)),N=s=>s===null?null:new Date(s*1e3),r=(s,e,t)=>s[e]&128?y.parse(s.slice(e,e+t)):j(s,e,t),q=s=>isNaN(s)?null:s,j=(s,e,t)=>q(parseInt(s.slice(e,e+t).toString("utf8").replace(/\0.*$/,"").trim(),8)),v={12:8589934591,8:2097151},c=(s,e,t,i)=>i===null?false:i>v[t]||i<0?(y.encode(i,s.slice(e,e+t)),true):($(s,e,t,i),false),$=(s,e,t,i)=>s.write(_(i,t),e,t,"ascii"),_=(s,e)=>z(Math.floor(s).toString(8),e),z=(s,e)=>(s.length===e-1?s:new Array(e-s.length-1).join("0")+s+" ")+"\0",g=(s,e,t,i)=>i===null?false:c(s,e,t,i.getTime()/1e3),A=new Array(156).join("\0"),m=(s,e,t,i)=>i===null?false:(s.write(i+A,e,t,"utf8"),i.length!==Buffer.byteLength(i)||i.length>t);return k=B,k} + +var e$3,t$3;function i$4(){return t$3||(t$3=1,e$3=function(o){o.prototype[Symbol.iterator]=function*(){for(let r=this.head;r;r=r.next)yield r.value;};}),e$3} + +var u$4,a$8;function c$3(){if(a$8)return u$4;a$8=1,u$4=r,r.Node=s,r.create=r;function r(t){var i=this;if(i instanceof r||(i=new r),i.tail=null,i.head=null,i.length=0,t&&typeof t.forEach=="function")t.forEach(function(n){i.push(n);});else if(arguments.length>0)for(var e=0,h=arguments.length;e1)e=i;else if(this.head)h=this.head.next,e=this.head.value;else throw new TypeError("Reduce of empty list with no initial value");for(var n=0;h!==null;n++)e=t(e,h.value,n),h=h.next;return e},r.prototype.reduceReverse=function(t,i){var e,h=this.tail;if(arguments.length>1)e=i;else if(this.tail)h=this.tail.prev,e=this.tail.value;else throw new TypeError("Reduce of empty list with no initial value");for(var n=this.length-1;h!==null;n--)e=t(e,h.value,n),h=h.prev;return e},r.prototype.toArray=function(){for(var t=new Array(this.length),i=0,e=this.head;e!==null;i++)t[i]=e.value,e=e.next;return t},r.prototype.toArrayReverse=function(){for(var t=new Array(this.length),i=0,e=this.tail;e!==null;i++)t[i]=e.value,e=e.prev;return t},r.prototype.slice=function(t,i){i=i||this.length,i<0&&(i+=this.length),t=t||0,t<0&&(t+=this.length);var e=new r;if(ithis.length&&(i=this.length);for(var h=0,n=this.head;n!==null&&hthis.length&&(i=this.length);for(var h=this.length,n=this.tail;n!==null&&h>i;h--)n=n.prev;for(;n!==null&&h>t;h--,n=n.prev)e.push(n.value);return e},r.prototype.splice=function(t,i,...e){t>this.length&&(t=this.length-1),t<0&&(t=this.length+t);for(var h=0,n=this.head;n!==null&&hPromise.resolve().then(h),J=commonjsGlobal._MP_NO_ITERATOR_SYMBOLS_!=="1",K=J&&Symbol.asyncIterator||Symbol("asyncIterator not implemented"),W=J&&Symbol.iterator||Symbol("iterator not implemented"),k=h=>h==="end"||h==="finish"||h==="prefinish",tt=h=>h instanceof ArrayBuffer||typeof h=="object"&&h.constructor&&h.constructor.name==="ArrayBuffer"&&h.byteLength>=0,et=h=>!Buffer.isBuffer(h)&&ArrayBuffer.isView(h);class z{constructor(t,e,s){this.src=t,this.dest=e,this.opts=s,this.ondrain=()=>t[b](),e.on("drain",this.ondrain);}unpipe(){this.dest.removeListener("drain",this.ondrain);}proxyErrors(){}end(){this.unpipe(),this.opts.end&&this.dest.end();}}class st extends z{unpipe(){this.src.removeListener("error",this.proxyErrors),super.unpipe();}constructor(t,e,s){super(t,e,s),this.proxyErrors=l=>e.emit("error",l),t.on("error",this.proxyErrors);}}class F extends q{constructor(t){super(),this[M]=false,this[S]=false,this[a]=[],this[i]=[],this[o]=t&&t.objectMode||false,this[o]?this[f]=null:this[f]=t&&t.encoding||null,this[f]==="buffer"&&(this[f]=null),this[p]=t&&!!t.async||false,this[c]=this[f]?new G(this[f]):null,this[m]=false,this[y]=false,this[R]=false,this[B]=false,this[g]=null,this.writable=true,this.readable=true,this[n]=0,this[r]=false,t&&t.debugExposeBuffer===true&&Object.defineProperty(this,"buffer",{get:()=>this[i]}),t&&t.debugExposePipes===true&&Object.defineProperty(this,"pipes",{get:()=>this[a]}),this[E]=t&&t.signal,this[O]=false,this[E]&&(this[E].addEventListener("abort",()=>this[_]()),this[E].aborted&&this[_]());}get bufferLength(){return this[n]}get encoding(){return this[f]}set encoding(t){if(this[o])throw new Error("cannot set encoding in objectMode");if(this[f]&&t!==this[f]&&(this[c]&&this[c].lastNeed||this[n]))throw new Error("cannot change encoding");this[f]!==t&&(this[c]=t?new G(t):null,this[i].length&&(this[i]=this[i].map(e=>this[c].write(e)))),this[f]=t;}setEncoding(t){this.encoding=t;}get objectMode(){return this[o]}set objectMode(t){this[o]=this[o]||!!t;}get async(){return this[p]}set async(t){this[p]=this[p]||!!t;}[_](){this[O]=true,this.emit("abort",this[E].reason),this.destroy(this[E].reason);}get aborted(){return this[O]}set aborted(t){}write(t,e,s){if(this[O])return false;if(this[m])throw new Error("write after end");if(this[r])return this.emit("error",Object.assign(new Error("Cannot call write after a stream was destroyed"),{code:"ERR_STREAM_DESTROYED"})),true;typeof e=="function"&&(s=e,e="utf8"),e||(e="utf8");const l=this[p]?w:u=>u();return !this[o]&&!Buffer.isBuffer(t)&&(et(t)?t=Buffer.from(t.buffer,t.byteOffset,t.byteLength):tt(t)?t=Buffer.from(t):typeof t!="string"&&(this.objectMode=true)),this[o]?(this.flowing&&this[n]!==0&&this[T](true),this.flowing?this.emit("data",t):this[j](t),this[n]!==0&&this.emit("readable"),s&&l(s),this.flowing):t.length?(typeof t=="string"&&!(e===this[f]&&!this[c].lastNeed)&&(t=Buffer.from(t,e)),Buffer.isBuffer(t)&&this[f]&&(t=this[c].write(t)),this.flowing&&this[n]!==0&&this[T](true),this.flowing?this.emit("data",t):this[j](t),this[n]!==0&&this.emit("readable"),s&&l(s),this.flowing):(this[n]!==0&&this.emit("readable"),s&&l(s),this.flowing)}read(t){if(this[r])return null;if(this[n]===0||t===0||t>this[n])return this[d](),null;this[o]&&(t=null),this[i].length>1&&!this[o]&&(this.encoding?this[i]=[this[i].join("")]:this[i]=[Buffer.concat(this[i],this[n])]);const e=this[Y](t||null,this[i][0]);return this[d](),e}[Y](t,e){return t===e.length||t===null?this[I]():(this[i][0]=e.slice(t),e=e.slice(0,t),this[n]-=t),this.emit("data",e),!this[i].length&&!this[m]&&this.emit("drain"),e}end(t,e,s){return typeof t=="function"&&(s=t,t=null),typeof e=="function"&&(s=e,e="utf8"),t&&this.write(t,e),s&&this.once("end",s),this[m]=true,this.writable=false,(this.flowing||!this[S])&&this[d](),this}[b](){this[r]||(this[S]=false,this[M]=true,this.emit("resume"),this[i].length?this[T]():this[m]?this[d]():this.emit("drain"));}resume(){return this[b]()}pause(){this[M]=false,this[S]=true;}get destroyed(){return this[r]}get flowing(){return this[M]}get paused(){return this[S]}[j](t){this[o]?this[n]+=1:this[n]+=t.length,this[i].push(t);}[I](){return this[o]?this[n]-=1:this[n]-=this[i][0].length,this[i].shift()}[T](t){do;while(this[$](this[I]())&&this[i].length);!t&&!this[i].length&&!this[m]&&this.emit("drain");}[$](t){return this.emit("data",t),this.flowing}pipe(t,e){if(this[r])return;const s=this[y];return e=e||{},t===H.stdout||t===H.stderr?e.end=false:e.end=e.end!==false,e.proxyErrors=!!e.proxyErrors,s?e.end&&t.end():(this[a].push(e.proxyErrors?new st(this,t,e):new z(this,t,e)),this[p]?w(()=>this[b]()):this[b]()),t}unpipe(t){const e=this[a].find(s=>s.dest===t);e&&(this[a].splice(this[a].indexOf(e),1),e.unpipe());}addListener(t,e){return this.on(t,e)}on(t,e){const s=super.on(t,e);return t==="data"&&!this[a].length&&!this.flowing?this[b]():t==="readable"&&this[n]!==0?super.emit("readable"):k(t)&&this[y]?(super.emit(t),this.removeAllListeners(t)):t==="error"&&this[g]&&(this[p]?w(()=>e.call(this,this[g])):e.call(this,this[g])),s}get emittedEnd(){return this[y]}[d](){!this[R]&&!this[y]&&!this[r]&&this[i].length===0&&this[m]&&(this[R]=true,this.emit("end"),this.emit("prefinish"),this.emit("finish"),this[B]&&this.emit("close"),this[R]=false);}emit(t,e,...s){if(t!=="error"&&t!=="close"&&t!==r&&this[r])return;if(t==="data")return !this[o]&&!e?false:this[p]?w(()=>this[x](e)):this[x](e);if(t==="end")return this[V]();if(t==="close"){if(this[B]=true,!this[y]&&!this[r])return;const u=super.emit("close");return this.removeAllListeners("close"),u}else if(t==="error"){this[g]=e,super.emit(P,e);const u=!this[E]||this.listeners("error").length?super.emit("error",e):false;return this[d](),u}else if(t==="resume"){const u=super.emit("resume");return this[d](),u}else if(t==="finish"||t==="prefinish"){const u=super.emit(t);return this.removeAllListeners(t),u}const l=super.emit(t,e,...s);return this[d](),l}[x](t){for(const s of this[a])s.dest.write(t)===false&&this.pause();const e=super.emit("data",t);return this[d](),e}[V](){this[y]||(this[y]=true,this.readable=false,this[p]?w(()=>this[N]()):this[N]());}[N](){if(this[c]){const e=this[c].end();if(e){for(const s of this[a])s.dest.write(e);super.emit("data",e);}}for(const e of this[a])e.end();const t=super.emit("end");return this.removeAllListeners("end"),t}collect(){const t=[];this[o]||(t.dataLength=0);const e=this.promise();return this.on("data",s=>{t.push(s),this[o]||(t.dataLength+=s.length);}),e.then(()=>t)}concat(){return this[o]?Promise.reject(new Error("cannot concat in objectMode")):this.collect().then(t=>this[o]?Promise.reject(new Error("cannot concat in objectMode")):this[f]?t.join(""):Buffer.concat(t,t.dataLength))}promise(){return new Promise((t,e)=>{this.on(r,()=>e(new Error("stream destroyed"))),this.on("error",s=>e(s)),this.on("end",()=>t());})}[K](){let t=false;const e=()=>(this.pause(),t=true,Promise.resolve({done:true}));return {next:()=>{if(t)return e();const l=this.read();if(l!==null)return Promise.resolve({done:false,value:l});if(this[m])return e();let u=null,Q=null;const A=L=>{this.removeListener("data",U),this.removeListener("end",C),this.removeListener(r,D),e(),Q(L);},U=L=>{this.removeListener("error",A),this.removeListener("end",C),this.removeListener(r,D),this.pause(),u({value:L,done:!!this[m]});},C=()=>{this.removeListener("error",A),this.removeListener("data",U),this.removeListener(r,D),e(),u({done:true});},D=()=>A(new Error("stream destroyed"));return new Promise((L,it)=>{Q=it,u=L,this.once(r,D),this.once("error",A),this.once("end",C),this.once("data",U);})},throw:e,return:e,[K](){return this}}}[W](){let t=false;const e=()=>(this.pause(),this.removeListener(P,e),this.removeListener(r,e),this.removeListener("end",e),t=true,{done:true}),s=()=>{if(t)return e();const l=this.read();return l===null?e():{value:l}};return this.once("end",e),this.once(P,e),this.once(r,e),{next:s,throw:e,return:e,[W](){return this}}}destroy(t){return this[r]?(t?this.emit("error",t):this.emit(r),this):(this[r]=true,this[i].length=0,this[n]=0,typeof this.close=="function"&&!this[B]&&this.close(),t?this.emit("error",t):this.emit(r),this)}static isStream(t){return !!t&&(t instanceof F||t instanceof q||t instanceof Z&&(typeof t.pipe=="function"||typeof t.write=="function"&&typeof t.end=="function"))}}return s$5.Minipass=F,s$5} + +var e$2,o$4;function a$7(){return o$4||(o$4=1,e$2=(process.env.TESTING_TAR_FAKE_PLATFORM||process.platform)!=="win32"?r=>r:r=>r&&r.replace(/\\/g,"/")),e$2} + +var n$2,a$6;function u$3(){if(a$6)return n$2;a$6=1;const{Minipass:o}=ft(),s=a$7(),r=Symbol("slurp");return n$2=class extends o{constructor(t,e,i){switch(super(),this.pause(),this.extended=e,this.globalExtended=i,this.header=t,this.startBlockSize=512*Math.ceil(t.size/512),this.blockRemain=this.startBlockSize,this.remain=t.size,this.type=t.type,this.meta=false,this.ignore=false,this.type){case "File":case "OldFile":case "Link":case "SymbolicLink":case "CharacterDevice":case "BlockDevice":case "Directory":case "FIFO":case "ContiguousFile":case "GNUDumpDir":break;case "NextFileHasLongLinkpath":case "NextFileHasLongPath":case "OldGnuLongPath":case "GlobalExtendedHeader":case "ExtendedHeader":case "OldExtendedHeader":this.meta=true;break;default:this.ignore=true;}this.path=s(t.path),this.mode=t.mode,this.mode&&(this.mode=this.mode&4095),this.uid=t.uid,this.gid=t.gid,this.uname=t.uname,this.gname=t.gname,this.size=t.size,this.mtime=t.mtime,this.atime=t.atime,this.ctime=t.ctime,this.linkpath=s(t.linkpath),this.uname=t.uname,this.gname=t.gname,e&&this[r](e),i&&this[r](i,true);}write(t){const e=t.length;if(e>this.blockRemain)throw new Error("writing more to entry than is appropriate");const i=this.remain,c=this.blockRemain;return this.remain=Math.max(0,i-e),this.blockRemain=Math.max(0,c-e),this.ignore?true:i>=e?super.write(t):super.write(t.slice(0,i))}[r](t,e){for(const i in t)t[i]!==null&&t[i]!==void 0&&!(e&&i==="path")&&(this[i]=i==="path"||i==="linkpath"?s(t[i]):t[i]);}},n$2} + +var r$2,a$5;function f$2(){if(a$5)return r$2;a$5=1;const c=E(),d=H$2;class h{constructor(e,n){this.atime=e.atime||null,this.charset=e.charset||null,this.comment=e.comment||null,this.ctime=e.ctime||null,this.gid=e.gid||null,this.gname=e.gname||null,this.linkpath=e.linkpath||null,this.mtime=e.mtime||null,this.path=e.path||null,this.size=e.size||null,this.uid=e.uid||null,this.uname=e.uname||null,this.dev=e.dev||null,this.ino=e.ino||null,this.nlink=e.nlink||null,this.global=n||false;}encode(){const e=this.encodeBody();if(e==="")return null;const n=Buffer.byteLength(e),l=512*Math.ceil(1+n/512),i=Buffer.allocUnsafe(l);for(let t=0;t<512;t++)i[t]=0;new c({path:("PaxHeader/"+d.basename(this.path)).slice(0,99),mode:this.mode||420,uid:this.uid||null,gid:this.gid||null,size:n,mtime:this.mtime||null,type:this.global?"GlobalExtendedHeader":"ExtendedHeader",linkpath:"",uname:this.uname||"",gname:this.gname||"",devmaj:0,devmin:0,atime:this.atime||null,ctime:this.ctime||null}).encode(i),i.write(e,512,n,"utf8");for(let t=n+512;t=Math.pow(10,t)&&(t+=1),t+i+l}}h.parse=(s,e,n)=>new h(o(u(s),e),n);const o=(s,e)=>e?Object.keys(s).reduce((n,l)=>(n[l]=s[l],n),e):s,u=s=>s.replace(/\n$/,"").split(` +`).reduce(m,Object.create(null)),m=(s,e)=>{const n=parseInt(e,10);if(n!==Buffer.byteLength(e)+1)return s;e=e.slice((n+" ").length);const l=e.split("="),i=l.shift().replace(/^SCHILY\.(dev|ino|nlink)/,"$1");if(!i)return s;const t=l.join("=");return s[i]=/^([A-Z]+\.)?([mac]|birth|creation)time$/.test(i)?new Date(t*1e3):/^[0-9]+$/.test(t)?+t:t,s};return r$2=h,r$2} + +var i$3={}; + +var _,R$1;function T(){if(R$1)return _;R$1=1;const E=O$2.constants||{ZLIB_VERNUM:4736};return _=Object.freeze(Object.assign(Object.create(null),{Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_MEM_ERROR:-4,Z_BUF_ERROR:-5,Z_VERSION_ERROR:-6,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,DEFLATE:1,INFLATE:2,GZIP:3,GUNZIP:4,DEFLATERAW:5,INFLATERAW:6,UNZIP:7,BROTLI_DECODE:8,BROTLI_ENCODE:9,Z_MIN_WINDOWBITS:8,Z_MAX_WINDOWBITS:15,Z_DEFAULT_WINDOWBITS:15,Z_MIN_CHUNK:64,Z_MAX_CHUNK:1/0,Z_DEFAULT_CHUNK:16384,Z_MIN_MEMLEVEL:1,Z_MAX_MEMLEVEL:9,Z_DEFAULT_MEMLEVEL:8,Z_MIN_LEVEL:-1,Z_MAX_LEVEL:9,Z_DEFAULT_LEVEL:-1,BROTLI_OPERATION_PROCESS:0,BROTLI_OPERATION_FLUSH:1,BROTLI_OPERATION_FINISH:2,BROTLI_OPERATION_EMIT_METADATA:3,BROTLI_MODE_GENERIC:0,BROTLI_MODE_TEXT:1,BROTLI_MODE_FONT:2,BROTLI_DEFAULT_MODE:0,BROTLI_MIN_QUALITY:0,BROTLI_MAX_QUALITY:11,BROTLI_DEFAULT_QUALITY:11,BROTLI_MIN_WINDOW_BITS:10,BROTLI_MAX_WINDOW_BITS:24,BROTLI_LARGE_MAX_WINDOW_BITS:30,BROTLI_DEFAULT_WINDOW:22,BROTLI_MIN_INPUT_BLOCK_BITS:16,BROTLI_MAX_INPUT_BLOCK_BITS:24,BROTLI_PARAM_MODE:0,BROTLI_PARAM_QUALITY:1,BROTLI_PARAM_LGWIN:2,BROTLI_PARAM_LGBLOCK:3,BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING:4,BROTLI_PARAM_SIZE_HINT:5,BROTLI_PARAM_LARGE_WINDOW:6,BROTLI_PARAM_NPOSTFIX:7,BROTLI_PARAM_NDIRECT:8,BROTLI_DECODER_RESULT_ERROR:0,BROTLI_DECODER_RESULT_SUCCESS:1,BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:2,BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION:0,BROTLI_DECODER_PARAM_LARGE_WINDOW:1,BROTLI_DECODER_NO_ERROR:0,BROTLI_DECODER_SUCCESS:1,BROTLI_DECODER_NEEDS_MORE_INPUT:2,BROTLI_DECODER_NEEDS_MORE_OUTPUT:3,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE:-1,BROTLI_DECODER_ERROR_FORMAT_RESERVED:-2,BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE:-3,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET:-4,BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME:-5,BROTLI_DECODER_ERROR_FORMAT_CL_SPACE:-6,BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE:-7,BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT:-8,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1:-9,BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2:-10,BROTLI_DECODER_ERROR_FORMAT_TRANSFORM:-11,BROTLI_DECODER_ERROR_FORMAT_DICTIONARY:-12,BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS:-13,BROTLI_DECODER_ERROR_FORMAT_PADDING_1:-14,BROTLI_DECODER_ERROR_FORMAT_PADDING_2:-15,BROTLI_DECODER_ERROR_FORMAT_DISTANCE:-16,BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET:-19,BROTLI_DECODER_ERROR_INVALID_ARGUMENTS:-20,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES:-21,BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS:-22,BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP:-25,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1:-26,BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2:-27,BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES:-30,BROTLI_DECODER_ERROR_UNREACHABLE:-31},E)),_} + +var j,H$1;function tt(){if(H$1)return j;H$1=1;const I=typeof process=="object"&&process?process:{stdout:null,stderr:null},Y=nt,x=ot,N=ht.StringDecoder,u=Symbol("EOF"),a=Symbol("maybeEmitEnd"),c=Symbol("emittedEnd"),S=Symbol("emittingEnd"),E=Symbol("emittedError"),w=Symbol("closed"),P=Symbol("read"),L=Symbol("flush"),_=Symbol("flushChunk"),h=Symbol("encoding"),m=Symbol("decoder"),M=Symbol("flowing"),y=Symbol("paused"),p=Symbol("resume"),s=Symbol("bufferLength"),T=Symbol("bufferPush"),B=Symbol("bufferShift"),r=Symbol("objectMode"),n=Symbol("destroyed"),D=Symbol("emitData"),F=Symbol("emitEnd"),R=Symbol("emitEnd2"),d=Symbol("async"),b=o=>Promise.resolve().then(o),C=commonjsGlobal._MP_NO_ITERATOR_SYMBOLS_!=="1",$=C&&Symbol.asyncIterator||Symbol("asyncIterator not implemented"),G=C&&Symbol.iterator||Symbol("iterator not implemented"),V=o=>o==="end"||o==="finish"||o==="prefinish",v=o=>o instanceof ArrayBuffer||typeof o=="object"&&o.constructor&&o.constructor.name==="ArrayBuffer"&&o.byteLength>=0,J=o=>!Buffer.isBuffer(o)&&ArrayBuffer.isView(o);class U{constructor(t,e,i){this.src=t,this.dest=e,this.opts=i,this.ondrain=()=>t[p](),e.on("drain",this.ondrain);}unpipe(){this.dest.removeListener("drain",this.ondrain);}proxyErrors(){}end(){this.unpipe(),this.opts.end&&this.dest.end();}}class K extends U{unpipe(){this.src.removeListener("error",this.proxyErrors),super.unpipe();}constructor(t,e,i){super(t,e,i),this.proxyErrors=l=>e.emit("error",l),t.on("error",this.proxyErrors);}}return j=class q extends x{constructor(t){super(),this[M]=false,this[y]=false,this.pipes=[],this.buffer=[],this[r]=t&&t.objectMode||false,this[r]?this[h]=null:this[h]=t&&t.encoding||null,this[h]==="buffer"&&(this[h]=null),this[d]=t&&!!t.async||false,this[m]=this[h]?new N(this[h]):null,this[u]=false,this[c]=false,this[S]=false,this[w]=false,this[E]=null,this.writable=true,this.readable=true,this[s]=0,this[n]=false;}get bufferLength(){return this[s]}get encoding(){return this[h]}set encoding(t){if(this[r])throw new Error("cannot set encoding in objectMode");if(this[h]&&t!==this[h]&&(this[m]&&this[m].lastNeed||this[s]))throw new Error("cannot change encoding");this[h]!==t&&(this[m]=t?new N(t):null,this.buffer.length&&(this.buffer=this.buffer.map(e=>this[m].write(e)))),this[h]=t;}setEncoding(t){this.encoding=t;}get objectMode(){return this[r]}set objectMode(t){this[r]=this[r]||!!t;}get async(){return this[d]}set async(t){this[d]=this[d]||!!t;}write(t,e,i){if(this[u])throw new Error("write after end");if(this[n])return this.emit("error",Object.assign(new Error("Cannot call write after a stream was destroyed"),{code:"ERR_STREAM_DESTROYED"})),true;typeof e=="function"&&(i=e,e="utf8"),e||(e="utf8");const l=this[d]?b:f=>f();return !this[r]&&!Buffer.isBuffer(t)&&(J(t)?t=Buffer.from(t.buffer,t.byteOffset,t.byteLength):v(t)?t=Buffer.from(t):typeof t!="string"&&(this.objectMode=true)),this[r]?(this.flowing&&this[s]!==0&&this[L](true),this.flowing?this.emit("data",t):this[T](t),this[s]!==0&&this.emit("readable"),i&&l(i),this.flowing):t.length?(typeof t=="string"&&!(e===this[h]&&!this[m].lastNeed)&&(t=Buffer.from(t,e)),Buffer.isBuffer(t)&&this[h]&&(t=this[m].write(t)),this.flowing&&this[s]!==0&&this[L](true),this.flowing?this.emit("data",t):this[T](t),this[s]!==0&&this.emit("readable"),i&&l(i),this.flowing):(this[s]!==0&&this.emit("readable"),i&&l(i),this.flowing)}read(t){if(this[n])return null;if(this[s]===0||t===0||t>this[s])return this[a](),null;this[r]&&(t=null),this.buffer.length>1&&!this[r]&&(this.encoding?this.buffer=[this.buffer.join("")]:this.buffer=[Buffer.concat(this.buffer,this[s])]);const e=this[P](t||null,this.buffer[0]);return this[a](),e}[P](t,e){return t===e.length||t===null?this[B]():(this.buffer[0]=e.slice(t),e=e.slice(0,t),this[s]-=t),this.emit("data",e),!this.buffer.length&&!this[u]&&this.emit("drain"),e}end(t,e,i){return typeof t=="function"&&(i=t,t=null),typeof e=="function"&&(i=e,e="utf8"),t&&this.write(t,e),i&&this.once("end",i),this[u]=true,this.writable=false,(this.flowing||!this[y])&&this[a](),this}[p](){this[n]||(this[y]=false,this[M]=true,this.emit("resume"),this.buffer.length?this[L]():this[u]?this[a]():this.emit("drain"));}resume(){return this[p]()}pause(){this[M]=false,this[y]=true;}get destroyed(){return this[n]}get flowing(){return this[M]}get paused(){return this[y]}[T](t){this[r]?this[s]+=1:this[s]+=t.length,this.buffer.push(t);}[B](){return this.buffer.length&&(this[r]?this[s]-=1:this[s]-=this.buffer[0].length),this.buffer.shift()}[L](t){do;while(this[_](this[B]()));!t&&!this.buffer.length&&!this[u]&&this.emit("drain");}[_](t){return t?(this.emit("data",t),this.flowing):false}pipe(t,e){if(this[n])return;const i=this[c];return e=e||{},t===I.stdout||t===I.stderr?e.end=false:e.end=e.end!==false,e.proxyErrors=!!e.proxyErrors,i?e.end&&t.end():(this.pipes.push(e.proxyErrors?new K(this,t,e):new U(this,t,e)),this[d]?b(()=>this[p]()):this[p]()),t}unpipe(t){const e=this.pipes.find(i=>i.dest===t);e&&(this.pipes.splice(this.pipes.indexOf(e),1),e.unpipe());}addListener(t,e){return this.on(t,e)}on(t,e){const i=super.on(t,e);return t==="data"&&!this.pipes.length&&!this.flowing?this[p]():t==="readable"&&this[s]!==0?super.emit("readable"):V(t)&&this[c]?(super.emit(t),this.removeAllListeners(t)):t==="error"&&this[E]&&(this[d]?b(()=>e.call(this,this[E])):e.call(this,this[E])),i}get emittedEnd(){return this[c]}[a](){!this[S]&&!this[c]&&!this[n]&&this.buffer.length===0&&this[u]&&(this[S]=true,this.emit("end"),this.emit("prefinish"),this.emit("finish"),this[w]&&this.emit("close"),this[S]=false);}emit(t,e,...i){if(t!=="error"&&t!=="close"&&t!==n&&this[n])return;if(t==="data")return e?this[d]?b(()=>this[D](e)):this[D](e):false;if(t==="end")return this[F]();if(t==="close"){if(this[w]=true,!this[c]&&!this[n])return;const f=super.emit("close");return this.removeAllListeners("close"),f}else if(t==="error"){this[E]=e;const f=super.emit("error",e);return this[a](),f}else if(t==="resume"){const f=super.emit("resume");return this[a](),f}else if(t==="finish"||t==="prefinish"){const f=super.emit(t);return this.removeAllListeners(t),f}const l=super.emit(t,e,...i);return this[a](),l}[D](t){for(const i of this.pipes)i.dest.write(t)===false&&this.pause();const e=super.emit("data",t);return this[a](),e}[F](){this[c]||(this[c]=true,this.readable=false,this[d]?b(()=>this[R]()):this[R]());}[R](){if(this[m]){const e=this[m].end();if(e){for(const i of this.pipes)i.dest.write(e);super.emit("data",e);}}for(const e of this.pipes)e.end();const t=super.emit("end");return this.removeAllListeners("end"),t}collect(){const t=[];this[r]||(t.dataLength=0);const e=this.promise();return this.on("data",i=>{t.push(i),this[r]||(t.dataLength+=i.length);}),e.then(()=>t)}concat(){return this[r]?Promise.reject(new Error("cannot concat in objectMode")):this.collect().then(t=>this[r]?Promise.reject(new Error("cannot concat in objectMode")):this[h]?t.join(""):Buffer.concat(t,t.dataLength))}promise(){return new Promise((t,e)=>{this.on(n,()=>e(new Error("stream destroyed"))),this.on("error",i=>e(i)),this.on("end",()=>t());})}[$](){return {next:()=>{const e=this.read();if(e!==null)return Promise.resolve({done:false,value:e});if(this[u])return Promise.resolve({done:true});let i=null,l=null;const f=g=>{this.removeListener("data",A),this.removeListener("end",O),l(g);},A=g=>{this.removeListener("error",f),this.removeListener("end",O),this.pause(),i({value:g,done:!!this[u]});},O=()=>{this.removeListener("error",f),this.removeListener("data",A),i({done:true});},W=()=>f(new Error("stream destroyed"));return new Promise((g,z)=>{l=z,i=g,this.once(n,W),this.once("error",f),this.once("end",O),this.once("data",A);})}}}[G](){return {next:()=>{const e=this.read();return {value:e,done:e===null}}}}destroy(t){return this[n]?(t?this.emit("error",t):this.emit(n),this):(this[n]=true,this.buffer.length=0,this[s]=0,typeof this.close=="function"&&!this[w]&&this.close(),t?this.emit("error",t):this.emit(n),this)}static isStream(t){return !!t&&(t instanceof q||t instanceof x||t instanceof Y&&(typeof t.pipe=="function"||typeof t.write=="function"&&typeof t.end=="function"))}},j} + +var C;function J(){if(C)return i$3;C=1;const w=j$1,n=P.Buffer,z=O$2,u=i$3.constants=T(),L=tt(),E=n.concat,c=Symbol("_superWrite");class d extends Error{constructor(s){super("zlib: "+s.message),this.code=s.code,this.errno=s.errno,this.code||(this.code="ZLIB_ERROR"),this.message="zlib: "+s.message,Error.captureStackTrace(this,this.constructor);}get name(){return "ZlibError"}}const Z=Symbol("opts"),p=Symbol("flushFlag"),I=Symbol("finishFlushFlag"),y=Symbol("fullFlushFlag"),t=Symbol("handle"),_=Symbol("onError"),f=Symbol("sawError"),F=Symbol("level"),S=Symbol("strategy"),g=Symbol("ended");class x extends L{constructor(s,e){if(!s||typeof s!="object")throw new TypeError("invalid options for ZlibBase constructor");super(s),this[f]=false,this[g]=false,this[Z]=s,this[p]=s.flush,this[I]=s.finishFlush;try{this[t]=new z[e](s);}catch(i){throw new d(i)}this[_]=i=>{this[f]||(this[f]=true,this.close(),this.emit("error",i));},this[t].on("error",i=>this[_](new d(i))),this.once("end",()=>this.close);}close(){this[t]&&(this[t].close(),this[t]=null,this.emit("close"));}reset(){if(!this[f])return w(this[t],"zlib binding closed"),this[t].reset()}flush(s){this.ended||(typeof s!="number"&&(s=this[y]),this.write(Object.assign(n.alloc(0),{[p]:s})));}end(s,e,i){return s&&this.write(s,e),this.flush(this[I]),this[g]=true,super.end(null,null,i)}get ended(){return this[g]}write(s,e,i){if(typeof e=="function"&&(i=e,e="utf8"),typeof s=="string"&&(s=n.from(s,e)),this[f])return;w(this[t],"zlib binding closed");const m=this[t]._handle,R=m.close;m.close=()=>{};const G=this[t].close;this[t].close=()=>{},n.concat=l=>l;let h;try{const l=typeof s[p]=="number"?s[p]:this[p];h=this[t]._processChunk(s,l),n.concat=E;}catch(l){n.concat=E,this[_](new d(l));}finally{this[t]&&(this[t]._handle=m,m.close=R,this[t].close=G,this[t].removeAllListeners("error"));}this[t]&&this[t].on("error",l=>this[_](new d(l)));let b;if(h)if(Array.isArray(h)&&h.length>0){b=this[c](n.from(h[0]));for(let l=1;l{this.flush(m),R();};try{this[t].params(s,e);}finally{this[t].flush=i;}this[t]&&(this[F]=s,this[S]=e);}}}}class q extends a{constructor(s){super(s,"Deflate");}}class D extends a{constructor(s){super(s,"Inflate");}}const B=Symbol("_portable");class $ extends a{constructor(s){super(s,"Gzip"),this[B]=s&&!!s.portable;}[c](s){return this[B]?(this[B]=false,s[9]=255,super[c](s)):super[c](s)}}class N extends a{constructor(s){super(s,"Gunzip");}}class H extends a{constructor(s){super(s,"DeflateRaw");}}let T$1 = class T extends a{constructor(s){super(s,"InflateRaw");}};class U extends a{constructor(s){super(s,"Unzip");}}class O extends x{constructor(s,e){s=s||{},s.flush=s.flush||u.BROTLI_OPERATION_PROCESS,s.finishFlush=s.finishFlush||u.BROTLI_OPERATION_FINISH,super(s,e),this[y]=u.BROTLI_OPERATION_FLUSH;}}class v extends O{constructor(s){super(s,"BrotliCompress");}}class A extends O{constructor(s){super(s,"BrotliDecompress");}}return i$3.Deflate=q,i$3.Inflate=D,i$3.Gzip=$,i$3.Gunzip=N,i$3.DeflateRaw=H,i$3.InflateRaw=T$1,i$3.Unzip=U,typeof z.BrotliCompress=="function"?(i$3.BrotliCompress=v,i$3.BrotliDecompress=A):i$3.BrotliCompress=i$3.BrotliDecompress=class{constructor(){throw new Error("Brotli is not supported in this version of Node.js")}},i$3} + +var O$1,F$2;function rt(){if(F$2)return O$1;F$2=1;const P=c$4(),$=E(),v=nt,W=c$3(),G=1024*1024,k=u$3(),C=f$2(),x=J(),{nextTick:j}=nt$1,B=Buffer.from([31,139]),h=Symbol("state"),d=Symbol("writeEntry"),a=Symbol("readEntry"),I=Symbol("nextEntry"),U=Symbol("processEntry"),l=Symbol("extendedHeader"),y=Symbol("globalExtendedHeader"),c=Symbol("meta"),H=Symbol("emitMeta"),n=Symbol("buffer"),f=Symbol("queue"),u=Symbol("ended"),L=Symbol("emittedEnd"),b=Symbol("emit"),r=Symbol("unzip"),_=Symbol("consumeChunk"),g=Symbol("consumeChunkSub"),q=Symbol("consumeBody"),z=Symbol("consumeMeta"),Y=Symbol("consumeHeader"),N=Symbol("consuming"),D=Symbol("bufferConcat"),M=Symbol("maybeEnd"),S=Symbol("writing"),m=Symbol("aborted"),T=Symbol("onDone"),E$1=Symbol("sawValidEntry"),R=Symbol("sawNullBlock"),A=Symbol("sawEOF"),V=Symbol("closeStream"),K=X=>true;return O$1=P(class extends v{constructor(t){t=t||{},super(t),this.file=t.file||"",this[E$1]=null,this.on(T,s=>{(this[h]==="begin"||this[E$1]===false)&&this.warn("TAR_BAD_ARCHIVE","Unrecognized archive format");}),t.ondone?this.on(T,t.ondone):this.on(T,s=>{this.emit("prefinish"),this.emit("finish"),this.emit("end");}),this.strict=!!t.strict,this.maxMetaEntrySize=t.maxMetaEntrySize||G,this.filter=typeof t.filter=="function"?t.filter:K;const i=t.file&&(t.file.endsWith(".tar.br")||t.file.endsWith(".tbr"));this.brotli=!t.gzip&&t.brotli!==void 0?t.brotli:i?void 0:false,this.writable=true,this.readable=false,this[f]=new W,this[n]=null,this[a]=null,this[d]=null,this[h]="begin",this[c]="",this[l]=null,this[y]=null,this[u]=false,this[r]=null,this[m]=false,this[R]=false,this[A]=false,this.on("end",()=>this[V]()),typeof t.onwarn=="function"&&this.on("warn",t.onwarn),typeof t.onentry=="function"&&this.on("entry",t.onentry);}[Y](t,i){this[E$1]===null&&(this[E$1]=false);let s;try{s=new $(t,i,this[l],this[y]);}catch(o){return this.warn("TAR_ENTRY_INVALID",o)}if(s.nullBlock)this[R]?(this[A]=true,this[h]==="begin"&&(this[h]="header"),this[b]("eof")):(this[R]=true,this[b]("nullBlock"));else if(this[R]=false,!s.cksumValid)this.warn("TAR_ENTRY_INVALID","checksum failure",{header:s});else if(!s.path)this.warn("TAR_ENTRY_INVALID","path is required",{header:s});else {const o=s.type;if(/^(Symbolic)?Link$/.test(o)&&!s.linkpath)this.warn("TAR_ENTRY_INVALID","linkpath required",{header:s});else if(!/^(Symbolic)?Link$/.test(o)&&s.linkpath)this.warn("TAR_ENTRY_INVALID","linkpath forbidden",{header:s});else {const e=this[d]=new k(s,this[l],this[y]);if(!this[E$1])if(e.remain){const w=()=>{e.invalid||(this[E$1]=true);};e.on("end",w);}else this[E$1]=true;e.meta?e.size>this.maxMetaEntrySize?(e.ignore=true,this[b]("ignoredEntry",e),this[h]="ignore",e.resume()):e.size>0&&(this[c]="",e.on("data",w=>this[c]+=w),this[h]="meta"):(this[l]=null,e.ignore=e.ignore||!this.filter(e.path,e),e.ignore?(this[b]("ignoredEntry",e),this[h]=e.remain?"ignore":"header",e.resume()):(e.remain?this[h]="body":(this[h]="header",e.end()),this[a]?this[f].push(e):(this[f].push(e),this[I]())));}}}[V](){j(()=>this.emit("close"));}[U](t){let i=true;return t?Array.isArray(t)?this.emit.apply(this,t):(this[a]=t,this.emit("entry",t),t.emittedEnd||(t.on("end",s=>this[I]()),i=false)):(this[a]=null,i=false),i}[I](){do;while(this[U](this[f].shift()));if(!this[f].length){const t=this[a];!t||t.flowing||t.size===t.remain?this[S]||this.emit("drain"):t.once("drain",s=>this.emit("drain"));}}[q](t,i){const s=this[d],o=s.blockRemain,e=o>=t.length&&i===0?t:t.slice(i,i+o);return s.write(e),s.blockRemain||(this[h]="header",this[d]=null,s.end()),e.length}[z](t,i){const s=this[d],o=this[q](t,i);return this[d]||this[H](s),o}[b](t,i,s){!this[f].length&&!this[a]?this.emit(t,i,s):this[f].push([t,i,s]);}[H](t){switch(this[b]("meta",this[c]),t.type){case "ExtendedHeader":case "OldExtendedHeader":this[l]=C.parse(this[c],this[l],false);break;case "GlobalExtendedHeader":this[y]=C.parse(this[c],this[y],true);break;case "NextFileHasLongPath":case "OldGnuLongPath":this[l]=this[l]||Object.create(null),this[l].path=this[c].replace(/\0.*/,"");break;case "NextFileHasLongLinkpath":this[l]=this[l]||Object.create(null),this[l].linkpath=this[c].replace(/\0.*/,"");break;default:throw new Error("unknown meta: "+t.type)}}abort(t){this[m]=true,this.emit("abort",t),this.warn("TAR_ABORT",t,{recoverable:false});}write(t){if(this[m])return;if((this[r]===null||this.brotli===void 0&&this[r]===false)&&t){if(this[n]&&(t=Buffer.concat([this[n],t]),this[n]=null),t.lengththis[_](p)),this[r].on("error",p=>this.abort(p)),this[r].on("end",p=>{this[u]=true,this[_]();}),this[S]=true;const w=this[r][e?"end":"write"](t);return this[S]=false,w}}this[S]=true,this[r]?this[r].write(t):this[_](t),this[S]=false;const s=this[f].length?false:this[a]?this[a].flowing:true;return !s&&!this[f].length&&this[a].once("drain",o=>this.emit("drain")),s}[D](t){t&&!this[m]&&(this[n]=this[n]?Buffer.concat([this[n],t]):t);}[M](){if(this[u]&&!this[L]&&!this[m]&&!this[N]){this[L]=true;const t=this[d];if(t&&t.blockRemain){const i=this[n]?this[n].length:0;this.warn("TAR_BAD_ARCHIVE",`Truncated input (needed ${t.blockRemain} more bytes, only ${i} available)`,{entry:t}),this[n]&&t.write(this[n]),t.end();}this[b](T);}}[_](t){if(this[N])this[D](t);else if(!t&&!this[n])this[M]();else {if(this[N]=true,this[n]){this[D](t);const i=this[n];this[n]=null,this[g](i);}else this[g](t);for(;this[n]&&this[n].length>=512&&!this[m]&&!this[A];){const i=this[n];this[n]=null,this[g](i);}this[N]=false;}(!this[n]||this[u])&&this[M]();}[g](t){let i=0;const s=t.length;for(;i+512<=s&&!this[m]&&!this[A];)switch(this[h]){case "begin":case "header":this[Y](t,i),i+=512;break;case "ignore":case "body":i+=this[q](t,i);break;case "meta":i+=this[z](t,i);break;default:throw new Error("invalid state: "+this[h])}i{const G=(J,K)=>A(J,K,i),j=new t;j.oncomplete=G,c.writeBuffers(e,i,$,j);};}const m=Symbol("_autoClose"),h=Symbol("_close"),g=Symbol("_ended"),s=Symbol("_fd"),B=Symbol("_finished"),o=Symbol("_flags"),x=Symbol("_flush"),z=Symbol("_handleChunk"),T=Symbol("_makeBuf"),q=Symbol("_mode"),E=Symbol("_needDrain"),d=Symbol("_onerror"),y=Symbol("_onopen"),W=Symbol("_onread"),_=Symbol("_onwrite"),a=Symbol("_open"),l=Symbol("_path"),u=Symbol("_pos"),n=Symbol("_queue"),S=Symbol("_read"),M=Symbol("_readSize"),f=Symbol("_reading"),k=Symbol("_remain"),N=Symbol("_size"),C=Symbol("_write"),b=Symbol("_writing"),F=Symbol("_defaultFlag"),p=Symbol("_errored");class D extends H{constructor(t,e){if(e=e||{},super(e),this.readable=true,this.writable=false,typeof t!="string")throw new TypeError("path must be a string");this[p]=false,this[s]=typeof e.fd=="number"?e.fd:null,this[l]=t,this[M]=e.readSize||16*1024*1024,this[f]=false,this[N]=typeof e.size=="number"?e.size:1/0,this[k]=this[N],this[m]=typeof e.autoClose=="boolean"?e.autoClose:true,typeof this[s]=="number"?this[S]():this[a]();}get fd(){return this[s]}get path(){return this[l]}write(){throw new TypeError("this is a readable stream")}end(){throw new TypeError("this is a readable stream")}[a](){r.open(this[l],"r",(t,e)=>this[y](t,e));}[y](t,e){t?this[d](t):(this[s]=e,this.emit("open",e),this[S]());}[T](){return Buffer.allocUnsafe(Math.min(this[M],this[k]))}[S](){if(!this[f]){this[f]=true;const t=this[T]();if(t.length===0)return process.nextTick(()=>this[W](null,0,t));r.read(this[s],t,0,t.length,null,(e,i,$)=>this[W](e,i,$));}}[W](t,e,i){this[f]=false,t?this[d](t):this[z](e,i)&&this[S]();}[h](){if(this[m]&&typeof this[s]=="number"){const t=this[s];this[s]=null,r.close(t,e=>e?this.emit("error",e):this.emit("close"));}}[d](t){this[f]=true,this[h](),this.emit("error",t);}[z](t,e){let i=false;return this[k]-=t,t>0&&(i=super.write(tthis[y](t,e));}[y](t,e){this[F]&&this[o]==="r+"&&t&&t.code==="ENOENT"?(this[o]="w",this[a]()):t?this[d](t):(this[s]=e,this.emit("open",e),this[x]());}end(t,e){return t&&this.write(t,e),this[g]=true,!this[b]&&!this[n].length&&typeof this[s]=="number"&&this[_](null,0),this}write(t,e){return typeof t=="string"&&(t=Buffer.from(t,e)),this[g]?(this.emit("error",new Error("write() after end()")),false):this[s]===null||this[b]||this[n].length?(this[n].push(t),this[E]=true,false):(this[b]=true,this[C](t),true)}[C](t){r.write(this[s],t,0,t.length,this[u],(e,i)=>this[_](e,i));}[_](t,e){t?this[d](t):(this[u]!==null&&(this[u]+=e),this[n].length?this[x]():(this[b]=false,this[g]&&!this[B]?(this[B]=true,this[h](),this.emit("finish")):this[E]&&(this[E]=false,this.emit("drain"))));}[x](){if(this[n].length===0)this[g]&&this[_](null,0);else if(this[n].length===1)this[C](this[n].pop());else {const t=this[n];this[n]=[],R(this[s],t,this[u],(e,i)=>this[_](e,i));}}[h](){if(this[m]&&typeof this[s]=="number"){const t=this[s];this[s]=null,r.close(t,e=>e?this.emit("error",e):this.emit("close"));}}}class U extends O{[a](){let t;if(this[F]&&this[o]==="r+")try{t=r.openSync(this[l],this[o],this[q]);}catch(e){if(e.code==="ENOENT")return this[o]="w",this[a]();throw e}else t=r.openSync(this[l],this[o],this[q]);this[y](null,t);}[h](){if(this[m]&&typeof this[s]=="number"){const t=this[s];this[s]=null,r.closeSync(t),this.emit("close");}}[C](t){let e=true;try{this[_](null,r.writeSync(this[s],t,0,t.length,this[u])),e=!1;}finally{if(e)try{this[h]();}catch{}}}}return s$4.ReadStream=D,s$4.ReadStreamSync=P,s$4.WriteStream=O,s$4.WriteStreamSync=U,s$4} + +var r$1={exports:{}}; + +var i$2,m$2;function t$2(){if(m$2)return i$2;m$2=1;const{promisify:n}=a$a,e=V;return i$2=r=>{if(!r)r={mode:511,fs:e};else if(typeof r=="object")r={mode:511,fs:e,...r};else if(typeof r=="number")r={mode:r,fs:e};else if(typeof r=="string")r={mode:parseInt(r,8),fs:e};else throw new TypeError("invalid options argument");return r.mkdir=r.mkdir||r.fs.mkdir||e.mkdir,r.mkdirAsync=n(r.mkdir),r.stat=r.stat||r.fs.stat||e.stat,r.statAsync=n(r.stat),r.statSync=r.statSync||r.fs.statSync||e.statSync,r.mkdirSync=r.mkdirSync||r.fs.mkdirSync||e.mkdirSync,r},i$2} + +var e$1,t$1;function u$2(){if(t$1)return e$1;t$1=1;const s=process.env.__TESTING_MKDIRP_PLATFORM__||process.platform,{resolve:o,parse:n}=H$2;return e$1=r=>{if(/\0/.test(r))throw Object.assign(new TypeError("path must be a string without null bytes"),{path:r,code:"ERR_INVALID_ARG_VALUE"});if(r=o(r),s==="win32"){const i=/[*|"<>?:]/,{root:a}=n(r);if(i.test(r.substr(a.length)))throw Object.assign(new Error("Illegal characters in path."),{path:r,code:"EINVAL"})}return r},e$1} + +var i$1,c$2;function t(){if(c$2)return i$1;c$2=1;const{dirname:u}=H$2,f=(r,e,n=void 0)=>n===e?Promise.resolve():r.statAsync(e).then(d=>d.isDirectory()?n:void 0,d=>d.code==="ENOENT"?f(r,u(e),e):void 0),o=(r,e,n=void 0)=>{if(n!==e)try{return r.statSync(e).isDirectory()?n:void 0}catch(d){return d.code==="ENOENT"?o(r,u(e),e):void 0}};return i$1={findMade:f,findMadeSync:o},i$1} + +var o$3,a$4;function y$2(){if(a$4)return o$3;a$4=1;const{dirname:f}=H$2,t=(n,e,c)=>{e.recursive=false;const i=f(n);return i===n?e.mkdirAsync(n,e).catch(r=>{if(r.code!=="EISDIR")throw r}):e.mkdirAsync(n,e).then(()=>c||n,r=>{if(r.code==="ENOENT")return t(i,e).then(u=>t(n,e,u));if(r.code!=="EEXIST"&&r.code!=="EROFS")throw r;return e.statAsync(n).then(u=>{if(u.isDirectory())return c;throw r},()=>{throw r})})},d=(n,e,c)=>{const i=f(n);if(e.recursive=false,i===n)try{return e.mkdirSync(n,e)}catch(r){if(r.code!=="EISDIR")throw r;return}try{return e.mkdirSync(n,e),c||n}catch(r){if(r.code==="ENOENT")return d(n,e,d(i,e,c));if(r.code!=="EEXIST"&&r.code!=="EROFS")throw r;try{if(!e.statSync(n).isDirectory())throw r}catch{throw r}}};return o$3={mkdirpManual:t,mkdirpManualSync:d},o$3} + +var c$1,m$1;function s$3(){if(m$1)return c$1;m$1=1;const{dirname:u}=H$2,{findMade:d,findMadeSync:t$1}=t(),{mkdirpManual:a,mkdirpManualSync:k}=y$2();return c$1={mkdirpNative:(e,r)=>(r.recursive=true,u(e)===e?r.mkdirAsync(e,r):d(r,e).then(n=>r.mkdirAsync(e,r).then(()=>n).catch(i=>{if(i.code==="ENOENT")return a(e,r);throw i}))),mkdirpNativeSync:(e,r)=>{if(r.recursive=true,u(e)===e)return r.mkdirSync(e,r);const n=t$1(r,e);try{return r.mkdirSync(e,r),n}catch(i){if(i.code==="ENOENT")return k(e,r);throw i}}},c$1} + +var s$2,n$1;function a$3(){if(n$1)return s$2;n$1=1;const i=V,e=(process.env.__TESTING_MKDIRP_NODE_VERSION__||process.version).replace(/^v/,"").split("."),t=+e[0]>10||+e[0]==10&&+e[1]>=12;return s$2={useNative:t?r=>r.mkdir===i.mkdir:()=>false,useNativeSync:t?r=>r.mkdirSync===i.mkdirSync:()=>false},s$2} + +var m,s$1;function S(){if(s$1)return m;s$1=1;const i=t$2(),u=u$2(),{mkdirpNative:a,mkdirpNativeSync:c}=s$3(),{mkdirpManual:o,mkdirpManualSync:q}=y$2(),{useNative:t,useNativeSync:_}=a$3(),n=(e,r)=>(e=u(e),r=i(r),t(r)?a(e,r):o(e,r)),d=(e,r)=>(e=u(e),r=i(r),_(r)?c(e,r):q(e,r));return n.sync=d,n.native=(e,r)=>a(u(e),i(r)),n.manual=(e,r)=>o(u(e),i(r)),n.nativeSync=(e,r)=>c(u(e),i(r)),n.manualSync=(e,r)=>q(u(e),i(r)),m=n,m} + +var y$1,O;function F$1(){if(O)return y$1;O=1;const c=V,a=H$2,T=c.lchown?"lchown":"chown",I=c.lchownSync?"lchownSync":"chownSync",i=c.lchown&&!process.version.match(/v1[1-9]+\./)&&!process.version.match(/v10\.[6-9]/),u=(r,e,n)=>{try{return c[I](r,e,n)}catch(t){if(t.code!=="ENOENT")throw t}},D=(r,e,n)=>{try{return c.chownSync(r,e,n)}catch(t){if(t.code!=="ENOENT")throw t}},_=i?(r,e,n,t)=>o=>{!o||o.code!=="EISDIR"?t(o):c.chown(r,e,n,t);}:(r,e,n,t)=>t,w=i?(r,e,n)=>{try{return u(r,e,n)}catch(t){if(t.code!=="EISDIR")throw t;D(r,e,n);}}:(r,e,n)=>u(r,e,n),R=process.version;let N=(r,e,n)=>c.readdir(r,e,n),q=(r,e)=>c.readdirSync(r,e);/^v4\./.test(R)&&(N=(r,e,n)=>c.readdir(r,n));const h=(r,e,n,t)=>{c[T](r,e,n,_(r,e,n,o=>{t(o&&o.code!=="ENOENT"?o:null);}));},S=(r,e,n,t,o)=>{if(typeof e=="string")return c.lstat(a.resolve(r,e),(s,f)=>{if(s)return o(s.code!=="ENOENT"?s:null);f.name=e,S(r,f,n,t,o);});if(e.isDirectory())E(a.resolve(r,e.name),n,t,s=>{if(s)return o(s);const f=a.resolve(r,e.name);h(f,n,t,o);});else {const s=a.resolve(r,e.name);h(s,n,t,o);}},E=(r,e,n,t)=>{N(r,{withFileTypes:true},(o,s)=>{if(o){if(o.code==="ENOENT")return t();if(o.code!=="ENOTDIR"&&o.code!=="ENOTSUP")return t(o)}if(o||!s.length)return h(r,e,n,t);let f=s.length,v=null;const H=l=>{if(!v){if(l)return t(v=l);if(--f===0)return h(r,e,n,t)}};s.forEach(l=>S(r,l,e,n,H));});},C=(r,e,n,t)=>{if(typeof e=="string")try{const o=c.lstatSync(a.resolve(r,e));o.name=e,e=o;}catch(o){if(o.code==="ENOENT")return;throw o}e.isDirectory()&&m(a.resolve(r,e.name),n,t),w(a.resolve(r,e.name),n,t);},m=(r,e,n)=>{let t;try{t=q(r,{withFileTypes:!0});}catch(o){if(o.code==="ENOENT")return;if(o.code==="ENOTDIR"||o.code==="ENOTSUP")return w(r,e,n);throw o}return t&&t.length&&t.forEach(o=>C(r,o,e,n)),w(r,e,n)};return y$1=E,E.sync=m,y$1} + +var R;function H(){if(R)return r$1.exports;R=1;const g=S(),l=V,p=H$2,x=F$1(),y=a$7();class D extends Error{constructor(e,s){super("Cannot extract through symbolic link"),this.path=s,this.symlink=e;}get name(){return "SylinkError"}}class E extends Error{constructor(e,s){super(s+": Cannot cd into '"+e+"'"),this.path=e,this.code=s;}get name(){return "CwdError"}}const v=(n,e)=>n.get(y(e)),q=(n,e,s)=>n.set(y(e),s),I=(n,e)=>{l.stat(n,(s,r)=>{(s||!r.isDirectory())&&(s=new E(n,s&&s.code||"ENOTDIR")),e(s);});};r$1.exports=(n,e,s)=>{n=y(n);const r=e.umask,c=e.mode|448,f=(c&r)!==0,t=e.uid,i=e.gid,a=typeof t=="number"&&typeof i=="number"&&(t!==e.processUid||i!==e.processGid),u=e.preserve,m=e.unlink,h=e.cache,d=y(e.cwd),w=(k,o)=>{k?s(k):(q(h,n,true),o&&a?x(o,t,i,G=>w(G)):f?l.chmod(n,c,s):s());};if(h&&v(h,n)===true)return w();if(n===d)return I(n,w);if(u)return g(n,{mode:c}).then(k=>w(null,k),w);const S=y(p.relative(d,n)).split("/");C(d,S,c,h,m,d,null,w);};const C=(n,e,s,r,c,f,t,i)=>{if(!e.length)return i(null,t);const a=e.shift(),u=y(p.resolve(n+"/"+a));if(v(r,u))return C(u,e,s,r,c,f,t,i);l.mkdir(u,s,j(u,e,s,r,c,f,t,i));},j=(n,e,s,r,c,f,t,i)=>a=>{a?l.lstat(n,(u,m)=>{if(u)u.path=u.path&&y(u.path),i(u);else if(m.isDirectory())C(n,e,s,r,c,f,t,i);else if(c)l.unlink(n,h=>{if(h)return i(h);l.mkdir(n,s,j(n,e,s,r,c,f,t,i));});else {if(m.isSymbolicLink())return i(new D(n,n+"/"+e.join("/")));i(a);}}):(t=t||n,C(n,e,s,r,c,f,t,i));},L=n=>{let e=false,s="ENOTDIR";try{e=l.statSync(n).isDirectory();}catch(r){s=r.code;}finally{if(!e)throw new E(n,s)}};return r$1.exports.sync=(n,e)=>{n=y(n);const s=e.umask,r=e.mode|448,c=(r&s)!==0,f=e.uid,t=e.gid,i=typeof f=="number"&&typeof t=="number"&&(f!==e.processUid||t!==e.processGid),a=e.preserve,u=e.unlink,m=e.cache,h=y(e.cwd),d=k=>{q(m,n,true),k&&i&&x.sync(k,f,t),c&&l.chmodSync(n,r);};if(m&&v(m,n)===true)return d();if(n===h)return L(h),d();if(a)return d(g.sync(n,r));const $=y(p.relative(h,n)).split("/");let S=null;for(let k=$.shift(),o=h;k&&(o+="/"+k);k=$.shift())if(o=y(p.resolve(o)),!v(m,o))try{l.mkdirSync(o,r),S=S||o,q(m,o,!0);}catch{const M=l.lstatSync(o);if(M.isDirectory()){q(m,o,true);continue}else if(u){l.unlinkSync(o),l.mkdirSync(o,r),S=S||o,q(m,o,true);continue}else if(M.isSymbolicLink())return new D(o,o+"/"+$.join("/"))}return d(S)},r$1.exports} + +var a$2,i;function p(){if(i)return a$2;i=1;const o=["|","<",">","?",":"],t=o.map(e=>String.fromCharCode(61440+e.charCodeAt(0))),s=new Map(o.map((e,r)=>[e,t[r]])),c=new Map(t.map((e,r)=>[e,o[r]]));return a$2={encode:e=>o.reduce((r,n)=>r.split(n).join(s.get(n)),e),decode:e=>t.reduce((r,n)=>r.split(n).join(c.get(n)),e)},a$2} + +var o$2,n;function a$1(){if(n)return o$2;n=1;const r=Object.create(null),{hasOwnProperty:i}=Object.prototype;return o$2=e=>(i.call(r,e)||(r[e]=e.normalize("NFD")),r[e]),o$2} + +var a,l;function s(){return l||(l=1,a=r=>{let e=r.length-1,i=-1;for(;e>-1&&r.charAt(e)==="/";)i=e,e--;return i===-1?r:r.slice(0,i)}),a} + +var u$1,f$1;function z(){if(f$1)return u$1;f$1=1;const l=j$1,m=a$1(),g=s(),{join:d}=H$2,q=(process.env.TESTING_TAR_FAKE_PLATFORM||process.platform)==="win32";return u$1=()=>{const i=new Map,c=new Map,v=e=>e.split("/").slice(0,-1).reduce((o,r)=>(o.length&&(r=d(o[o.length-1],r)),o.push(r||"/"),o),[]),a=new Set,w=e=>{const s=c.get(e);if(!s)throw new Error("function does not have any path reservations");return {paths:s.paths.map(o=>i.get(o)),dirs:[...s.dirs].map(o=>i.get(o))}},h=e=>{const{paths:s,dirs:o}=w(e);return s.every(r=>r[0]===e)&&o.every(r=>r[0]instanceof Set&&r[0].has(e))},p=e=>a.has(e)||!h(e)?false:(a.add(e),e(()=>S(e)),true),S=e=>{if(!a.has(e))return false;const{paths:s,dirs:o}=c.get(e),r=new Set;return s.forEach(t=>{const n=i.get(t);l.equal(n[0],e),n.length===1?i.delete(t):(n.shift(),typeof n[0]=="function"?r.add(n[0]):n[0].forEach(E=>r.add(E)));}),o.forEach(t=>{const n=i.get(t);l(n[0]instanceof Set),n[0].size===1&&n.length===1?i.delete(t):n[0].size===1?(n.shift(),r.add(n[0])):n[0].delete(e);}),a.delete(e),r.forEach(t=>p(t)),true};return {check:h,reserve:(e,s)=>{e=q?["win32 parallelization disabled"]:e.map(r=>g(d(m(r))).toLowerCase());const o=new Set(e.map(r=>v(r)).reduce((r,t)=>r.concat(t)));return c.set(s,{dirs:o,paths:e}),e.forEach(r=>{const t=i.get(r);t?t.push(s):i.set(r,[s]);}),o.forEach(r=>{const t=i.get(r);t?t[t.length-1]instanceof Set?t[t.length-1].add(s):t.push(new Set([s])):i.set(r,[new Set([s])]);}),p(s)}}},u$1} + +var o$1,u;function c(){if(u)return o$1;u=1;const{isAbsolute:l,parse:t}=H$2.win32;return o$1=r=>{let s="",e=t(r);for(;l(r)||e.root;){const i=r.charAt(0)==="/"&&r.slice(0,4)!=="//?/"?"/":e.root;r=r.slice(i.length),s+=i,e=t(r);}return [s,r]},o$1} + +var e,o;function F(){if(o)return e;o=1;const t=process.env.__FAKE_PLATFORM__||process.platform,s=typeof Bun<"u"?false:t==="win32",n=commonjsGlobal.__FAKE_TESTING_FS__||V,{O_CREAT:_,O_TRUNC:a,O_WRONLY:i,UV_FS_O_FILEMAP:r=0}=n.constants,c=s&&!!r,f=512*1024,p=r|a|_|i;return e=c?l=>l"w",e} + +var G,y;function Os(){if(y)return G;y=1;const ss=j$1,is=rt(),r=V,es=X(),w=H$2,M=H(),K=p(),ts=z(),os=c(),l=a$7(),rs=s(),hs=a$1(),H$1=Symbol("onEntry"),q=Symbol("checkFs"),Y=Symbol("checkFs2"),v=Symbol("pruneCache"),N=Symbol("isReusable"),d=Symbol("makeFs"),U=Symbol("file"),F$1=Symbol("directory"),O=Symbol("link"),B=Symbol("symlink"),z$1=Symbol("hardlink"),W=Symbol("unsupported"),j=Symbol("checkPath"),b=Symbol("mkdir"),m=Symbol("onError"),$=Symbol("pending"),V$1=Symbol("pend"),S=Symbol("unpend"),P=Symbol("ended"),A=Symbol("maybeClose"),x=Symbol("skip"),E=Symbol("doChown"),R=Symbol("uid"),_=Symbol("gid"),g=Symbol("checkedCwd"),X$1=Ds,J=F(),C=(process.env.TESTING_TAR_FAKE_PLATFORM||process.platform)==="win32",cs=1024,as=(a,s)=>{if(!C)return r.unlink(a,s);const i=a+".DELETE."+X$1.randomBytes(16).toString("hex");r.rename(a,i,e=>{if(e)return s(e);r.unlink(i,s);});},us=a=>{if(!C)return r.unlinkSync(a);const s=a+".DELETE."+X$1.randomBytes(16).toString("hex");r.renameSync(a,s),r.unlinkSync(s);},Q=(a,s,i)=>a===a>>>0?a:s===s>>>0?s:i,Z=a=>rs(l(hs(a))).toLowerCase(),ns=(a,s)=>{s=Z(s);for(const i of a.keys()){const e=Z(i);(e===s||e.indexOf(s+"/")===0)&&a.delete(i);}},ms=a=>{for(const s of a.keys())a.delete(s);};class L extends is{constructor(s){if(s||(s={}),s.ondone=i=>{this[P]=true,this[A]();},super(s),this[g]=false,this.reservations=ts(),this.transform=typeof s.transform=="function"?s.transform:null,this.writable=true,this.readable=false,this[$]=0,this[P]=false,this.dirCache=s.dirCache||new Map,typeof s.uid=="number"||typeof s.gid=="number"){if(typeof s.uid!="number"||typeof s.gid!="number")throw new TypeError("cannot set owner without number uid and gid");if(s.preserveOwner)throw new TypeError("cannot preserve owner in archive and also set owner explicitly");this.uid=s.uid,this.gid=s.gid,this.setOwner=true;}else this.uid=null,this.gid=null,this.setOwner=false;s.preserveOwner===void 0&&typeof s.uid!="number"?this.preserveOwner=process.getuid&&process.getuid()===0:this.preserveOwner=!!s.preserveOwner,this.processUid=(this.preserveOwner||this.setOwner)&&process.getuid?process.getuid():null,this.processGid=(this.preserveOwner||this.setOwner)&&process.getgid?process.getgid():null,this.maxDepth=typeof s.maxDepth=="number"?s.maxDepth:cs,this.forceChown=s.forceChown===true,this.win32=!!s.win32||C,this.newer=!!s.newer,this.keep=!!s.keep,this.noMtime=!!s.noMtime,this.preservePaths=!!s.preservePaths,this.unlink=!!s.unlink,this.cwd=l(w.resolve(s.cwd||process.cwd())),this.strip=+s.strip||0,this.processUmask=s.noChmod?0:process.umask(),this.umask=typeof s.umask=="number"?s.umask:this.processUmask,this.dmode=s.dmode||511&~this.umask,this.fmode=s.fmode||438&~this.umask,this.on("entry",i=>this[H$1](i));}warn(s,i,e={}){return (s==="TAR_BAD_ARCHIVE"||s==="TAR_ABORT")&&(e.recoverable=false),super.warn(s,i,e)}[A](){this[P]&&this[$]===0&&(this.emit("prefinish"),this.emit("finish"),this.emit("end"));}[j](s){const i=l(s.path),e=i.split("/");if(this.strip){if(e.length=this.strip)s.linkpath=t.slice(this.strip).join("/");else return false}e.splice(0,this.strip),s.path=e.join("/");}if(isFinite(this.maxDepth)&&e.length>this.maxDepth)return this.warn("TAR_ENTRY_ERROR","path excessively deep",{entry:s,path:i,depth:e.length,maxDepth:this.maxDepth}),false;if(!this.preservePaths){if(e.includes("..")||C&&/^[a-z]:\.\.$/i.test(e[0]))return this.warn("TAR_ENTRY_ERROR","path contains '..'",{entry:s,path:i}),false;const[t,o]=os(i);t&&(s.path=o,this.warn("TAR_ENTRY_INFO",`stripping ${t} from absolute path`,{entry:s,path:i}));}if(w.isAbsolute(s.path)?s.absolute=l(w.resolve(s.path)):s.absolute=l(w.resolve(this.cwd,s.path)),!this.preservePaths&&s.absolute.indexOf(this.cwd+"/")!==0&&s.absolute!==this.cwd)return this.warn("TAR_ENTRY_ERROR","path escaped extraction target",{entry:s,path:l(s.path),resolvedPath:s.absolute,cwd:this.cwd}),false;if(s.absolute===this.cwd&&s.type!=="Directory"&&s.type!=="GNUDumpDir")return false;if(this.win32){const{root:t}=w.win32.parse(s.absolute);s.absolute=t+K.encode(s.absolute.slice(t.length));const{root:o}=w.win32.parse(s.path);s.path=o+K.encode(s.path.slice(o.length));}return true}[H$1](s){if(!this[j](s))return s.resume();switch(ss.equal(typeof s.absolute,"string"),s.type){case "Directory":case "GNUDumpDir":s.mode&&(s.mode=s.mode|448);case "File":case "OldFile":case "ContiguousFile":case "Link":case "SymbolicLink":return this[q](s);case "CharacterDevice":case "BlockDevice":case "FIFO":default:return this[W](s)}}[m](s,i){s.name==="CwdError"?this.emit("error",s):(this.warn("TAR_ENTRY_ERROR",s,{entry:i}),this[S](),i.resume());}[b](s,i,e){M(l(s),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:i,noChmod:this.noChmod},e);}[E](s){return this.forceChown||this.preserveOwner&&(typeof s.uid=="number"&&s.uid!==this.processUid||typeof s.gid=="number"&&s.gid!==this.processGid)||typeof this.uid=="number"&&this.uid!==this.processUid||typeof this.gid=="number"&&this.gid!==this.processGid}[R](s){return Q(this.uid,s.uid,this.processUid)}[_](s){return Q(this.gid,s.gid,this.processGid)}[U](s,i){const e=s.mode&4095||this.fmode,t=new es.WriteStream(s.absolute,{flags:J(s.size),mode:e,autoClose:false});t.on("error",c=>{t.fd&&r.close(t.fd,()=>{}),t.write=()=>true,this[m](c,s),i();});let o=1;const u=c=>{if(c){t.fd&&r.close(t.fd,()=>{}),this[m](c,s),i();return}--o===0&&r.close(t.fd,n=>{n?this[m](n,s):this[S](),i();});};t.on("finish",c=>{const n=s.absolute,p=t.fd;if(s.mtime&&!this.noMtime){o++;const f=s.atime||new Date,k=s.mtime;r.futimes(p,f,k,D=>D?r.utimes(n,f,k,I=>u(I&&D)):u());}if(this[E](s)){o++;const f=this[R](s),k=this[_](s);r.fchown(p,f,k,D=>D?r.chown(n,f,k,I=>u(I&&D)):u());}u();});const h=this.transform&&this.transform(s)||s;h!==s&&(h.on("error",c=>{this[m](c,s),i();}),s.pipe(h)),h.pipe(t);}[F$1](s,i){const e=s.mode&4095||this.dmode;this[b](s.absolute,e,t=>{if(t){this[m](t,s),i();return}let o=1;const u=h=>{--o===0&&(i(),this[S](),s.resume());};s.mtime&&!this.noMtime&&(o++,r.utimes(s.absolute,s.atime||new Date,s.mtime,u)),this[E](s)&&(o++,r.chown(s.absolute,this[R](s),this[_](s),u)),u();});}[W](s){s.unsupported=true,this.warn("TAR_ENTRY_UNSUPPORTED",`unsupported entry type: ${s.type}`,{entry:s}),s.resume();}[B](s,i){this[O](s,s.linkpath,"symlink",i);}[z$1](s,i){const e=l(w.resolve(this.cwd,s.linkpath));this[O](s,e,"link",i);}[V$1](){this[$]++;}[S](){this[$]--,this[A]();}[x](s){this[S](),s.resume();}[N](s,i){return s.type==="File"&&!this.unlink&&i.isFile()&&i.nlink<=1&&!C}[q](s){this[V$1]();const i=[s.path];s.linkpath&&i.push(s.linkpath),this.reservations.reserve(i,e=>this[Y](s,e));}[v](s){s.type==="SymbolicLink"?ms(this.dirCache):s.type!=="Directory"&&ns(this.dirCache,s.absolute);}[Y](s,i){this[v](s);const e=h=>{this[v](s),i(h);},t=()=>{this[b](this.cwd,this.dmode,h=>{if(h){this[m](h,s),e();return}this[g]=true,o();});},o=()=>{if(s.absolute!==this.cwd){const h=l(w.dirname(s.absolute));if(h!==this.cwd)return this[b](h,this.dmode,c=>{if(c){this[m](c,s),e();return}u();})}u();},u=()=>{r.lstat(s.absolute,(h,c)=>{if(c&&(this.keep||this.newer&&c.mtime>s.mtime)){this[x](s),e();return}if(h||this[N](s,c))return this[d](null,s,e);if(c.isDirectory()){if(s.type==="Directory"){const n=!this.noChmod&&s.mode&&(c.mode&4095)!==s.mode,p=f=>this[d](f,s,e);return n?r.chmod(s.absolute,s.mode,p):p()}if(s.absolute!==this.cwd)return r.rmdir(s.absolute,n=>this[d](n,s,e))}if(s.absolute===this.cwd)return this[d](null,s,e);as(s.absolute,n=>this[d](n,s,e));});};this[g]?o():t();}[d](s,i,e){if(s){this[m](s,i),e();return}switch(i.type){case "File":case "OldFile":case "ContiguousFile":return this[U](i,e);case "Link":return this[z$1](i,e);case "SymbolicLink":return this[B](i,e);case "Directory":case "GNUDumpDir":return this[F$1](i,e)}}[O](s,i,e,t){r[e](i,s.absolute,o=>{o?this[m](o,s):(this[S](),s.resume()),t();});}}const T=a=>{try{return [null,a()]}catch(s){return [s,null]}};class ls extends L{[d](s,i){return super[d](s,i,()=>{})}[q](s){if(this[v](s),!this[g]){const o=this[b](this.cwd,this.dmode);if(o)return this[m](o,s);this[g]=true;}if(s.absolute!==this.cwd){const o=l(w.dirname(s.absolute));if(o!==this.cwd){const u=this[b](o,this.dmode);if(u)return this[m](u,s)}}const[i,e]=T(()=>r.lstatSync(s.absolute));if(e&&(this.keep||this.newer&&e.mtime>s.mtime))return this[x](s);if(i||this[N](s,e))return this[d](null,s);if(e.isDirectory()){if(s.type==="Directory"){const u=!this.noChmod&&s.mode&&(e.mode&4095)!==s.mode,[h]=u?T(()=>{r.chmodSync(s.absolute,s.mode);}):[];return this[d](h,s)}const[o]=T(()=>r.rmdirSync(s.absolute));this[d](o,s);}const[t]=s.absolute===this.cwd?[]:T(()=>us(s.absolute));this[d](t,s);}[U](s,i){const e=s.mode&4095||this.fmode,t=h=>{let c;try{r.closeSync(o);}catch(n){c=n;}(h||c)&&this[m](h||c,s),i();};let o;try{o=r.openSync(s.absolute,J(s.size),e);}catch(h){return t(h)}const u=this.transform&&this.transform(s)||s;u!==s&&(u.on("error",h=>this[m](h,s)),s.pipe(u)),u.on("data",h=>{try{r.writeSync(o,h,0,h.length);}catch(c){t(c);}}),u.on("end",h=>{let c=null;if(s.mtime&&!this.noMtime){const n=s.atime||new Date,p=s.mtime;try{r.futimesSync(o,n,p);}catch(f){try{r.utimesSync(s.absolute,n,p);}catch{c=f;}}}if(this[E](s)){const n=this[R](s),p=this[_](s);try{r.fchownSync(o,n,p);}catch(f){try{r.chownSync(s.absolute,n,p);}catch{c=c||f;}}}t(c);});}[F$1](s,i){const e=s.mode&4095||this.dmode,t=this[b](s.absolute,e);if(t){this[m](t,s),i();return}if(s.mtime&&!this.noMtime)try{r.utimesSync(s.absolute,s.atime||new Date,s.mtime);}catch{}if(this[E](s))try{r.chownSync(s.absolute,this[R](s),this[_](s));}catch{}i(),s.resume();}[b](s,i){try{return M.sync(l(s),{uid:this.uid,gid:this.gid,processUid:this.processUid,processGid:this.processGid,umask:this.processUmask,preserve:this.preservePaths,unlink:this.unlink,cache:this.dirCache,cwd:this.cwd,mode:i})}catch(e){return e}}[O](s,i,e,t){try{r[e+"Sync"](i,s.absolute),t(),s.resume();}catch(o){return this[m](o,s)}}}return L.Sync=ls,G=L,G} + +var f,q;function v(){if(q)return f;q=1;const w=s$6(),u=Os(),p=V,y=X(),l=H$2,m=s();f=(r,e,o)=>{typeof r=="function"?(o=r,e=null,r={}):Array.isArray(r)&&(e=r,r={}),typeof e=="function"&&(o=e,e=null),e?e=Array.from(e):e=[];const t=w(r);if(t.sync&&typeof o=="function")throw new TypeError("callback not supported for sync tar functions");if(!t.file&&typeof o=="function")throw new TypeError("callback only supported with file option");return e.length&&d(t,e),t.file&&t.sync?$(t):t.file?h(t,o):t.sync?x(t):z(t)};const d=(r,e)=>{const o=new Map(e.map(n=>[m(n),true])),t=r.filter,s=(n,i)=>{const a=i||l.parse(n).root||".",c=n===a?false:o.has(n)?o.get(n):s(l.dirname(n),a);return o.set(n,c),c};r.filter=t?(n,i)=>t(n,i)&&s(m(n)):n=>s(m(n));},$=r=>{const e=new u.Sync(r),o=r.file,t=p.statSync(o),s=r.maxReadSize||16*1024*1024;new y.ReadStreamSync(o,{readSize:s,size:t.size}).pipe(e);},h=(r,e)=>{const o=new u(r),t=r.maxReadSize||16*1024*1024,s=r.file,n=new Promise((i,a)=>{o.on("error",a),o.on("close",i),p.stat(s,(c,R)=>{if(c)a(c);else {const S=new y.ReadStream(s,{readSize:t,size:R.size});S.on("error",a),S.pipe(o);}});});return e?n.then(e,e):n},x=r=>new u.Sync(r),z=r=>new u(r);return f} + +var r=v();const tarExtract = getDefaultExportFromCjs(r); + +async function download(url, filePath, options = {}) { + const infoPath = filePath + ".json"; + const info = JSON.parse( + await readFile(infoPath, "utf8").catch(() => "{}") + ); + const headResponse = await sendFetch(url, { + method: "HEAD", + headers: options.headers + }).catch(() => void 0); + const etag = headResponse?.headers.get("etag"); + if (info.etag === etag && existsSync(filePath)) { + return; + } + if (typeof etag === "string") { + info.etag = etag; + } + const response = await sendFetch(url, { headers: options.headers }); + if (response.status >= 400) { + throw new Error( + `Failed to download ${url}: ${response.status} ${response.statusText}` + ); + } + const stream = createWriteStream(filePath); + await promisify(pipeline)(response.body, stream); + await writeFile(infoPath, JSON.stringify(info), "utf8"); +} +const inputRegex = /^(?[\w.-]+\/[\w.-]+)(?[^#]+)?(?#[\w./@-]+)?/; +function parseGitURI(input) { + const m = input.match(inputRegex)?.groups || {}; + return { + repo: m.repo, + subdir: m.subdir || "/", + ref: m.ref ? m.ref.slice(1) : "main" + }; +} +function debug(...args) { + if (process.env.DEBUG) { + console.debug("[giget]", ...args); + } +} +async function sendFetch(url, options = {}) { + if (options.headers?.["sec-fetch-mode"]) { + options.mode = options.headers["sec-fetch-mode"]; + } + const res = await fetch(url, { + ...options, + headers: normalizeHeaders(options.headers) + }).catch((error) => { + throw new Error(`Failed to download ${url}: ${error}`, { cause: error }); + }); + if (options.validateStatus && res.status >= 400) { + throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`); + } + return res; +} +function cacheDirectory() { + const cacheDir = process.env.XDG_CACHE_HOME ? resolve(process.env.XDG_CACHE_HOME, "giget") : resolve(homedir(), ".cache/giget"); + if (process.platform === "win32") { + const windowsCacheDir = resolve(tmpdir(), "giget"); + if (!existsSync(windowsCacheDir) && existsSync(cacheDir)) { + try { + renameSync(cacheDir, windowsCacheDir); + } catch { + } + } + return windowsCacheDir; + } + return cacheDir; +} +function normalizeHeaders(headers = {}) { + const normalized = {}; + for (const [key, value] of Object.entries(headers)) { + if (!value) { + continue; + } + normalized[key.toLowerCase()] = value; + } + return normalized; +} +function currentShell() { + if (process.env.SHELL) { + return process.env.SHELL; + } + if (process.platform === "win32") { + return "cmd.exe"; + } + return "/bin/bash"; +} +function startShell(cwd) { + cwd = resolve(cwd); + const shell = currentShell(); + console.info( + `(experimental) Opening shell in ${relative(process.cwd(), cwd)}...` + ); + spawnSync(shell, [], { + cwd, + shell: true, + stdio: "inherit" + }); +} + +const http = async (input, options) => { + if (input.endsWith(".json")) { + return await _httpJSON(input, options); + } + const url = new URL(input); + let name = basename(url.pathname); + try { + const head = await sendFetch(url.href, { + method: "HEAD", + validateStatus: true, + headers: { + authorization: options.auth ? `Bearer ${options.auth}` : void 0 + } + }); + const _contentType = head.headers.get("content-type") || ""; + if (_contentType.includes("application/json")) { + return await _httpJSON(input, options); + } + const filename = head.headers.get("content-disposition")?.match(/filename="?(.+)"?/)?.[1]; + if (filename) { + name = filename.split(".")[0]; + } + } catch (error) { + debug(`Failed to fetch HEAD for ${url.href}:`, error); + } + return { + name: `${name}-${url.href.slice(0, 8)}`, + version: "", + subdir: "", + tar: url.href, + defaultDir: name, + headers: { + Authorization: options.auth ? `Bearer ${options.auth}` : void 0 + } + }; +}; +const _httpJSON = async (input, options) => { + const result = await sendFetch(input, { + validateStatus: true, + headers: { + authorization: options.auth ? `Bearer ${options.auth}` : void 0 + } + }); + const info = await result.json(); + if (!info.tar || !info.name) { + throw new Error( + `Invalid template info from ${input}. name or tar fields are missing!` + ); + } + return info; +}; +const github = (input, options) => { + const parsed = parseGitURI(input); + const githubAPIURL = process.env.GIGET_GITHUB_URL || "https://api.github.com"; + return { + name: parsed.repo.replace("/", "-"), + version: parsed.ref, + subdir: parsed.subdir, + headers: { + Authorization: options.auth ? `Bearer ${options.auth}` : void 0, + Accept: "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28" + }, + url: `${githubAPIURL.replace("api.github.com", "github.com")}/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`, + tar: `${githubAPIURL}/repos/${parsed.repo}/tarball/${parsed.ref}` + }; +}; +const gitlab = (input, options) => { + const parsed = parseGitURI(input); + const gitlab2 = process.env.GIGET_GITLAB_URL || "https://gitlab.com"; + return { + name: parsed.repo.replace("/", "-"), + version: parsed.ref, + subdir: parsed.subdir, + headers: { + authorization: options.auth ? `Bearer ${options.auth}` : void 0, + // https://gitlab.com/gitlab-org/gitlab/-/commit/50c11f278d18fe1f3fb12eb595067216bb58ade2 + "sec-fetch-mode": "same-origin" + }, + url: `${gitlab2}/${parsed.repo}/tree/${parsed.ref}${parsed.subdir}`, + tar: `${gitlab2}/${parsed.repo}/-/archive/${parsed.ref}.tar.gz` + }; +}; +const bitbucket = (input, options) => { + const parsed = parseGitURI(input); + return { + name: parsed.repo.replace("/", "-"), + version: parsed.ref, + subdir: parsed.subdir, + headers: { + authorization: options.auth ? `Bearer ${options.auth}` : void 0 + }, + url: `https://bitbucket.com/${parsed.repo}/src/${parsed.ref}${parsed.subdir}`, + tar: `https://bitbucket.org/${parsed.repo}/get/${parsed.ref}.tar.gz` + }; +}; +const sourcehut = (input, options) => { + const parsed = parseGitURI(input); + return { + name: parsed.repo.replace("/", "-"), + version: parsed.ref, + subdir: parsed.subdir, + headers: { + authorization: options.auth ? `Bearer ${options.auth}` : void 0 + }, + url: `https://git.sr.ht/~${parsed.repo}/tree/${parsed.ref}/item${parsed.subdir}`, + tar: `https://git.sr.ht/~${parsed.repo}/archive/${parsed.ref}.tar.gz` + }; +}; +const providers = { + http, + https: http, + github, + gh: github, + gitlab, + bitbucket, + sourcehut +}; + +const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/unjs/giget/main/templates"; +const registryProvider = (registryEndpoint = DEFAULT_REGISTRY, options = {}) => { + return async (input) => { + const start = Date.now(); + const registryURL = `${registryEndpoint}/${input}.json`; + const result = await sendFetch(registryURL, { + headers: { + authorization: options.auth ? `Bearer ${options.auth}` : void 0 + } + }); + if (result.status >= 400) { + throw new Error( + `Failed to download ${input} template info from ${registryURL}: ${result.status} ${result.statusText}` + ); + } + const info = await result.json(); + if (!info.tar || !info.name) { + throw new Error( + `Invalid template info from ${registryURL}. name or tar fields are missing!` + ); + } + debug( + `Fetched ${input} template info from ${registryURL} in ${Date.now() - start}ms` + ); + return info; + }; +}; + +const sourceProtoRe = /^([\w-.]+):/; +async function downloadTemplate(input, options = {}) { + options = defu( + { + registry: process.env.GIGET_REGISTRY, + auth: process.env.GIGET_AUTH + }, + options + ); + const registry = options.registry === false ? void 0 : registryProvider(options.registry, { auth: options.auth }); + let providerName = options.provider || (registry ? "registry" : "github"); + let source = input; + const sourceProviderMatch = input.match(sourceProtoRe); + if (sourceProviderMatch) { + providerName = sourceProviderMatch[1]; + source = input.slice(sourceProviderMatch[0].length); + if (providerName === "http" || providerName === "https") { + source = input; + } + } + const provider = options.providers?.[providerName] || providers[providerName] || registry; + if (!provider) { + throw new Error(`Unsupported provider: ${providerName}`); + } + const template = await Promise.resolve().then(() => provider(source, { auth: options.auth })).catch((error) => { + throw new Error( + `Failed to download template from ${providerName}: ${error.message}` + ); + }); + if (!template) { + throw new Error(`Failed to resolve template from ${providerName}`); + } + template.name = (template.name || "template").replace(/[^\da-z-]/gi, "-"); + template.defaultDir = (template.defaultDir || template.name).replace( + /[^\da-z-]/gi, + "-" + ); + const temporaryDirectory = resolve( + cacheDirectory(), + providerName, + template.name + ); + const tarPath = resolve( + temporaryDirectory, + (template.version || template.name) + ".tar.gz" + ); + if (options.preferOffline && existsSync(tarPath)) { + options.offline = true; + } + if (!options.offline) { + await mkdir(dirname(tarPath), { recursive: true }); + const s2 = Date.now(); + await download(template.tar, tarPath, { + headers: { + Authorization: options.auth ? `Bearer ${options.auth}` : void 0, + ...normalizeHeaders(template.headers) + } + }).catch((error) => { + if (!existsSync(tarPath)) { + throw error; + } + debug("Download error. Using cached version:", error); + options.offline = true; + }); + debug(`Downloaded ${template.tar} to ${tarPath} in ${Date.now() - s2}ms`); + } + if (!existsSync(tarPath)) { + throw new Error( + `Tarball not found: ${tarPath} (offline: ${options.offline})` + ); + } + const cwd = resolve(options.cwd || "."); + const extractPath = resolve(cwd, options.dir || template.defaultDir); + if (options.forceClean) { + await rm(extractPath, { recursive: true, force: true }); + } + if (!options.force && existsSync(extractPath) && readdirSync(extractPath).length > 0) { + throw new Error(`Destination ${extractPath} already exists.`); + } + await mkdir(extractPath, { recursive: true }); + const s = Date.now(); + const subdir = template.subdir?.replace(/^\//, "") || ""; + await tarExtract({ + file: tarPath, + cwd: extractPath, + onentry(entry) { + entry.path = entry.path.split("/").splice(1).join("/"); + if (subdir) { + if (entry.path.startsWith(subdir + "/")) { + entry.path = entry.path.slice(subdir.length); + } else { + entry.path = ""; + } + } + } + }); + debug(`Extracted to ${extractPath} in ${Date.now() - s}ms`); + if (options.install) { + debug("Installing dependencies..."); + await installDependencies({ + cwd: extractPath, + silent: options.silent + }); + } + return { + ...template, + source, + dir: extractPath + }; +} + +export { downloadTemplate as d, registryProvider as r, startShell as s }; diff --git a/backend/node_modules/rc9/dist/index.cjs b/backend/node_modules/rc9/dist/index.cjs new file mode 100644 index 0000000000000000000000000000000000000000..f0680b52735d652e0f900e85c36eff5ae9e48f3f --- /dev/null +++ b/backend/node_modules/rc9/dist/index.cjs @@ -0,0 +1,262 @@ +'use strict'; + +const node_fs = require('node:fs'); +const node_path = require('node:path'); +const node_os = require('node:os'); +const destr = require('destr'); +const defu = require('defu'); + +function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; } + +const destr__default = /*#__PURE__*/_interopDefaultCompat(destr); + +function isBuffer (obj) { + return obj && + obj.constructor && + (typeof obj.constructor.isBuffer === 'function') && + obj.constructor.isBuffer(obj) +} + +function keyIdentity (key) { + return key +} + +function flatten (target, opts) { + opts = opts || {}; + + const delimiter = opts.delimiter || '.'; + const maxDepth = opts.maxDepth; + const transformKey = opts.transformKey || keyIdentity; + const output = {}; + + function step (object, prev, currentDepth) { + currentDepth = currentDepth || 1; + Object.keys(object).forEach(function (key) { + const value = object[key]; + const isarray = opts.safe && Array.isArray(value); + const type = Object.prototype.toString.call(value); + const isbuffer = isBuffer(value); + const isobject = ( + type === '[object Object]' || + type === '[object Array]' + ); + + const newKey = prev + ? prev + delimiter + transformKey(key) + : transformKey(key); + + if (!isarray && !isbuffer && isobject && Object.keys(value).length && + (!opts.maxDepth || currentDepth < maxDepth)) { + return step(value, newKey, currentDepth + 1) + } + + output[newKey] = value; + }); + } + + step(target); + + return output +} + +function unflatten (target, opts) { + opts = opts || {}; + + const delimiter = opts.delimiter || '.'; + const overwrite = opts.overwrite || false; + const transformKey = opts.transformKey || keyIdentity; + const result = {}; + + const isbuffer = isBuffer(target); + if (isbuffer || Object.prototype.toString.call(target) !== '[object Object]') { + return target + } + + // safely ensure that the key is + // an integer. + function getkey (key) { + const parsedKey = Number(key); + + return ( + isNaN(parsedKey) || + key.indexOf('.') !== -1 || + opts.object + ) + ? key + : parsedKey + } + + function addKeys (keyPrefix, recipient, target) { + return Object.keys(target).reduce(function (result, key) { + result[keyPrefix + delimiter + key] = target[key]; + + return result + }, recipient) + } + + function isEmpty (val) { + const type = Object.prototype.toString.call(val); + const isArray = type === '[object Array]'; + const isObject = type === '[object Object]'; + + if (!val) { + return true + } else if (isArray) { + return !val.length + } else if (isObject) { + return !Object.keys(val).length + } + } + + target = Object.keys(target).reduce(function (result, key) { + const type = Object.prototype.toString.call(target[key]); + const isObject = (type === '[object Object]' || type === '[object Array]'); + if (!isObject || isEmpty(target[key])) { + result[key] = target[key]; + return result + } else { + return addKeys( + key, + result, + flatten(target[key], opts) + ) + } + }, {}); + + Object.keys(target).forEach(function (key) { + const split = key.split(delimiter).map(transformKey); + let key1 = getkey(split.shift()); + let key2 = getkey(split[0]); + let recipient = result; + + while (key2 !== undefined) { + if (key1 === '__proto__') { + return + } + + const type = Object.prototype.toString.call(recipient[key1]); + const isobject = ( + type === '[object Object]' || + type === '[object Array]' + ); + + // do not write over falsey, non-undefined values if overwrite is false + if (!overwrite && !isobject && typeof recipient[key1] !== 'undefined') { + return + } + + if ((overwrite && !isobject) || (!overwrite && recipient[key1] == null)) { + recipient[key1] = ( + typeof key2 === 'number' && + !opts.object + ? [] + : {} + ); + } + + recipient = recipient[key1]; + if (split.length > 0) { + key1 = getkey(split.shift()); + key2 = getkey(split[0]); + } + } + + // unflatten again for 'messy objects' + recipient[key1] = unflatten(target[key], opts); + }); + + return result +} + +const RE_KEY_VAL = /^\s*([^\s=]+)\s*=\s*(.*)?\s*$/; +const RE_LINES = /\n|\r|\r\n/; +const defaults = { + name: ".conf", + dir: process.cwd(), + flat: false +}; +function withDefaults(options) { + if (typeof options === "string") { + options = { name: options }; + } + return { ...defaults, ...options }; +} +function parse(contents, options = {}) { + const config = {}; + const lines = contents.split(RE_LINES); + for (const line of lines) { + const match = line.match(RE_KEY_VAL); + if (!match) { + continue; + } + const key = match[1]; + if (!key || key === "__proto__" || key === "constructor") { + continue; + } + const value = destr__default( + (match[2] || "").trim() + /* val */ + ); + if (key.endsWith("[]")) { + const nkey = key.slice(0, Math.max(0, key.length - 2)); + config[nkey] = (config[nkey] || []).concat(value); + continue; + } + config[key] = value; + } + return options.flat ? config : unflatten(config, { overwrite: true }); +} +function parseFile(path, options) { + if (!node_fs.existsSync(path)) { + return {}; + } + return parse(node_fs.readFileSync(path, "utf8"), options); +} +function read(options) { + options = withDefaults(options); + return parseFile(node_path.resolve(options.dir, options.name), options); +} +function readUser(options) { + options = withDefaults(options); + options.dir = process.env.XDG_CONFIG_HOME || node_os.homedir(); + return read(options); +} +function serialize(config) { + return Object.entries(flatten(config)).map(([key, value]) => `${key}=${JSON.stringify(value)}`).join("\n"); +} +function write(config, options) { + options = withDefaults(options); + node_fs.writeFileSync(node_path.resolve(options.dir, options.name), serialize(config), { + encoding: "utf8" + }); +} +function writeUser(config, options) { + options = withDefaults(options); + options.dir = process.env.XDG_CONFIG_HOME || node_os.homedir(); + write(config, options); +} +function update(config, options) { + options = withDefaults(options); + if (!options.flat) { + config = unflatten(config, { overwrite: true }); + } + const newConfig = defu.defu(config, read(options)); + write(newConfig, options); + return newConfig; +} +function updateUser(config, options) { + options = withDefaults(options); + options.dir = process.env.XDG_CONFIG_HOME || node_os.homedir(); + return update(config, options); +} + +exports.defaults = defaults; +exports.parse = parse; +exports.parseFile = parseFile; +exports.read = read; +exports.readUser = readUser; +exports.serialize = serialize; +exports.update = update; +exports.updateUser = updateUser; +exports.write = write; +exports.writeUser = writeUser; diff --git a/backend/node_modules/rc9/dist/index.d.cts b/backend/node_modules/rc9/dist/index.d.cts new file mode 100644 index 0000000000000000000000000000000000000000..a7db3dd72e0dea626180690e24f5677b8be5afc8 --- /dev/null +++ b/backend/node_modules/rc9/dist/index.d.cts @@ -0,0 +1,18 @@ +type RC = Record; +interface RCOptions { + name?: string; + dir?: string; + flat?: boolean; +} +declare const defaults: RCOptions; +declare function parse(contents: string, options?: RCOptions): T; +declare function parseFile(path: string, options?: RCOptions): T; +declare function read(options?: RCOptions | string): T; +declare function readUser(options?: RCOptions | string): T; +declare function serialize(config: T): string; +declare function write(config: T, options?: RCOptions | string): void; +declare function writeUser(config: T, options?: RCOptions | string): void; +declare function update(config: T, options?: RCOptions | string): T; +declare function updateUser(config: T, options?: RCOptions | string): T; + +export { defaults, parse, parseFile, read, readUser, serialize, update, updateUser, write, writeUser }; diff --git a/backend/node_modules/rc9/dist/index.d.mts b/backend/node_modules/rc9/dist/index.d.mts new file mode 100644 index 0000000000000000000000000000000000000000..a7db3dd72e0dea626180690e24f5677b8be5afc8 --- /dev/null +++ b/backend/node_modules/rc9/dist/index.d.mts @@ -0,0 +1,18 @@ +type RC = Record; +interface RCOptions { + name?: string; + dir?: string; + flat?: boolean; +} +declare const defaults: RCOptions; +declare function parse(contents: string, options?: RCOptions): T; +declare function parseFile(path: string, options?: RCOptions): T; +declare function read(options?: RCOptions | string): T; +declare function readUser(options?: RCOptions | string): T; +declare function serialize(config: T): string; +declare function write(config: T, options?: RCOptions | string): void; +declare function writeUser(config: T, options?: RCOptions | string): void; +declare function update(config: T, options?: RCOptions | string): T; +declare function updateUser(config: T, options?: RCOptions | string): T; + +export { defaults, parse, parseFile, read, readUser, serialize, update, updateUser, write, writeUser }; diff --git a/backend/node_modules/rc9/dist/index.d.ts b/backend/node_modules/rc9/dist/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..a7db3dd72e0dea626180690e24f5677b8be5afc8 --- /dev/null +++ b/backend/node_modules/rc9/dist/index.d.ts @@ -0,0 +1,18 @@ +type RC = Record; +interface RCOptions { + name?: string; + dir?: string; + flat?: boolean; +} +declare const defaults: RCOptions; +declare function parse(contents: string, options?: RCOptions): T; +declare function parseFile(path: string, options?: RCOptions): T; +declare function read(options?: RCOptions | string): T; +declare function readUser(options?: RCOptions | string): T; +declare function serialize(config: T): string; +declare function write(config: T, options?: RCOptions | string): void; +declare function writeUser(config: T, options?: RCOptions | string): void; +declare function update(config: T, options?: RCOptions | string): T; +declare function updateUser(config: T, options?: RCOptions | string): T; + +export { defaults, parse, parseFile, read, readUser, serialize, update, updateUser, write, writeUser }; diff --git a/backend/node_modules/rc9/dist/index.mjs b/backend/node_modules/rc9/dist/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..d7206a90eb470071a2203d8a9595361d71a5625d --- /dev/null +++ b/backend/node_modules/rc9/dist/index.mjs @@ -0,0 +1,247 @@ +import { existsSync, readFileSync, writeFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { homedir } from 'node:os'; +import destr from 'destr'; +import { defu } from 'defu'; + +function isBuffer (obj) { + return obj && + obj.constructor && + (typeof obj.constructor.isBuffer === 'function') && + obj.constructor.isBuffer(obj) +} + +function keyIdentity (key) { + return key +} + +function flatten (target, opts) { + opts = opts || {}; + + const delimiter = opts.delimiter || '.'; + const maxDepth = opts.maxDepth; + const transformKey = opts.transformKey || keyIdentity; + const output = {}; + + function step (object, prev, currentDepth) { + currentDepth = currentDepth || 1; + Object.keys(object).forEach(function (key) { + const value = object[key]; + const isarray = opts.safe && Array.isArray(value); + const type = Object.prototype.toString.call(value); + const isbuffer = isBuffer(value); + const isobject = ( + type === '[object Object]' || + type === '[object Array]' + ); + + const newKey = prev + ? prev + delimiter + transformKey(key) + : transformKey(key); + + if (!isarray && !isbuffer && isobject && Object.keys(value).length && + (!opts.maxDepth || currentDepth < maxDepth)) { + return step(value, newKey, currentDepth + 1) + } + + output[newKey] = value; + }); + } + + step(target); + + return output +} + +function unflatten (target, opts) { + opts = opts || {}; + + const delimiter = opts.delimiter || '.'; + const overwrite = opts.overwrite || false; + const transformKey = opts.transformKey || keyIdentity; + const result = {}; + + const isbuffer = isBuffer(target); + if (isbuffer || Object.prototype.toString.call(target) !== '[object Object]') { + return target + } + + // safely ensure that the key is + // an integer. + function getkey (key) { + const parsedKey = Number(key); + + return ( + isNaN(parsedKey) || + key.indexOf('.') !== -1 || + opts.object + ) + ? key + : parsedKey + } + + function addKeys (keyPrefix, recipient, target) { + return Object.keys(target).reduce(function (result, key) { + result[keyPrefix + delimiter + key] = target[key]; + + return result + }, recipient) + } + + function isEmpty (val) { + const type = Object.prototype.toString.call(val); + const isArray = type === '[object Array]'; + const isObject = type === '[object Object]'; + + if (!val) { + return true + } else if (isArray) { + return !val.length + } else if (isObject) { + return !Object.keys(val).length + } + } + + target = Object.keys(target).reduce(function (result, key) { + const type = Object.prototype.toString.call(target[key]); + const isObject = (type === '[object Object]' || type === '[object Array]'); + if (!isObject || isEmpty(target[key])) { + result[key] = target[key]; + return result + } else { + return addKeys( + key, + result, + flatten(target[key], opts) + ) + } + }, {}); + + Object.keys(target).forEach(function (key) { + const split = key.split(delimiter).map(transformKey); + let key1 = getkey(split.shift()); + let key2 = getkey(split[0]); + let recipient = result; + + while (key2 !== undefined) { + if (key1 === '__proto__') { + return + } + + const type = Object.prototype.toString.call(recipient[key1]); + const isobject = ( + type === '[object Object]' || + type === '[object Array]' + ); + + // do not write over falsey, non-undefined values if overwrite is false + if (!overwrite && !isobject && typeof recipient[key1] !== 'undefined') { + return + } + + if ((overwrite && !isobject) || (!overwrite && recipient[key1] == null)) { + recipient[key1] = ( + typeof key2 === 'number' && + !opts.object + ? [] + : {} + ); + } + + recipient = recipient[key1]; + if (split.length > 0) { + key1 = getkey(split.shift()); + key2 = getkey(split[0]); + } + } + + // unflatten again for 'messy objects' + recipient[key1] = unflatten(target[key], opts); + }); + + return result +} + +const RE_KEY_VAL = /^\s*([^\s=]+)\s*=\s*(.*)?\s*$/; +const RE_LINES = /\n|\r|\r\n/; +const defaults = { + name: ".conf", + dir: process.cwd(), + flat: false +}; +function withDefaults(options) { + if (typeof options === "string") { + options = { name: options }; + } + return { ...defaults, ...options }; +} +function parse(contents, options = {}) { + const config = {}; + const lines = contents.split(RE_LINES); + for (const line of lines) { + const match = line.match(RE_KEY_VAL); + if (!match) { + continue; + } + const key = match[1]; + if (!key || key === "__proto__" || key === "constructor") { + continue; + } + const value = destr( + (match[2] || "").trim() + /* val */ + ); + if (key.endsWith("[]")) { + const nkey = key.slice(0, Math.max(0, key.length - 2)); + config[nkey] = (config[nkey] || []).concat(value); + continue; + } + config[key] = value; + } + return options.flat ? config : unflatten(config, { overwrite: true }); +} +function parseFile(path, options) { + if (!existsSync(path)) { + return {}; + } + return parse(readFileSync(path, "utf8"), options); +} +function read(options) { + options = withDefaults(options); + return parseFile(resolve(options.dir, options.name), options); +} +function readUser(options) { + options = withDefaults(options); + options.dir = process.env.XDG_CONFIG_HOME || homedir(); + return read(options); +} +function serialize(config) { + return Object.entries(flatten(config)).map(([key, value]) => `${key}=${JSON.stringify(value)}`).join("\n"); +} +function write(config, options) { + options = withDefaults(options); + writeFileSync(resolve(options.dir, options.name), serialize(config), { + encoding: "utf8" + }); +} +function writeUser(config, options) { + options = withDefaults(options); + options.dir = process.env.XDG_CONFIG_HOME || homedir(); + write(config, options); +} +function update(config, options) { + options = withDefaults(options); + if (!options.flat) { + config = unflatten(config, { overwrite: true }); + } + const newConfig = defu(config, read(options)); + write(newConfig, options); + return newConfig; +} +function updateUser(config, options) { + options = withDefaults(options); + options.dir = process.env.XDG_CONFIG_HOME || homedir(); + return update(config, options); +} + +export { defaults, parse, parseFile, read, readUser, serialize, update, updateUser, write, writeUser }; diff --git a/backend/node_modules/readdirp/esm/index.d.ts b/backend/node_modules/readdirp/esm/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..df939404f66d46db3c473bbd0a53b6a8fc7a716f --- /dev/null +++ b/backend/node_modules/readdirp/esm/index.d.ts @@ -0,0 +1,108 @@ +/** + * Recursive version of readdir. Exposes a streaming API and promise API. + * Streaming API allows to use a small amount of RAM. + * + * @module + * @example +```js +import readdirp from 'readdirp'; +for await (const entry of readdirp('.')) { + const {path} = entry; + console.log(`${JSON.stringify({path})}`); +} +``` + */ +/*! readdirp - MIT License (c) 2012-2019 Thorsten Lorenz, Paul Miller (https://paulmillr.com) */ +import type { Stats, Dirent } from 'node:fs'; +import { Readable } from 'node:stream'; +/** Path in file system. */ +export type Path = string; +/** Emitted entry. Contains relative & absolute path, basename, and either stats or dirent. */ +export interface EntryInfo { + path: string; + fullPath: string; + stats?: Stats; + dirent?: Dirent; + basename: string; +} +/** Path or dir entries (files) */ +export type PathOrDirent = Dirent | Path; +/** Filterer for files */ +export type Tester = (entryInfo: EntryInfo) => boolean; +export type Predicate = string[] | string | Tester; +export declare const EntryTypes: { + readonly FILE_TYPE: "files"; + readonly DIR_TYPE: "directories"; + readonly FILE_DIR_TYPE: "files_directories"; + readonly EVERYTHING_TYPE: "all"; +}; +export type EntryType = (typeof EntryTypes)[keyof typeof EntryTypes]; +/** + * Options for readdirp. + * * type: files, directories, or both + * * lstat: whether to use symlink-friendly stat + * * depth: max depth + * * alwaysStat: whether to use stat (more resources) or dirent + * * highWaterMark: streaming param, specifies max amount of resources per entry + */ +export type ReaddirpOptions = { + root: string; + fileFilter?: Predicate; + directoryFilter?: Predicate; + type?: EntryType; + lstat?: boolean; + depth?: number; + alwaysStat?: boolean; + highWaterMark?: number; +}; +/** Directory entry. Contains path, depth count, and files. */ +export interface DirEntry { + files: PathOrDirent[]; + depth: number; + path: Path; +} +/** Readable readdir stream, emitting new files as they're being listed. */ +export declare class ReaddirpStream extends Readable { + parents: any[]; + reading: boolean; + parent?: DirEntry; + _stat: Function; + _maxDepth: number; + _wantsDir: boolean; + _wantsFile: boolean; + _wantsEverything: boolean; + _root: Path; + _isDirent: boolean; + _statsProp: 'dirent' | 'stats'; + _rdOptions: { + encoding: 'utf8'; + withFileTypes: boolean; + }; + _fileFilter: Tester; + _directoryFilter: Tester; + constructor(options?: Partial); + _read(batch: number): Promise; + _exploreDir(path: Path, depth: number): Promise<{ + files: string[] | undefined; + depth: number; + path: string; + }>; + _formatEntry(dirent: PathOrDirent, path: Path): Promise; + _onError(err: Error): void; + _getEntryType(entry: EntryInfo): Promise; + _includeAsFile(entry: EntryInfo): boolean | undefined; +} +/** + * Streaming version: Reads all files and directories in given root recursively. + * Consumes ~constant small amount of RAM. + * @param root Root directory + * @param options Options to specify root (start directory), filters and recursion depth + */ +export declare function readdirp(root: Path, options?: Partial): ReaddirpStream; +/** + * Promise version: Reads all files and directories in given root recursively. + * Compared to streaming version, will consume a lot of RAM e.g. when 1 million files are listed. + * @returns array of paths and their entry infos + */ +export declare function readdirpPromise(root: Path, options?: Partial): Promise; +export default readdirp; diff --git a/backend/node_modules/readdirp/esm/index.js b/backend/node_modules/readdirp/esm/index.js new file mode 100644 index 0000000000000000000000000000000000000000..ae8ca782ccf9866de67e4b578a678559d4e0c365 --- /dev/null +++ b/backend/node_modules/readdirp/esm/index.js @@ -0,0 +1,257 @@ +import { stat, lstat, readdir, realpath } from 'node:fs/promises'; +import { Readable } from 'node:stream'; +import { resolve as presolve, relative as prelative, join as pjoin, sep as psep } from 'node:path'; +export const EntryTypes = { + FILE_TYPE: 'files', + DIR_TYPE: 'directories', + FILE_DIR_TYPE: 'files_directories', + EVERYTHING_TYPE: 'all', +}; +const defaultOptions = { + root: '.', + fileFilter: (_entryInfo) => true, + directoryFilter: (_entryInfo) => true, + type: EntryTypes.FILE_TYPE, + lstat: false, + depth: 2147483648, + alwaysStat: false, + highWaterMark: 4096, +}; +Object.freeze(defaultOptions); +const RECURSIVE_ERROR_CODE = 'READDIRP_RECURSIVE_ERROR'; +const NORMAL_FLOW_ERRORS = new Set(['ENOENT', 'EPERM', 'EACCES', 'ELOOP', RECURSIVE_ERROR_CODE]); +const ALL_TYPES = [ + EntryTypes.DIR_TYPE, + EntryTypes.EVERYTHING_TYPE, + EntryTypes.FILE_DIR_TYPE, + EntryTypes.FILE_TYPE, +]; +const DIR_TYPES = new Set([ + EntryTypes.DIR_TYPE, + EntryTypes.EVERYTHING_TYPE, + EntryTypes.FILE_DIR_TYPE, +]); +const FILE_TYPES = new Set([ + EntryTypes.EVERYTHING_TYPE, + EntryTypes.FILE_DIR_TYPE, + EntryTypes.FILE_TYPE, +]); +const isNormalFlowError = (error) => NORMAL_FLOW_ERRORS.has(error.code); +const wantBigintFsStats = process.platform === 'win32'; +const emptyFn = (_entryInfo) => true; +const normalizeFilter = (filter) => { + if (filter === undefined) + return emptyFn; + if (typeof filter === 'function') + return filter; + if (typeof filter === 'string') { + const fl = filter.trim(); + return (entry) => entry.basename === fl; + } + if (Array.isArray(filter)) { + const trItems = filter.map((item) => item.trim()); + return (entry) => trItems.some((f) => entry.basename === f); + } + return emptyFn; +}; +/** Readable readdir stream, emitting new files as they're being listed. */ +export class ReaddirpStream extends Readable { + constructor(options = {}) { + super({ + objectMode: true, + autoDestroy: true, + highWaterMark: options.highWaterMark, + }); + const opts = { ...defaultOptions, ...options }; + const { root, type } = opts; + this._fileFilter = normalizeFilter(opts.fileFilter); + this._directoryFilter = normalizeFilter(opts.directoryFilter); + const statMethod = opts.lstat ? lstat : stat; + // Use bigint stats if it's windows and stat() supports options (node 10+). + if (wantBigintFsStats) { + this._stat = (path) => statMethod(path, { bigint: true }); + } + else { + this._stat = statMethod; + } + this._maxDepth = opts.depth ?? defaultOptions.depth; + this._wantsDir = type ? DIR_TYPES.has(type) : false; + this._wantsFile = type ? FILE_TYPES.has(type) : false; + this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE; + this._root = presolve(root); + this._isDirent = !opts.alwaysStat; + this._statsProp = this._isDirent ? 'dirent' : 'stats'; + this._rdOptions = { encoding: 'utf8', withFileTypes: this._isDirent }; + // Launch stream with one parent, the root dir. + this.parents = [this._exploreDir(root, 1)]; + this.reading = false; + this.parent = undefined; + } + async _read(batch) { + if (this.reading) + return; + this.reading = true; + try { + while (!this.destroyed && batch > 0) { + const par = this.parent; + const fil = par && par.files; + if (fil && fil.length > 0) { + const { path, depth } = par; + const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path)); + const awaited = await Promise.all(slice); + for (const entry of awaited) { + if (!entry) + continue; + if (this.destroyed) + return; + const entryType = await this._getEntryType(entry); + if (entryType === 'directory' && this._directoryFilter(entry)) { + if (depth <= this._maxDepth) { + this.parents.push(this._exploreDir(entry.fullPath, depth + 1)); + } + if (this._wantsDir) { + this.push(entry); + batch--; + } + } + else if ((entryType === 'file' || this._includeAsFile(entry)) && + this._fileFilter(entry)) { + if (this._wantsFile) { + this.push(entry); + batch--; + } + } + } + } + else { + const parent = this.parents.pop(); + if (!parent) { + this.push(null); + break; + } + this.parent = await parent; + if (this.destroyed) + return; + } + } + } + catch (error) { + this.destroy(error); + } + finally { + this.reading = false; + } + } + async _exploreDir(path, depth) { + let files; + try { + files = await readdir(path, this._rdOptions); + } + catch (error) { + this._onError(error); + } + return { files, depth, path }; + } + async _formatEntry(dirent, path) { + let entry; + const basename = this._isDirent ? dirent.name : dirent; + try { + const fullPath = presolve(pjoin(path, basename)); + entry = { path: prelative(this._root, fullPath), fullPath, basename }; + entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath); + } + catch (err) { + this._onError(err); + return; + } + return entry; + } + _onError(err) { + if (isNormalFlowError(err) && !this.destroyed) { + this.emit('warn', err); + } + else { + this.destroy(err); + } + } + async _getEntryType(entry) { + // entry may be undefined, because a warning or an error were emitted + // and the statsProp is undefined + if (!entry && this._statsProp in entry) { + return ''; + } + const stats = entry[this._statsProp]; + if (stats.isFile()) + return 'file'; + if (stats.isDirectory()) + return 'directory'; + if (stats && stats.isSymbolicLink()) { + const full = entry.fullPath; + try { + const entryRealPath = await realpath(full); + const entryRealPathStats = await lstat(entryRealPath); + if (entryRealPathStats.isFile()) { + return 'file'; + } + if (entryRealPathStats.isDirectory()) { + const len = entryRealPath.length; + if (full.startsWith(entryRealPath) && full.substr(len, 1) === psep) { + const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`); + // @ts-ignore + recursiveError.code = RECURSIVE_ERROR_CODE; + return this._onError(recursiveError); + } + return 'directory'; + } + } + catch (error) { + this._onError(error); + return ''; + } + } + } + _includeAsFile(entry) { + const stats = entry && entry[this._statsProp]; + return stats && this._wantsEverything && !stats.isDirectory(); + } +} +/** + * Streaming version: Reads all files and directories in given root recursively. + * Consumes ~constant small amount of RAM. + * @param root Root directory + * @param options Options to specify root (start directory), filters and recursion depth + */ +export function readdirp(root, options = {}) { + // @ts-ignore + let type = options.entryType || options.type; + if (type === 'both') + type = EntryTypes.FILE_DIR_TYPE; // backwards-compatibility + if (type) + options.type = type; + if (!root) { + throw new Error('readdirp: root argument is required. Usage: readdirp(root, options)'); + } + else if (typeof root !== 'string') { + throw new TypeError('readdirp: root argument must be a string. Usage: readdirp(root, options)'); + } + else if (type && !ALL_TYPES.includes(type)) { + throw new Error(`readdirp: Invalid type passed. Use one of ${ALL_TYPES.join(', ')}`); + } + options.root = root; + return new ReaddirpStream(options); +} +/** + * Promise version: Reads all files and directories in given root recursively. + * Compared to streaming version, will consume a lot of RAM e.g. when 1 million files are listed. + * @returns array of paths and their entry infos + */ +export function readdirpPromise(root, options = {}) { + return new Promise((resolve, reject) => { + const files = []; + readdirp(root, options) + .on('data', (entry) => files.push(entry)) + .on('end', () => resolve(files)) + .on('error', (error) => reject(error)); + }); +} +export default readdirp; diff --git a/backend/node_modules/readdirp/esm/package.json b/backend/node_modules/readdirp/esm/package.json new file mode 100644 index 0000000000000000000000000000000000000000..876964185fee0ed0caaf9038f647c8f54411f688 --- /dev/null +++ b/backend/node_modules/readdirp/esm/package.json @@ -0,0 +1 @@ +{ "type": "module", "sideEffects": false }

, f: Fn] +) => ( + self: Matcher +) => Matcher< + I, + Types.AddWithout>>, + Types.ApplyFilters>>>, + A | ReturnType, + Pr, + Ret +> = internal.discriminator + +/** + * Matches values where a specified field starts with a given prefix. + * + * **Details** + * + * This function is useful for working with discriminated unions where the + * discriminant field follows a hierarchical or namespaced structure. It allows + * you to match values based on whether the specified field starts with a given + * prefix, making it easier to handle grouped cases. + * + * Instead of checking for exact matches, this function lets you match values + * that share a common prefix. For example, if your discriminant field contains + * hierarchical names like `"A"`, `"A.A"`, and `"B"`, you can match all values + * starting with `"A"` using a single rule. + * + * @example + * ```ts + * import { Match, pipe } from "effect" + * + * const match = pipe( + * Match.type<{ type: "A" } | { type: "B" } | { type: "A.A" } | {}>(), + * Match.discriminatorStartsWith("type")("A", (_) => 1 as const), + * Match.discriminatorStartsWith("type")("B", (_) => 2 as const), + * Match.orElse((_) => 3 as const) + * ) + * + * console.log(match({ type: "A" })) // 1 + * console.log(match({ type: "B" })) // 2 + * console.log(match({ type: "A.A" })) // 1 + * ``` + * + * @category Defining patterns + * @since 1.0.0 + */ +export const discriminatorStartsWith: ( + field: D +) => >) => Ret>( + pattern: P, + f: Fn +) => ( + self: Matcher +) => Matcher< + I, + Types.AddWithout>>, + Types.ApplyFilters>>>, + A | ReturnType, + Pr, + Ret +> = internal.discriminatorStartsWith + +/** + * Matches values based on a field that serves as a discriminator, mapping each + * possible value to a corresponding handler. + * + * **Details** + * + * This function simplifies working with discriminated unions by letting you + * define a set of handlers for each possible value of a given field. Instead of + * chaining multiple calls to {@link discriminator}, this function allows + * defining all possible cases at once using an object where the keys are the + * possible values of the field, and the values are the corresponding handler + * functions. + * + * @example + * ```ts + * import { Match, pipe } from "effect" + * + * const match = pipe( + * Match.type<{ type: "A"; a: string } | { type: "B"; b: number } | { type: "C"; c: boolean }>(), + * Match.discriminators("type")({ + * A: (a) => a.a, + * B: (b) => b.b, + * C: (c) => c.c + * }), + * Match.exhaustive + * ) + * ``` + * + * @category Defining patterns + * @since 1.0.0 + */ +export const discriminators: ( + field: D +) => < + R, + Ret, + P extends + & { readonly [Tag in Types.Tags & string]?: ((_: Extract>) => Ret) | undefined } + & { readonly [Tag in Exclude>]: never } +>( + fields: P +) => ( + self: Matcher +) => Matcher< + I, + Types.AddWithout>>, + Types.ApplyFilters>>>, + A | ReturnType, + Pr, + Ret +> = internal.discriminators + +/** + * Matches values based on a discriminator field and **ensures all cases are + * handled**. + * + * **Details*+ + * + * This function is similar to {@link discriminators}, but **requires that all + * possible cases** are explicitly handled. It is useful when working with + * discriminated unions, where a specific field (e.g., `"type"`) determines the + * shape of an object. Each possible value of the field must have a + * corresponding handler, ensuring **exhaustiveness checking** at compile time. + * + * This function **does not require** `Match.exhaustive` at the end of the + * pipeline because it enforces exhaustiveness by design. + * + * @example + * ```ts + * import { Match, pipe } from "effect" + * + * const match = pipe( + * Match.type<{ type: "A"; a: string } | { type: "B"; b: number } | { type: "C"; c: boolean }>(), + * Match.discriminatorsExhaustive("type")({ + * A: (a) => a.a, + * B: (b) => b.b, + * C: (c) => c.c + * }) + * ) + * ``` + * + * @category Defining patterns + * @since 1.0.0 + */ +export const discriminatorsExhaustive: ( + field: D +) => < + R, + Ret, + P extends + & { readonly [Tag in Types.Tags & string]: (_: Extract>) => Ret } + & { readonly [Tag in Exclude>]: never } +>( + fields: P +) => ( + self: Matcher +) => [Pr] extends [never] ? (u: I) => Unify> : Unify> = + internal.discriminatorsExhaustive + +/** + * The `Match.tag` function allows pattern matching based on the `_tag` field in + * a [Discriminated Union](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#discriminated-unions). + * You can specify multiple tags to match within a single pattern. + * + * **Note** + * + * The `Match.tag` function relies on the convention within the Effect ecosystem + * of naming the tag field as `"_tag"`. Ensure that your discriminated unions + * follow this naming convention for proper functionality. + * + * **Example** (Matching a Discriminated Union by Tag) + * + * ```ts + * import { Match } from "effect" + * + * type Event = + * | { readonly _tag: "fetch" } + * | { readonly _tag: "success"; readonly data: string } + * | { readonly _tag: "error"; readonly error: Error } + * | { readonly _tag: "cancel" } + * + * // Create a Matcher for Either + * const match = Match.type().pipe( + * // Match either "fetch" or "success" + * Match.tag("fetch", "success", () => `Ok!`), + * // Match "error" and extract the error message + * Match.tag("error", (event) => `Error: ${event.error.message}`), + * // Match "cancel" + * Match.tag("cancel", () => "Cancelled"), + * Match.exhaustive + * ) + * + * console.log(match({ _tag: "success", data: "Hello" })) + * // Output: "Ok!" + * + * console.log(match({ _tag: "error", error: new Error("Oops!") })) + * // Output: "Error: Oops!" + * ``` + * + * @category Defining patterns + * @since 1.0.0 + */ +export const tag: < + R, + P extends Types.Tags<"_tag", R> & string, + Ret, + Fn extends (_: Extract>) => Ret +>( + ...pattern: [first: P, ...values: Array