diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufGenerateTask.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufGenerateTask.kt index 88c2bf490..e18615a65 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufGenerateTask.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/BufGenerateTask.kt @@ -7,17 +7,16 @@ package kotlinx.rpc.buf.tasks import kotlinx.rpc.proto.PROTO_GROUP import kotlinx.rpc.rpcExtension import org.gradle.api.Project -import org.gradle.api.file.FileCollection import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property -import org.gradle.api.provider.Provider import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskProvider import java.io.File import kotlinx.rpc.buf.BufGenerateExtension +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.InputDirectory /** * Buf `generate` command. @@ -26,8 +25,12 @@ import kotlinx.rpc.buf.BufGenerateExtension */ public abstract class BufGenerateTask : BufExecTask() { // unsued, but required for Gradle to properly recognize inputs - @get:InputFiles - internal abstract val protoFiles: ListProperty + @get:InputDirectory + internal abstract val protoFilesDir: Property + + // unsued, but required for Gradle to properly recognize inputs + @get:InputDirectory + internal abstract val importFilesDir: Property /** * Whether to include imports. @@ -103,15 +106,16 @@ public abstract class BufGenerateTask : BufExecTask() { internal fun Project.registerBufGenerateTask( name: String, - workingDir: Provider, - outputDirectory: Provider, - protoFiles: Provider, + workingDir: File, + outputDirectory: File, + protoFilesDir: File, + importFilesDir: File, configure: BufGenerateTask.() -> Unit = {}, ): TaskProvider { val capitalName = name.replaceFirstChar { it.uppercase() } val bufGenerateTaskName = "${BufGenerateTask.NAME_PREFIX}$capitalName" - return registerBufExecTask(bufGenerateTaskName, workingDir) { + return registerBufExecTask(bufGenerateTaskName, provider { workingDir }) { group = PROTO_GROUP description = "Generates code from .proto files using 'buf generate'" @@ -122,7 +126,9 @@ internal fun Project.registerBufGenerateTask( errorFormat.set(generate.errorFormat) this.outputDirectory.set(outputDirectory) - this.protoFiles.set(protoFiles) + + this.protoFilesDir.set(protoFilesDir) + this.importFilesDir.set(importFilesDir) configure() } diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufGenYaml.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufGenYaml.kt index 5f523b755..061cfe9b2 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufGenYaml.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufGenYaml.kt @@ -8,7 +8,6 @@ import kotlinx.rpc.buf.BUF_GEN_YAML import kotlinx.rpc.proto.PROTO_FILES_DIR import kotlinx.rpc.proto.PROTO_GROUP import kotlinx.rpc.proto.ProtocPlugin -import kotlinx.rpc.proto.protoBuildDirSourceSets import kotlinx.rpc.util.ensureRegularFileExists import org.gradle.api.DefaultTask import org.gradle.api.GradleException @@ -136,7 +135,7 @@ public abstract class GenerateBufGenYaml : DefaultTask() { internal fun Project.registerGenerateBufGenYamlTask( name: String, - dir: String, + buildSourceSetsDir: File, protocPlugins: Iterable, configure: GenerateBufGenYaml.() -> Unit = {}, ): TaskProvider { @@ -176,8 +175,7 @@ internal fun Project.registerGenerateBufGenYamlTask( plugins.set(pluginsProvider) - val bufGenYamlFile = project.protoBuildDirSourceSets - .resolve(dir) + val bufGenYamlFile = buildSourceSetsDir .resolve(BUF_GEN_YAML) .ensureRegularFileExists() diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufYaml.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufYaml.kt index 23ff47bed..2b39e4085 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufYaml.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/buf/tasks/GenerateBufYaml.kt @@ -5,17 +5,13 @@ package kotlinx.rpc.buf.tasks import kotlinx.rpc.buf.BUF_YAML -import kotlinx.rpc.proto.PROTO_FILES_IMPORT_DIR -import kotlinx.rpc.proto.PROTO_FILES_DIR import kotlinx.rpc.proto.PROTO_GROUP -import kotlinx.rpc.proto.protoBuildDirSourceSets -import kotlinx.rpc.util.ensureDirectoryExists import kotlinx.rpc.util.ensureRegularFileExists import org.gradle.api.DefaultTask import org.gradle.api.Project import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputDirectory -import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskProvider @@ -29,10 +25,12 @@ public abstract class GenerateBufYaml : DefaultTask() { @get:InputDirectory internal abstract val protoSourceDir: Property - @get:Optional @get:InputDirectory internal abstract val importSourceDir: Property + @get:Input + internal abstract val withImport: Property + /** * The `buf.yaml` file to generate/update. */ @@ -69,8 +67,8 @@ public abstract class GenerateBufYaml : DefaultTask() { writer.appendLine(" - path: $modulePath") } - val importDir = importSourceDir.orNull - if (importDir != null && importDir.exists()) { + val importDir = importSourceDir.get() + if (withImport.get() && importDir.exists()) { val modulePath = importDir.relativeTo(file.parentFile) writer.appendLine(" - path: $modulePath") } @@ -86,28 +84,19 @@ public abstract class GenerateBufYaml : DefaultTask() { internal fun Project.registerGenerateBufYamlTask( name: String, - dir: String, + buildSourceSetsDir: File, + buildSourceSetsProtoDir: File, + buildSourceSetsImportDir: File, withImport: Boolean, configure: GenerateBufYaml.() -> Unit = {}, ): TaskProvider { val capitalizeName = name.replaceFirstChar { it.uppercase() } return tasks.register("${GenerateBufYaml.NAME_PREFIX}$capitalizeName") { - val baseDir = project.protoBuildDirSourceSets.resolve(dir) - val protoDir = baseDir - .resolve(PROTO_FILES_DIR) - .ensureDirectoryExists() - - protoSourceDir.set(protoDir) - - if (withImport) { - val importDir = baseDir - .resolve(PROTO_FILES_IMPORT_DIR) - .ensureDirectoryExists() - - importSourceDir.set(importDir) - } + protoSourceDir.set(buildSourceSetsProtoDir) + importSourceDir.set(buildSourceSetsImportDir) + this.withImport.set(withImport) - val bufYamlFile = baseDir + val bufYamlFile = buildSourceSetsDir .resolve(BUF_YAML) .ensureRegularFileExists() diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt index 5f180791a..7caa1bcd0 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/grpc/DefaultGrpcExtension.kt @@ -18,6 +18,7 @@ import kotlinx.rpc.proto.ProtocPlugin.Companion.GRPC_JAVA import kotlinx.rpc.proto.ProtocPlugin.Companion.GRPC_KOTLIN import kotlinx.rpc.proto.ProtocPlugin.Companion.KXRPC import kotlinx.rpc.proto.ProtocPlugin.Companion.PROTOBUF_JAVA +import kotlinx.rpc.util.ensureDirectoryExists import org.gradle.api.Action import org.gradle.api.GradleException import org.gradle.api.NamedDomainObjectContainer @@ -59,7 +60,7 @@ internal open class DefaultGrpcExtension @Inject constructor( createDefaultProtocPlugins() - project.configureProtoExtensions { _, protoSourceSet -> + project.protoSourceSets.forEach { protoSourceSet -> protoSourceSet.protocPlugin(protocPlugins.protobufJava) protoSourceSet.protocPlugin(protocPlugins.grpcJava) protoSourceSet.protocPlugin(protocPlugins.grpcKotlin) @@ -80,7 +81,15 @@ internal open class DefaultGrpcExtension @Inject constructor( @Suppress("detekt.LongMethod", "detekt.CyclomaticComplexMethod") private fun Project.configureTasks(protoSourceSet: DefaultProtoSourceSet) { val baseName = protoSourceSet.name - val baseGenDir = project.protoBuildDirSourceSets.resolve(baseName) + + val buildSourceSetsDir = project.protoBuildDirSourceSets.resolve(baseName) + .ensureDirectoryExists() + + val buildSourceSetsProtoDir = buildSourceSetsDir.resolve(PROTO_FILES_DIR) + .ensureDirectoryExists() + + val buildSourceSetsImportDir = buildSourceSetsDir.resolve(PROTO_FILES_IMPORT_DIR) + .ensureDirectoryExists() val pairSourceSet = protoSourceSet.correspondingMainSourceSetOrNull() @@ -93,17 +102,18 @@ internal open class DefaultGrpcExtension @Inject constructor( } val protoFiles = protoSourceSet.proto - val hasFiles = !protoFiles.isEmpty val generateBufYamlTask = registerGenerateBufYamlTask( name = baseName, - dir = baseName, + buildSourceSetsDir = buildSourceSetsDir, + buildSourceSetsProtoDir = buildSourceSetsProtoDir, + buildSourceSetsImportDir = buildSourceSetsImportDir, withImport = pairSourceSet != null, ) val generateBufGenYamlTask = registerGenerateBufGenYamlTask( name = baseName, - dir = baseName, + buildSourceSetsDir = buildSourceSetsDir, protocPlugins = includedProtocPlugins, ) { dependsOn(generateBufYamlTask) @@ -111,9 +121,8 @@ internal open class DefaultGrpcExtension @Inject constructor( val processProtoTask = registerProcessProtoFilesTask( name = baseName, - baseGenDir = provider { baseGenDir }, + destination = buildSourceSetsProtoDir, protoFiles = protoFiles, - toDir = PROTO_FILES_DIR, ) { dependsOn(generateBufYamlTask) dependsOn(generateBufGenYamlTask) @@ -124,9 +133,8 @@ internal open class DefaultGrpcExtension @Inject constructor( registerProcessProtoFilesTask( name = "${baseName}Import", - baseGenDir = provider { baseGenDir }, + destination = buildSourceSetsImportDir, protoFiles = importProtoFiles, - toDir = PROTO_FILES_IMPORT_DIR, ) { dependsOn(generateBufYamlTask) dependsOn(generateBufGenYamlTask) @@ -138,19 +146,14 @@ internal open class DefaultGrpcExtension @Inject constructor( val out = protoBuildDirGenerated.resolve(baseName) + val destinationFileTree = fileTree(buildSourceSetsProtoDir) + val bufGenerateTask = registerBufGenerateTask( name = baseName, - workingDir = provider { baseGenDir }, - outputDirectory = provider { out }, - protoFiles = provider { - protoFiles.asFileTree.let { - if (pairSourceSet != null) { - it + pairSourceSet.proto - } else { - it - } - } - }, + workingDir = buildSourceSetsDir, + outputDirectory = out, + protoFilesDir = buildSourceSetsProtoDir, + importFilesDir = buildSourceSetsImportDir, ) { dependsOn(generateBufGenYamlTask) dependsOn(generateBufYamlTask) @@ -163,7 +166,7 @@ internal open class DefaultGrpcExtension @Inject constructor( dependsOn(pairSourceSet.generateTask) } - onlyIf { hasFiles } + onlyIf { !destinationFileTree.filter { it.extension == "proto" }.isEmpty } } protoSourceSet.generateTask.set(bufGenerateTask) @@ -236,7 +239,7 @@ internal open class DefaultGrpcExtension @Inject constructor( val customTask = registerBufExecTask( clazz = definition.kClass, - workingDir = provider { baseGenDir }, + workingDir = provider { buildSourceSetsDir }, name = taskName, ) { dependsOn(generateBufYamlTask) @@ -246,7 +249,7 @@ internal open class DefaultGrpcExtension @Inject constructor( dependsOn(processImportProtoTask) } - onlyIf { hasFiles } + onlyIf { !destinationFileTree.filter { it.extension == "proto" }.isEmpty } } when { @@ -310,7 +313,7 @@ internal open class DefaultGrpcExtension @Inject constructor( } name.lowercase().endsWith("test") -> { - project.protoSourceSets.getByName(correspondingMainName()) as DefaultProtoSourceSet + project.protoSourceSets.findByName(correspondingMainName()) as? DefaultProtoSourceSet } else -> { diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/DefaultProtoSourceSet.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/DefaultProtoSourceSet.kt index f8fd271f2..0c59d9f30 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/DefaultProtoSourceSet.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/DefaultProtoSourceSet.kt @@ -54,7 +54,7 @@ internal open class DefaultProtoSourceSet @Inject constructor( PROTO_SOURCE_DIRECTORY_NAME, "Proto sources", ).apply { - srcDirs("src/$name/proto") + srcDirs("src/${this@DefaultProtoSourceSet.name}/proto") } override fun proto(action: Action) { @@ -62,12 +62,7 @@ internal open class DefaultProtoSourceSet @Inject constructor( } } -internal fun Project.configureProtoExtensions( - configure: Project.( - languageSourceSet: Any, - protoSourceSet: DefaultProtoSourceSet, - ) -> Unit -) { +internal fun Project.createProtoExtensions() { fun findOrCreateAndConfigure(languageSourceSetName: String, languageSourceSet: Any) { val container = project.findOrCreate(PROTO_SOURCE_SETS) { val container = objects.domainObjectContainer( @@ -82,7 +77,7 @@ internal fun Project.configureProtoExtensions( val protoSourceSet = container.maybeCreate(languageSourceSetName) as DefaultProtoSourceSet - configure(languageSourceSet, protoSourceSet) + protoSourceSet.languageSourceSets.add(languageSourceSet) } project.withKotlinJvmExtension { @@ -109,13 +104,3 @@ internal fun Project.configureProtoExtensions( } } } - -internal fun Project.createProtoExtensions() { - configureProtoExtensions { languageSourceSet, sourceSet -> - sourceSet.initExtension(languageSourceSet) - } -} - -private fun DefaultProtoSourceSet.initExtension(languageSourceSet: Any) { - this.languageSourceSets.add(languageSourceSet) -} diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProcessProtoFiles.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProcessProtoFiles.kt index bf7d245e0..a00e42f0e 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProcessProtoFiles.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/ProcessProtoFiles.kt @@ -4,13 +4,15 @@ package kotlinx.rpc.proto +import kotlinx.rpc.util.ensureDirectoryExists +import kotlinx.rpc.util.ensureRegularFileExists import org.gradle.api.Project import org.gradle.api.file.SourceDirectorySet -import org.gradle.api.provider.Provider import org.gradle.api.tasks.Copy import org.gradle.api.tasks.TaskProvider import org.gradle.kotlin.dsl.register import java.io.File +import java.nio.file.Files /** * Copy proto files to a temporary directory for Buf to process. @@ -23,28 +25,31 @@ public abstract class ProcessProtoFiles : Copy() { internal fun Project.registerProcessProtoFilesTask( name: String, - baseGenDir: Provider, + destination: File, protoFiles: SourceDirectorySet, - toDir: String, configure: ProcessProtoFiles.() -> Unit = {}, ): TaskProvider { val capitalName = name.replaceFirstChar { it.uppercase() } return tasks.register("process${capitalName}ProtoFiles") { - val protoGenDir = baseGenDir.map { it.resolve(toDir) } - val allFiles = protoFiles.files + // this task deletes the destination directory if it results in NO-SOURCE, + // which breaks the configuration cache for bufGenerate + // so we prevent No-SOURCE by creating a .keep file in the destination directory + val keep = protoBuildDirSourceSetsKeep.ensureRegularFileExists() + from(keep) + from(protoFiles.srcDirs) { include { it.file in allFiles } } - into(protoGenDir) + into(destination) doFirst { - protoGenDir.get().deleteRecursively() + destination.deleteRecursively() } configure() diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/derictory.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/derictory.kt index 00cbe83f7..d3231e6b5 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/derictory.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/proto/derictory.kt @@ -19,6 +19,11 @@ internal val Project.protoBuildDirSourceSets: File return protoBuildDir.resolve(PROTO_BUILD_SOURCE_SETS) } +internal val Project.protoBuildDirSourceSetsKeep: File + get() { + return protoBuildDirSourceSets.resolve(".keep") + } + internal val Project.protoBuildDirGenerated: File get() { return protoBuildDir.resolve(PROTO_BUILD_GENERATED) diff --git a/gradle-plugin/src/main/kotlin/kotlinx/rpc/util/files.kt b/gradle-plugin/src/main/kotlin/kotlinx/rpc/util/files.kt index bc1a6d684..4916938be 100644 --- a/gradle-plugin/src/main/kotlin/kotlinx/rpc/util/files.kt +++ b/gradle-plugin/src/main/kotlin/kotlinx/rpc/util/files.kt @@ -7,9 +7,7 @@ package kotlinx.rpc.util import java.io.File internal fun File.ensureDirectoryExists(): File { - if (!exists()) { - mkdirs() - } + mkdirs() return this } diff --git a/kotlin-js-store/package-lock.json b/kotlin-js-store/package-lock.json index 50ab5ab3d..a0464a095 100644 --- a/kotlin-js-store/package-lock.json +++ b/kotlin-js-store/package-lock.json @@ -12,6 +12,10 @@ "packages/kotlinx-rpc-core-test", "packages/kotlinx-rpc-utils", "packages/kotlinx-rpc-utils-test", + "packages/kotlinx-rpc-grpc-grpc-core", + "packages/kotlinx-rpc-grpc-grpc-core-test", + "packages/kotlinx-rpc-grpc-grpc-ktor-server", + "packages/kotlinx-rpc-grpc-grpc-ktor-server-test", "packages/kotlinx-rpc-krpc-krpc-client", "packages/kotlinx-rpc-krpc-krpc-client-test", "packages/kotlinx-rpc-krpc-krpc-core", @@ -2386,6 +2390,22 @@ "resolved": "packages/kotlinx-rpc-core-test", "link": true }, + "node_modules/kotlinx-rpc-grpc-grpc-core": { + "resolved": "packages/kotlinx-rpc-grpc-grpc-core", + "link": true + }, + "node_modules/kotlinx-rpc-grpc-grpc-core-test": { + "resolved": "packages/kotlinx-rpc-grpc-grpc-core-test", + "link": true + }, + "node_modules/kotlinx-rpc-grpc-grpc-ktor-server": { + "resolved": "packages/kotlinx-rpc-grpc-grpc-ktor-server", + "link": true + }, + "node_modules/kotlinx-rpc-grpc-grpc-ktor-server-test": { + "resolved": "packages/kotlinx-rpc-grpc-grpc-ktor-server-test", + "link": true + }, "node_modules/kotlinx-rpc-krpc-krpc-client": { "resolved": "packages/kotlinx-rpc-krpc-krpc-client", "link": true @@ -4446,6 +4466,52 @@ "webpack-cli": "5.1.4" } }, + "packages/kotlinx-rpc-grpc-grpc-core": { + "version": "0.9.1", + "devDependencies": {} + }, + "packages/kotlinx-rpc-grpc-grpc-core-test": { + "version": "0.9.1", + "dependencies": { + "puppeteer": "24.9.0" + }, + "devDependencies": { + "karma": "6.4.4", + "karma-chrome-launcher": "3.2.0", + "karma-mocha": "2.0.1", + "karma-sourcemap-loader": "0.4.0", + "karma-webpack": "5.0.1", + "kotlin-web-helpers": "2.0.0", + "mocha": "10.7.3", + "source-map-loader": "5.0.0", + "source-map-support": "0.5.21", + "webpack": "5.94.0", + "webpack-cli": "5.1.4" + } + }, + "packages/kotlinx-rpc-grpc-grpc-ktor-server": { + "version": "0.9.1", + "devDependencies": {} + }, + "packages/kotlinx-rpc-grpc-grpc-ktor-server-test": { + "version": "0.9.1", + "dependencies": { + "puppeteer": "24.9.0" + }, + "devDependencies": { + "karma": "6.4.4", + "karma-chrome-launcher": "3.2.0", + "karma-mocha": "2.0.1", + "karma-sourcemap-loader": "0.4.0", + "karma-webpack": "5.0.1", + "kotlin-web-helpers": "2.0.0", + "mocha": "10.7.3", + "source-map-loader": "5.0.0", + "source-map-support": "0.5.21", + "webpack": "5.94.0", + "webpack-cli": "5.1.4" + } + }, "packages/kotlinx-rpc-krpc-krpc-client": { "version": "0.9.1", "devDependencies": {} diff --git a/kotlin-js-store/wasm/package-lock.json b/kotlin-js-store/wasm/package-lock.json index 1d255d66c..b868c8bf2 100644 --- a/kotlin-js-store/wasm/package-lock.json +++ b/kotlin-js-store/wasm/package-lock.json @@ -12,6 +12,10 @@ "packages/kotlinx-rpc-core-test", "packages/kotlinx-rpc-utils", "packages/kotlinx-rpc-utils-test", + "packages/kotlinx-rpc-grpc-grpc-core", + "packages/kotlinx-rpc-grpc-grpc-core-test", + "packages/kotlinx-rpc-grpc-grpc-ktor-server", + "packages/kotlinx-rpc-grpc-grpc-ktor-server-test", "packages/kotlinx-rpc-krpc-krpc-client", "packages/kotlinx-rpc-krpc-krpc-client-test", "packages/kotlinx-rpc-krpc-krpc-core", @@ -2386,6 +2390,22 @@ "resolved": "packages/kotlinx-rpc-core-test", "link": true }, + "node_modules/kotlinx-rpc-grpc-grpc-core": { + "resolved": "packages/kotlinx-rpc-grpc-grpc-core", + "link": true + }, + "node_modules/kotlinx-rpc-grpc-grpc-core-test": { + "resolved": "packages/kotlinx-rpc-grpc-grpc-core-test", + "link": true + }, + "node_modules/kotlinx-rpc-grpc-grpc-ktor-server": { + "resolved": "packages/kotlinx-rpc-grpc-grpc-ktor-server", + "link": true + }, + "node_modules/kotlinx-rpc-grpc-grpc-ktor-server-test": { + "resolved": "packages/kotlinx-rpc-grpc-grpc-ktor-server-test", + "link": true + }, "node_modules/kotlinx-rpc-krpc-krpc-client": { "resolved": "packages/kotlinx-rpc-krpc-krpc-client", "link": true @@ -4445,6 +4465,50 @@ "webpack-cli": "5.1.4" } }, + "packages/kotlinx-rpc-grpc-grpc-core": { + "version": "0.9.1", + "devDependencies": {} + }, + "packages/kotlinx-rpc-grpc-grpc-core-test": { + "version": "0.9.1", + "dependencies": { + "puppeteer": "24.9.0" + }, + "devDependencies": { + "karma": "6.4.4", + "karma-chrome-launcher": "3.2.0", + "karma-mocha": "2.0.1", + "karma-sourcemap-loader": "0.4.0", + "karma-webpack": "5.0.1", + "kotlin-web-helpers": "2.0.0", + "mocha": "10.7.3", + "source-map-loader": "5.0.0", + "webpack": "5.94.0", + "webpack-cli": "5.1.4" + } + }, + "packages/kotlinx-rpc-grpc-grpc-ktor-server": { + "version": "0.9.1", + "devDependencies": {} + }, + "packages/kotlinx-rpc-grpc-grpc-ktor-server-test": { + "version": "0.9.1", + "dependencies": { + "puppeteer": "24.9.0" + }, + "devDependencies": { + "karma": "6.4.4", + "karma-chrome-launcher": "3.2.0", + "karma-mocha": "2.0.1", + "karma-sourcemap-loader": "0.4.0", + "karma-webpack": "5.0.1", + "kotlin-web-helpers": "2.0.0", + "mocha": "10.7.3", + "source-map-loader": "5.0.0", + "webpack": "5.94.0", + "webpack-cli": "5.1.4" + } + }, "packages/kotlinx-rpc-krpc-krpc-client": { "version": "0.9.1", "devDependencies": {}