diff --git a/.changeset/quiet-runners-provide.md b/.changeset/quiet-runners-provide.md new file mode 100644 index 00000000..38a0d064 --- /dev/null +++ b/.changeset/quiet-runners-provide.md @@ -0,0 +1,5 @@ +--- +"@effect/language-service": patch +--- + +Update Effect v4 compatibility to 4.0.0-rc.115 and allow `Effect.provide` at recognized application entry points. diff --git a/.gitignore b/.gitignore index e3d3ab0a..3e30890b 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ specs/ .context/ .cuggino.json .cuggino/ +.zvec-grep diff --git a/package.json b/package.json index dbc13a6e..6575ef19 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ }, "pnpm": { "overrides": { - "@effect/platform-node-shared": "4.0.0-beta.107" + "@effect/platform-node-shared": "4.0.0-rc.115" } } } diff --git a/packages/harness-effect-v4/__snapshots__/diagnostics/strictEffectProvide.ts.codefixes b/packages/harness-effect-v4/__snapshots__/diagnostics/strictEffectProvide.ts.codefixes index 19490e13..f5b7170c 100644 --- a/packages/harness-effect-v4/__snapshots__/diagnostics/strictEffectProvide.ts.codefixes +++ b/packages/harness-effect-v4/__snapshots__/diagnostics/strictEffectProvide.ts.codefixes @@ -1,8 +1,10 @@ -strictEffectProvide_skipNextLine from 667 to 714 -strictEffectProvide_skipFile from 667 to 714 -strictEffectProvide_skipNextLine from 525 to 559 -strictEffectProvide_skipFile from 525 to 559 -strictEffectProvide_skipNextLine from 833 to 867 -strictEffectProvide_skipFile from 833 to 867 -strictEffectProvide_skipNextLine from 991 to 1061 -strictEffectProvide_skipFile from 991 to 1061 \ No newline at end of file +strictEffectProvide_skipNextLine from 2432 to 2466 +strictEffectProvide_skipFile from 2432 to 2466 +strictEffectProvide_skipNextLine from 769 to 816 +strictEffectProvide_skipFile from 769 to 816 +strictEffectProvide_skipNextLine from 627 to 661 +strictEffectProvide_skipFile from 627 to 661 +strictEffectProvide_skipNextLine from 935 to 969 +strictEffectProvide_skipFile from 935 to 969 +strictEffectProvide_skipNextLine from 1093 to 1163 +strictEffectProvide_skipFile from 1093 to 1163 \ No newline at end of file diff --git a/packages/harness-effect-v4/__snapshots__/diagnostics/strictEffectProvide.ts.output b/packages/harness-effect-v4/__snapshots__/diagnostics/strictEffectProvide.ts.output index 200650dc..0b259148 100644 --- a/packages/harness-effect-v4/__snapshots__/diagnostics/strictEffectProvide.ts.output +++ b/packages/harness-effect-v4/__snapshots__/diagnostics/strictEffectProvide.ts.output @@ -1,11 +1,14 @@ Effect.provide(MyService1.Default) -18:2 - 18:36 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide) +20:2 - 20:36 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide) Effect.provide(Effect.void, MyService1.Default) -22:29 - 22:76 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide) +24:29 - 24:76 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide) Effect.provide(MyService1.Default) -27:2 - 27:36 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide) +29:2 - 29:36 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide) Effect.provide(Layer.mergeAll(MyService1.Default, MyService2.Default)) -33:2 - 33:72 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide) \ No newline at end of file +35:2 - 35:72 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide) + +Effect.provide(MyService1.Default) +79:17 - 79:51 | 0 | Effect.provide with a Layer should only be used at application entry points. If this is an entry point, you can safely disable this diagnostic. Otherwise, using Effect.provide may break scope lifetimes. Compose all layers at your entry point and provide them at once. effect(strictEffectProvide) \ No newline at end of file diff --git a/packages/harness-effect-v4/examples/diagnostics/strictEffectProvide.ts b/packages/harness-effect-v4/examples/diagnostics/strictEffectProvide.ts index ce522876..46036e17 100644 --- a/packages/harness-effect-v4/examples/diagnostics/strictEffectProvide.ts +++ b/packages/harness-effect-v4/examples/diagnostics/strictEffectProvide.ts @@ -1,4 +1,6 @@ // @effect-diagnostics strictEffectProvide:warning +import { BunRuntime } from "@effect/platform-bun" +import { NodeRuntime } from "@effect/platform-node" import { Context, Effect, Layer } from "effect" class MyService1 extends Context.Service()("MyService1", { @@ -49,3 +51,29 @@ export const shouldNotReport3 = Effect.gen(function*() { const ctx = yield* Effect.context() return yield* Effect.provide(Effect.void, ctx) }) + +// Should NOT report: entry-point runners +Effect.void.pipe( + Effect.provide(MyService1.Default), + Effect.runPromise +) + +Effect.runSync( + Effect.void.pipe(Effect.provide(MyService1.Default)) +) + +Effect.runFork(Effect.provide(Effect.void, MyService1.Default)) +Effect.runPromiseExit(Effect.void.pipe(Effect.provide(MyService1.Default))) +Effect.runSyncExit(Effect.void.pipe(Effect.provide(MyService1.Default))) + +NodeRuntime.runMain( + Effect.void.pipe(Effect.provide(MyService1.Default)) +) + +BunRuntime.runMain( + Effect.void.pipe(Effect.provide(MyService1.Default)) +) + +// Should report: a similarly named local function is not an entry point +const FakeEffect = { runPromise: (value: A) => value } +Effect.void.pipe(Effect.provide(MyService1.Default), FakeEffect.runPromise) diff --git a/packages/harness-effect-v4/package.json b/packages/harness-effect-v4/package.json index 5d36411a..a7606041 100644 --- a/packages/harness-effect-v4/package.json +++ b/packages/harness-effect-v4/package.json @@ -5,8 +5,10 @@ "check": "tsc -b tsconfig.json" }, "dependencies": { + "@effect/platform-bun": "4.0.0-rc.115", + "@effect/platform-node": "4.0.0-rc.115", "@standard-schema/spec": "^1.1.0", - "effect": "4.0.0-beta.107" + "effect": "4.0.0-rc.115" }, "devDependencies": { "@types/node": "^25.0.6" diff --git a/packages/language-service/package.json b/packages/language-service/package.json index 989accbe..ccf3aa21 100644 --- a/packages/language-service/package.json +++ b/packages/language-service/package.json @@ -43,10 +43,10 @@ "perf": "tsx test/perf.ts" }, "devDependencies": { - "@effect/platform-node": "4.0.0-beta.107", + "@effect/platform-node": "4.0.0-rc.115", "@types/pako": "^2.0.4", "@typescript-eslint/project-service": "^8.52.0", - "effect": "4.0.0-beta.107", + "effect": "4.0.0-rc.115", "pako": "^2.1.0", "ts-patch": "^3.3.0" } diff --git a/packages/language-service/src/cli/check.ts b/packages/language-service/src/cli/check.ts index 04167c13..1576ba5b 100644 --- a/packages/language-service/src/cli/check.ts +++ b/packages/language-service/src/cli/check.ts @@ -7,7 +7,7 @@ import { extractAppliedEffectLspPatches, getModuleFilePath, getPackageJsonData, const LOCAL_TYPESCRIPT_DIR = "./node_modules/typescript" -const dirPath = Flag.directory("dir").pipe( +const dirPath = Flag.Directory("dir").pipe( Flag.withDefault(LOCAL_TYPESCRIPT_DIR), Flag.withDescription("The directory of the typescript package to patch.") ) diff --git a/packages/language-service/src/cli/codegen.ts b/packages/language-service/src/cli/codegen.ts index 08575488..d6d6832b 100644 --- a/packages/language-service/src/cli/codegen.ts +++ b/packages/language-service/src/cli/codegen.ts @@ -26,22 +26,22 @@ export class NoFilesToCodegenError extends Data.TaggedError("NoFilesToCodegenErr } } -const file = Flag.file("file").pipe( +const file = Flag.File("file").pipe( Flag.optional, Flag.withDescription("The full path of the file to codegen.") ) -const project = Flag.file("project").pipe( +const project = Flag.File("project").pipe( Flag.optional, Flag.withDescription("The full path of the project tsconfig.json file to codegen.") ) -const verbose = Flag.boolean("verbose").pipe( +const verbose = Flag.Boolean("verbose").pipe( Flag.withDefault(false), Flag.withDescription("Verbose output.") ) -const force = Flag.boolean("force").pipe( +const force = Flag.Boolean("force").pipe( Flag.withDefault(false), Flag.withDescription("Force codegen even if no changes are needed.") ) diff --git a/packages/language-service/src/cli/diagnostics.ts b/packages/language-service/src/cli/diagnostics.ts index f50ddbac..6da892af 100644 --- a/packages/language-service/src/cli/diagnostics.ts +++ b/packages/language-service/src/cli/diagnostics.ts @@ -289,35 +289,35 @@ const BATCH_SIZE = 50 export const diagnostics = Command.make( "diagnostics", { - file: Flag.file("file").pipe( + file: Flag.File("file").pipe( Flag.optional, Flag.withDescription("The full path of the file to check for diagnostics.") ), - project: Flag.file("project").pipe( + project: Flag.File("project").pipe( Flag.optional, Flag.withDescription("The full path of the project tsconfig.json file to check for diagnostics.") ), - format: Flag.choice("format", ["json", "pretty", "text", "github-actions"] as ReadonlyArray) + format: Flag.Literals("format", ["json", "pretty", "text", "github-actions"] as ReadonlyArray) .pipe( Flag.withDefault("pretty" as const), Flag.withDescription( "Output format: json (machine-readable), pretty (colored with context), text (plain text), github-actions (workflow commands)" ) ), - strict: Flag.boolean("strict").pipe( + strict: Flag.Boolean("strict").pipe( Flag.withDefault(false), Flag.withDescription("Treat warnings as errors (affects exit code)") ), - severity: Flag.string("severity").pipe( + severity: Flag.String("severity").pipe( Flag.optional, Flag.withDescription("Filter by severity levels (comma-separated: error,warning,message)") ), - progress: Flag.boolean("progress").pipe( + progress: Flag.Boolean("progress").pipe( Flag.withDefault(false), Flag.withDescription("Show progress as files are checked (outputs to stderr)") ), - lspconfig: Flag.string("lspconfig").pipe( + lspconfig: Flag.String("lspconfig").pipe( Flag.optional, Flag.withDescription( "An optional inline JSON lsp config that replaces the current project lsp config. e.g. '{ \"effectFn\": [\"untraced\"] }'" diff --git a/packages/language-service/src/cli/layerinfo.ts b/packages/language-service/src/cli/layerinfo.ts index 2be7381e..b66a5cab 100644 --- a/packages/language-service/src/cli/layerinfo.ts +++ b/packages/language-service/src/cli/layerinfo.ts @@ -423,13 +423,13 @@ const parseOutputIndices = (outputs: Option.Option): ReadonlyArray { // Validate that the code is a known diagnostic name or code @@ -147,15 +147,15 @@ export const quickfixes = Command.make( }), Flag.optional ), - line: Flag.integer("line").pipe( + line: Flag.Int("line").pipe( Flag.withDescription("Filter by line number (1-based)."), Flag.optional ), - column: Flag.integer("column").pipe( + column: Flag.Int("column").pipe( Flag.withDescription("Filter by column number (1-based). Requires --line to be specified."), Flag.optional ), - fix: Flag.string("fix").pipe( + fix: Flag.String("fix").pipe( Flag.withDescription("Filter by fix name (e.g., 'floatingEffect_yieldStar')."), Flag.optional ) diff --git a/packages/language-service/src/cli/setup/changes.ts b/packages/language-service/src/cli/setup/changes.ts index 352f9d2c..ebe7a2c7 100644 --- a/packages/language-service/src/cli/setup/changes.ts +++ b/packages/language-service/src/cli/setup/changes.ts @@ -998,7 +998,7 @@ export const reviewAndApplyChanges = ( return } - const shouldProceed = yield* Prompt.confirm({ + const shouldProceed = yield* Prompt.Confirm({ message: options?.confirmMessage ?? "Apply all changes?", initial: true }) diff --git a/packages/language-service/src/cli/setup/diagnostic-prompt.ts b/packages/language-service/src/cli/setup/diagnostic-prompt.ts index b714d70d..a1673ebf 100644 --- a/packages/language-service/src/cli/setup/diagnostic-prompt.ts +++ b/packages/language-service/src/cli/setup/diagnostic-prompt.ts @@ -599,7 +599,7 @@ export function createDiagnosticPrompt( ): Prompt.Prompt> { const entries = getPromptEntries(diagnostics) - return Prompt.custom(buildState(entries, 0, "", initialSeverities), { + return Prompt.Custom(buildState(entries, 0, "", initialSeverities), { render: (state, action) => { switch (action._tag) { case "Beep": diff --git a/packages/language-service/src/cli/setup/target-prompt.ts b/packages/language-service/src/cli/setup/target-prompt.ts index 2e5e5976..e4c20eed 100644 --- a/packages/language-service/src/cli/setup/target-prompt.ts +++ b/packages/language-service/src/cli/setup/target-prompt.ts @@ -29,7 +29,7 @@ export const gatherTargetState = ( }) // Ask what user wants to do - const lspDependencyType = yield* Prompt.select({ + const lspDependencyType = yield* Prompt.Select({ message: "Language service installation:", choices: [ { @@ -73,7 +73,7 @@ export const gatherTargetState = ( onSome: (options) => options.diagnosticSeverity }) - const selectedDiagnosticModes = yield* Prompt.multiSelect({ + const selectedDiagnosticModes = yield* Prompt.MultiSelect({ message: "Which diagnostic presets would you like to use?", choices: [ { @@ -113,7 +113,7 @@ export const gatherTargetState = ( onSome: (script) => script.hasPatch }) - const prepareScript = yield* Prompt.select({ + const prepareScript = yield* Prompt.Select({ message: "Enable language service diagnostics during TypeScript compilation?", choices: [ { @@ -136,7 +136,7 @@ export const gatherTargetState = ( // Pre-select VSCode if .vscode/settings.json exists const hasVscodeSettings = Option.isSome(assessment.vscodeSettings) - const editors = yield* Prompt.multiSelect({ + const editors = yield* Prompt.MultiSelect({ message: "Which editors do you use?", choices: [ { diff --git a/packages/language-service/src/cli/setup/tsconfig-prompt.ts b/packages/language-service/src/cli/setup/tsconfig-prompt.ts index 9cb7277b..6bb49f4e 100644 --- a/packages/language-service/src/cli/setup/tsconfig-prompt.ts +++ b/packages/language-service/src/cli/setup/tsconfig-prompt.ts @@ -28,7 +28,7 @@ const findTsConfigFiles = ( }) const promptForTsConfigPath = (currentDir: string) => - Prompt.file({ + Prompt.File({ type: "file", message: "Select tsconfig to configure", startingPath: currentDir, @@ -65,7 +65,7 @@ export const selectTsConfigFile = ( } ] - const selected = yield* Prompt.select({ + const selected = yield* Prompt.Select({ message: "Select tsconfig to configure", choices }) diff --git a/packages/language-service/src/cli/unpatch.ts b/packages/language-service/src/cli/unpatch.ts index 917fbc12..35cf5d3c 100644 --- a/packages/language-service/src/cli/unpatch.ts +++ b/packages/language-service/src/cli/unpatch.ts @@ -5,12 +5,12 @@ import { getModuleFilePath, getSourceFileText, getUnpatchedSourceFile } from "./ const LOCAL_TYPESCRIPT_DIR = "./node_modules/typescript" -const dirPath = Flag.directory("dir").pipe( +const dirPath = Flag.Directory("dir").pipe( Flag.withDefault(LOCAL_TYPESCRIPT_DIR), Flag.withDescription("The directory of the typescript package to patch.") ) -const moduleNames = Flag.choice("module", [ +const moduleNames = Flag.Literals("module", [ "tsc", "typescript" ]).pipe( diff --git a/packages/language-service/src/core/TypeParser.ts b/packages/language-service/src/core/TypeParser.ts index 0a242b16..081a15ee 100644 --- a/packages/language-service/src/core/TypeParser.ts +++ b/packages/language-service/src/core/TypeParser.ts @@ -98,6 +98,10 @@ export interface TypeParser { importedEffectModule: ( node: ts.Node ) => Nano.Nano + isNodeReferenceToPackageModuleApi: ( + packageName: string, + memberName: string + ) => (node: ts.Node) => Nano.Nano isNodeReferenceToEffectModuleApi: ( memberName: string ) => (node: ts.Node) => Nano.Nano @@ -905,6 +909,20 @@ export function make( (node) => node ) + const isNodeReferenceToPackageModuleApi = (packageName: string, memberName: string) => + Nano.cachedBy( + Nano.fn("TypeParser.isNodeReferenceToPackageModuleApi")(function*(node: ts.Node) { + return yield* isNodeReferenceToExportOfPackageModule( + node, + packageName, + (sourceFile) => Nano.succeed(sourceFile), + memberName + ) + }), + `TypeParser.isNodeReferenceToPackageModuleApi(${packageName}, ${memberName})`, + (node) => node + ) + const layerType = Nano.cachedBy( Nano.fn("TypeParser.layerType")(function*( type: ts.Type, @@ -3354,6 +3372,7 @@ export function make( return { isNodeReferenceToEffectModuleApi, + isNodeReferenceToPackageModuleApi, isNodeReferenceToEffectSchemaModuleApi, isNodeReferenceToEffectParseResultModuleApi, isNodeReferenceToEffectDataModuleApi, diff --git a/packages/language-service/src/diagnostics/outdatedApi.db.ts b/packages/language-service/src/diagnostics/outdatedApi.db.ts index 41e959c9..bc52638e 100644 --- a/packages/language-service/src/diagnostics/outdatedApi.db.ts +++ b/packages/language-service/src/diagnostics/outdatedApi.db.ts @@ -384,9 +384,7 @@ export const effectModuleMigrationDb: ModuleMigrationDb = { "getRuntimeFlags": asRemoved( "Runtime flags have been removed in Effect v4." ), - "head": asRemoved( - "Use Array.head and Effect.flatMap instead." - ), + "head": asUnchanged, "if": asRemoved( "Use Effect.when instead of Effect.if." ), diff --git a/packages/language-service/src/diagnostics/strictEffectProvide.ts b/packages/language-service/src/diagnostics/strictEffectProvide.ts index 4e4eeba6..868678b5 100644 --- a/packages/language-service/src/diagnostics/strictEffectProvide.ts +++ b/packages/language-service/src/diagnostics/strictEffectProvide.ts @@ -20,6 +20,23 @@ export const strictEffectProvide = LSP.createDiagnostic({ const typeCheckerUtils = yield* Nano.service(TypeCheckerUtils.TypeCheckerUtils) const typeParser = yield* Nano.service(TypeParser.TypeParser) + const entryPointEffectRunners = [ + "runPromise", + "runSync", + "runFork", + "runPromiseExit", + "runSyncExit" + ] + + const isEntryPointRunner = (node: ts.Expression) => + Nano.firstSuccessOf([ + ...entryPointEffectRunners.map((name) => typeParser.isNodeReferenceToEffectModuleApi(name)(node)), + typeParser.isNodeReferenceToPackageModuleApi("@effect/platform-node", "runMain")(node), + typeParser.isNodeReferenceToPackageModuleApi("@effect/platform-bun", "runMain")(node), + typeParser.isNodeReferenceToPackageModuleApi("effect", "make")(node), + typeParser.isNodeReferenceToEffectLayerModuleApi("launch")(node) + ]) + const parseEffectProvideWithLayerGen = Nano.fn("strictEffectProvide.parseEffectProvideWithLayer")( function*(node: ts.CallExpression) { // Check if the expression is from the Effect module @@ -49,6 +66,35 @@ export const strictEffectProvide = LSP.createDiagnostic({ } const nodeToVisit: Array = [] + const entryPointProvides = new Set() + const flows = yield* typeParser.pipingFlows(false)(sourceFile) + + for (const flow of flows) { + for (let index = 0; index < flow.transformations.length; index++) { + const transformation = flow.transformations[index] + const nextTransformation = flow.transformations[index + 1] + if (!nextTransformation) continue + + const runner = yield* pipe(isEntryPointRunner(nextTransformation.callee), Nano.option) + if (Option.isNone(runner)) continue + + if ( + ts.isCallExpression(transformation.callee.parent) && + transformation.callee.parent.expression === transformation.callee + ) { + entryPointProvides.add(transformation.callee.parent) + } + } + + const firstTransformation = flow.transformations[0] + if ( + ts.isCallExpression(flow.subject.node) && + firstTransformation && + Option.isSome(yield* pipe(isEntryPointRunner(firstTransformation.callee), Nano.option)) + ) { + entryPointProvides.add(flow.subject.node) + } + } const appendNodeToVisit = (node: ts.Node) => { nodeToVisit.push(node) return undefined @@ -60,6 +106,7 @@ export const strictEffectProvide = LSP.createDiagnostic({ ts.forEachChild(node, appendNodeToVisit) if (ts.isCallExpression(node)) { + if (entryPointProvides.has(node)) continue const layerCheck = yield* pipe(parseEffectProvideWithLayer(node), Nano.option) if (Option.isSome(layerCheck)) { report({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 863b0e42..ccbe521b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,7 @@ settings: excludeLinksFromLockfile: false overrides: - '@effect/platform-node-shared': 4.0.0-beta.107 + '@effect/platform-node-shared': 4.0.0-rc.115 importers: @@ -123,12 +123,18 @@ importers: packages/harness-effect-v4: dependencies: + '@effect/platform-bun': + specifier: 4.0.0-rc.115 + version: 4.0.0-rc.115(effect@4.0.0-rc.115) + '@effect/platform-node': + specifier: 4.0.0-rc.115 + version: 4.0.0-rc.115(effect@4.0.0-rc.115)(redis@6.2.1) '@standard-schema/spec': specifier: ^1.1.0 version: 1.1.0 effect: - specifier: 4.0.0-beta.107 - version: 4.0.0-beta.107 + specifier: 4.0.0-rc.115 + version: 4.0.0-rc.115 devDependencies: '@types/node': specifier: ^25.0.6 @@ -137,8 +143,8 @@ importers: packages/language-service: devDependencies: '@effect/platform-node': - specifier: 4.0.0-beta.107 - version: 4.0.0-beta.107(effect@4.0.0-beta.107)(ioredis@5.10.0) + specifier: 4.0.0-rc.115 + version: 4.0.0-rc.115(effect@4.0.0-rc.115)(redis@6.2.1) '@types/pako': specifier: ^2.0.4 version: 2.0.4 @@ -146,8 +152,8 @@ importers: specifier: ^8.52.0 version: 8.52.0(typescript@5.9.3) effect: - specifier: 4.0.0-beta.107 - version: 4.0.0-beta.107 + specifier: 4.0.0-rc.115 + version: 4.0.0-rc.115 pako: specifier: ^2.1.0 version: 2.1.0 @@ -578,36 +584,45 @@ packages: uuid: 11.1.0 dev: false - /@effect/platform-node-shared@4.0.0-beta.107(effect@4.0.0-beta.107): - resolution: {integrity: sha512-y6BqcRi86BfTJv+tvDrob4ozYVHxxlHYcn/zIQqZjXI9CvKnkgD6ng+38G1o45c4f2ucU+6HRI9POCmFdMoVGA==} + /@effect/platform-bun@4.0.0-rc.115(effect@4.0.0-rc.115): + resolution: {integrity: sha512-ilTFcs66ghInP8WHCJYa4bx/yzohYM9dRR//qjmVBBpSKu1hrCTiRWpEcc1N6zrnOEPk2kyVaKg5ykSMgiBMqQ==} + peerDependencies: + effect: ^4.0.0-rc.115 + dependencies: + '@effect/platform-node-shared': 4.0.0-rc.115(effect@4.0.0-rc.115) + effect: 4.0.0-rc.115 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@effect/platform-node-shared@4.0.0-rc.115(effect@4.0.0-rc.115): + resolution: {integrity: sha512-rcBwhDIfb82akJoTv7Vwh8K5x9vC/XfuePS7JjOr+z+dORXzsmKqI1BUQF27ARCN9fTAbDh7I6YvBlWhLjnqNg==} engines: {node: '>=18.0.0'} peerDependencies: - effect: ^4.0.0-beta.107 + effect: ^4.0.0-rc.115 dependencies: '@types/ws': 8.18.1 - effect: 4.0.0-beta.107 - ws: 8.21.2 + effect: 4.0.0-rc.115 + ws: 8.21.3 transitivePeerDependencies: - bufferutil - utf-8-validate - dev: true - /@effect/platform-node@4.0.0-beta.107(effect@4.0.0-beta.107)(ioredis@5.10.0): - resolution: {integrity: sha512-k+6YNbV4Ck0L6YXtlgkvEnuP5tlxWD8EeWOrpn46PDqbGEwt4ONpRltTwm3tn2cyBXD0i+2P11cUH/6sdFagTA==} + /@effect/platform-node@4.0.0-rc.115(effect@4.0.0-rc.115)(redis@6.2.1): + resolution: {integrity: sha512-mW03Wjq2FiTL5oi9yOkaKpCyUNBaduKgTk7qMHNELvC21Jq2qOAfdsfH+p+s2zmpB9w2RSa+ApODv4WjO9wQfw==} engines: {node: '>=18.0.0'} peerDependencies: - effect: ^4.0.0-beta.107 - ioredis: '>=5.7.0 <6.0.0' - dependencies: - '@effect/platform-node-shared': 4.0.0-beta.107(effect@4.0.0-beta.107) - effect: 4.0.0-beta.107 - ioredis: 5.10.0 - mime: 4.1.0 - undici: 8.10.0 + effect: ^4.0.0-rc.115 + redis: '>=5.0.0 <7.0.0' + dependencies: + '@effect/platform-node-shared': 4.0.0-rc.115(effect@4.0.0-rc.115) + effect: 4.0.0-rc.115 + redis: 6.2.1 + undici: 8.10.2 transitivePeerDependencies: - bufferutil - utf-8-validate - dev: true /@effect/platform@0.94.1(effect@3.19.14): resolution: {integrity: sha512-SlL8OMTogHmMNnFLnPAHHo3ua1yrB1LNQOVQMiZsqYu9g3216xjr0gn5WoDgCxUyOdZcseegMjWJ7dhm/2vnfg==} @@ -1064,10 +1079,6 @@ packages: iconv-lite: 0.7.2 dev: true - /@ioredis/commands@1.5.1: - resolution: {integrity: sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==} - dev: true - /@isaacs/balanced-match@4.0.1: resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} @@ -1173,6 +1184,7 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true + dev: false optional: true /@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4: @@ -1180,6 +1192,7 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true + dev: false optional: true /@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4: @@ -1187,6 +1200,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true + dev: false optional: true /@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4: @@ -1194,6 +1208,7 @@ packages: cpu: [arm] os: [linux] requiresBuild: true + dev: false optional: true /@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4: @@ -1201,6 +1216,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true + dev: false optional: true /@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4: @@ -1208,6 +1224,7 @@ packages: cpu: [x64] os: [win32] requiresBuild: true + dev: false optional: true /@napi-rs/wasm-runtime@0.2.12: @@ -1253,6 +1270,52 @@ packages: engines: {node: '>=16.14'} dev: true + /@redis/bloom@6.2.1(@redis/client@6.2.1): + resolution: {integrity: sha512-huQgNLaCIZfQ9SeLn4q9124uOUd8HbZDYHwwUzNcRgHqCHiHKl2dDxMqJCeWh8cMqZAoWuHR8XnWbDMIf+o7ag==} + engines: {node: '>= 20.0.0'} + peerDependencies: + '@redis/client': ^6.2.1 + dependencies: + '@redis/client': 6.2.1 + + /@redis/client@6.2.1: + resolution: {integrity: sha512-LzxBY7SIBvvJiyCgcaJZZakE3fJrZZ++i24+EDW9fKpCl68D35uJcKFpZZwCfOoG9WZTbyZlMzMeM0gtOAMU9Q==} + engines: {node: '>= 20.0.0'} + peerDependencies: + '@node-rs/xxhash': ^1.1.0 + '@opentelemetry/api': '>=1 <2' + peerDependenciesMeta: + '@node-rs/xxhash': + optional: true + '@opentelemetry/api': + optional: true + dependencies: + cluster-key-slot: 1.1.2 + + /@redis/json@6.2.1(@redis/client@6.2.1): + resolution: {integrity: sha512-AFIUJ8Gj0DaaSBHYuSt8+O0oYWM+50OK1c0OmodB7XERIA8+BbyV3O4v76f9iccWasd1/7qjfZTpuzexUaZtrQ==} + engines: {node: '>= 20.0.0'} + peerDependencies: + '@redis/client': ^6.2.1 + dependencies: + '@redis/client': 6.2.1 + + /@redis/search@6.2.1(@redis/client@6.2.1): + resolution: {integrity: sha512-2vfOAOyYFE7UUw3sBBlkqqruBtOUS4HRY5MtW4hp83llrwvtrTE4r22CEqXddlV+54zkLxBE4nmsIJ/dpezQrQ==} + engines: {node: '>= 20.0.0'} + peerDependencies: + '@redis/client': ^6.2.1 + dependencies: + '@redis/client': 6.2.1 + + /@redis/time-series@6.2.1(@redis/client@6.2.1): + resolution: {integrity: sha512-kiYniph04dJOole+L359B6C9E+jYS2uDP7hca6Onj0xF38ZIpyxARO0Iq0W4ZRn1e8Q6vqW00QFZVSMRA/2Ijw==} + engines: {node: '>= 20.0.0'} + peerDependencies: + '@redis/client': ^6.2.1 + dependencies: + '@redis/client': 6.2.1 + /@rollup/pluginutils@5.3.0: resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} @@ -1634,7 +1697,6 @@ packages: resolution: {integrity: sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==} dependencies: undici-types: 7.18.2 - dev: true /@types/normalize-package-data@2.4.4: resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1656,7 +1718,6 @@ packages: resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} dependencies: '@types/node': 25.3.3 - dev: true /@types/yargs-parser@21.0.3: resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -2479,7 +2540,6 @@ packages: /cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} - dev: true /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -2648,11 +2708,6 @@ packages: object-keys: 1.1.1 dev: true - /denque@2.1.0: - resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} - engines: {node: '>=0.10'} - dev: true - /dependency-tree@11.2.0: resolution: {integrity: sha512-+C1H3mXhcvMCeu5i2Jpg9dc0N29TWTuT6vJD7mHLAfVmAbo9zW8NlkvQ1tYd3PDMab0IRQM0ccoyX68EZtx9xw==} engines: {node: '>=18'} @@ -2675,6 +2730,7 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} requiresBuild: true + dev: false optional: true /detective-amd@6.0.1: @@ -2838,14 +2894,8 @@ packages: fast-check: 3.23.2 dev: false - /effect@4.0.0-beta.107: - resolution: {integrity: sha512-OoBAv8eF+yanc+C6xhgEUnWeXUSHA6ynnscYqpkAY9GSnzZWystsIjBowVqCkLpHGlnRtdIqYT3wHwpOY6JDnQ==} - dependencies: - '@standard-schema/spec': 1.1.0 - fast-check: 4.9.0 - kubernetes-types: 1.30.0 - msgpackr: 2.0.5 - uuid: 14.0.1 + /effect@4.0.0-rc.115: + resolution: {integrity: sha512-ogYulZ5ffeOzrJqQrG0XOkDO5lKn2s9KNHhoxJy/6wKUkF0i12dlVXWA9TgsgQ+zV/JzizyG0+XMPepZEQX6vw==} /electron-to-chromium@1.5.267: resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} @@ -3401,12 +3451,6 @@ packages: pure-rand: 6.1.0 dev: false - /fast-check@4.9.0: - resolution: {integrity: sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg==} - engines: {node: '>=12.17.0'} - dependencies: - pure-rand: 8.4.0 - /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true @@ -3901,23 +3945,6 @@ packages: fp-ts: 2.16.11 dev: true - /ioredis@5.10.0: - resolution: {integrity: sha512-HVBe9OFuqs+Z6n64q09PQvP1/R4Bm+30PAyyD4wIEqssh3v9L21QjCVk4kRLucMBcDokJTcLjsGeVRlq/nH6DA==} - engines: {node: '>=12.22.0'} - dependencies: - '@ioredis/commands': 1.5.1 - cluster-key-slot: 1.1.2 - debug: 4.4.3 - denque: 2.1.0 - lodash.defaults: 4.2.0 - lodash.isarguments: 3.1.0 - redis-errors: 1.2.0 - redis-parser: 3.0.0 - standard-as-callback: 2.1.0 - transitivePeerDependencies: - - supports-color - dev: true - /is-alphabetical@1.0.4: resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} dev: true @@ -4351,9 +4378,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /kubernetes-types@1.30.0: - resolution: {integrity: sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==} - /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -4390,14 +4414,6 @@ packages: p-locate: 5.0.0 dev: true - /lodash.defaults@4.2.0: - resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} - dev: true - - /lodash.isarguments@3.1.0: - resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} - dev: true - /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true @@ -4524,12 +4540,6 @@ packages: picomatch: 2.3.1 dev: true - /mime@4.1.0: - resolution: {integrity: sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==} - engines: {node: '>=16'} - hasBin: true - dev: true - /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -4615,6 +4625,7 @@ packages: '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.4 '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.4 '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.4 + dev: false optional: true /msgpackr@1.11.8: @@ -4623,11 +4634,6 @@ packages: msgpackr-extract: 3.0.4 dev: false - /msgpackr@2.0.5: - resolution: {integrity: sha512-cef05H/dSYpLpqp3sj/qyZh5vhUYCalnaLO7j1yOmpsR0y/XwLVtK7r5gn+U/F7CTEfMowcGhlUQJDLcLf7jcA==} - optionalDependencies: - msgpackr-extract: 3.0.4 - /multipasta@0.2.7: resolution: {integrity: sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==} dev: false @@ -4678,6 +4684,7 @@ packages: requiresBuild: true dependencies: detect-libc: 2.1.2 + dev: false optional: true /node-releases@2.0.27: @@ -5127,9 +5134,6 @@ packages: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} dev: false - /pure-rand@8.4.0: - resolution: {integrity: sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==} - /quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} dev: true @@ -5210,17 +5214,18 @@ packages: tslib: 2.8.1 dev: true - /redis-errors@1.2.0: - resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} - engines: {node: '>=4'} - dev: true - - /redis-parser@3.0.0: - resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} - engines: {node: '>=4'} + /redis@6.2.1: + resolution: {integrity: sha512-Z9VHtgYs48PiQC77X9O2Er8Hj4T+5BtFjT91/vi5Is1D04N72cA946ZslM1ImJw8ZctFBZWAVjM7S5wJNeHMpg==} + engines: {node: '>= 20.0.0'} dependencies: - redis-errors: 1.2.0 - dev: true + '@redis/bloom': 6.2.1(@redis/client@6.2.1) + '@redis/client': 6.2.1 + '@redis/json': 6.2.1(@redis/client@6.2.1) + '@redis/search': 6.2.1(@redis/client@6.2.1) + '@redis/time-series': 6.2.1(@redis/client@6.2.1) + transitivePeerDependencies: + - '@node-rs/xxhash' + - '@opentelemetry/api' /reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} @@ -5586,10 +5591,6 @@ packages: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} dev: true - /standard-as-callback@2.1.0: - resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} - dev: true - /std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} dev: true @@ -6011,17 +6012,15 @@ packages: /undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} - dev: true /undici@7.18.2: resolution: {integrity: sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==} engines: {node: '>=20.18.1'} dev: true - /undici@8.10.0: - resolution: {integrity: sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ==} + /undici@8.10.2: + resolution: {integrity: sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==} engines: {node: '>=22.19.0'} - dev: true /unist-util-stringify-position@2.0.3: resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} @@ -6087,10 +6086,6 @@ packages: hasBin: true dev: false - /uuid@14.0.1: - resolution: {integrity: sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew==} - hasBin: true - /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: @@ -6359,8 +6354,8 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true - /ws@8.21.2: - resolution: {integrity: sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==} + /ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -6370,7 +6365,6 @@ packages: optional: true utf-8-validate: optional: true - dev: true /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}