From 5bbf13d9e19386d5d613712c13e1abb78fc8f5e6 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Tue, 18 Mar 2025 10:59:11 +0000 Subject: [PATCH 01/22] chore: add platform interface and method channel implementation for Cloud Functions stream --- .../cloud_functions/lib/cloud_functions.dart | 2 ++ .../lib/src/firebase_functions.dart | 6 +++++ .../lib/src/https_callable_stream.dart | 23 ++++++++++++++++ .../lib/src/https_callable_stream_result.dart | 21 +++++++++++++++ .../cloud_functions_platform_interface.dart | 1 + .../method_channel_firebase_functions.dart | 6 +++++ ...method_channel_https_callable_streams.dart | 27 +++++++++++++++++++ ...platform_interface_firebase_functions.dart | 4 +++ ...form_interface_https_callable_streams.dart | 24 +++++++++++++++++ 9 files changed, 114 insertions(+) create mode 100644 packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart create mode 100644 packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart create mode 100644 packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart create mode 100644 packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart diff --git a/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart b/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart index 5750bd226326..4c79d7075c25 100644 --- a/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart +++ b/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart @@ -8,6 +8,7 @@ import 'dart:async'; // ignore: unnecessary_import import 'dart:typed_data'; +import 'package:cloud_functions/src/https_callable_stream_result.dart'; import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart' @@ -20,3 +21,4 @@ export 'package:cloud_functions_platform_interface/cloud_functions_platform_inte part 'src/firebase_functions.dart'; part 'src/https_callable.dart'; part 'src/https_callable_result.dart'; +part 'src/https_callable_stream.dart'; diff --git a/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart b/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart index 94a3e25e85d1..61a147957838 100644 --- a/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart @@ -96,6 +96,12 @@ class FirebaseFunctions extends FirebasePluginPlatform { delegate.httpsCallableWithUri(_origin, uri, options)); } + HttpsCallableStream httpsStreamCallable( + String name) { + assert(name.isNotEmpty); + return HttpsCallableStream._(delegate.httpsStreamCallable(name, _origin)); + } + /// Changes this instance to point to a Cloud Functions emulator running locally. /// /// Set the [host] of the local emulator, such as "localhost" diff --git a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart new file mode 100644 index 000000000000..c46a0a295be2 --- /dev/null +++ b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart @@ -0,0 +1,23 @@ +// ignore_for_file: require_trailing_commas +// Copyright 2020, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +part of '../cloud_functions.dart'; + +class HttpsCallableStream { + HttpsCallableStream._(this.delegate); + + /// Returns the underlying [HttpsCallableStream] delegate for this + /// [HttpsCallableStreamsPlatform] instance. This is useful for testing purposes only. + @visibleForTesting + final HttpsCallableStreamsPlatform delegate; + +Stream> stream(Object? input) async* { + await for (final T value in delegate.stream(input)) { + yield Chunk(value); + } +} + +// Future get data => delegate.data; +} diff --git a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart new file mode 100644 index 000000000000..2ff2bca381c4 --- /dev/null +++ b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart @@ -0,0 +1,21 @@ +// ignore_for_file: require_trailing_commas +// Copyright 2020, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:cloud_functions/cloud_functions.dart'; + +/// Represents a response from a Server-Sent Event (SSE) stream. +sealed class StreamResponse {} + +/// A chunk received during the stream. +class Chunk extends StreamResponse { + final T partialData; + Chunk(this.partialData); +} + +/// The final result of the computation, marking the end of the stream. +class Result extends StreamResponse { + final HttpsCallableResult result; + Result(this.result); +} diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/cloud_functions_platform_interface.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/cloud_functions_platform_interface.dart index 81b3072393df..60f8ea822179 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/cloud_functions_platform_interface.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/cloud_functions_platform_interface.dart @@ -7,3 +7,4 @@ export 'src/firebase_functions_exception.dart'; export 'src/https_callable_options.dart'; export 'src/platform_interface/platform_interface_firebase_functions.dart'; export 'src/platform_interface/platform_interface_https_callable.dart'; +export 'src/platform_interface/platform_interface_https_callable_streams.dart'; diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart index 8f27e436e1ff..8604a45d81ee 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart @@ -3,6 +3,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:cloud_functions_platform_interface/src/method_channel/method_channel_https_callable_streams.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/services.dart'; @@ -50,4 +51,9 @@ class MethodChannelFirebaseFunctions extends FirebaseFunctionsPlatform { String? origin, Uri uri, HttpsCallableOptions options) { return MethodChannelHttpsCallable(this, origin, null, options, uri); } + + @override + HttpsCallableStreamsPlatform httpsStreamCallable(String name, String? origin) { + return MethodChannelHttpsCallableStreams(name, origin); + } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart new file mode 100644 index 000000000000..d9b8f715a76b --- /dev/null +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart @@ -0,0 +1,27 @@ +// ignore_for_file: require_trailing_commas +// Copyright 2020, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:flutter/services.dart'; + +import '../../cloud_functions_platform_interface.dart'; + + +class MethodChannelHttpsCallableStreams + extends HttpsCallableStreamsPlatform { + + MethodChannelHttpsCallableStreams(String name, String? origin) + : _channel = EventChannel('plugins.flutter.io/firebase_functions/$name'), + super(name, origin); + + final EventChannel _channel; + + @override + Stream stream(Object? object) { + return _channel.receiveBroadcastStream(object).cast(); + } + + @override + Future get data => throw UnimplementedError(); +} diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart index f8339facf7ad..2ae0adb32f20 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart @@ -72,4 +72,8 @@ abstract class FirebaseFunctionsPlatform extends PlatformInterface { String? origin, Uri uri, HttpsCallableOptions options) { throw UnimplementedError('httpsCallable() is not implemented'); } + + HttpsCallableStreamsPlatform httpsStreamCallable(String name, String? origin) { + throw UnimplementedError('httpsCallable() is not implemented'); + } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart new file mode 100644 index 000000000000..f47bbdb033b1 --- /dev/null +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart @@ -0,0 +1,24 @@ +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +abstract class HttpsCallableStreamsPlatform extends PlatformInterface { + HttpsCallableStreamsPlatform( + this.name, + this.origin, + ) : super(token: _token); + + static final Object _token = Object(); + + static void verify(HttpsCallableStreamsPlatform instance) { + PlatformInterface.verify(instance, _token); + } + + /// The [origin] of the local emulator, such as "http://localhost:5001" + final String? origin; + + /// The name of the function (required, non-nullable) + final String name; + + Stream stream(Object? object); + + Future get data; +} From 24acdda0c1ea4de049c5aee7b022bc74227f98c6 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Tue, 18 Mar 2025 15:39:29 +0000 Subject: [PATCH 02/22] chore: add `httpsCallableStreamFromUrl` and `httpsStreamCallableWithUri` --- .../lib/src/firebase_functions.dart | 25 +++++++++++++++++-- .../method_channel_firebase_functions.dart | 9 +++++-- ...method_channel_https_callable_streams.dart | 6 ++--- ...platform_interface_firebase_functions.dart | 10 +++++++- ...form_interface_https_callable_streams.dart | 11 +++++--- 5 files changed, 49 insertions(+), 12 deletions(-) diff --git a/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart b/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart index 61a147957838..ea9e84f53d72 100644 --- a/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart @@ -96,10 +96,31 @@ class FirebaseFunctions extends FirebasePluginPlatform { delegate.httpsCallableWithUri(_origin, uri, options)); } + /// A reference to the streaming Callable HTTPS trigger with the given name. + /// + /// Should be the name of the Callable function in Firebase that supports streaming. HttpsCallableStream httpsStreamCallable( - String name) { + String name, + ) { assert(name.isNotEmpty); - return HttpsCallableStream._(delegate.httpsStreamCallable(name, _origin)); + return HttpsCallableStream._(delegate.httpsStreamCallable(_origin, name)); + } + + /// A reference to the streaming Callable HTTPS trigger with the given name. + /// + /// Should be URL of the 2nd gen Callable function in Firebase. + HttpsCallableStream httpsCallableStreamFromUrl(String url) { + final uri = Uri.parse(url); + return HttpsCallableStream._( + delegate.httpsStreamCallableWithUri(_origin, uri)); + } + + /// A reference to the streaming Callable HTTPS trigger with the given name. + /// + /// Should be Uri of the 2nd gen Callable function in Firebase. + HttpsCallableStream httpsCallableStreamFromUri(Uri uri) { + return HttpsCallableStream._( + delegate.httpsStreamCallableWithUri(_origin, uri)); } /// Changes this instance to point to a Cloud Functions emulator running locally. diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart index 8604a45d81ee..c23335270af0 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart @@ -53,7 +53,12 @@ class MethodChannelFirebaseFunctions extends FirebaseFunctionsPlatform { } @override - HttpsCallableStreamsPlatform httpsStreamCallable(String name, String? origin) { - return MethodChannelHttpsCallableStreams(name, origin); + HttpsCallableStreamsPlatform httpsStreamCallable(String? origin, String name) { + return MethodChannelHttpsCallableStreams(origin, name, null); + } + + @override + HttpsCallableStreamsPlatform httpsStreamCallableWithUri(String? origin, Uri uri) { + return MethodChannelHttpsCallableStreams(origin, null, uri); } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart index d9b8f715a76b..1d9f0a3562ef 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart @@ -7,13 +7,11 @@ import 'package:flutter/services.dart'; import '../../cloud_functions_platform_interface.dart'; - class MethodChannelHttpsCallableStreams extends HttpsCallableStreamsPlatform { - - MethodChannelHttpsCallableStreams(String name, String? origin) + MethodChannelHttpsCallableStreams(String? name, String? origin, Uri? uri) : _channel = EventChannel('plugins.flutter.io/firebase_functions/$name'), - super(name, origin); + super(origin, name, uri); final EventChannel _channel; diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart index 2ae0adb32f20..46569aab59aa 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart @@ -73,7 +73,15 @@ abstract class FirebaseFunctionsPlatform extends PlatformInterface { throw UnimplementedError('httpsCallable() is not implemented'); } - HttpsCallableStreamsPlatform httpsStreamCallable(String name, String? origin) { + HttpsCallableStreamsPlatform httpsStreamCallable( + String? origin, + String name, + ) { throw UnimplementedError('httpsCallable() is not implemented'); } + + HttpsCallableStreamsPlatform httpsStreamCallableWithUri( + String? origin, Uri uri) { + throw UnimplementedError('httpsStreamCallableWithUri() is not implemented'); + } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart index f47bbdb033b1..facae3b12fbc 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart @@ -2,9 +2,11 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart'; abstract class HttpsCallableStreamsPlatform extends PlatformInterface { HttpsCallableStreamsPlatform( - this.name, this.origin, - ) : super(token: _token); + this.name, + this.uri, + ) : assert(name != null || uri != null), + super(token: _token); static final Object _token = Object(); @@ -16,7 +18,10 @@ abstract class HttpsCallableStreamsPlatform extends PlatformInterface { final String? origin; /// The name of the function (required, non-nullable) - final String name; + final String? name; + + /// The URI of the function for 2nd gen functions + final Uri? uri; Stream stream(Object? object); From fa00dd9620236990fd5b7ddfdd10871994ce3899 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Fri, 21 Mar 2025 13:21:54 +0000 Subject: [PATCH 03/22] chore: resolve comments --- .../method_channel_https_callable_streams.dart | 6 +++--- .../lib/src/method_channel/utils/extensions.dart | 10 ++++++++++ .../platform_interface_https_callable_streams.dart | 5 +++++ .../firebase_core/android/gradle.properties | 2 +- 4 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/utils/extensions.dart diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart index 1d9f0a3562ef..12c4211d3003 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart @@ -4,13 +4,13 @@ // BSD-style license that can be found in the LICENSE file. import 'package:flutter/services.dart'; - import '../../cloud_functions_platform_interface.dart'; +import 'package:cloud_functions_platform_interface/src/method_channel/utils/extensions.dart'; class MethodChannelHttpsCallableStreams extends HttpsCallableStreamsPlatform { - MethodChannelHttpsCallableStreams(String? name, String? origin, Uri? uri) - : _channel = EventChannel('plugins.flutter.io/firebase_functions/$name'), + MethodChannelHttpsCallableStreams(String? origin, String? name, Uri? uri) + : _channel = EventChannel('plugins.flutter.io/firebase_functions/${name ?? uri?.toChannelPath()}'), super(origin, name, uri); final EventChannel _channel; diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/utils/extensions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/utils/extensions.dart new file mode 100644 index 000000000000..b66edfb64542 --- /dev/null +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/utils/extensions.dart @@ -0,0 +1,10 @@ +// ignore_for_file: require_trailing_commas +// Copyright 2020, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +extension FirebaseFunctionUriExtension on Uri { + String toChannelPath() { + return path.replaceAll('/', '_').replaceAll('.', '_'); + } +} diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart index facae3b12fbc..c118a75bbe4b 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart @@ -1,3 +1,8 @@ +// ignore_for_file: require_trailing_commas +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + import 'package:plugin_platform_interface/plugin_platform_interface.dart'; abstract class HttpsCallableStreamsPlatform extends PlatformInterface { diff --git a/packages/firebase_core/firebase_core/android/gradle.properties b/packages/firebase_core/firebase_core/android/gradle.properties index e076daec0a3f..0e9e14c660ae 100644 --- a/packages/firebase_core/firebase_core/android/gradle.properties +++ b/packages/firebase_core/firebase_core/android/gradle.properties @@ -1,2 +1,2 @@ # https://firebase.google.com/support/release-notes/android -FirebaseSDKVersion=33.9.0 +FirebaseSDKVersion=33.11.0 From fa750ed7b564ce3acc1ee1e9599648f3c7b8147c Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Fri, 21 Mar 2025 16:12:52 +0000 Subject: [PATCH 04/22] chore: add Android implementation for Cloud Functions stream --- .../FlutterFirebaseFunctionsPlugin.java | 164 +++++++++++------- .../method_channel_firebase_functions.dart | 4 +- ...method_channel_https_callable_streams.dart | 32 +++- .../src/method_channel/utils/extensions.dart | 10 -- ...form_interface_https_callable_streams.dart | 5 + .../firebase_core/android/gradle.properties | 2 +- 6 files changed, 136 insertions(+), 81 deletions(-) delete mode 100644 packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/utils/extensions.dart diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java index e93575011d84..fa4341d27f83 100644 --- a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java @@ -5,8 +5,10 @@ package io.flutter.plugins.firebase.functions; import android.net.Uri; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; + import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.TaskCompletionSource; import com.google.android.gms.tasks.Tasks; @@ -16,14 +18,18 @@ import com.google.firebase.functions.HttpsCallableOptions; import com.google.firebase.functions.HttpsCallableReference; import com.google.firebase.functions.HttpsCallableResult; + import io.flutter.embedding.engine.plugins.FlutterPlugin; +import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugins.firebase.core.FlutterFirebasePlugin; + import java.io.IOException; import java.io.InterruptedIOException; +import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map; @@ -31,20 +37,28 @@ import java.util.concurrent.TimeUnit; public class FlutterFirebaseFunctionsPlugin - implements FlutterPlugin, FlutterFirebasePlugin, MethodCallHandler { + implements FlutterPlugin, FlutterFirebasePlugin, MethodCallHandler, EventChannel.StreamHandler { private static final String METHOD_CHANNEL_NAME = "plugins.flutter.io/firebase_functions"; private MethodChannel channel; + private FlutterPluginBinding pluginBinding; + + private FirebaseFunctions firebaseFunctions; + + private @Nullable String functionName; + private @Nullable String functionUri; /** * Default Constructor. * *

Use this when adding the plugin to your FlutterEngine */ - public FlutterFirebaseFunctionsPlugin() {} + public FlutterFirebaseFunctionsPlugin() { + } @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { + pluginBinding = binding; channel = new MethodChannel(binding.getBinaryMessenger(), METHOD_CHANNEL_NAME); channel.setMethodCallHandler(this); } @@ -55,6 +69,19 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { channel = null; } + private void setupEventChannel(Map arguments) { + final String eventId = (String) Objects.requireNonNull(arguments.get("eventId")); + final String eventChannelName = METHOD_CHANNEL_NAME + "/" + eventId; + final EventChannel eventChannel = new EventChannel(pluginBinding.getBinaryMessenger(), eventChannelName); + eventChannel.setStreamHandler(this); + } + + private void retrieveArguments(Map arguments) { + firebaseFunctions = getFunctions(arguments); + functionName = (String) arguments.get("functionName"); + functionUri = (String) arguments.get("functionUri"); + } + private FirebaseFunctions getFunctions(Map arguments) { String appName = (String) Objects.requireNonNull(arguments.get("appName")); String region = (String) Objects.requireNonNull(arguments.get("region")); @@ -66,74 +93,79 @@ private Task httpsFunctionCall(Map arguments) { TaskCompletionSource taskCompletionSource = new TaskCompletionSource<>(); cachedThreadPool.execute( - () -> { - try { - - FirebaseFunctions firebaseFunctions = getFunctions(arguments); - - String functionName = (String) arguments.get("functionName"); - String functionUri = (String) arguments.get("functionUri"); - String origin = (String) arguments.get("origin"); - Integer timeout = (Integer) arguments.get("timeout"); - boolean limitedUseAppCheckToken = - (boolean) Objects.requireNonNull(arguments.get("limitedUseAppCheckToken")); - Object parameters = arguments.get("parameters"); - - if (origin != null) { - Uri originUri = Uri.parse(origin); - firebaseFunctions.useEmulator(originUri.getHost(), originUri.getPort()); - } + () -> { + try { + + FirebaseFunctions firebaseFunctions = getFunctions(arguments); + + String functionName = (String) arguments.get("functionName"); + String functionUri = (String) arguments.get("functionUri"); + String origin = (String) arguments.get("origin"); + Integer timeout = (Integer) arguments.get("timeout"); + boolean limitedUseAppCheckToken = + (boolean) Objects.requireNonNull(arguments.get("limitedUseAppCheckToken")); + Object parameters = arguments.get("parameters"); + + if (origin != null) { + Uri originUri = Uri.parse(origin); + firebaseFunctions.useEmulator(originUri.getHost(), originUri.getPort()); + } - HttpsCallableReference httpsCallableReference; - HttpsCallableOptions options = - new HttpsCallableOptions.Builder() - .setLimitedUseAppCheckTokens(limitedUseAppCheckToken) - .build(); - - if (functionName != null) { - httpsCallableReference = firebaseFunctions.getHttpsCallable(functionName, options); - } else if (functionUri != null) { - httpsCallableReference = - firebaseFunctions.getHttpsCallableFromUrl(new URL(functionUri), options); - } else { - throw new IllegalArgumentException("Either functionName or functionUri must be set"); - } + HttpsCallableReference httpsCallableReference; + HttpsCallableOptions options = + new HttpsCallableOptions.Builder() + .setLimitedUseAppCheckTokens(limitedUseAppCheckToken) + .build(); + + if (functionName != null) { + httpsCallableReference = firebaseFunctions.getHttpsCallable(functionName, options); + } else if (functionUri != null) { + httpsCallableReference = + firebaseFunctions.getHttpsCallableFromUrl(new URL(functionUri), options); + } else { + throw new IllegalArgumentException("Either functionName or functionUri must be set"); + } - if (timeout != null) { - httpsCallableReference.setTimeout(timeout.longValue(), TimeUnit.MILLISECONDS); - } + if (timeout != null) { + httpsCallableReference.setTimeout(timeout.longValue(), TimeUnit.MILLISECONDS); + } - HttpsCallableResult result = Tasks.await(httpsCallableReference.call(parameters)); - taskCompletionSource.setResult(result.getData()); + HttpsCallableResult result = Tasks.await(httpsCallableReference.call(parameters)); + taskCompletionSource.setResult(result.getData()); - } catch (Exception e) { - taskCompletionSource.setException(e); - } - }); + } catch (Exception e) { + taskCompletionSource.setException(e); + } + }); return taskCompletionSource.getTask(); } @Override public void onMethodCall(MethodCall call, @NonNull final Result result) { - if (!call.method.equals("FirebaseFunctions#call")) { + if (call.method.equals("FirebaseFunctions#setEventChannelId")) { + assert call.arguments() != null; + setupEventChannel(call.arguments()); + retrieveArguments(call.arguments()); + } else if (!call.method.equals("FirebaseFunctions#call")) { + httpsFunctionCall(call.arguments()) + .addOnCompleteListener( + task -> { + if (task.isSuccessful()) { + result.success(task.getResult()); + } else { + Exception exception = task.getException(); + result.error( + "firebase_functions", + exception != null ? exception.getMessage() : null, + getExceptionDetails(exception)); + } + }); + } else { result.notImplemented(); - return; } - httpsFunctionCall(call.arguments()) - .addOnCompleteListener( - task -> { - if (task.isSuccessful()) { - result.success(task.getResult()); - } else { - Exception exception = task.getException(); - result.error( - "firebase_functions", - exception != null ? exception.getMessage() : null, - getExceptionDetails(exception)); - } - }); + } private Map getExceptionDetails(@Nullable Exception exception) { @@ -149,19 +181,19 @@ private Map getExceptionDetails(@Nullable Exception exception) { if (exception.getCause() instanceof FirebaseFunctionsException) { FirebaseFunctionsException functionsException = - (FirebaseFunctionsException) exception.getCause(); + (FirebaseFunctionsException) exception.getCause(); code = functionsException.getCode().name(); message = functionsException.getMessage(); additionalData = functionsException.getDetails(); if (functionsException.getCause() instanceof IOException - && "Canceled".equals(functionsException.getCause().getMessage())) { + && "Canceled".equals(functionsException.getCause().getMessage())) { // return DEADLINE_EXCEEDED for IOException cancel errors, to match iOS & Web code = FirebaseFunctionsException.Code.DEADLINE_EXCEEDED.name(); message = FirebaseFunctionsException.Code.DEADLINE_EXCEEDED.name(); } else if (functionsException.getCause() instanceof InterruptedIOException - // return DEADLINE_EXCEEDED for InterruptedIOException errors, to match iOS & Web - && "timeout".equals(functionsException.getCause().getMessage())) { + // return DEADLINE_EXCEEDED for InterruptedIOException errors, to match iOS & Web + && "timeout".equals(functionsException.getCause().getMessage())) { code = FirebaseFunctionsException.Code.DEADLINE_EXCEEDED.name(); message = FirebaseFunctionsException.Code.DEADLINE_EXCEEDED.name(); } else if (functionsException.getCause() instanceof IOException) { @@ -198,4 +230,14 @@ public Task didReinitializeFirebaseCore() { return taskCompletionSource.getTask(); } + + @Override + public void onListen(Object arguments, EventChannel.EventSink events) { + // TODO: Implement callable streams + } + + @Override + public void onCancel(Object arguments) { + + } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart index c23335270af0..b893f0e2a06f 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart @@ -54,11 +54,11 @@ class MethodChannelFirebaseFunctions extends FirebaseFunctionsPlatform { @override HttpsCallableStreamsPlatform httpsStreamCallable(String? origin, String name) { - return MethodChannelHttpsCallableStreams(origin, name, null); + return MethodChannelHttpsCallableStreams(this, origin, name, null); } @override HttpsCallableStreamsPlatform httpsStreamCallableWithUri(String? origin, Uri uri) { - return MethodChannelHttpsCallableStreams(origin, null, uri); + return MethodChannelHttpsCallableStreams(this, origin, null, uri); } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart index 12c4211d3003..ba519892dc0f 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart @@ -3,21 +3,39 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'package:cloud_functions_platform_interface/src/method_channel/method_channel_firebase_functions.dart'; +import 'package:cloud_functions_platform_interface/src/method_channel/utils/exception.dart'; import 'package:flutter/services.dart'; import '../../cloud_functions_platform_interface.dart'; -import 'package:cloud_functions_platform_interface/src/method_channel/utils/extensions.dart'; class MethodChannelHttpsCallableStreams extends HttpsCallableStreamsPlatform { - MethodChannelHttpsCallableStreams(String? origin, String? name, Uri? uri) - : _channel = EventChannel('plugins.flutter.io/firebase_functions/${name ?? uri?.toChannelPath()}'), - super(origin, name, uri); + MethodChannelHttpsCallableStreams(FirebaseFunctionsPlatform functions, + String? origin, String? name, Uri? uri) + : _eventChannelId = uri?.pathSegments.join('_').replaceAll('.', '_') ?? '', + super(functions, origin, name, uri) { + _channel = EventChannel( + 'plugins.flutter.io/firebase_functions/${name ?? _eventChannelId}'); + } - final EventChannel _channel; + late final EventChannel _channel; + final String _eventChannelId; @override - Stream stream(Object? object) { - return _channel.receiveBroadcastStream(object).cast(); + Stream stream(Object? object) async* { + try { + await MethodChannelFirebaseFunctions.channel + .invokeMethod('FirebaseFunctions#setEventChannelId', { + 'eventChannelId': _eventChannelId, + 'appName': functions.app!.name, + 'functionName': name, + 'functionUri': uri?.toString(), + 'origin': origin, + }); + yield* _channel.receiveBroadcastStream(object).cast(); + } catch (e, s) { + convertPlatformException(e, s); + } } @override diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/utils/extensions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/utils/extensions.dart deleted file mode 100644 index b66edfb64542..000000000000 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/utils/extensions.dart +++ /dev/null @@ -1,10 +0,0 @@ -// ignore_for_file: require_trailing_commas -// Copyright 2020, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -extension FirebaseFunctionUriExtension on Uri { - String toChannelPath() { - return path.replaceAll('/', '_').replaceAll('.', '_'); - } -} diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart index c118a75bbe4b..e24b3e7aa71b 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart @@ -3,10 +3,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; abstract class HttpsCallableStreamsPlatform extends PlatformInterface { HttpsCallableStreamsPlatform( + this.functions, this.origin, this.name, this.uri, @@ -19,6 +21,9 @@ abstract class HttpsCallableStreamsPlatform extends PlatformInterface { PlatformInterface.verify(instance, _token); } + /// The [FirebaseFunctionsPlatform] instance. + final FirebaseFunctionsPlatform functions; + /// The [origin] of the local emulator, such as "http://localhost:5001" final String? origin; diff --git a/packages/firebase_core/firebase_core/android/gradle.properties b/packages/firebase_core/firebase_core/android/gradle.properties index 0e9e14c660ae..e076daec0a3f 100644 --- a/packages/firebase_core/firebase_core/android/gradle.properties +++ b/packages/firebase_core/firebase_core/android/gradle.properties @@ -1,2 +1,2 @@ # https://firebase.google.com/support/release-notes/android -FirebaseSDKVersion=33.11.0 +FirebaseSDKVersion=33.9.0 From 3e8ac293a63b50404bf2c58cc6036927b379c1d5 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Fri, 21 Mar 2025 16:15:40 +0000 Subject: [PATCH 05/22] chore: resolve formatting issues --- .../FlutterFirebaseFunctionsPlugin.java | 131 ++++++++---------- .../lib/src/https_callable_stream.dart | 8 +- .../method_channel_firebase_functions.dart | 10 +- ...method_channel_https_callable_streams.dart | 7 +- 4 files changed, 75 insertions(+), 81 deletions(-) diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java index fa4341d27f83..79c57800f808 100644 --- a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java @@ -5,10 +5,8 @@ package io.flutter.plugins.firebase.functions; import android.net.Uri; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; - import com.google.android.gms.tasks.Task; import com.google.android.gms.tasks.TaskCompletionSource; import com.google.android.gms.tasks.Tasks; @@ -18,7 +16,6 @@ import com.google.firebase.functions.HttpsCallableOptions; import com.google.firebase.functions.HttpsCallableReference; import com.google.firebase.functions.HttpsCallableResult; - import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodCall; @@ -26,10 +23,8 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugins.firebase.core.FlutterFirebasePlugin; - import java.io.IOException; import java.io.InterruptedIOException; -import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map; @@ -37,7 +32,7 @@ import java.util.concurrent.TimeUnit; public class FlutterFirebaseFunctionsPlugin - implements FlutterPlugin, FlutterFirebasePlugin, MethodCallHandler, EventChannel.StreamHandler { + implements FlutterPlugin, FlutterFirebasePlugin, MethodCallHandler, EventChannel.StreamHandler { private static final String METHOD_CHANNEL_NAME = "plugins.flutter.io/firebase_functions"; private MethodChannel channel; @@ -53,8 +48,7 @@ public class FlutterFirebaseFunctionsPlugin * *

Use this when adding the plugin to your FlutterEngine */ - public FlutterFirebaseFunctionsPlugin() { - } + public FlutterFirebaseFunctionsPlugin() {} @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { @@ -72,7 +66,8 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { private void setupEventChannel(Map arguments) { final String eventId = (String) Objects.requireNonNull(arguments.get("eventId")); final String eventChannelName = METHOD_CHANNEL_NAME + "/" + eventId; - final EventChannel eventChannel = new EventChannel(pluginBinding.getBinaryMessenger(), eventChannelName); + final EventChannel eventChannel = + new EventChannel(pluginBinding.getBinaryMessenger(), eventChannelName); eventChannel.setStreamHandler(this); } @@ -93,50 +88,50 @@ private Task httpsFunctionCall(Map arguments) { TaskCompletionSource taskCompletionSource = new TaskCompletionSource<>(); cachedThreadPool.execute( - () -> { - try { - - FirebaseFunctions firebaseFunctions = getFunctions(arguments); - - String functionName = (String) arguments.get("functionName"); - String functionUri = (String) arguments.get("functionUri"); - String origin = (String) arguments.get("origin"); - Integer timeout = (Integer) arguments.get("timeout"); - boolean limitedUseAppCheckToken = - (boolean) Objects.requireNonNull(arguments.get("limitedUseAppCheckToken")); - Object parameters = arguments.get("parameters"); - - if (origin != null) { - Uri originUri = Uri.parse(origin); - firebaseFunctions.useEmulator(originUri.getHost(), originUri.getPort()); - } + () -> { + try { + + FirebaseFunctions firebaseFunctions = getFunctions(arguments); + + String functionName = (String) arguments.get("functionName"); + String functionUri = (String) arguments.get("functionUri"); + String origin = (String) arguments.get("origin"); + Integer timeout = (Integer) arguments.get("timeout"); + boolean limitedUseAppCheckToken = + (boolean) Objects.requireNonNull(arguments.get("limitedUseAppCheckToken")); + Object parameters = arguments.get("parameters"); + + if (origin != null) { + Uri originUri = Uri.parse(origin); + firebaseFunctions.useEmulator(originUri.getHost(), originUri.getPort()); + } - HttpsCallableReference httpsCallableReference; - HttpsCallableOptions options = - new HttpsCallableOptions.Builder() - .setLimitedUseAppCheckTokens(limitedUseAppCheckToken) - .build(); - - if (functionName != null) { - httpsCallableReference = firebaseFunctions.getHttpsCallable(functionName, options); - } else if (functionUri != null) { - httpsCallableReference = - firebaseFunctions.getHttpsCallableFromUrl(new URL(functionUri), options); - } else { - throw new IllegalArgumentException("Either functionName or functionUri must be set"); - } + HttpsCallableReference httpsCallableReference; + HttpsCallableOptions options = + new HttpsCallableOptions.Builder() + .setLimitedUseAppCheckTokens(limitedUseAppCheckToken) + .build(); + + if (functionName != null) { + httpsCallableReference = firebaseFunctions.getHttpsCallable(functionName, options); + } else if (functionUri != null) { + httpsCallableReference = + firebaseFunctions.getHttpsCallableFromUrl(new URL(functionUri), options); + } else { + throw new IllegalArgumentException("Either functionName or functionUri must be set"); + } - if (timeout != null) { - httpsCallableReference.setTimeout(timeout.longValue(), TimeUnit.MILLISECONDS); - } + if (timeout != null) { + httpsCallableReference.setTimeout(timeout.longValue(), TimeUnit.MILLISECONDS); + } - HttpsCallableResult result = Tasks.await(httpsCallableReference.call(parameters)); - taskCompletionSource.setResult(result.getData()); + HttpsCallableResult result = Tasks.await(httpsCallableReference.call(parameters)); + taskCompletionSource.setResult(result.getData()); - } catch (Exception e) { - taskCompletionSource.setException(e); - } - }); + } catch (Exception e) { + taskCompletionSource.setException(e); + } + }); return taskCompletionSource.getTask(); } @@ -149,23 +144,21 @@ public void onMethodCall(MethodCall call, @NonNull final Result result) { retrieveArguments(call.arguments()); } else if (!call.method.equals("FirebaseFunctions#call")) { httpsFunctionCall(call.arguments()) - .addOnCompleteListener( - task -> { - if (task.isSuccessful()) { - result.success(task.getResult()); - } else { - Exception exception = task.getException(); - result.error( - "firebase_functions", - exception != null ? exception.getMessage() : null, - getExceptionDetails(exception)); - } - }); + .addOnCompleteListener( + task -> { + if (task.isSuccessful()) { + result.success(task.getResult()); + } else { + Exception exception = task.getException(); + result.error( + "firebase_functions", + exception != null ? exception.getMessage() : null, + getExceptionDetails(exception)); + } + }); } else { result.notImplemented(); } - - } private Map getExceptionDetails(@Nullable Exception exception) { @@ -181,19 +174,19 @@ private Map getExceptionDetails(@Nullable Exception exception) { if (exception.getCause() instanceof FirebaseFunctionsException) { FirebaseFunctionsException functionsException = - (FirebaseFunctionsException) exception.getCause(); + (FirebaseFunctionsException) exception.getCause(); code = functionsException.getCode().name(); message = functionsException.getMessage(); additionalData = functionsException.getDetails(); if (functionsException.getCause() instanceof IOException - && "Canceled".equals(functionsException.getCause().getMessage())) { + && "Canceled".equals(functionsException.getCause().getMessage())) { // return DEADLINE_EXCEEDED for IOException cancel errors, to match iOS & Web code = FirebaseFunctionsException.Code.DEADLINE_EXCEEDED.name(); message = FirebaseFunctionsException.Code.DEADLINE_EXCEEDED.name(); } else if (functionsException.getCause() instanceof InterruptedIOException - // return DEADLINE_EXCEEDED for InterruptedIOException errors, to match iOS & Web - && "timeout".equals(functionsException.getCause().getMessage())) { + // return DEADLINE_EXCEEDED for InterruptedIOException errors, to match iOS & Web + && "timeout".equals(functionsException.getCause().getMessage())) { code = FirebaseFunctionsException.Code.DEADLINE_EXCEEDED.name(); message = FirebaseFunctionsException.Code.DEADLINE_EXCEEDED.name(); } else if (functionsException.getCause() instanceof IOException) { @@ -237,7 +230,5 @@ public void onListen(Object arguments, EventChannel.EventSink events) { } @Override - public void onCancel(Object arguments) { - - } + public void onCancel(Object arguments) {} } diff --git a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart index c46a0a295be2..c5eec6bbce56 100644 --- a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart +++ b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart @@ -13,11 +13,11 @@ class HttpsCallableStream { @visibleForTesting final HttpsCallableStreamsPlatform delegate; -Stream> stream(Object? input) async* { - await for (final T value in delegate.stream(input)) { - yield Chunk(value); + Stream> stream(Object? input) async* { + await for (final T value in delegate.stream(input)) { + yield Chunk(value); + } } -} // Future get data => delegate.data; } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart index b893f0e2a06f..18f7cfc7a3e7 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart @@ -53,12 +53,14 @@ class MethodChannelFirebaseFunctions extends FirebaseFunctionsPlatform { } @override - HttpsCallableStreamsPlatform httpsStreamCallable(String? origin, String name) { - return MethodChannelHttpsCallableStreams(this, origin, name, null); + HttpsCallableStreamsPlatform httpsStreamCallable( + String? origin, String name) { + return MethodChannelHttpsCallableStreams(this, origin, name, null); } @override - HttpsCallableStreamsPlatform httpsStreamCallableWithUri(String? origin, Uri uri) { - return MethodChannelHttpsCallableStreams(this, origin, null, uri); + HttpsCallableStreamsPlatform httpsStreamCallableWithUri( + String? origin, Uri uri) { + return MethodChannelHttpsCallableStreams(this, origin, null, uri); } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart index ba519892dc0f..67433e973206 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart @@ -12,7 +12,8 @@ class MethodChannelHttpsCallableStreams extends HttpsCallableStreamsPlatform { MethodChannelHttpsCallableStreams(FirebaseFunctionsPlatform functions, String? origin, String? name, Uri? uri) - : _eventChannelId = uri?.pathSegments.join('_').replaceAll('.', '_') ?? '', + : _eventChannelId = + uri?.pathSegments.join('_').replaceAll('.', '_') ?? '', super(functions, origin, name, uri) { _channel = EventChannel( 'plugins.flutter.io/firebase_functions/${name ?? _eventChannelId}'); @@ -24,8 +25,8 @@ class MethodChannelHttpsCallableStreams @override Stream stream(Object? object) async* { try { - await MethodChannelFirebaseFunctions.channel - .invokeMethod('FirebaseFunctions#setEventChannelId', { + await MethodChannelFirebaseFunctions.channel.invokeMethod( + 'FirebaseFunctions#setEventChannelId', { 'eventChannelId': _eventChannelId, 'appName': functions.app!.name, 'functionName': name, From c248cd6e10e65f5b84dea77eb6b4a17f8452c95a Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Fri, 21 Mar 2025 16:32:07 +0000 Subject: [PATCH 06/22] chore: correct variable name --- .../firebase/functions/FlutterFirebaseFunctionsPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java index 79c57800f808..121cdd261b6a 100644 --- a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java @@ -64,7 +64,7 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { } private void setupEventChannel(Map arguments) { - final String eventId = (String) Objects.requireNonNull(arguments.get("eventId")); + final String eventId = (String) Objects.requireNonNull(arguments.get("eventChannelId")); final String eventChannelName = METHOD_CHANNEL_NAME + "/" + eventId; final EventChannel eventChannel = new EventChannel(pluginBinding.getBinaryMessenger(), eventChannelName); From 1ac4533f170c517dc2d4d708a068eb8e9bf74197 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Sun, 23 Mar 2025 23:05:36 +0000 Subject: [PATCH 07/22] chore: add support for Cloud Functions Stream(Android) --- .../cloud_functions/android/build.gradle | 1 + .../FlutterFirebaseFunctionsPlugin.java | 75 ++++++++++++++----- .../functions/StreamResponseSubscriber.java | 72 ++++++++++++++++++ .../lib/src/https_callable_stream.dart | 7 +- ...method_channel_https_callable_streams.dart | 43 ++++++++--- ...form_interface_https_callable_streams.dart | 4 +- 6 files changed, 168 insertions(+), 34 deletions(-) create mode 100644 packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java diff --git a/packages/cloud_functions/cloud_functions/android/build.gradle b/packages/cloud_functions/cloud_functions/android/build.gradle index 6b840fd6ca6f..23c3411b6c46 100644 --- a/packages/cloud_functions/cloud_functions/android/build.gradle +++ b/packages/cloud_functions/cloud_functions/android/build.gradle @@ -64,6 +64,7 @@ android { implementation platform("com.google.firebase:firebase-bom:${getRootProjectExtOrCoreProperty("FirebaseSDKVersion", firebaseCoreProject)}") implementation 'com.google.firebase:firebase-functions' implementation 'androidx.annotation:annotation:1.7.0' + implementation 'org.reactivestreams:reactive-streams:1.0.4' } } diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java index 121cdd261b6a..42976b9fdc97 100644 --- a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java @@ -16,6 +16,7 @@ import com.google.firebase.functions.HttpsCallableOptions; import com.google.firebase.functions.HttpsCallableReference; import com.google.firebase.functions.HttpsCallableResult; +import com.google.firebase.functions.StreamResponse; import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodCall; @@ -30,6 +31,7 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.TimeUnit; +import org.reactivestreams.Publisher; public class FlutterFirebaseFunctionsPlugin implements FlutterPlugin, FlutterFirebasePlugin, MethodCallHandler, EventChannel.StreamHandler { @@ -38,10 +40,7 @@ public class FlutterFirebaseFunctionsPlugin private MethodChannel channel; private FlutterPluginBinding pluginBinding; - private FirebaseFunctions firebaseFunctions; - - private @Nullable String functionName; - private @Nullable String functionUri; + private StreamResponseSubscriber subscriber; /** * Default Constructor. @@ -63,7 +62,7 @@ public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { channel = null; } - private void setupEventChannel(Map arguments) { + private void registerEventChannel(Map arguments) { final String eventId = (String) Objects.requireNonNull(arguments.get("eventChannelId")); final String eventChannelName = METHOD_CHANNEL_NAME + "/" + eventId; final EventChannel eventChannel = @@ -71,12 +70,6 @@ private void setupEventChannel(Map arguments) { eventChannel.setStreamHandler(this); } - private void retrieveArguments(Map arguments) { - firebaseFunctions = getFunctions(arguments); - functionName = (String) arguments.get("functionName"); - functionUri = (String) arguments.get("functionUri"); - } - private FirebaseFunctions getFunctions(Map arguments) { String appName = (String) Objects.requireNonNull(arguments.get("appName")); String region = (String) Objects.requireNonNull(arguments.get("region")); @@ -136,13 +129,26 @@ private Task httpsFunctionCall(Map arguments) { return taskCompletionSource.getTask(); } + private void getCompleteResult(Result result) { + cachedThreadPool.execute( + () -> { + try { + Object completeResult = subscriber.getResult(); + result.success(completeResult); + } catch (Exception e) { + result.error("firebase_functions", e.getMessage(), getExceptionDetails(e)); + } + }); + } + @Override public void onMethodCall(MethodCall call, @NonNull final Result result) { - if (call.method.equals("FirebaseFunctions#setEventChannelId")) { - assert call.arguments() != null; - setupEventChannel(call.arguments()); - retrieveArguments(call.arguments()); - } else if (!call.method.equals("FirebaseFunctions#call")) { + if (call.method.equals("FirebaseFunctions#registerEventChannel")) { + registerEventChannel(call.arguments()); + result.success(null); + } else if (call.method.equals("FirebaseFunctions#getCompleteResult")) { + getCompleteResult(result); + } else if (call.method.equals("FirebaseFunctions#call")) { httpsFunctionCall(call.arguments()) .addOnCompleteListener( task -> { @@ -226,9 +232,42 @@ public Task didReinitializeFirebaseCore() { @Override public void onListen(Object arguments, EventChannel.EventSink events) { - // TODO: Implement callable streams + @SuppressWarnings("unchecked") + Map argumentsMap = (Map) arguments; + httpsStreamCall(argumentsMap, events); + } + + private void httpsStreamCall(Map arguments, EventChannel.EventSink events) { + try { + FirebaseFunctions firebaseFunctions = getFunctions(arguments); + + String functionName = (String) arguments.get("functionName"); + String functionUri = (String) arguments.get("functionUri"); + String origin = (String) arguments.get("origin"); + Object parameters = arguments.get("parameters"); + + if (origin != null) { + Uri originUri = Uri.parse(origin); + firebaseFunctions.useEmulator(originUri.getHost(), originUri.getPort()); + } + + Publisher publisher; + if (functionName != null) { + publisher = firebaseFunctions.getHttpsCallable(functionName).stream(parameters); + } else if (functionUri != null) { + publisher = firebaseFunctions.getHttpsCallableFromUrl(new URL(functionUri)).stream(); + } else { + throw new IllegalArgumentException("Either functionName or functionUri must be set"); + } + subscriber = new StreamResponseSubscriber(events); + publisher.subscribe(subscriber); + } catch (Exception e) { + events.error("firebase_functions", e.getMessage(), null); + } } @Override - public void onCancel(Object arguments) {} + public void onCancel(Object arguments) { + subscriber.cancel(); + } } diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java new file mode 100644 index 000000000000..af4e9c7b959a --- /dev/null +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java @@ -0,0 +1,72 @@ +package io.flutter.plugins.firebase.functions; + +import android.os.Handler; +import android.os.Looper; +import com.google.firebase.functions.StreamResponse; +import io.flutter.plugin.common.EventChannel; +import java.util.concurrent.CountDownLatch; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; + +public class StreamResponseSubscriber implements Subscriber { + private Subscription subscription; + private final EventChannel.EventSink eventSink; + + private final Handler mainThreadHandler = new Handler(Looper.getMainLooper()); + + private CountDownLatch latch = new CountDownLatch(1); + + private Object result; + + public StreamResponseSubscriber(EventChannel.EventSink eventSink) { + this.eventSink = eventSink; + } + + @Override + public void onSubscribe(Subscription s) { + this.subscription = s; + subscription.request(Long.MAX_VALUE); + } + + @Override + public void onNext(StreamResponse streamResponse) { + if (streamResponse instanceof StreamResponse.Message) { + Object message = ((StreamResponse.Message) streamResponse).getMessage().getData(); + mainThreadHandler.post(() -> eventSink.success(message)); + } else { + this.result = ((StreamResponse.Result) streamResponse).getResult().getData(); + latch.countDown(); + } + } + + @Override + public void onError(Throwable t) { + if (eventSink != null) { + eventSink.error("firebase_functions", t.getMessage(), null); + latch.countDown(); + } + } + + @Override + public void onComplete() { + if (eventSink != null) { + eventSink.endOfStream(); + } + } + + public void cancel() { + if (subscription != null) { + subscription.cancel(); + latch.countDown(); + } + } + + public Object getResult() { + try { + latch.await(); + return this.result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart index c5eec6bbce56..7361cbeb3980 100644 --- a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart +++ b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart @@ -13,11 +13,12 @@ class HttpsCallableStream { @visibleForTesting final HttpsCallableStreamsPlatform delegate; - Stream> stream(Object? input) async* { - await for (final T value in delegate.stream(input)) { + Stream> stream([Object? input]) async* { + await for (final value in delegate.stream(input)) { yield Chunk(value); } } -// Future get data => delegate.data; + Future> get data async => + Result(HttpsCallableResult._(await delegate.data)); } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart index 67433e973206..ba2db99e7e98 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart @@ -12,33 +12,54 @@ class MethodChannelHttpsCallableStreams extends HttpsCallableStreamsPlatform { MethodChannelHttpsCallableStreams(FirebaseFunctionsPlatform functions, String? origin, String? name, Uri? uri) - : _eventChannelId = - uri?.pathSegments.join('_').replaceAll('.', '_') ?? '', + : _transformedUri = uri?.pathSegments.join('_').replaceAll('.', '_'), super(functions, origin, name, uri) { - _channel = EventChannel( - 'plugins.flutter.io/firebase_functions/${name ?? _eventChannelId}'); + _eventChannelId = name ?? _transformedUri ?? ''; + _channel = + EventChannel('plugins.flutter.io/firebase_functions/$_eventChannelId'); } late final EventChannel _channel; - final String _eventChannelId; + final String? _transformedUri; + late String _eventChannelId; @override - Stream stream(Object? object) async* { + Stream stream(Object? parameters) async* { try { - await MethodChannelFirebaseFunctions.channel.invokeMethod( - 'FirebaseFunctions#setEventChannelId', { - 'eventChannelId': _eventChannelId, + await _registerEventChannelOnNative(); + final eventData = { 'appName': functions.app!.name, 'functionName': name, 'functionUri': uri?.toString(), 'origin': origin, + 'region': functions.region, + 'parameters': parameters, + }; + yield* _channel.receiveBroadcastStream(eventData).map((message) { + if (message is Map) { + return Map.from(message); + } + return message; }); - yield* _channel.receiveBroadcastStream(object).cast(); } catch (e, s) { convertPlatformException(e, s); } } + Future _registerEventChannelOnNative() async { + await MethodChannelFirebaseFunctions.channel.invokeMethod( + 'FirebaseFunctions#registerEventChannel', { + 'eventChannelId': _eventChannelId, + }); + } + @override - Future get data => throw UnimplementedError(); + Future get data async { + final result = await MethodChannelFirebaseFunctions.channel + .invokeMethod('FirebaseFunctions#getCompleteResult'); + if (result is Map) { + return Map.from(result); + } + return result; + } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart index e24b3e7aa71b..ef8922f7225a 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart @@ -33,7 +33,7 @@ abstract class HttpsCallableStreamsPlatform extends PlatformInterface { /// The URI of the function for 2nd gen functions final Uri? uri; - Stream stream(Object? object); + Stream stream(Object? parameters); - Future get data; + Future get data; } From 95236c84e3831b008cbeaf4f9cbda177d36a1689 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Mon, 24 Mar 2025 12:36:14 +0000 Subject: [PATCH 08/22] chore: create dedicated StreamHandler class --- .../FirebaseFunctionsStreamHandler.java | 65 +++++++++++++++++++ .../FlutterFirebaseFunctionsPlugin.java | 53 ++------------- .../example/android/settings.gradle | 2 +- ...method_channel_https_callable_streams.dart | 4 +- 4 files changed, 74 insertions(+), 50 deletions(-) create mode 100644 packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java new file mode 100644 index 000000000000..a35f3c8a738a --- /dev/null +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java @@ -0,0 +1,65 @@ +package io.flutter.plugins.firebase.functions; + +import android.net.Uri; +import com.google.firebase.functions.FirebaseFunctions; +import com.google.firebase.functions.StreamResponse; +import io.flutter.plugin.common.EventChannel; +import io.flutter.plugin.common.EventChannel.StreamHandler; +import java.net.URL; +import java.util.Map; +import org.reactivestreams.Publisher; + +public class FirebaseFunctionsStreamHandler implements StreamHandler { + + private final FirebaseFunctions firebaseFunctions; + + private StreamResponseSubscriber subscriber; + + public FirebaseFunctionsStreamHandler(FirebaseFunctions functions) { + this.firebaseFunctions = functions; + } + + @Override + public void onListen(Object arguments, EventChannel.EventSink events) { + @SuppressWarnings("unchecked") + Map argumentsMap = (Map) arguments; + httpsStreamCall(argumentsMap, events); + } + + @Override + public void onCancel(Object arguments) { + subscriber.cancel(); + } + + private void httpsStreamCall(Map arguments, EventChannel.EventSink events) { + try { + + String functionName = (String) arguments.get("functionName"); + String functionUri = (String) arguments.get("functionUri"); + String origin = (String) arguments.get("origin"); + Object parameters = arguments.get("parameters"); + + if (origin != null) { + Uri originUri = Uri.parse(origin); + firebaseFunctions.useEmulator(originUri.getHost(), originUri.getPort()); + } + + Publisher publisher; + if (functionName != null) { + publisher = firebaseFunctions.getHttpsCallable(functionName).stream(parameters); + } else if (functionUri != null) { + publisher = firebaseFunctions.getHttpsCallableFromUrl(new URL(functionUri)).stream(); + } else { + throw new IllegalArgumentException("Either functionName or functionUri must be set"); + } + subscriber = new StreamResponseSubscriber(events); + publisher.subscribe(subscriber); + } catch (Exception e) { + events.error("firebase_functions", e.getMessage(), null); + } + } + + public Object getResult() { + return subscriber.getResult(); + } +} diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java index 42976b9fdc97..311ffa90a674 100644 --- a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java @@ -16,7 +16,6 @@ import com.google.firebase.functions.HttpsCallableOptions; import com.google.firebase.functions.HttpsCallableReference; import com.google.firebase.functions.HttpsCallableResult; -import com.google.firebase.functions.StreamResponse; import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.MethodCall; @@ -31,16 +30,15 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.TimeUnit; -import org.reactivestreams.Publisher; public class FlutterFirebaseFunctionsPlugin - implements FlutterPlugin, FlutterFirebasePlugin, MethodCallHandler, EventChannel.StreamHandler { + implements FlutterPlugin, FlutterFirebasePlugin, MethodCallHandler { private static final String METHOD_CHANNEL_NAME = "plugins.flutter.io/firebase_functions"; private MethodChannel channel; private FlutterPluginBinding pluginBinding; - private StreamResponseSubscriber subscriber; + private FirebaseFunctionsStreamHandler streamHandler; /** * Default Constructor. @@ -67,7 +65,9 @@ private void registerEventChannel(Map arguments) { final String eventChannelName = METHOD_CHANNEL_NAME + "/" + eventId; final EventChannel eventChannel = new EventChannel(pluginBinding.getBinaryMessenger(), eventChannelName); - eventChannel.setStreamHandler(this); + FirebaseFunctions functions = getFunctions(arguments); + streamHandler = new FirebaseFunctionsStreamHandler(functions); + eventChannel.setStreamHandler(streamHandler); } private FirebaseFunctions getFunctions(Map arguments) { @@ -133,7 +133,7 @@ private void getCompleteResult(Result result) { cachedThreadPool.execute( () -> { try { - Object completeResult = subscriber.getResult(); + Object completeResult = streamHandler.getResult(); result.success(completeResult); } catch (Exception e) { result.error("firebase_functions", e.getMessage(), getExceptionDetails(e)); @@ -229,45 +229,4 @@ public Task didReinitializeFirebaseCore() { return taskCompletionSource.getTask(); } - - @Override - public void onListen(Object arguments, EventChannel.EventSink events) { - @SuppressWarnings("unchecked") - Map argumentsMap = (Map) arguments; - httpsStreamCall(argumentsMap, events); - } - - private void httpsStreamCall(Map arguments, EventChannel.EventSink events) { - try { - FirebaseFunctions firebaseFunctions = getFunctions(arguments); - - String functionName = (String) arguments.get("functionName"); - String functionUri = (String) arguments.get("functionUri"); - String origin = (String) arguments.get("origin"); - Object parameters = arguments.get("parameters"); - - if (origin != null) { - Uri originUri = Uri.parse(origin); - firebaseFunctions.useEmulator(originUri.getHost(), originUri.getPort()); - } - - Publisher publisher; - if (functionName != null) { - publisher = firebaseFunctions.getHttpsCallable(functionName).stream(parameters); - } else if (functionUri != null) { - publisher = firebaseFunctions.getHttpsCallableFromUrl(new URL(functionUri)).stream(); - } else { - throw new IllegalArgumentException("Either functionName or functionUri must be set"); - } - subscriber = new StreamResponseSubscriber(events); - publisher.subscribe(subscriber); - } catch (Exception e) { - events.error("firebase_functions", e.getMessage(), null); - } - } - - @Override - public void onCancel(Object arguments) { - subscriber.cancel(); - } } diff --git a/packages/cloud_functions/cloud_functions/example/android/settings.gradle b/packages/cloud_functions/cloud_functions/example/android/settings.gradle index 7fb86d70412c..2e250e5af7d5 100644 --- a/packages/cloud_functions/cloud_functions/example/android/settings.gradle +++ b/packages/cloud_functions/cloud_functions/example/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.3.0" apply false + id "com.android.application" version "8.1.0" apply false // START: FlutterFire Configuration id "com.google.gms.google-services" version "4.3.15" apply false // END: FlutterFire Configuration diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart index ba2db99e7e98..b761c82f0c4a 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart @@ -28,11 +28,9 @@ class MethodChannelHttpsCallableStreams try { await _registerEventChannelOnNative(); final eventData = { - 'appName': functions.app!.name, 'functionName': name, 'functionUri': uri?.toString(), 'origin': origin, - 'region': functions.region, 'parameters': parameters, }; yield* _channel.receiveBroadcastStream(eventData).map((message) { @@ -50,6 +48,8 @@ class MethodChannelHttpsCallableStreams await MethodChannelFirebaseFunctions.channel.invokeMethod( 'FirebaseFunctions#registerEventChannel', { 'eventChannelId': _eventChannelId, + 'appName': functions.app!.name, + 'region': functions.region, }); } From 6161988b647cab50508a080a57a96a16ad13cd83 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Tue, 25 Mar 2025 12:50:11 +0000 Subject: [PATCH 09/22] chore: add streamhandler implementation for ios --- .../android/app/src/main/AndroidManifest.xml | 1 + .../FLTFirebaseFunctionsPlugin.m | 93 ++++++++++++------- .../FLTFunctionsStreamHandler.m | 70 ++++++++++++++ .../include/FLTFunctionsStreamHandler.h | 23 +++++ 4 files changed, 156 insertions(+), 31 deletions(-) create mode 100644 packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FLTFunctionsStreamHandler.m create mode 100644 packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/include/FLTFunctionsStreamHandler.h diff --git a/packages/cloud_functions/cloud_functions/example/android/app/src/main/AndroidManifest.xml b/packages/cloud_functions/cloud_functions/example/android/app/src/main/AndroidManifest.xml index 74a78b939e5e..a975611c0582 100644 --- a/packages/cloud_functions/cloud_functions/example/android/app/src/main/AndroidManifest.xml +++ b/packages/cloud_functions/cloud_functions/example/android/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ ) @@ -14,6 +15,8 @@ NSString *const kFLTFirebaseFunctionsChannelName = @"plugins.flutter.io/firebase_functions"; @interface FLTFirebaseFunctionsPlugin () +@property(nonatomic, strong) NSObject *registrar; +@property(nonatomic, strong) FLTFunctionsStreamHandler *streamHandler; @end @implementation FLTFirebaseFunctionsPlugin @@ -38,46 +41,55 @@ + (void)registerWithRegistrar:(NSObject *)registrar { FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:kFLTFirebaseFunctionsChannelName binaryMessenger:[registrar messenger]]; + FLTFirebaseFunctionsPlugin *instance = [FLTFirebaseFunctionsPlugin sharedInstance]; + instance.registrar = registrar; [registrar addMethodCallDelegate:instance channel:channel]; } - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)flutterResult { - if (![@"FirebaseFunctions#call" isEqualToString:call.method]) { + if ([@"FirebaseFunctions#registerEventChannel" isEqualToString:call.method]){ + [self registerEventChannel: call.arguments]; + flutterResult(nil); + } + else if ([@"FirebaseFunctions#call" isEqualToString:call.method]) { + FLTFirebaseMethodCallErrorBlock errorBlock = + ^(NSString *_Nullable code, NSString *_Nullable message, NSDictionary *_Nullable details, + NSError *_Nullable error) { + NSMutableDictionary *httpsErrorDetails = [NSMutableDictionary dictionary]; + NSString *httpsErrorCode = [NSString stringWithFormat:@"%ld", error.code]; + NSString *httpsErrorMessage = error.localizedDescription; + // FIRFunctionsErrorDomain has been removed and replaced with Swift implementation + // https://github.com/firebase/firebase-ios-sdk/blob/main/FirebaseFunctions/Sources/FunctionsError.swift#L18 + NSString *errorDomain = @"com.firebase.functions"; + // FIRFunctionsErrorDetailsKey has been deprecated and replaced with Swift implementation + // https://github.com/firebase/firebase-ios-sdk/blob/main/FirebaseFunctions/Sources/FunctionsError.swift#L21 + NSString *detailsKey = @"details"; + // See also https://github.com/firebase/firebase-ios-sdk/pull/9569 + if ([error.domain isEqualToString:errorDomain]) { + httpsErrorCode = [self mapFunctionsErrorCodes:error.code]; + if (error.userInfo[detailsKey] != nil) { + httpsErrorDetails[@"additionalData"] = error.userInfo[detailsKey]; + } + } + httpsErrorDetails[@"code"] = httpsErrorCode; + httpsErrorDetails[@"message"] = httpsErrorMessage; + flutterResult([FlutterError errorWithCode:httpsErrorCode + message:httpsErrorMessage + details:httpsErrorDetails]); + }; + + FLTFirebaseMethodCallResult *methodCallResult = + [FLTFirebaseMethodCallResult createWithSuccess:flutterResult andErrorBlock:errorBlock]; + + [self httpsFunctionCall:call.arguments withMethodCallResult:methodCallResult]; + } + else { flutterResult(FlutterMethodNotImplemented); return; } - FLTFirebaseMethodCallErrorBlock errorBlock = - ^(NSString *_Nullable code, NSString *_Nullable message, NSDictionary *_Nullable details, - NSError *_Nullable error) { - NSMutableDictionary *httpsErrorDetails = [NSMutableDictionary dictionary]; - NSString *httpsErrorCode = [NSString stringWithFormat:@"%ld", error.code]; - NSString *httpsErrorMessage = error.localizedDescription; - // FIRFunctionsErrorDomain has been removed and replaced with Swift implementation - // https://github.com/firebase/firebase-ios-sdk/blob/main/FirebaseFunctions/Sources/FunctionsError.swift#L18 - NSString *errorDomain = @"com.firebase.functions"; - // FIRFunctionsErrorDetailsKey has been deprecated and replaced with Swift implementation - // https://github.com/firebase/firebase-ios-sdk/blob/main/FirebaseFunctions/Sources/FunctionsError.swift#L21 - NSString *detailsKey = @"details"; - // See also https://github.com/firebase/firebase-ios-sdk/pull/9569 - if ([error.domain isEqualToString:errorDomain]) { - httpsErrorCode = [self mapFunctionsErrorCodes:error.code]; - if (error.userInfo[detailsKey] != nil) { - httpsErrorDetails[@"additionalData"] = error.userInfo[detailsKey]; - } - } - httpsErrorDetails[@"code"] = httpsErrorCode; - httpsErrorDetails[@"message"] = httpsErrorMessage; - flutterResult([FlutterError errorWithCode:httpsErrorCode - message:httpsErrorMessage - details:httpsErrorDetails]); - }; - - FLTFirebaseMethodCallResult *methodCallResult = - [FLTFirebaseMethodCallResult createWithSuccess:flutterResult andErrorBlock:errorBlock]; - - [self httpsFunctionCall:call.arguments withMethodCallResult:methodCallResult]; + } #pragma mark - Firebase Functions API @@ -127,6 +139,25 @@ - (void)httpsFunctionCall:(id)arguments withMethodCallResult:(FLTFirebaseMethodC }]; } +- (void)registerEventChannel:(id)arguments { + NSString *eventId = arguments[@"eventChannelId"]; + NSString *eventChannelName = [NSString stringWithFormat:@"%@/%@", kFLTFirebaseFunctionsChannelName, eventId]; + + FlutterEventChannel *eventChannel = + [FlutterEventChannel eventChannelWithName:eventChannelName binaryMessenger:self.registrar.messenger]; + + NSString *appName = arguments[@"appName"]; + NSString *region = arguments[@"region"]; + + FIRApp *app = [FLTFirebasePlugin firebaseAppNamed:appName]; + FIRFunctions *functions = [FIRFunctions functionsForApp:app region:region]; + + self.streamHandler = [[FLTFunctionsStreamHandler alloc] initWithFunctions:functions]; + + [eventChannel setStreamHandler:self.streamHandler]; + +} + #pragma mark - Utilities // Map function error code objects to Strings that match error names on Android. diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FLTFunctionsStreamHandler.m b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FLTFunctionsStreamHandler.m new file mode 100644 index 000000000000..c6cc790e02b7 --- /dev/null +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FLTFunctionsStreamHandler.m @@ -0,0 +1,70 @@ +// Copyright 2022, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// +// FLTLoadBundleStreamHandler.m +// cloud_firestore +// +// Created by Russell Wheatley on 05/05/2021. +// + +@import FirebaseFunctions; +#if __has_include() +#import +#else +#import +#endif + +#import "include/FLTFunctionsStreamHandler.h" + +@implementation FLTFunctionsStreamHandler + +- (nonnull instancetype)initWithFunctions:(nonnull FIRFunctions *)functions { + self = [super init]; + if (self) { + _functions = functions; + } + return self; + } + + - (FlutterError *_Nullable)onListenWithArguments:(id _Nullable)arguments + eventSink:(nonnull FlutterEventSink)events { + + [self httpsStreamCall:arguments eventSink:events]; + return nil; + } + + - (FlutterError *_Nullable)onCancelWithArguments:(id _Nullable)arguments { + return nil; + } + +- (void)httpsStreamCall:(id _Nullable)arguments eventSink:(nonnull FlutterEventSink)events{ + NSString *functionName = arguments[@"functionName"]; + NSString *functionUri = arguments[@"functionUri"]; + NSString *origin = arguments[@"origin"]; + NSObject *parameters = arguments[@"parameters"]; + + + if (origin != nil && origin != (id)[NSNull null]) { + NSURL *url = [NSURL URLWithString:origin]; + [_functions useEmulatorWithHost:[url host] port:[[url port] intValue]]; + } + + if (![functionName isEqual:[NSNull null]]) { + FIRHTTPSCallable *callable = [_functions HTTPSCallableWithName:functionName]; + [callable ]; + } else if (![functionUri isEqual:[NSNull null]]) { + + } else { + NSDictionary *errorDetails = @{ + @"code": @"IllegalArgumentException", + @"message": @"Either functionName or functionUri must be set", + @"details": [NSNull null] + }; + events(errorDetails); + return; + } +} + @end + diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/include/FLTFunctionsStreamHandler.h b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/include/FLTFunctionsStreamHandler.h new file mode 100644 index 000000000000..f8d11103a09d --- /dev/null +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/include/FLTFunctionsStreamHandler.h @@ -0,0 +1,23 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#import + +#if TARGET_OS_OSX +#import +#else +#import +#endif + +#import +#if __has_include() +#import +#else +#import +#endif + +@interface FLTFunctionsStreamHandler : NSObject +@property(nonatomic, strong) FIRFunctions *functions; + +- (instancetype)initWithFunctions:(FIRFunctions *)functions; +@end From 4d0c10efeb25dbc3c51ec94faa33b4bd1c432cc0 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Fri, 28 Mar 2025 13:31:08 +0000 Subject: [PATCH 10/22] chore: add iOS implementation for Cloud Functions stream --- .../cloud_functions/CodecUtility.swift | 117 +++++++++++++++++ .../FirebaseFunctionsPlugin.swift | 55 ++++++-- .../FunctionsStreamHandler.swift | 121 ++++++++++++++++++ 3 files changed, 284 insertions(+), 9 deletions(-) create mode 100644 packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/CodecUtility.swift create mode 100644 packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/CodecUtility.swift b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/CodecUtility.swift new file mode 100644 index 000000000000..656393470a68 --- /dev/null +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/CodecUtility.swift @@ -0,0 +1,117 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +public struct AnyEncodable: Encodable { + private let value: Any? + + public init(_ value: Any?) { + self.value = value ?? NSNull() + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + + switch value { + case is NSNull: + try container.encodeNil() + case let stringValue as String: + try container.encode(stringValue) + case let intValue as Int: + try container.encode(intValue) + case let int8Value as Int8: + try container.encode(int8Value) + case let int16Value as Int16: + try container.encode(int16Value) + case let int32Value as Int32: + try container.encode(int32Value) + case let int64Value as Int64: + try container.encode(int64Value) + case let uintValue as UInt: + try container.encode(uintValue) + case let uint8Value as UInt8: + try container.encode(uint8Value) + case let uint16Value as UInt16: + try container.encode(uint16Value) + case let uint32Value as UInt32: + try container.encode(uint32Value) + case let uint64Value as UInt64: + try container.encode(uint64Value) + case let doubleValue as Double: + try container.encode(doubleValue) + case let floatValue as Float: + try container.encode(floatValue) + case let boolValue as Bool: + try container.encode(boolValue) + case let arrayValue as [Any]: + try container.encode(arrayValue.map { AnyEncodable($0) }) + case let dictionaryValue as [String: Any]: + try container.encode(dictionaryValue.mapValues { AnyEncodable($0) }) + default: + throw EncodingError.invalidValue( + value as Any, + EncodingError.Context( + codingPath: encoder.codingPath, + debugDescription: "Unsupported type: \(type(of: value))" + ) + ) + } + } +} + +public struct AnyDecodable: Decodable { + public let value: Any? + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + + if container.decodeNil() { + value = NSNull() + return + } + + if let stringValue = try? container.decode(String.self) { + value = stringValue + } else if let intValue = try? container.decode(Int.self) { + value = intValue + } else if let int8Value = try? container.decode(Int8.self) { + value = int8Value + } else if let int16Value = try? container.decode(Int16.self) { + value = int16Value + } else if let int32Value = try? container.decode(Int32.self) { + value = int32Value + } else if let int64Value = try? container.decode(Int64.self) { + value = int64Value + } else if let uintValue = try? container.decode(UInt.self) { + value = uintValue + } else if let uint8Value = try? container.decode(UInt8.self) { + value = uint8Value + } else if let uint16Value = try? container.decode(UInt16.self) { + value = uint16Value + } else if let uint32Value = try? container.decode(UInt32.self) { + value = uint32Value + } else if let uint64Value = try? container.decode(UInt64.self) { + value = uint64Value + } else if let doubleValue = try? container.decode(Double.self) { + value = doubleValue + } else if let floatValue = try? container.decode(Float.self) { + value = floatValue + } else if let boolValue = try? container.decode(Bool.self) { + value = boolValue + } else if let arrayValue = try? container.decode([AnyDecodable].self) { + value = arrayValue.map(\.value) + } else if let dictionaryValue = try? container.decode([String: AnyDecodable].self) { + value = dictionaryValue.mapValues { $0.value } + + } else { + throw DecodingError.dataCorruptedError( + in: container, + debugDescription: "Unable to decode value of type: \(type(of: value))" + ) + } + } + + public init(_ value: Any?) { + self.value = value + } +} diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FirebaseFunctionsPlugin.swift b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FirebaseFunctionsPlugin.swift index 66766bec71b0..85be6a1c5b3f 100644 --- a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FirebaseFunctionsPlugin.swift +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FirebaseFunctionsPlugin.swift @@ -18,6 +18,13 @@ import FirebaseFunctions let kFLTFirebaseFunctionsChannelName = "plugins.flutter.io/firebase_functions" public class FirebaseFunctionsPlugin: NSObject, FLTFirebasePluginProtocol, FlutterPlugin { + private let binaryMessenger: FlutterBinaryMessenger + private var streamHandler: FunctionsStreamHandler? + + init(binaryMessenger: FlutterBinaryMessenger) { + self.binaryMessenger = binaryMessenger + } + public func firebaseLibraryVersion() -> String { versionNumber } @@ -40,7 +47,6 @@ public class FirebaseFunctionsPlugin: NSObject, FLTFirebasePluginProtocol, Flutt public static func register(with registrar: FlutterPluginRegistrar) { let binaryMessenger: FlutterBinaryMessenger - #if os(macOS) binaryMessenger = registrar.messenger #elseif os(iOS) @@ -51,13 +57,24 @@ public class FirebaseFunctionsPlugin: NSObject, FLTFirebasePluginProtocol, Flutt name: kFLTFirebaseFunctionsChannelName, binaryMessenger: binaryMessenger ) - let instance = FirebaseFunctionsPlugin() + let instance = FirebaseFunctionsPlugin(binaryMessenger: binaryMessenger) registrar.addMethodCallDelegate(instance, channel: channel) } + private func registerEventChannel(arguments: [String: Any]) { + let eventChannelId = arguments["eventChannelId"]! + let eventChannelName = "\(kFLTFirebaseFunctionsChannelName)/\(eventChannelId)" + let eventChannel = FlutterEventChannel(name: eventChannelName, binaryMessenger: binaryMessenger) + let functions = getFunctions(arguments: arguments) + streamHandler = FunctionsStreamHandler(functions: functions) + eventChannel.setStreamHandler(streamHandler) + } + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - guard call.method == "FirebaseFunctions#call" else { - result(FlutterMethodNotImplemented) + if call.method == "FirebaseFunctions#getCompleteResult" { + Task { + await getCompleteResult(result: result) + } return } @@ -68,12 +85,20 @@ public class FirebaseFunctionsPlugin: NSObject, FLTFirebasePluginProtocol, Flutt return } - httpsFunctionCall(arguments: arguments) { success, error in - if let error { - result(error) - } else { - result(success) + if call.method == "FirebaseFunctions#registerEventChannel" { + registerEventChannel(arguments: arguments) + result(nil) + } else if call.method == "FirebaseFunctions#call" { + httpsFunctionCall(arguments: arguments) { success, error in + if let error { + result(error) + } else { + result(success) + } } + } else { + result(FlutterMethodNotImplemented) + return } } @@ -132,6 +157,18 @@ public class FirebaseFunctionsPlugin: NSObject, FLTFirebasePluginProtocol, Flutt } } + private func getCompleteResult(result: @escaping FlutterResult) async { + let value = await streamHandler?.getResult() + result(value) + } + + private func getFunctions(arguments: [String: Any]) -> Functions { + let appName = arguments["appName"] as? String ?? "" + let region = arguments["region"] as? String + let app = FLTFirebasePlugin.firebaseAppNamed(appName)! + return Functions.functions(app: app, region: region ?? "") + } + private func createFlutterError(from error: Error) -> FlutterError { let nsError = error as NSError var errorCode = "unknown" diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift new file mode 100644 index 000000000000..d530f43c2c85 --- /dev/null +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift @@ -0,0 +1,121 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#if canImport(FlutterMacOS) + import FlutterMacOS +#else + import Flutter +#endif + +import FirebaseFunctions + +class FunctionsStreamHandler: NSObject, FlutterStreamHandler { + var functions: Functions + private var streamTask: Task? + @MainActor private var streamResult: Any? + private let continuation: AsyncStream.Continuation + private let stream: AsyncStream + + init(functions: Functions) { + self.functions = functions + (stream, continuation) = AsyncStream.makeStream(of: Any?.self) + super.init() + } + + func onListen(withArguments arguments: Any?, + eventSink events: @escaping FlutterEventSink) -> FlutterError? { + streamTask = Task { + await httpsStreamCall(arguments: arguments, events: events) + } + return nil + } + + func onCancel(withArguments arguments: Any?) -> FlutterError? { + streamTask?.cancel() + continuation.finish() + return nil + } + + private func httpsStreamCall(arguments: Any?, events: @escaping FlutterEventSink) async { + guard let arguments = arguments as? [String: Any] else { + await MainActor.run { + events(FlutterError(code: "invalid_arguments", + message: "Invalid arguments", + details: nil)) + } + return + } + let functionName = arguments["functionName"] as? String + let functionUri = arguments["functionUri"] as? String + let origin = arguments["origin"] as? String + let parameters = arguments["arguments"] + + if let origin, + let url = URL(string: origin), + let host = url.host, + let port = url.port { + functions.useEmulator(withHost: host, port: port) + } + + // Stream handling for iOS 15+ + if #available(iOS 15.0, *) { + let function: Callable> + + if let functionName { + function = self.functions.httpsCallable(functionName) + } else if let functionUri, let url = URL(string: functionUri) { + function = self.functions.httpsCallable(url) + } else { + await MainActor.run { + events(FlutterError(code: "IllegalArgumentException", + message: "Either functionName or functionUri must be set", + details: nil)) + } + return + } + + do { + let encodedParameters = AnyEncodable(parameters) + + let stream = try function.stream(encodedParameters) + + for try await response in stream { + await MainActor.run { + switch response { + case let .message(message): + events(message.value) + case let .result(result): + self.streamResult = result.value + continuation.yield(result.value) + } + } + } + } catch { + await MainActor.run { + events(FlutterError(code: "unknown", + message: error.localizedDescription, + details: ["code": "unknown", "message": error.localizedDescription])) + continuation.yield(nil) + continuation.finish() + } + } + } else { + await MainActor.run { + events(FlutterError(code: "unknown", + message: "Streaming requires iOS 15+", + details: nil)) + continuation.yield(nil) + } + continuation.finish() + } + } + + @MainActor + func getResult() async -> Any? { + for await result in stream { + return result + } + return nil + } +} From 1190fde50a6ff1372d057b97999394c3e8d17f5e Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Fri, 28 Mar 2025 17:03:20 +0000 Subject: [PATCH 11/22] chore: add license header to stream handler files --- .../firebase/functions/FirebaseFunctionsStreamHandler.java | 4 ++++ .../plugins/firebase/functions/StreamResponseSubscriber.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java index a35f3c8a738a..186d40b09d7e 100644 --- a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java @@ -1,3 +1,7 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + package io.flutter.plugins.firebase.functions; import android.net.Uri; diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java index af4e9c7b959a..f6d4b0e953f0 100644 --- a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java @@ -1,3 +1,7 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + package io.flutter.plugins.firebase.functions; import android.os.Handler; From 6bbde2f3a96da525099da22b384a866430b653da Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Tue, 1 Apr 2025 12:42:53 +0000 Subject: [PATCH 12/22] chore: web Cloud Functions stream wip --- ...platform_interface_firebase_functions.dart | 4 +- .../lib/cloud_functions_web.dart | 6 ++ .../lib/https_callable_stream_web.dart | 45 +++++++++++++ .../lib/interop/functions.dart | 36 ++++++++++- .../lib/interop/functions_interop.dart | 64 +++++++++++++++++++ 5 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 packages/cloud_functions/cloud_functions_web/lib/https_callable_stream_web.dart diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart index 46569aab59aa..7112127b5abf 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart @@ -70,14 +70,14 @@ abstract class FirebaseFunctionsPlatform extends PlatformInterface { /// Creates a [HttpsCallablePlatform] instance from a [Uri] HttpsCallablePlatform httpsCallableWithUri( String? origin, Uri uri, HttpsCallableOptions options) { - throw UnimplementedError('httpsCallable() is not implemented'); + throw UnimplementedError('httpsCallableWithUri() is not implemented'); } HttpsCallableStreamsPlatform httpsStreamCallable( String? origin, String name, ) { - throw UnimplementedError('httpsCallable() is not implemented'); + throw UnimplementedError('httpsStreamCallable() is not implemented'); } HttpsCallableStreamsPlatform httpsStreamCallableWithUri( diff --git a/packages/cloud_functions/cloud_functions_web/lib/cloud_functions_web.dart b/packages/cloud_functions/cloud_functions_web/lib/cloud_functions_web.dart index 594c90a56985..81d3ad237695 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/cloud_functions_web.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/cloud_functions_web.dart @@ -4,6 +4,7 @@ // found in the LICENSE file. import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; +import 'package:cloud_functions_web/https_callable_stream_web.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core_web/firebase_core_web.dart'; import 'package:firebase_core_web/firebase_core_web_interop.dart' @@ -62,4 +63,9 @@ class FirebaseFunctionsWeb extends FirebaseFunctionsPlatform { String? origin, Uri uri, HttpsCallableOptions options) { return HttpsCallableWeb(this, _delegate, origin, null, options, uri); } + + @override + HttpsCallableStreamsPlatform httpsStreamCallable(String? origin, String name) { + return HttpsCallableStreamWeb(this, _delegate, origin, name, null); + } } diff --git a/packages/cloud_functions/cloud_functions_web/lib/https_callable_stream_web.dart b/packages/cloud_functions/cloud_functions_web/lib/https_callable_stream_web.dart new file mode 100644 index 000000000000..cfe0900b9279 --- /dev/null +++ b/packages/cloud_functions/cloud_functions_web/lib/https_callable_stream_web.dart @@ -0,0 +1,45 @@ +// ignore_for_file: require_trailing_commas +// Copyright 2020, the Chromium project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:js_interop'; + +import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; + +import 'interop/functions.dart' as functions_interop; + +class HttpsCallableStreamWeb extends HttpsCallableStreamsPlatform { + HttpsCallableStreamWeb( + super.functions, this._webFunctions, super.origin, super.name, super.uri); + + final functions_interop.Functions _webFunctions; + + @override + Future get data => throw UnimplementedError(); + + @override + Stream stream(Object? parameters) async* { + if (origin != null) { + final uri = Uri.parse(origin!); + + _webFunctions.useFunctionsEmulator(uri.host, uri.port); + } + + late functions_interop.HttpsCallable callable; + + if (name != null) { + callable = _webFunctions.httpsCallable(name!); + } else if (uri != null) { + callable = _webFunctions.httpsCallableUri(uri!); + } else { + throw ArgumentError('Either name or uri must be provided'); + } + + final JSAny? parametersJS = parameters?.jsify(); + + await for (final value in callable.stream(parametersJS)){ + yield value; + } + } +} diff --git a/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart b/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart index 30319f68f5cb..9913a427bc4d 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart @@ -6,7 +6,6 @@ // ignore_for_file: public_member_api_docs import 'dart:js_interop'; - import 'package:firebase_core_web/firebase_core_web_interop.dart'; import 'functions_interop.dart' as functions_interop; @@ -84,6 +83,19 @@ class HttpsCallable extends JsObjectWrapper { result! as functions_interop.HttpsCallableResultJsImpl, ); } + + Stream stream(JSAny? data) async* { + final streamCallable = + await (jsObject as functions_interop.HttpsCallable).stream().toDart; + final streamResult = + streamCallable! as functions_interop.HttpsCallableStreamResultJsImpl; + + await for (final value in streamResult.stream.asStream()) { + yield HttpsCallableResult.getInstance( + value as functions_interop.HttpsCallableResultJsImpl, + ); + } + } } /// Returns Dart representation from JS Object. @@ -137,3 +149,25 @@ class HttpsCallableResult return _data; } } + +class HttpsCallableStreamResult + extends JsObjectWrapper { + HttpsCallableStreamResult._fromJsObject( + functions_interop.HttpsCallableStreamResultJsImpl jsObject) + : _data = _dartify(jsObject.data), + super.fromJsObject(jsObject); + + static final _expando = Expando(); + final dynamic _data; + + /// Creates a new HttpsCallableResult from a [jsObject]. + static HttpsCallableStreamResult getInstance( + functions_interop.HttpsCallableStreamResultJsImpl jsObject) { + return _expando[jsObject] ??= + HttpsCallableStreamResult._fromJsObject(jsObject); + } + + dynamic get data { + return _data; + } +} diff --git a/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart b/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart index ce70773e96a2..8bf204e9bfe3 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart @@ -76,3 +76,67 @@ abstract class HttpsCallableResultJsImpl {} extension HttpsCallableResultJsImplExtension on HttpsCallableResultJsImpl { external JSAny? get data; } + +@JS('HttpsCallable') +@staticInterop +class HttpsCallable {} + +extension HttpsCallableExtension on HttpsCallable { + external JSPromise stream( + [JSAny? data, HttpsCallableStreamOptions? options]); +} + + +@JS('HttpsCallableStreamResult') +@staticInterop +class HttpsCallableStreamResultJsImpl {} + +extension HttpsCallableStreamResultJsImplExtension + on HttpsCallableStreamResultJsImpl { + external JSPromise data; + external JsAsyncIterator stream; +} + + +@JS('HttpsCallableStreamOptions') +@staticInterop +@anonymous +abstract class HttpsCallableStreamOptions { + external factory HttpsCallableStreamOptions( + {JSBoolean? limitedUseAppCheckTokens}); +} + +extension HttpsCallableStreamOptionsExtension on HttpsCallableStreamOptions { + external JSBoolean? get limitedUseAppCheckTokens; + external set limitedUseAppCheckTokens(JSBoolean? t); +} + +extension type JsAsyncIterator._(JSObject _) + implements JSObject { + external JSPromise> next(); + + Stream asStream() async* { + this as SymbolJsImpl; + while (true) { + final result = await next().toDart; + if (result.done) break; + yield result.value; + } + } +} + +extension type JsAsyncIteratorState._(JSObject _) + implements JSObject { + external bool get done; + + external T get value; +} + + +@JS('Symbol') +@staticInterop +extension type SymbolJsImpl(JSObject _) implements JSObject { + + @JS('asyncIterator') + external static JSSymbol asyncIterator; +} From 66be89ba7c2f371c810da8600cb8cb924d0d1edd Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Tue, 1 Apr 2025 13:00:58 +0000 Subject: [PATCH 13/22] chore: push all --- .../scripts/functions/package-lock.json | 84 ++--- .../workflows/scripts/functions/package.json | 2 +- .../workflows/scripts/functions/src/index.ts | 300 ++++++++++-------- .../cloud_functions/example/lib/main.dart | 27 ++ 4 files changed, 221 insertions(+), 192 deletions(-) diff --git a/.github/workflows/scripts/functions/package-lock.json b/.github/workflows/scripts/functions/package-lock.json index 7b93503efa03..6d8d411e9180 100644 --- a/.github/workflows/scripts/functions/package-lock.json +++ b/.github/workflows/scripts/functions/package-lock.json @@ -8,7 +8,7 @@ "hasInstallScript": true, "dependencies": { "firebase-admin": "^11.5.0", - "firebase-functions": "^4.5.0" + "firebase-functions": "^6.3.2" }, "devDependencies": { "firebase-functions-test": "^0.2.0", @@ -324,12 +324,13 @@ "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" }, "node_modules/@types/express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.3.tgz", - "integrity": "sha512-I8cGRJj3pyOLs/HndoP+25vOqhqWkAZsWMEmq1qXy/b/M3ppufecUwaK2/TVDVxcV61/iSdhykUjQQ2DLSrTdg==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", "@types/serve-static": "*" } }, @@ -1244,15 +1245,14 @@ } }, "node_modules/firebase-functions": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-4.5.0.tgz", - "integrity": "sha512-y6HsasHtGLfXCp3Pfrz+JA19lO9hSzYiNxFDIDMffrfcsG7UbXzv0zfi2ASadMVRoDCaox5ppZBa1QJxZbctPQ==", + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-6.3.2.tgz", + "integrity": "sha512-FC3A1/nhqt1ZzxRnj5HZLScQaozAcFSD/vSR8khqSoFNOfxuXgwJS6ZABTB7+v+iMD5z6Mmxw6OfqITUBuI7OQ==", "dependencies": { "@types/cors": "^2.8.5", - "@types/express": "4.17.3", + "@types/express": "^4.17.21", "cors": "^2.8.5", - "express": "^4.17.1", - "node-fetch": "^2.6.7", + "express": "^4.21.0", "protobufjs": "^7.2.2" }, "bin": { @@ -1262,7 +1262,7 @@ "node": ">=14.10.0" }, "peerDependencies": { - "firebase-admin": "^10.0.0 || ^11.0.0" + "firebase-admin": "^11.10.0 || ^12.0.0 || ^13.0.0" } }, "node_modules/firebase-functions-test": { @@ -1789,17 +1789,6 @@ "node": ">=14" } }, - "node_modules/jwks-rsa/node_modules/@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, "node_modules/jws": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", @@ -2050,6 +2039,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "optional": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -2694,7 +2684,8 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "optional": true }, "node_modules/tslib": { "version": "2.6.2", @@ -2812,7 +2803,8 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "optional": true }, "node_modules/websocket-driver": { "version": "0.7.4", @@ -2839,6 +2831,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "optional": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -3203,12 +3196,13 @@ "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" }, "@types/express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.3.tgz", - "integrity": "sha512-I8cGRJj3pyOLs/HndoP+25vOqhqWkAZsWMEmq1qXy/b/M3ppufecUwaK2/TVDVxcV61/iSdhykUjQQ2DLSrTdg==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "requires": { "@types/body-parser": "*", - "@types/express-serve-static-core": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", "@types/serve-static": "*" } }, @@ -3923,15 +3917,14 @@ } }, "firebase-functions": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-4.5.0.tgz", - "integrity": "sha512-y6HsasHtGLfXCp3Pfrz+JA19lO9hSzYiNxFDIDMffrfcsG7UbXzv0zfi2ASadMVRoDCaox5ppZBa1QJxZbctPQ==", + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-6.3.2.tgz", + "integrity": "sha512-FC3A1/nhqt1ZzxRnj5HZLScQaozAcFSD/vSR8khqSoFNOfxuXgwJS6ZABTB7+v+iMD5z6Mmxw6OfqITUBuI7OQ==", "requires": { "@types/cors": "^2.8.5", - "@types/express": "4.17.3", + "@types/express": "^4.17.21", "cors": "^2.8.5", - "express": "^4.17.1", - "node-fetch": "^2.6.7", + "express": "^4.21.0", "protobufjs": "^7.2.2" } }, @@ -4337,19 +4330,6 @@ "jose": "^4.10.4", "limiter": "^1.1.5", "lru-memoizer": "^2.1.4" - }, - "dependencies": { - "@types/express": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", - "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - } } }, "jws": { @@ -4550,6 +4530,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "optional": true, "requires": { "whatwg-url": "^5.0.0" } @@ -5036,7 +5017,8 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "optional": true }, "tslib": { "version": "2.6.2", @@ -5119,7 +5101,8 @@ "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "optional": true }, "websocket-driver": { "version": "0.7.4", @@ -5140,6 +5123,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "optional": true, "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" diff --git a/.github/workflows/scripts/functions/package.json b/.github/workflows/scripts/functions/package.json index e6561975ef4b..e1fcbdcf63be 100644 --- a/.github/workflows/scripts/functions/package.json +++ b/.github/workflows/scripts/functions/package.json @@ -15,7 +15,7 @@ "main": "lib/index.js", "dependencies": { "firebase-admin": "^11.5.0", - "firebase-functions": "^4.5.0" + "firebase-functions": "^6.3.2" }, "devDependencies": { "firebase-functions-test": "^0.2.0", diff --git a/.github/workflows/scripts/functions/src/index.ts b/.github/workflows/scripts/functions/src/index.ts index 6d587bf363a7..a90de80a75b8 100644 --- a/.github/workflows/scripts/functions/src/index.ts +++ b/.github/workflows/scripts/functions/src/index.ts @@ -1,5 +1,6 @@ import * as assert from 'assert'; import * as functions from 'firebase-functions'; +import { onCall } from 'firebase-functions/https'; import * as functionsv2 from 'firebase-functions/v2'; // For example app. @@ -14,148 +15,165 @@ export const listfruits2ndgen = functionsv2.https.onCall(() => { // For e2e testing a custom region. // noinspection JSUnusedGlobalSymbols -export const testFunctionCustomRegion = functions - .region('europe-west1') - .https.onCall(() => 'europe-west1'); - -// For e2e testing timeouts. -export const testFunctionTimeout = functions.https.onCall((data) => { - console.log(JSON.stringify({ data })); - return new Promise((resolve, reject) => { - if (data && data.testTimeout) { - setTimeout( - () => resolve({ timeLimit: 'exceeded' }), - parseInt(data.testTimeout, 10) - ); - } else { - reject( - new functions.https.HttpsError( - 'invalid-argument', - 'testTimeout must be provided.' - ) - ); - } - }); -}); - -// For e2e testing errors & return values. -// noinspection JSUnusedGlobalSymbols -export const testFunctionDefaultRegion = functions.https.onCall((data) => { - console.log(JSON.stringify({ data })); - if (typeof data === 'undefined') { - return 'undefined'; - } - - if (typeof data === 'string') { - return 'string'; - } - - if (typeof data === 'number') { - return 'number'; - } - - if (typeof data === 'boolean') { - return 'boolean'; - } - - if (data === null) { - return 'null'; - } - - if (Array.isArray(data)) { - return 'array'; - } - - if(data.type === 'rawData') { - return data; - } - - const sampleData: { - [key: string]: any; - } = { - number: 1234, - string: 'acde', - boolean: true, - null: null, - map: { - number: 1234, - string: 'acde', - boolean: true, - null: null, - }, - list: [1234, 'acde', true, null], - deepMap: { - number: 123, - string: 'foo', - booleanTrue: true, - booleanFalse: false, - null: null, - list: ['1', 2, true, false], - map: { - number: 123, - string: 'foo', - booleanTrue: true, - booleanFalse: false, - null: null, - }, - }, - deepList: [ - '1', - 2, - true, - false, - ['1', 2, true, false], - { - number: 123, - string: 'foo', - booleanTrue: true, - booleanFalse: false, - null: null, - }, - ], - }; - - const { - type, - asError, - inputData, - }: { - type: string; - asError?: boolean; - inputData?: any; - } = data; - if (!Object.hasOwnProperty.call(sampleData, type)) { - throw new functions.https.HttpsError( - 'invalid-argument', - 'Invalid test requested.' - ); - } - - const outputData = sampleData[type]; - - try { - assert.deepEqual(outputData, inputData); - } catch (e) { - console.error(e); - throw new functions.https.HttpsError( - 'invalid-argument', - 'Input and Output types did not match.', - (e as any).message - ); - } - - // all good - if (asError) { - throw new functions.https.HttpsError( - 'cancelled', - 'Response data was requested to be sent as part of an Error payload, so here we are!', - outputData - ); - } - - return outputData; -}); +// export const testFunctionCustomRegion = functions +// .region('europe-west1') +// .https.onCall(() => 'europe-west1'); + +// // For e2e testing timeouts. +// export const testFunctionTimeout = functions.https.onCall((data) => { +// console.log(JSON.stringify({ data })); +// return new Promise((resolve, reject) => { +// if (data && data.testTimeout) { +// setTimeout( +// () => resolve({ timeLimit: 'exceeded' }), +// parseInt(data.testTimeout, 10) +// ); +// } else { +// reject( +// new functions.https.HttpsError( +// 'invalid-argument', +// 'testTimeout must be provided.' +// ) +// ); +// } +// }); +// }); + +// // For e2e testing errors & return values. +// // noinspection JSUnusedGlobalSymbols +// export const testFunctionDefaultRegion = functions.https.onCall((data) => { +// console.log(JSON.stringify({ data })); +// if (typeof data === 'undefined') { +// return 'undefined'; +// } + +// if (typeof data === 'string') { +// return 'string'; +// } + +// if (typeof data === 'number') { +// return 'number'; +// } + +// if (typeof data === 'boolean') { +// return 'boolean'; +// } + +// if (data === null) { +// return 'null'; +// } + +// if (Array.isArray(data)) { +// return 'array'; +// } + +// if(data.type === 'rawData') { +// return data; +// } + +// const sampleData: { +// [key: string]: any; +// } = { +// number: 1234, +// string: 'acde', +// boolean: true, +// null: null, +// map: { +// number: 1234, +// string: 'acde', +// boolean: true, +// null: null, +// }, +// list: [1234, 'acde', true, null], +// deepMap: { +// number: 123, +// string: 'foo', +// booleanTrue: true, +// booleanFalse: false, +// null: null, +// list: ['1', 2, true, false], +// map: { +// number: 123, +// string: 'foo', +// booleanTrue: true, +// booleanFalse: false, +// null: null, +// }, +// }, +// deepList: [ +// '1', +// 2, +// true, +// false, +// ['1', 2, true, false], +// { +// number: 123, +// string: 'foo', +// booleanTrue: true, +// booleanFalse: false, +// null: null, +// }, +// ], +// }; + +// const { +// type, +// asError, +// inputData, +// }: { +// type: string; +// asError?: boolean; +// inputData?: any; +// } = data; +// if (!Object.hasOwnProperty.call(sampleData, type)) { +// throw new functions.https.HttpsError( +// 'invalid-argument', +// 'Invalid test requested.' +// ); +// } + +// const outputData = sampleData[type]; + +// try { +// assert.deepEqual(outputData, inputData); +// } catch (e) { +// console.error(e); +// throw new functions.https.HttpsError( +// 'invalid-argument', +// 'Input and Output types did not match.', +// (e as any).message +// ); +// } + +// // all good +// if (asError) { +// throw new functions.https.HttpsError( +// 'cancelled', +// 'Response data was requested to be sent as part of an Error payload, so here we are!', +// outputData +// ); +// } + +// return outputData; +// }); export const testMapConvertType = functions.https.onCall((data) => ({ foo: 'bar', })); + +exports.getForecast = onCall(async (request, response) => { + const fruits = ['Apple', 'Mango', 'Banana'] + + const allFruits = fruits.map(async (fruit) => { + + // Stream each forecast as it resolves! + if (request.acceptsStreaming) { + response?.sendChunk(fruit); + } + + return fruit; + }); + + // Fallback for non-streaming clients + return Promise.all(allFruits); +}); \ No newline at end of file diff --git a/packages/cloud_functions/cloud_functions/example/lib/main.dart b/packages/cloud_functions/cloud_functions/example/lib/main.dart index ff18093d8117..0f0cd1dc3cf0 100644 --- a/packages/cloud_functions/cloud_functions/example/lib/main.dart +++ b/packages/cloud_functions/cloud_functions/example/lib/main.dart @@ -34,6 +34,24 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { List fruit = []; + @override + void initState() { + super.initState(); + FirebaseFunctions.instance + .httpsStreamCallable('getFruits') + .stream() + .listen((data) { + print("Chunk >>>> ${data.partialData}"); + }); + } + + Future _getTestValues() async { + final streamResult = + FirebaseFunctions.instance.httpsStreamCallable('getFruits'); + final result = await streamResult.data; + print("result is >>> ${result.result.data}"); + } + @override Widget build(BuildContext context) { final localhostMapped = @@ -60,6 +78,15 @@ class _MyAppState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.end, children: [ + FloatingActionButton.extended( + onPressed: () async { + _getTestValues(); + }, + label: const Text('Call Test Values'), + icon: const Icon(Icons.cloud), + backgroundColor: Colors.deepOrange, + ), + const SizedBox(height: 10), FloatingActionButton.extended( onPressed: () async { // See .github/workflows/scripts/functions/src/index.ts for the example function we From 4804ab9e70b3873a58bd1663cba55acbaa3369fb Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Wed, 2 Apr 2025 17:05:03 +0000 Subject: [PATCH 14/22] chore: update functions based on API Doc modification --- .../FirebaseFunctionsStreamHandler.java | 4 --- .../FlutterFirebaseFunctionsPlugin.java | 18 +------------ .../functions/StreamResponseSubscriber.java | 27 ++++++------------- .../FirebaseFunctionsPlugin.swift | 15 +---------- .../FunctionsStreamHandler.swift | 24 +++-------------- .../cloud_functions/lib/cloud_functions.dart | 2 +- .../lib/src/https_callable_stream.dart | 15 ++++++----- .../lib/src/https_callable_stream_result.dart | 10 +++---- 8 files changed, 29 insertions(+), 86 deletions(-) diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java index 186d40b09d7e..a00163390262 100644 --- a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java @@ -62,8 +62,4 @@ private void httpsStreamCall(Map arguments, EventChannel.EventSi events.error("firebase_functions", e.getMessage(), null); } } - - public Object getResult() { - return subscriber.getResult(); - } } diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java index 311ffa90a674..7141fd4d7717 100644 --- a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FlutterFirebaseFunctionsPlugin.java @@ -38,8 +38,6 @@ public class FlutterFirebaseFunctionsPlugin private MethodChannel channel; private FlutterPluginBinding pluginBinding; - private FirebaseFunctionsStreamHandler streamHandler; - /** * Default Constructor. * @@ -66,7 +64,7 @@ private void registerEventChannel(Map arguments) { final EventChannel eventChannel = new EventChannel(pluginBinding.getBinaryMessenger(), eventChannelName); FirebaseFunctions functions = getFunctions(arguments); - streamHandler = new FirebaseFunctionsStreamHandler(functions); + FirebaseFunctionsStreamHandler streamHandler = new FirebaseFunctionsStreamHandler(functions); eventChannel.setStreamHandler(streamHandler); } @@ -129,25 +127,11 @@ private Task httpsFunctionCall(Map arguments) { return taskCompletionSource.getTask(); } - private void getCompleteResult(Result result) { - cachedThreadPool.execute( - () -> { - try { - Object completeResult = streamHandler.getResult(); - result.success(completeResult); - } catch (Exception e) { - result.error("firebase_functions", e.getMessage(), getExceptionDetails(e)); - } - }); - } - @Override public void onMethodCall(MethodCall call, @NonNull final Result result) { if (call.method.equals("FirebaseFunctions#registerEventChannel")) { registerEventChannel(call.arguments()); result.success(null); - } else if (call.method.equals("FirebaseFunctions#getCompleteResult")) { - getCompleteResult(result); } else if (call.method.equals("FirebaseFunctions#call")) { httpsFunctionCall(call.arguments()) .addOnCompleteListener( diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java index f6d4b0e953f0..877d27d454ba 100644 --- a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java @@ -8,7 +8,8 @@ import android.os.Looper; import com.google.firebase.functions.StreamResponse; import io.flutter.plugin.common.EventChannel; -import java.util.concurrent.CountDownLatch; +import java.util.HashMap; +import java.util.Map; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; @@ -18,10 +19,6 @@ public class StreamResponseSubscriber implements Subscriber { private final Handler mainThreadHandler = new Handler(Looper.getMainLooper()); - private CountDownLatch latch = new CountDownLatch(1); - - private Object result; - public StreamResponseSubscriber(EventChannel.EventSink eventSink) { this.eventSink = eventSink; } @@ -34,12 +31,15 @@ public void onSubscribe(Subscription s) { @Override public void onNext(StreamResponse streamResponse) { + Map messageMap = new HashMap<>(); if (streamResponse instanceof StreamResponse.Message) { Object message = ((StreamResponse.Message) streamResponse).getMessage().getData(); - mainThreadHandler.post(() -> eventSink.success(message)); + messageMap.put("message", message); + mainThreadHandler.post(() -> eventSink.success(messageMap)); } else { - this.result = ((StreamResponse.Result) streamResponse).getResult().getData(); - latch.countDown(); + Object result = ((StreamResponse.Result) streamResponse).getResult().getData(); + messageMap.put("result", result); + mainThreadHandler.post(() -> eventSink.success(messageMap)); } } @@ -47,7 +47,6 @@ public void onNext(StreamResponse streamResponse) { public void onError(Throwable t) { if (eventSink != null) { eventSink.error("firebase_functions", t.getMessage(), null); - latch.countDown(); } } @@ -61,16 +60,6 @@ public void onComplete() { public void cancel() { if (subscription != null) { subscription.cancel(); - latch.countDown(); - } - } - - public Object getResult() { - try { - latch.await(); - return this.result; - } catch (Exception e) { - throw new RuntimeException(e); } } } diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FirebaseFunctionsPlugin.swift b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FirebaseFunctionsPlugin.swift index 85be6a1c5b3f..ec875e782abf 100644 --- a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FirebaseFunctionsPlugin.swift +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FirebaseFunctionsPlugin.swift @@ -19,7 +19,6 @@ let kFLTFirebaseFunctionsChannelName = "plugins.flutter.io/firebase_functions" public class FirebaseFunctionsPlugin: NSObject, FLTFirebasePluginProtocol, FlutterPlugin { private let binaryMessenger: FlutterBinaryMessenger - private var streamHandler: FunctionsStreamHandler? init(binaryMessenger: FlutterBinaryMessenger) { self.binaryMessenger = binaryMessenger @@ -66,18 +65,11 @@ public class FirebaseFunctionsPlugin: NSObject, FLTFirebasePluginProtocol, Flutt let eventChannelName = "\(kFLTFirebaseFunctionsChannelName)/\(eventChannelId)" let eventChannel = FlutterEventChannel(name: eventChannelName, binaryMessenger: binaryMessenger) let functions = getFunctions(arguments: arguments) - streamHandler = FunctionsStreamHandler(functions: functions) + let streamHandler = FunctionsStreamHandler(functions: functions) eventChannel.setStreamHandler(streamHandler) } public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - if call.method == "FirebaseFunctions#getCompleteResult" { - Task { - await getCompleteResult(result: result) - } - return - } - guard let arguments = call.arguments as? [String: Any] else { result(FlutterError(code: "invalid_arguments", message: "Invalid arguments", @@ -157,11 +149,6 @@ public class FirebaseFunctionsPlugin: NSObject, FLTFirebasePluginProtocol, Flutt } } - private func getCompleteResult(result: @escaping FlutterResult) async { - let value = await streamHandler?.getResult() - result(value) - } - private func getFunctions(arguments: [String: Any]) -> Functions { let appName = arguments["appName"] as? String ?? "" let region = arguments["region"] as? String diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift index d530f43c2c85..80d1819bdcae 100644 --- a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift @@ -13,13 +13,9 @@ import FirebaseFunctions class FunctionsStreamHandler: NSObject, FlutterStreamHandler { var functions: Functions private var streamTask: Task? - @MainActor private var streamResult: Any? - private let continuation: AsyncStream.Continuation - private let stream: AsyncStream init(functions: Functions) { self.functions = functions - (stream, continuation) = AsyncStream.makeStream(of: Any?.self) super.init() } @@ -33,7 +29,6 @@ class FunctionsStreamHandler: NSObject, FlutterStreamHandler { func onCancel(withArguments arguments: Any?) -> FlutterError? { streamTask?.cancel() - continuation.finish() return nil } @@ -84,10 +79,11 @@ class FunctionsStreamHandler: NSObject, FlutterStreamHandler { await MainActor.run { switch response { case let .message(message): - events(message.value) + var wrappedMessage: [String: Any?] = ["message": message.value] + events(wrappedMessage) case let .result(result): - self.streamResult = result.value - continuation.yield(result.value) + var wrappedResult: [String: Any?] = ["result": result.value] + events(wrappedResult) } } } @@ -96,8 +92,6 @@ class FunctionsStreamHandler: NSObject, FlutterStreamHandler { events(FlutterError(code: "unknown", message: error.localizedDescription, details: ["code": "unknown", "message": error.localizedDescription])) - continuation.yield(nil) - continuation.finish() } } } else { @@ -105,17 +99,7 @@ class FunctionsStreamHandler: NSObject, FlutterStreamHandler { events(FlutterError(code: "unknown", message: "Streaming requires iOS 15+", details: nil)) - continuation.yield(nil) } - continuation.finish() } } - - @MainActor - func getResult() async -> Any? { - for await result in stream { - return result - } - return nil - } } diff --git a/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart b/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart index 4c79d7075c25..a316dc7afcb2 100644 --- a/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart +++ b/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart @@ -8,7 +8,6 @@ import 'dart:async'; // ignore: unnecessary_import import 'dart:typed_data'; -import 'package:cloud_functions/src/https_callable_stream_result.dart'; import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core_platform_interface/firebase_core_platform_interface.dart' @@ -22,3 +21,4 @@ part 'src/firebase_functions.dart'; part 'src/https_callable.dart'; part 'src/https_callable_result.dart'; part 'src/https_callable_stream.dart'; +part 'src/https_callable_stream_result.dart'; diff --git a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart index 7361cbeb3980..deaefbf9a889 100644 --- a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart +++ b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart @@ -5,7 +5,7 @@ part of '../cloud_functions.dart'; -class HttpsCallableStream { +class HttpsCallableStream { HttpsCallableStream._(this.delegate); /// Returns the underlying [HttpsCallableStream] delegate for this @@ -13,12 +13,15 @@ class HttpsCallableStream { @visibleForTesting final HttpsCallableStreamsPlatform delegate; - Stream> stream([Object? input]) async* { + Stream stream([Object? input]) async* { await for (final value in delegate.stream(input)) { - yield Chunk(value); + if (value is Map) { + if (value.containsKey('message')) { + yield Chunk(value['message'] as T); + } else if (value.containsKey('result')) { + yield Result(HttpsCallableResult._(value['result'] as R)); + } + } } } - - Future> get data async => - Result(HttpsCallableResult._(await delegate.data)); } diff --git a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart index 2ff2bca381c4..05e9a7aa7417 100644 --- a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart +++ b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart @@ -3,19 +3,19 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -import 'package:cloud_functions/cloud_functions.dart'; +part of '../cloud_functions.dart'; /// Represents a response from a Server-Sent Event (SSE) stream. -sealed class StreamResponse {} +sealed class StreamResponse {} /// A chunk received during the stream. -class Chunk extends StreamResponse { +class Chunk extends StreamResponse { final T partialData; Chunk(this.partialData); } /// The final result of the computation, marking the end of the stream. -class Result extends StreamResponse { - final HttpsCallableResult result; +class Result extends StreamResponse { + final HttpsCallableResult result; Result(this.result); } From 4f83c36c2fa4c683e575df3ef5921794cc311cd0 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Thu, 3 Apr 2025 00:04:11 +0000 Subject: [PATCH 15/22] chore: clean up code --- .../FirebaseFunctionsStreamHandler.java | 24 +++++++++- .../functions/StreamResponseSubscriber.java | 10 ++-- .../FunctionsStreamHandler.swift | 20 +++++--- .../lib/src/firebase_functions.dart | 25 +++++++--- .../method_channel_firebase_functions.dart | 8 ++-- ...method_channel_https_callable_streams.dart | 16 ++----- ...platform_interface_firebase_functions.dart | 6 +-- ...form_interface_https_callable_streams.dart | 6 ++- .../lib/cloud_functions_web.dart | 11 ++++- .../lib/https_callable_stream_web.dart | 26 +++++++--- .../lib/interop/functions.dart | 21 ++++++--- .../lib/interop/functions_interop.dart | 47 ++++++++----------- 12 files changed, 135 insertions(+), 85 deletions(-) diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java index a00163390262..09286763b910 100644 --- a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/FirebaseFunctionsStreamHandler.java @@ -6,11 +6,15 @@ import android.net.Uri; import com.google.firebase.functions.FirebaseFunctions; +import com.google.firebase.functions.HttpsCallableOptions; +import com.google.firebase.functions.HttpsCallableReference; import com.google.firebase.functions.StreamResponse; import io.flutter.plugin.common.EventChannel; import io.flutter.plugin.common.EventChannel.StreamHandler; import java.net.URL; import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; import org.reactivestreams.Publisher; public class FirebaseFunctionsStreamHandler implements StreamHandler { @@ -41,21 +45,37 @@ private void httpsStreamCall(Map arguments, EventChannel.EventSi String functionName = (String) arguments.get("functionName"); String functionUri = (String) arguments.get("functionUri"); String origin = (String) arguments.get("origin"); + Integer timeout = (Integer) arguments.get("timeout"); Object parameters = arguments.get("parameters"); + boolean limitedUseAppCheckToken = + (boolean) Objects.requireNonNull(arguments.get("limitedUseAppCheckToken")); if (origin != null) { Uri originUri = Uri.parse(origin); firebaseFunctions.useEmulator(originUri.getHost(), originUri.getPort()); } + HttpsCallableReference httpsCallableReference; + HttpsCallableOptions options = + new HttpsCallableOptions.Builder() + .setLimitedUseAppCheckTokens(limitedUseAppCheckToken) + .build(); + Publisher publisher; if (functionName != null) { - publisher = firebaseFunctions.getHttpsCallable(functionName).stream(parameters); + httpsCallableReference = firebaseFunctions.getHttpsCallable(functionName, options); + publisher = httpsCallableReference.stream(parameters); } else if (functionUri != null) { - publisher = firebaseFunctions.getHttpsCallableFromUrl(new URL(functionUri)).stream(); + httpsCallableReference = + firebaseFunctions.getHttpsCallableFromUrl(new URL(functionUri), options); + publisher = httpsCallableReference.stream(); } else { throw new IllegalArgumentException("Either functionName or functionUri must be set"); } + + if (timeout != null) { + httpsCallableReference.setTimeout(timeout.longValue(), TimeUnit.MILLISECONDS); + } subscriber = new StreamResponseSubscriber(events); publisher.subscribe(subscriber); } catch (Exception e) { diff --git a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java index 877d27d454ba..2ec7c050baf3 100644 --- a/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java +++ b/packages/cloud_functions/cloud_functions/android/src/main/java/io/flutter/plugins/firebase/functions/StreamResponseSubscriber.java @@ -31,15 +31,15 @@ public void onSubscribe(Subscription s) { @Override public void onNext(StreamResponse streamResponse) { - Map messageMap = new HashMap<>(); + Map responseMap = new HashMap<>(); if (streamResponse instanceof StreamResponse.Message) { Object message = ((StreamResponse.Message) streamResponse).getMessage().getData(); - messageMap.put("message", message); - mainThreadHandler.post(() -> eventSink.success(messageMap)); + responseMap.put("message", message); + mainThreadHandler.post(() -> eventSink.success(responseMap)); } else { Object result = ((StreamResponse.Result) streamResponse).getResult().getData(); - messageMap.put("result", result); - mainThreadHandler.post(() -> eventSink.success(messageMap)); + responseMap.put("result", result); + mainThreadHandler.post(() -> eventSink.success(responseMap)); } } diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift index 80d1819bdcae..a0f96c6ce844 100644 --- a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift @@ -45,6 +45,8 @@ class FunctionsStreamHandler: NSObject, FlutterStreamHandler { let functionUri = arguments["functionUri"] as? String let origin = arguments["origin"] as? String let parameters = arguments["arguments"] + let timeout = arguments["timeout"] as? Double + let limitedUseAppCheckToken = arguments["limitedUseAppCheckToken"] as? Bool ?? false if let origin, let url = URL(string: origin), @@ -53,14 +55,16 @@ class FunctionsStreamHandler: NSObject, FlutterStreamHandler { functions.useEmulator(withHost: host, port: port) } + let options = HTTPSCallableOptions(requireLimitedUseAppCheckTokens: limitedUseAppCheckToken) + // Stream handling for iOS 15+ if #available(iOS 15.0, *) { - let function: Callable> + var function: Callable> if let functionName { - function = self.functions.httpsCallable(functionName) + function = self.functions.httpsCallable(functionName, options: options) } else if let functionUri, let url = URL(string: functionUri) { - function = self.functions.httpsCallable(url) + function = self.functions.httpsCallable(url, options: options) } else { await MainActor.run { events(FlutterError(code: "IllegalArgumentException", @@ -70,6 +74,10 @@ class FunctionsStreamHandler: NSObject, FlutterStreamHandler { return } + if let timeout { + function.timeoutInterval = timeout / 1000 + } + do { let encodedParameters = AnyEncodable(parameters) @@ -79,11 +87,9 @@ class FunctionsStreamHandler: NSObject, FlutterStreamHandler { await MainActor.run { switch response { case let .message(message): - var wrappedMessage: [String: Any?] = ["message": message.value] - events(wrappedMessage) + events(["message": message.value]) case let .result(result): - var wrappedResult: [String: Any?] = ["result": result.value] - events(wrappedResult) + events(["result": result.value]) } } } diff --git a/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart b/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart index ea9e84f53d72..a85ae2d753a9 100644 --- a/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart @@ -100,27 +100,38 @@ class FirebaseFunctions extends FirebasePluginPlatform { /// /// Should be the name of the Callable function in Firebase that supports streaming. HttpsCallableStream httpsStreamCallable( - String name, - ) { + String name, { + HttpsCallableOptions? options, + }) { + options ??= HttpsCallableOptions(); assert(name.isNotEmpty); - return HttpsCallableStream._(delegate.httpsStreamCallable(_origin, name)); + return HttpsCallableStream._( + delegate.httpsStreamCallable(_origin, name, options)); } /// A reference to the streaming Callable HTTPS trigger with the given name. /// /// Should be URL of the 2nd gen Callable function in Firebase. - HttpsCallableStream httpsCallableStreamFromUrl(String url) { + HttpsCallableStream httpsCallableStreamFromUrl( + String url, { + HttpsCallableOptions? options, + }) { + options ??= HttpsCallableOptions(); final uri = Uri.parse(url); return HttpsCallableStream._( - delegate.httpsStreamCallableWithUri(_origin, uri)); + delegate.httpsStreamCallableWithUri(_origin, uri, options)); } /// A reference to the streaming Callable HTTPS trigger with the given name. /// /// Should be Uri of the 2nd gen Callable function in Firebase. - HttpsCallableStream httpsCallableStreamFromUri(Uri uri) { + HttpsCallableStream httpsCallableStreamFromUri( + Uri uri, { + HttpsCallableOptions? options, + }) { + options ??= HttpsCallableOptions(); return HttpsCallableStream._( - delegate.httpsStreamCallableWithUri(_origin, uri)); + delegate.httpsStreamCallableWithUri(_origin, uri, options)); } /// Changes this instance to point to a Cloud Functions emulator running locally. diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart index 18f7cfc7a3e7..78f0e8cdae94 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart @@ -54,13 +54,13 @@ class MethodChannelFirebaseFunctions extends FirebaseFunctionsPlatform { @override HttpsCallableStreamsPlatform httpsStreamCallable( - String? origin, String name) { - return MethodChannelHttpsCallableStreams(this, origin, name, null); + String? origin, String name, HttpsCallableOptions options) { + return MethodChannelHttpsCallableStreams(this, origin, name, options, null); } @override HttpsCallableStreamsPlatform httpsStreamCallableWithUri( - String? origin, Uri uri) { - return MethodChannelHttpsCallableStreams(this, origin, null, uri); + String? origin, Uri uri, HttpsCallableOptions options) { + return MethodChannelHttpsCallableStreams(this, origin, null, options, uri); } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart index b761c82f0c4a..4647fb163363 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart @@ -11,9 +11,9 @@ import '../../cloud_functions_platform_interface.dart'; class MethodChannelHttpsCallableStreams extends HttpsCallableStreamsPlatform { MethodChannelHttpsCallableStreams(FirebaseFunctionsPlatform functions, - String? origin, String? name, Uri? uri) + String? origin, String? name, HttpsCallableOptions options, Uri? uri) : _transformedUri = uri?.pathSegments.join('_').replaceAll('.', '_'), - super(functions, origin, name, uri) { + super(functions, origin, name, options, uri) { _eventChannelId = name ?? _transformedUri ?? ''; _channel = EventChannel('plugins.flutter.io/firebase_functions/$_eventChannelId'); @@ -32,6 +32,8 @@ class MethodChannelHttpsCallableStreams 'functionUri': uri?.toString(), 'origin': origin, 'parameters': parameters, + 'limitedUseAppCheckToken': options.limitedUseAppCheckToken, + 'timeout': options.timeout.inMilliseconds, }; yield* _channel.receiveBroadcastStream(eventData).map((message) { if (message is Map) { @@ -52,14 +54,4 @@ class MethodChannelHttpsCallableStreams 'region': functions.region, }); } - - @override - Future get data async { - final result = await MethodChannelFirebaseFunctions.channel - .invokeMethod('FirebaseFunctions#getCompleteResult'); - if (result is Map) { - return Map.from(result); - } - return result; - } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart index 7112127b5abf..7191ed40712d 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart @@ -74,14 +74,12 @@ abstract class FirebaseFunctionsPlatform extends PlatformInterface { } HttpsCallableStreamsPlatform httpsStreamCallable( - String? origin, - String name, - ) { + String? origin, String name, HttpsCallableOptions options) { throw UnimplementedError('httpsStreamCallable() is not implemented'); } HttpsCallableStreamsPlatform httpsStreamCallableWithUri( - String? origin, Uri uri) { + String? origin, Uri uri, HttpsCallableOptions options) { throw UnimplementedError('httpsStreamCallableWithUri() is not implemented'); } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart index ef8922f7225a..0b88221229a3 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart @@ -11,6 +11,7 @@ abstract class HttpsCallableStreamsPlatform extends PlatformInterface { this.functions, this.origin, this.name, + this.options, this.uri, ) : assert(name != null || uri != null), super(token: _token); @@ -33,7 +34,8 @@ abstract class HttpsCallableStreamsPlatform extends PlatformInterface { /// The URI of the function for 2nd gen functions final Uri? uri; - Stream stream(Object? parameters); + /// Used to set the options for this instance. + HttpsCallableOptions options; - Future get data; + Stream stream(Object? parameters); } diff --git a/packages/cloud_functions/cloud_functions_web/lib/cloud_functions_web.dart b/packages/cloud_functions/cloud_functions_web/lib/cloud_functions_web.dart index 81d3ad237695..fcee4552424a 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/cloud_functions_web.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/cloud_functions_web.dart @@ -65,7 +65,14 @@ class FirebaseFunctionsWeb extends FirebaseFunctionsPlatform { } @override - HttpsCallableStreamsPlatform httpsStreamCallable(String? origin, String name) { - return HttpsCallableStreamWeb(this, _delegate, origin, name, null); + HttpsCallableStreamsPlatform httpsStreamCallable( + String? origin, String name, HttpsCallableOptions options) { + return HttpsCallableStreamWeb(this, _delegate, origin, name, options, null); + } + + @override + HttpsCallableStreamsPlatform httpsStreamCallableWithUri( + String? origin, Uri uri, HttpsCallableOptions options) { + return HttpsCallableStreamWeb(this, _delegate, origin, null, options, null); } } diff --git a/packages/cloud_functions/cloud_functions_web/lib/https_callable_stream_web.dart b/packages/cloud_functions/cloud_functions_web/lib/https_callable_stream_web.dart index cfe0900b9279..f79ab210cb85 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/https_callable_stream_web.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/https_callable_stream_web.dart @@ -6,18 +6,23 @@ import 'dart:js_interop'; import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; +import 'package:cloud_functions_web/interop/functions_interop.dart' as interop; import 'interop/functions.dart' as functions_interop; +import 'utils.dart'; class HttpsCallableStreamWeb extends HttpsCallableStreamsPlatform { HttpsCallableStreamWeb( - super.functions, this._webFunctions, super.origin, super.name, super.uri); + FirebaseFunctionsPlatform functions, + this._webFunctions, + String? origin, + String? name, + HttpsCallableOptions options, + Uri? uri) + : super(functions, origin, name, options, uri); final functions_interop.Functions _webFunctions; - @override - Future get data => throw UnimplementedError(); - @override Stream stream(Object? parameters) async* { if (origin != null) { @@ -37,9 +42,16 @@ class HttpsCallableStreamWeb extends HttpsCallableStreamsPlatform { } final JSAny? parametersJS = parameters?.jsify(); - - await for (final value in callable.stream(parametersJS)){ - yield value; + interop.HttpsCallableStreamOptions callableStreamOptions = + interop.HttpsCallableStreamOptions( + limitedUseAppCheckTokens: options.limitedUseAppCheckToken.toJS); + try { + await for (final value + in callable.stream(parametersJS, callableStreamOptions)) { + yield value; + } + } catch (e, s) { + throw convertFirebaseFunctionsException(e as JSObject, s); } } } diff --git a/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart b/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart index 9913a427bc4d..564c6eef9b49 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart @@ -84,17 +84,26 @@ class HttpsCallable extends JsObjectWrapper { ); } - Stream stream(JSAny? data) async* { - final streamCallable = - await (jsObject as functions_interop.HttpsCallable).stream().toDart; + Stream stream(JSAny? data, + functions_interop.HttpsCallableStreamOptions? options) async* { + final streamCallable = await (jsObject as functions_interop.HttpsCallable) + .stream(data, options) + .toDart; final streamResult = streamCallable! as functions_interop.HttpsCallableStreamResultJsImpl; await for (final value in streamResult.stream.asStream()) { - yield HttpsCallableResult.getInstance( - value as functions_interop.HttpsCallableResultJsImpl, - ); + // ignore: invalid_runtime_check_with_js_interop_types + final message = value is JSObject + ? HttpsCallableResult.getInstance( + value as functions_interop.HttpsCallableResultJsImpl, + ) + : value; + yield {'message': message}; } + + final result = await streamResult.data.toDart; + yield {'result': result}; } } diff --git a/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart b/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart index 8bf204e9bfe3..b6e32f02bcc4 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart @@ -9,8 +9,11 @@ library; import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; +import 'package:web/web.dart' as web; import 'package:firebase_core_web/firebase_core_web_interop.dart'; +import 'dart:html'; @JS() @staticInterop @@ -82,11 +85,9 @@ extension HttpsCallableResultJsImplExtension on HttpsCallableResultJsImpl { class HttpsCallable {} extension HttpsCallableExtension on HttpsCallable { - external JSPromise stream( - [JSAny? data, HttpsCallableStreamOptions? options]); + external JSPromise stream([JSAny? data, HttpsCallableStreamOptions? options]); } - @JS('HttpsCallableStreamResult') @staticInterop class HttpsCallableStreamResultJsImpl {} @@ -97,7 +98,6 @@ extension HttpsCallableStreamResultJsImplExtension external JsAsyncIterator stream; } - @JS('HttpsCallableStreamOptions') @staticInterop @anonymous @@ -113,30 +113,23 @@ extension HttpsCallableStreamOptionsExtension on HttpsCallableStreamOptions { extension type JsAsyncIterator._(JSObject _) implements JSObject { - external JSPromise> next(); - - Stream asStream() async* { - this as SymbolJsImpl; + Stream asStream() async* { + final symbolJS = web.window.getProperty('Symbol'.toJS)! as JSFunction; + final asyncIterator = symbolJS.getProperty('asyncIterator'.toJS); + final iterator = + (this as JSObject).getProperty(asyncIterator!)! as JsAsyncIterator; + window.console.log(iterator); + final object = (iterator as JSFunction).callAsFunction()! as JSObject; while (true) { - final result = await next().toDart; - if (result.done) break; - yield result.value; + // Wait for the next iteration result. + final result = await ((object.getProperty('next'.toJS)! as JSFunction) + .callAsFunction()! as JSPromise) + .toDart; + final dartObject = (result.dartify()! as Map).cast(); + if (dartObject['done'] as bool) { + break; + } + yield (result as JSObject).getProperty('value'.toJS); } } } - -extension type JsAsyncIteratorState._(JSObject _) - implements JSObject { - external bool get done; - - external T get value; -} - - -@JS('Symbol') -@staticInterop -extension type SymbolJsImpl(JSObject _) implements JSObject { - - @JS('asyncIterator') - external static JSSymbol asyncIterator; -} From 213e28386971b4fd186eaa42156629a1552138a5 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Thu, 3 Apr 2025 07:39:25 +0000 Subject: [PATCH 16/22] chore: add web package --- packages/cloud_functions/cloud_functions_web/pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cloud_functions/cloud_functions_web/pubspec.yaml b/packages/cloud_functions/cloud_functions_web/pubspec.yaml index f8b1b8fd18a0..7bfd4954e291 100644 --- a/packages/cloud_functions/cloud_functions_web/pubspec.yaml +++ b/packages/cloud_functions/cloud_functions_web/pubspec.yaml @@ -13,6 +13,7 @@ dependencies: cloud_functions_platform_interface: ^5.6.4 firebase_core: ^3.12.1 firebase_core_web: ^2.21.1 + web: ^1.1.1 flutter: sdk: flutter flutter_web_plugins: From 794d441991ed182f767611d1cfec9ced9bb6c749 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Thu, 3 Apr 2025 12:38:35 +0000 Subject: [PATCH 17/22] chore: add streaming example --- .../workflows/scripts/functions/src/index.ts | 297 +++++++++--------- .../cloud_functions/example/lib/main.dart | 86 +++-- .../lib/interop/functions.dart | 14 +- .../lib/interop/functions_interop.dart | 12 +- 4 files changed, 225 insertions(+), 184 deletions(-) diff --git a/.github/workflows/scripts/functions/src/index.ts b/.github/workflows/scripts/functions/src/index.ts index a90de80a75b8..6d6cc82951a5 100644 --- a/.github/workflows/scripts/functions/src/index.ts +++ b/.github/workflows/scripts/functions/src/index.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; import * as functions from 'firebase-functions'; -import { onCall } from 'firebase-functions/https'; +// import { onCall } from 'firebase-functions/https'; import * as functionsv2 from 'firebase-functions/v2'; // For example app. @@ -15,163 +15,160 @@ export const listfruits2ndgen = functionsv2.https.onCall(() => { // For e2e testing a custom region. // noinspection JSUnusedGlobalSymbols -// export const testFunctionCustomRegion = functions -// .region('europe-west1') -// .https.onCall(() => 'europe-west1'); - -// // For e2e testing timeouts. -// export const testFunctionTimeout = functions.https.onCall((data) => { -// console.log(JSON.stringify({ data })); -// return new Promise((resolve, reject) => { -// if (data && data.testTimeout) { -// setTimeout( -// () => resolve({ timeLimit: 'exceeded' }), -// parseInt(data.testTimeout, 10) -// ); -// } else { -// reject( -// new functions.https.HttpsError( -// 'invalid-argument', -// 'testTimeout must be provided.' -// ) -// ); -// } -// }); -// }); - -// // For e2e testing errors & return values. -// // noinspection JSUnusedGlobalSymbols -// export const testFunctionDefaultRegion = functions.https.onCall((data) => { -// console.log(JSON.stringify({ data })); -// if (typeof data === 'undefined') { -// return 'undefined'; -// } - -// if (typeof data === 'string') { -// return 'string'; -// } - -// if (typeof data === 'number') { -// return 'number'; -// } - -// if (typeof data === 'boolean') { -// return 'boolean'; -// } - -// if (data === null) { -// return 'null'; -// } - -// if (Array.isArray(data)) { -// return 'array'; -// } - -// if(data.type === 'rawData') { -// return data; -// } - -// const sampleData: { -// [key: string]: any; -// } = { -// number: 1234, -// string: 'acde', -// boolean: true, -// null: null, -// map: { -// number: 1234, -// string: 'acde', -// boolean: true, -// null: null, -// }, -// list: [1234, 'acde', true, null], -// deepMap: { -// number: 123, -// string: 'foo', -// booleanTrue: true, -// booleanFalse: false, -// null: null, -// list: ['1', 2, true, false], -// map: { -// number: 123, -// string: 'foo', -// booleanTrue: true, -// booleanFalse: false, -// null: null, -// }, -// }, -// deepList: [ -// '1', -// 2, -// true, -// false, -// ['1', 2, true, false], -// { -// number: 123, -// string: 'foo', -// booleanTrue: true, -// booleanFalse: false, -// null: null, -// }, -// ], -// }; - -// const { -// type, -// asError, -// inputData, -// }: { -// type: string; -// asError?: boolean; -// inputData?: any; -// } = data; -// if (!Object.hasOwnProperty.call(sampleData, type)) { -// throw new functions.https.HttpsError( -// 'invalid-argument', -// 'Invalid test requested.' -// ); -// } - -// const outputData = sampleData[type]; - -// try { -// assert.deepEqual(outputData, inputData); -// } catch (e) { -// console.error(e); -// throw new functions.https.HttpsError( -// 'invalid-argument', -// 'Input and Output types did not match.', -// (e as any).message -// ); -// } - -// // all good -// if (asError) { -// throw new functions.https.HttpsError( -// 'cancelled', -// 'Response data was requested to be sent as part of an Error payload, so here we are!', -// outputData -// ); -// } - -// return outputData; -// }); +export const testFunctionCustomRegion = functions.https.onCall(() => 'europe-west1'); + +// For e2e testing timeouts. +export const testFunctionTimeout = functions.https.onCall((data) => { + console.log(JSON.stringify({ data })); + return new Promise((resolve, reject) => { + if (data && data.rawRequest) { + setTimeout( + () => resolve({ timeLimit: 'exceeded' }), + parseInt(data.rawRequest.body, 10) + ); + } else { + reject( + new functions.https.HttpsError( + 'invalid-argument', + 'testTimeout must be provided.' + ) + ); + } + }); +}); + +// For e2e testing errors & return values. +// noinspection JSUnusedGlobalSymbols +export const testFunctionDefaultRegion = functions.https.onCall((req, res) => { + const data = req.data; + console.log(JSON.stringify({ data })); + if (typeof data === 'undefined') { + return 'undefined'; + } + + if (typeof data === 'string') { + return 'string'; + } + + if (typeof data === 'number') { + return 'number'; + } + + if (typeof data === 'boolean') { + return 'boolean'; + } + + if (data === null) { + return 'null'; + } + + if (Array.isArray(data)) { + return 'array'; + } + + if (data.type === 'rawData') { + return data; + } + + const sampleData: { + [key: string]: any; + } = { + number: 1234, + string: 'acde', + boolean: true, + null: null, + map: { + number: 1234, + string: 'acde', + boolean: true, + null: null, + }, + list: [1234, 'acde', true, null], + deepMap: { + number: 123, + string: 'foo', + booleanTrue: true, + booleanFalse: false, + null: null, + list: ['1', 2, true, false], + map: { + number: 123, + string: 'foo', + booleanTrue: true, + booleanFalse: false, + null: null, + }, + }, + deepList: [ + '1', + 2, + true, + false, + ['1', 2, true, false], + { + number: 123, + string: 'foo', + booleanTrue: true, + booleanFalse: false, + null: null, + }, + ], + }; + + const { + type, + asError, + inputData, + }: { + type: string; + asError?: boolean; + inputData?: any; + } = data; + if (!Object.hasOwnProperty.call(sampleData, type)) { + throw new functions.https.HttpsError( + 'invalid-argument', + 'Invalid test requested.' + ); + } + + const outputData = sampleData[type]; + + try { + assert.deepEqual(outputData, inputData); + } catch (e) { + console.error(e); + throw new functions.https.HttpsError( + 'invalid-argument', + 'Input and Output types did not match.', + (e as any).message + ); + } + + // all good + if (asError) { + throw new functions.https.HttpsError( + 'cancelled', + 'Response data was requested to be sent as part of an Error payload, so here we are!', + outputData + ); + } + + return outputData; +}); export const testMapConvertType = functions.https.onCall((data) => ({ foo: 'bar', })); -exports.getForecast = onCall(async (request, response) => { +exports.getFruits = functions.https.onCall(async (request, response) => { const fruits = ['Apple', 'Mango', 'Banana'] const allFruits = fruits.map(async (fruit) => { - - // Stream each forecast as it resolves! - if (request.acceptsStreaming) { - response?.sendChunk(fruit); - } - - return fruit; + // Stream each fruit as it resolves! + if (request.acceptsStreaming) { + response?.sendChunk(fruit); + } + return fruit; }); // Fallback for non-streaming clients diff --git a/packages/cloud_functions/cloud_functions/example/lib/main.dart b/packages/cloud_functions/cloud_functions/example/lib/main.dart index 0f0cd1dc3cf0..550532ffeba8 100644 --- a/packages/cloud_functions/cloud_functions/example/lib/main.dart +++ b/packages/cloud_functions/cloud_functions/example/lib/main.dart @@ -33,23 +33,38 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { List fruit = []; + List streamResult = []; @override void initState() { super.initState(); - FirebaseFunctions.instance - .httpsStreamCallable('getFruits') - .stream() - .listen((data) { - print("Chunk >>>> ${data.partialData}"); - }); + streamFunction(); } - Future _getTestValues() async { - final streamResult = - FirebaseFunctions.instance.httpsStreamCallable('getFruits'); - final result = await streamResult.data; - print("result is >>> ${result.result.data}"); + void streamFunction() { + fruit.clear(); + FirebaseFunctions.instance.httpsStreamCallable('getFruits').stream().listen( + (data) { + if (data is Chunk) { + setState(() { + // adds individual stream values to list + fruit.add(data.partialData); + }); + } else if (data is Result) { + setState(() { + // stores complete stream result + streamResult = data.result.data; + }); + } + }, + onError: (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('ERROR: $e'), + ), + ); + }, + ); } @override @@ -62,15 +77,39 @@ class _MyAppState extends State { appBar: AppBar( title: const Text('Firebase Functions Example'), ), - body: Center( - child: ListView.builder( - itemCount: fruit.length, - itemBuilder: (context, index) { - return ListTile( - title: Text('${fruit[index]}'), - ); - }, - ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: ListView.builder( + itemCount: fruit.length, + itemBuilder: (context, index) { + return ListTile( + title: Text('${fruit[index]}'), + ); + }, + ), + ), + Visibility( + visible: streamResult.isNotEmpty, + child: const Text( + "Stream's Complete Result: ", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ), + Expanded( + child: ListView.builder( + itemCount: streamResult.length, + itemBuilder: (context, index) { + return ListTile( + title: Text('${streamResult[index]}'), + ); + }, + ), + ), + ], ), floatingActionButton: Builder( builder: (context) { @@ -79,10 +118,8 @@ class _MyAppState extends State { crossAxisAlignment: CrossAxisAlignment.end, children: [ FloatingActionButton.extended( - onPressed: () async { - _getTestValues(); - }, - label: const Text('Call Test Values'), + onPressed: streamFunction, + label: const Text('Call Stream Function'), icon: const Icon(Icons.cloud), backgroundColor: Colors.deepOrange, ), @@ -140,6 +177,7 @@ class _MyAppState extends State { final result = await callable(); setState(() { fruit.clear(); + streamResult.clear(); result.data.forEach((f) { fruit.add(f); }); diff --git a/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart b/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart index 564c6eef9b49..0b548c34748f 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/interop/functions.dart @@ -95,9 +95,9 @@ class HttpsCallable extends JsObjectWrapper { await for (final value in streamResult.stream.asStream()) { // ignore: invalid_runtime_check_with_js_interop_types final message = value is JSObject - ? HttpsCallableResult.getInstance( - value as functions_interop.HttpsCallableResultJsImpl, - ) + ? HttpsCallableStreamResult.getInstance( + value as functions_interop.HttpsStreamIterableResult, + ).data : value; yield {'message': message}; } @@ -160,10 +160,10 @@ class HttpsCallableResult } class HttpsCallableStreamResult - extends JsObjectWrapper { + extends JsObjectWrapper { HttpsCallableStreamResult._fromJsObject( - functions_interop.HttpsCallableStreamResultJsImpl jsObject) - : _data = _dartify(jsObject.data), + functions_interop.HttpsStreamIterableResult jsObject) + : _data = _dartify(jsObject.value), super.fromJsObject(jsObject); static final _expando = Expando(); @@ -171,7 +171,7 @@ class HttpsCallableStreamResult /// Creates a new HttpsCallableResult from a [jsObject]. static HttpsCallableStreamResult getInstance( - functions_interop.HttpsCallableStreamResultJsImpl jsObject) { + functions_interop.HttpsStreamIterableResult jsObject) { return _expando[jsObject] ??= HttpsCallableStreamResult._fromJsObject(jsObject); } diff --git a/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart b/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart index b6e32f02bcc4..e78bbe9a9cbe 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/interop/functions_interop.dart @@ -13,7 +13,6 @@ import 'dart:js_interop_unsafe'; import 'package:web/web.dart' as web; import 'package:firebase_core_web/firebase_core_web_interop.dart'; -import 'dart:html'; @JS() @staticInterop @@ -118,7 +117,6 @@ extension type JsAsyncIterator._(JSObject _) final asyncIterator = symbolJS.getProperty('asyncIterator'.toJS); final iterator = (this as JSObject).getProperty(asyncIterator!)! as JsAsyncIterator; - window.console.log(iterator); final object = (iterator as JSFunction).callAsFunction()! as JSObject; while (true) { // Wait for the next iteration result. @@ -129,7 +127,15 @@ extension type JsAsyncIterator._(JSObject _) if (dartObject['done'] as bool) { break; } - yield (result as JSObject).getProperty('value'.toJS); + yield result as JSObject; } } } + +@JS() +@staticInterop +abstract class HttpsStreamIterableResult {} + +extension HttpsStreamIterableResultExtension on HttpsStreamIterableResult { + external JSAny? get value; +} From 6ad08201a152a10b415a622b2557091925467e79 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Thu, 3 Apr 2025 20:54:30 +0000 Subject: [PATCH 18/22] chore: fix ci issues --- .../scripts/functions/package-lock.json | 2879 ++++++----------- .../workflows/scripts/functions/package.json | 2 +- .../workflows/scripts/functions/src/index.ts | 15 +- .../cloud_functions/CodecUtility.swift | 1 + .../cloud_functions/CodecUtility.swift | 1 + .../FunctionsStreamHandler.swift | 1 + .../cloud_functions_web/pubspec.yaml | 2 +- 7 files changed, 973 insertions(+), 1928 deletions(-) create mode 120000 packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/CodecUtility.swift create mode 120000 packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift diff --git a/.github/workflows/scripts/functions/package-lock.json b/.github/workflows/scripts/functions/package-lock.json index 6d8d411e9180..e48eda2f586d 100644 --- a/.github/workflows/scripts/functions/package-lock.json +++ b/.github/workflows/scripts/functions/package-lock.json @@ -7,7 +7,7 @@ "name": "functions", "hasInstallScript": true, "dependencies": { - "firebase-admin": "^11.5.0", + "firebase-admin": "^13.2.0", "firebase-functions": "^6.3.2" }, "devDependencies": { @@ -18,172 +18,174 @@ "node": "20" } }, - "node_modules/@babel/parser": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", - "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", - "optional": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@fastify/busboy": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-1.2.1.tgz", - "integrity": "sha512-7PQA7EH43S0CxcOa9OeAnaeA0oQ+e/DHNPZwSQM9CQHW76jle5+OvLdibRp/Aafs9KXbLhxyjOTkRjWUbQEd3Q==", - "dependencies": { - "text-decoding": "^1.0.0" - }, - "engines": { - "node": ">=14" - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.1.1.tgz", + "integrity": "sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw==" + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz", + "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==" }, "node_modules/@firebase/app-types": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", - "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==" + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz", + "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==" }, "node_modules/@firebase/auth-interop-types": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz", - "integrity": "sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz", + "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==" }, "node_modules/@firebase/component": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.4.tgz", - "integrity": "sha512-rLMyrXuO9jcAUCaQXCMjCMUsWrba5fzHlNK24xz5j2W6A/SRmK8mZJ/hn7V0fViLbxC0lPMtrK1eYzk6Fg03jA==", + "version": "0.6.13", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.13.tgz", + "integrity": "sha512-I/Eg1NpAtZ8AAfq8mpdfXnuUpcLxIDdCDtTzWSh+FXnp/9eCKJ3SNbOCKrUCyhLzNa2SiPJYruei0sxVjaOTeg==", "dependencies": { - "@firebase/util": "1.9.3", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@firebase/database": { - "version": "0.14.4", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.14.4.tgz", - "integrity": "sha512-+Ea/IKGwh42jwdjCyzTmeZeLM3oy1h0mFPsTy6OqCWzcu/KFqRAr5Tt1HRCOBlNOdbh84JPZC47WLU18n2VbxQ==", - "dependencies": { - "@firebase/auth-interop-types": "0.2.1", - "@firebase/component": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.14.tgz", + "integrity": "sha512-9nxYtkHAG02/Nh2Ssms1T4BbWPPjiwohCvkHDUl4hNxnki1kPgsLo5xe9kXNzbacOStmVys+RUXvwzynQSKmUQ==", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.6.13", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.11.0", "faye-websocket": "0.11.4", "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@firebase/database-compat": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.3.4.tgz", - "integrity": "sha512-kuAW+l+sLMUKBThnvxvUZ+Q1ZrF/vFJ58iUY9kAcbX48U03nVzIF6Tmkf0p3WVQwMqiXguSgtOPIB6ZCeF+5Gg==", - "dependencies": { - "@firebase/component": "0.6.4", - "@firebase/database": "0.14.4", - "@firebase/database-types": "0.10.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.5.tgz", + "integrity": "sha512-CNf1UbvWh6qIaSf4sn6sx2DTDz/em/D7QxULH1LTxxDQHr9+CeYGvlAqrKnk4ZH0P0eIHyQFQU7RwkUJI0B9gQ==", + "dependencies": { + "@firebase/component": "0.6.13", + "@firebase/database": "1.0.14", + "@firebase/database-types": "1.0.10", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@firebase/database-types": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.10.4.tgz", - "integrity": "sha512-dPySn0vJ/89ZeBac70T+2tWWPiJXWbmRygYv0smT5TfE3hDrQ09eKMF3Y+vMlTdrMWq7mUdYW5REWPSGH4kAZQ==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.10.tgz", + "integrity": "sha512-mH6RC1E9/Pv8jf1/p+M8YFTX+iu+iHDN89hecvyO7wHrI4R1V0TXjxOHvX3nLJN1sfh0CWG6CHZ0VlrSmK/cwg==", "dependencies": { - "@firebase/app-types": "0.9.0", - "@firebase/util": "1.9.3" + "@firebase/app-types": "0.9.3", + "@firebase/util": "1.11.0" } }, "node_modules/@firebase/logger": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.0.tgz", - "integrity": "sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.4.tgz", + "integrity": "sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g==", "dependencies": { "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@firebase/util": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz", - "integrity": "sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.11.0.tgz", + "integrity": "sha512-PzSrhIr++KI6y4P6C/IdgBNMkEx0Ex6554/cYd0Hm+ovyFSJtJXqb/3OSIdnBoa2cpwZT1/GW56EmRc5qEc5fQ==", + "hasInstallScript": true, "dependencies": { "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@google-cloud/firestore": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-6.8.0.tgz", - "integrity": "sha512-JRpk06SmZXLGz0pNx1x7yU3YhkUXheKgH5hbDZ4kMsdhtfV5qPLJLRI4wv69K0cZorIk+zTMOwptue7hizo0eA==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.11.0.tgz", + "integrity": "sha512-88uZ+jLsp1aVMj7gh3EKYH1aulTAMFAp8sH/v5a9w8q8iqSG27RiWLoxSAFr/XocZ9hGiWH1kEnBw+zl3xAgNA==", "optional": true, "dependencies": { + "@opentelemetry/api": "^1.3.0", "fast-deep-equal": "^3.1.1", "functional-red-black-tree": "^1.0.1", - "google-gax": "^3.5.7", - "protobufjs": "^7.2.5" + "google-gax": "^4.3.3", + "protobufjs": "^7.2.6" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/@google-cloud/paginator": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.7.tgz", - "integrity": "sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-5.0.2.tgz", + "integrity": "sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg==", "optional": true, "dependencies": { "arrify": "^2.0.0", "extend": "^3.0.2" }, "engines": { - "node": ">=10" + "node": ">=14.0.0" } }, "node_modules/@google-cloud/projectify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-3.0.0.tgz", - "integrity": "sha512-HRkZsNmjScY6Li8/kb70wjGlDDyLkVk3KvoEo9uIoxSjYLJasGiCch9+PqRVDOCGUFvEIqyogl+BeqILL4OJHA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-4.0.0.tgz", + "integrity": "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==", "optional": true, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/@google-cloud/promisify": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-3.0.1.tgz", - "integrity": "sha512-z1CjRjtQyBOYL+5Qr9DdYIfrdLBe746jRTYfaYU6MeXkqp7UfYs/jX16lFFVzZ7PGEJvqZNqYUEtb1mvDww4pA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-4.0.0.tgz", + "integrity": "sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==", "optional": true, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/@google-cloud/storage": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.12.0.tgz", - "integrity": "sha512-78nNAY7iiZ4O/BouWMWTD/oSF2YtYgYB3GZirn0To6eBOugjXVoK+GXgUXOl+HlqbAOyHxAVXOlsj3snfbQ1dw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-7.16.0.tgz", + "integrity": "sha512-7/5LRgykyOfQENcm6hDKP8SX/u9XxE5YOiWOkgkwcoO+cG8xT/cyOvp9wwN3IxfdYgpHs8CE7Nq2PKX2lNaEXw==", "optional": true, "dependencies": { - "@google-cloud/paginator": "^3.0.7", - "@google-cloud/projectify": "^3.0.0", - "@google-cloud/promisify": "^3.0.0", + "@google-cloud/paginator": "^5.0.0", + "@google-cloud/projectify": "^4.0.0", + "@google-cloud/promisify": "<4.1.0", "abort-controller": "^3.0.0", "async-retry": "^1.3.3", - "compressible": "^2.0.12", - "duplexify": "^4.0.0", - "ent": "^2.2.0", - "extend": "^3.0.2", - "fast-xml-parser": "^4.2.2", - "gaxios": "^5.0.0", - "google-auth-library": "^8.0.1", + "duplexify": "^4.1.3", + "fast-xml-parser": "^4.4.1", + "gaxios": "^6.0.2", + "google-auth-library": "^9.6.3", + "html-entities": "^2.5.2", "mime": "^3.0.0", - "mime-types": "^2.0.8", "p-limit": "^3.0.1", - "retry-request": "^5.0.0", - "teeny-request": "^8.0.0", + "retry-request": "^7.0.0", + "teeny-request": "^9.0.0", "uuid": "^8.0.0" }, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/@google-cloud/storage/node_modules/uuid": { @@ -196,27 +198,27 @@ } }, "node_modules/@grpc/grpc-js": { - "version": "1.8.22", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.22.tgz", - "integrity": "sha512-oAjDdN7fzbUi+4hZjKG96MR6KTEubAeMpQEb+77qy+3r0Ua5xTFuie6JOLr4ZZgl5g+W5/uRTS2M1V8mVAFPuA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.13.2.tgz", + "integrity": "sha512-nnR5nmL6lxF8YBqb6gWvEgLdLh/Fn+kvAdX5hUOnt48sNSb0riz/93ASd2E5gvanPA41X6Yp25bIfGRp1SMb2g==", "optional": true, "dependencies": { - "@grpc/proto-loader": "^0.7.0", - "@types/node": ">=12.12.47" + "@grpc/proto-loader": "^0.7.13", + "@js-sdsl/ordered-map": "^4.4.2" }, "engines": { - "node": "^8.13.0 || >=10.10.0" + "node": ">=12.10.0" } }, "node_modules/@grpc/proto-loader": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", - "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", + "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", "optional": true, "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", - "protobufjs": "^7.2.4", + "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { @@ -226,16 +228,23 @@ "node": ">=6" } }, - "node_modules/@jsdoc/salty": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.7.tgz", - "integrity": "sha512-mh8LbS9d4Jq84KLw8pzho7XC2q2/IJGiJss3xwRoLD1A+EE16SjN4PfaG4jRCzKegTFLlN0Zd8SdUPE6XdoPFg==", + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "optional": true, - "dependencies": { - "lodash": "^4.17.21" - }, "engines": { - "node": ">=v12.0.0" + "node": ">=8.0.0" } }, "node_modules/@protobufjs/aspromise": { @@ -310,6 +319,12 @@ "@types/node": "*" } }, + "node_modules/@types/caseless": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz", + "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", + "optional": true + }, "node_modules/@types/connect": { "version": "3.4.33", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", @@ -344,30 +359,15 @@ "@types/range-parser": "*" } }, - "node_modules/@types/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", - "optional": true, - "dependencies": { - "@types/minimatch": "^5.1.2", - "@types/node": "*" - } - }, "node_modules/@types/jsonwebtoken": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", - "integrity": "sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.9.tgz", + "integrity": "sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ==", "dependencies": { + "@types/ms": "*", "@types/node": "*" } }, - "node_modules/@types/linkify-it": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", - "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", - "optional": true - }, "node_modules/@types/lodash": { "version": "4.14.161", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz", @@ -380,39 +380,22 @@ "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", "optional": true }, - "node_modules/@types/markdown-it": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", - "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", - "optional": true, - "dependencies": { - "@types/linkify-it": "*", - "@types/mdurl": "*" - } - }, - "node_modules/@types/mdurl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", - "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", - "optional": true - }, "node_modules/@types/mime": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "optional": true + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" }, "node_modules/@types/node": { - "version": "20.10.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz", - "integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==", + "version": "22.14.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", + "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.21.0" } }, "node_modules/@types/qs": { @@ -425,14 +408,16 @@ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" }, - "node_modules/@types/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==", + "node_modules/@types/request": { + "version": "2.48.12", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.12.tgz", + "integrity": "sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==", "optional": true, "dependencies": { - "@types/glob": "*", - "@types/node": "*" + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" } }, "node_modules/@types/serve-static": { @@ -444,6 +429,12 @@ "@types/mime": "*" } }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "optional": true + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -468,37 +459,12 @@ "node": ">= 0.6" } }, - "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "optional": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "optional": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, - "dependencies": { - "debug": "4" - }, + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "engines": { - "node": ">= 6.0.0" + "node": ">= 14" } }, "node_modules/ansi-regex": { @@ -525,12 +491,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "optional": true - }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -554,10 +514,10 @@ "retry": "0.13.1" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "optional": true }, "node_modules/base64-js": { @@ -577,24 +537,16 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "optional": true + ] }, "node_modules/bignumber.js": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", - "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", - "optional": true, + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.2.0.tgz", + "integrity": "sha512-JocpCSOixzy5XFJi2ub6IMmV/G9i8Lrm2lZvwBv9xPdglmZM0ufDVBbjbrfU/zuLvBfD7Bv2eYxz9i+OHTgkew==", "engines": { "node": "*" } }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "optional": true - }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -631,15 +583,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "optional": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -671,32 +614,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/catharsis": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", - "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", - "optional": true, - "dependencies": { - "lodash": "^4.17.15" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "optional": true, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">= 0.4" } }, "node_modules/cliui": { @@ -731,24 +658,18 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "optional": true }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "optional": true, "dependencies": { - "mime-db": ">= 1.43.0 < 2" + "delayed-stream": "~1.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "optional": true - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -794,11 +715,11 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -809,12 +730,6 @@ } } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "optional": true - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -831,6 +746,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -848,16 +772,29 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", "optional": true, "dependencies": { "end-of-stream": "^1.4.1", "inherits": "^2.0.3", "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" + "stream-shift": "^1.0.2" } }, "node_modules/ecdsa-sig-formatter": { @@ -896,28 +833,10 @@ "once": "^1.4.0" } }, - "node_modules/ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", - "optional": true - }, - "node_modules/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "optional": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "engines": { "node": ">= 0.4" } @@ -930,119 +849,45 @@ "node": ">= 0.4" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "optional": true, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" + "es-errors": "^1.3.0" }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "optional": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "optional": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">= 0.4" } }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "optional": true, "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "optional": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { - "node": ">=4" + "node": ">= 0.4" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "optional": true, "engines": { - "node": ">=4.0" + "node": ">=6" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "node_modules/etag": { "version": "1.8.1", @@ -1130,8 +975,15 @@ "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "optional": true + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/farmhash-modern": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/farmhash-modern/-/farmhash-modern-1.1.0.tgz", + "integrity": "sha512-6ypT4XfgqJk/F3Yuv4SX26I3doUjt0GTG4a+JgWxXQpxXzTBq8fPUeGHfcYMMDPHJHm3yPOSjaeBwBGAHWXCdA==", + "engines": { + "node": ">=18.0.0" + } }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -1139,35 +991,19 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "optional": true }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "optional": true - }, - "node_modules/fast-text-encoding": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", - "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==", - "optional": true - }, "node_modules/fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz", + "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/NaturalIntelligence" - }, - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" } ], "optional": true, "dependencies": { - "strnum": "^1.0.5" + "strnum": "^1.1.1" }, "bin": { "fxparser": "src/cli/cli.js" @@ -1223,25 +1059,27 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/firebase-admin": { - "version": "11.11.1", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-11.11.1.tgz", - "integrity": "sha512-UyEbq+3u6jWzCYbUntv/HuJiTixwh36G1R9j0v71mSvGAx/YZEWEW7uSGLYxBYE6ckVRQoKMr40PYUEzrm/4dg==", - "dependencies": { - "@fastify/busboy": "^1.2.1", - "@firebase/database-compat": "^0.3.4", - "@firebase/database-types": "^0.10.4", - "@types/node": ">=12.12.47", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-13.2.0.tgz", + "integrity": "sha512-qQBTKo0QWCDaWwISry989pr8YfZSSk00rNCKaucjOgltEm3cCYzEe4rODqBd1uUwma+Iu5jtAzg89Nfsjr3fGg==", + "dependencies": { + "@fastify/busboy": "^3.0.0", + "@firebase/database-compat": "^2.0.0", + "@firebase/database-types": "^1.0.6", + "@types/node": "^22.8.7", + "farmhash-modern": "^1.1.0", + "google-auth-library": "^9.14.2", "jsonwebtoken": "^9.0.0", - "jwks-rsa": "^3.0.1", + "jwks-rsa": "^3.1.0", "node-forge": "^1.3.1", - "uuid": "^9.0.0" + "uuid": "^11.0.2" }, "engines": { - "node": ">=14" + "node": ">=18" }, "optionalDependencies": { - "@google-cloud/firestore": "^6.8.0", - "@google-cloud/storage": "^6.9.5" + "@google-cloud/firestore": "^7.11.0", + "@google-cloud/storage": "^7.14.0" } }, "node_modules/firebase-functions": { @@ -1282,6 +1120,22 @@ "firebase-functions": ">=2.0.0" } }, + "node_modules/form-data": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.3.tgz", + "integrity": "sha512-XHIrMD0NpDrNM/Ckf7XJiBbLl57KEhT3+i3yY+eWm+cqYZJQTZrKo8Y8AWKnuV5GT4scfuUGt9LzNoIx3dU1nQ==", + "optional": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.35", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1298,12 +1152,6 @@ "node": ">= 0.6" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "optional": true - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -1319,31 +1167,43 @@ "optional": true }, "node_modules/gaxios": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", - "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", - "optional": true, + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", "dependencies": { "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", + "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", - "node-fetch": "^2.6.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/gcp-metadata": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", - "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", - "optional": true, - "dependencies": { - "gaxios": "^5.0.0", - "json-bigint": "^1.0.0" + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" }, "engines": { - "node": ">=12" + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" } }, "node_modules/get-caller-file": { @@ -1356,15 +1216,20 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -1373,152 +1238,99 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "optional": true, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 0.4" } }, "node_modules/google-auth-library": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz", - "integrity": "sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==", - "optional": true, + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", + "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", "dependencies": { - "arrify": "^2.0.0", "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^5.0.0", - "gcp-metadata": "^5.3.0", - "gtoken": "^6.1.0", - "jws": "^4.0.0", - "lru-cache": "^6.0.0" + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" }, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/google-gax": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-3.6.1.tgz", - "integrity": "sha512-g/lcUjGcB6DSw2HxgEmCDOrI/CByOwqRvsuUvNalHUK2iPPPlmAIpbMbl62u0YufGMr8zgE3JL7th6dCb1Ry+w==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.4.1.tgz", + "integrity": "sha512-Phyp9fMfA00J3sZbJxbbB4jC55b7DBjE3F6poyL3wKMEBVKA79q6BGuHcTiM28yOzVql0NDbRL8MLLh8Iwk9Dg==", "optional": true, "dependencies": { - "@grpc/grpc-js": "~1.8.0", - "@grpc/proto-loader": "^0.7.0", + "@grpc/grpc-js": "^1.10.9", + "@grpc/proto-loader": "^0.7.13", "@types/long": "^4.0.0", - "@types/rimraf": "^3.0.2", "abort-controller": "^3.0.0", "duplexify": "^4.0.0", - "fast-text-encoding": "^1.0.3", - "google-auth-library": "^8.0.2", - "is-stream-ended": "^0.1.4", - "node-fetch": "^2.6.1", + "google-auth-library": "^9.3.0", + "node-fetch": "^2.7.0", "object-hash": "^3.0.0", - "proto3-json-serializer": "^1.0.0", - "protobufjs": "7.2.4", - "protobufjs-cli": "1.1.1", - "retry-request": "^5.0.0" - }, - "bin": { - "compileProtos": "build/tools/compileProtos.js", - "minifyProtoJson": "build/tools/minify.js" + "proto3-json-serializer": "^2.0.2", + "protobufjs": "^7.3.2", + "retry-request": "^7.0.0", + "uuid": "^9.0.1" }, "engines": { - "node": ">=12" + "node": ">=14" } }, - "node_modules/google-gax/node_modules/protobufjs": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz", - "integrity": "sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==", - "hasInstallScript": true, + "node_modules/google-gax/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "optional": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" + "bin": { + "uuid": "dist/bin/uuid" } }, - "node_modules/google-p12-pem": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz", - "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==", - "optional": true, - "dependencies": { - "node-forge": "^1.3.1" - }, - "bin": { - "gp12-pem": "build/src/bin/gp12-pem.js" - }, + "node_modules/google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", "engines": { - "node": ">=12.0.0" + "node": ">=14" } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "optional": true - }, "node_modules/gtoken": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", - "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", - "optional": true, + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", "dependencies": { - "gaxios": "^5.0.1", - "google-p12-pem": "^4.0.0", + "gaxios": "^6.0.0", "jws": "^4.0.0" }, "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "optional": true, - "engines": { - "node": ">=8" + "node": ">=14.0.0" } }, "node_modules/has-property-descriptors": { @@ -1532,10 +1344,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "engines": { "node": ">= 0.4" }, @@ -1543,10 +1355,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "optional": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { "node": ">= 0.4" }, @@ -1565,6 +1381,22 @@ "node": ">= 0.4" } }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "optional": true + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -1581,9 +1413,9 @@ } }, "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.9.tgz", + "integrity": "sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw==" }, "node_modules/http-proxy-agent": { "version": "5.0.0", @@ -1599,17 +1431,28 @@ "node": ">= 6" } }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "optional": true, "dependencies": { - "agent-base": "6", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 6.0.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" } }, "node_modules/iconv-lite": { @@ -1623,16 +1466,6 @@ "node": ">=0.10.0" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "optional": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -1659,7 +1492,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "optional": true, "engines": { "node": ">=8" }, @@ -1667,63 +1499,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-stream-ended": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", - "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", - "optional": true - }, "node_modules/jose": { - "version": "4.15.5", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz", - "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==", + "version": "4.15.9", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", + "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", "funding": { "url": "https://github.com/sponsors/panva" } }, - "node_modules/js2xmlparser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", - "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", - "optional": true, - "dependencies": { - "xmlcreate": "^2.0.4" - } - }, - "node_modules/jsdoc": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", - "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", - "optional": true, - "dependencies": { - "@babel/parser": "^7.20.15", - "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^12.2.3", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.2", - "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", - "marked": "^4.0.10", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "underscore": "~1.13.2" - }, - "bin": { - "jsdoc": "jsdoc.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "optional": true, "dependencies": { "bignumber.js": "^9.0.0" } @@ -1766,7 +1553,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "optional": true, "dependencies": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -1774,16 +1560,16 @@ } }, "node_modules/jwks-rsa": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.0.1.tgz", - "integrity": "sha512-UUOZ0CVReK1QVU3rbi9bC7N5/le8ziUj0A2ef1Q0M7OPD2KvjEYizptqIxGIo6fSLYDkqBrazILS18tYuRc8gw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.2.0.tgz", + "integrity": "sha512-PwchfHcQK/5PSydeKCs1ylNym0w/SSv8a62DgHJ//7x2ZclCoinlsjAfDxAAbpoTPybOum/Jgy+vkvMmKz89Ww==", "dependencies": { - "@types/express": "^4.17.14", - "@types/jsonwebtoken": "^9.0.0", + "@types/express": "^4.17.20", + "@types/jsonwebtoken": "^9.0.4", "debug": "^4.3.4", - "jose": "^4.10.4", + "jose": "^4.15.4", "limiter": "^1.1.5", - "lru-memoizer": "^2.1.4" + "lru-memoizer": "^2.2.0" }, "engines": { "node": ">=14" @@ -1793,48 +1579,16 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "optional": true, "dependencies": { "jwa": "^2.0.0", "safe-buffer": "^5.0.1" } }, - "node_modules/klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", - "optional": true, - "dependencies": { - "graceful-fs": "^4.1.9" - } - }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "optional": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/limiter": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" }, - "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "optional": true, - "dependencies": { - "uc.micro": "^1.0.1" - } - }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -1868,72 +1622,22 @@ } }, "node_modules/lru-memoizer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.2.0.tgz", - "integrity": "sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.3.0.tgz", + "integrity": "sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==", "dependencies": { "lodash.clonedeep": "^4.5.0", - "lru-cache": "~4.0.0" + "lru-cache": "6.0.0" } }, - "node_modules/lru-memoizer/node_modules/lru-cache": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", - "integrity": "sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==", - "dependencies": { - "pseudomap": "^1.0.1", - "yallist": "^2.0.0" - } - }, - "node_modules/lru-memoizer/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" - }, - "node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "optional": true, - "dependencies": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, - "node_modules/markdown-it-anchor": { - "version": "8.6.7", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", - "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", - "optional": true, - "peerDependencies": { - "@types/markdown-it": "*", - "markdown-it": "*" - } - }, - "node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "optional": true, - "bin": { - "marked": "bin/marked.js" - }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "engines": { - "node": ">= 12" + "node": ">= 0.4" } }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "optional": true - }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1989,43 +1693,10 @@ "node": ">= 0.6" } }, - "node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "optional": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "optional": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "optional": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/negotiator": { "version": "0.6.3", @@ -2039,7 +1710,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "optional": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -2111,23 +1781,6 @@ "wrappy": "1" } }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "optional": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -2151,45 +1804,27 @@ "node": ">= 0.8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-to-regexp": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "optional": true, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/proto3-json-serializer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-1.1.1.tgz", - "integrity": "sha512-AwAuY4g9nxx0u52DnSMkqqgyLHaW/XaPLtaAo3y/ZCfeaQB/g4YDH4kb8Wc/mWzWvu0YjOznVnfn373MVZZrgw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz", + "integrity": "sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ==", "optional": true, "dependencies": { - "protobufjs": "^7.0.0" + "protobufjs": "^7.2.5" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/protobufjs": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", - "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", "hasInstallScript": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", @@ -2209,34 +1844,6 @@ "node": ">=12.0.0" } }, - "node_modules/protobufjs-cli": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/protobufjs-cli/-/protobufjs-cli-1.1.1.tgz", - "integrity": "sha512-VPWMgIcRNyQwWUv8OLPyGQ/0lQY/QTQAVN5fh+XzfDwsVw1FZ2L3DM/bcBf8WPiRz2tNpaov9lPZfNcmNo6LXA==", - "optional": true, - "dependencies": { - "chalk": "^4.0.0", - "escodegen": "^1.13.0", - "espree": "^9.0.0", - "estraverse": "^5.1.0", - "glob": "^8.0.0", - "jsdoc": "^4.0.0", - "minimist": "^1.2.0", - "semver": "^7.1.2", - "tmp": "^0.2.1", - "uglify-js": "^3.7.7" - }, - "bin": { - "pbjs": "bin/pbjs", - "pbts": "bin/pbts" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "protobufjs": "^7.0.0" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2249,11 +1856,6 @@ "node": ">= 0.10" } }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" - }, "node_modules/qs": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", @@ -2296,109 +1898,44 @@ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "optional": true, "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", - "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", - "optional": true, - "dependencies": { - "lodash": "^4.17.21" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "optional": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/retry-request": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-5.0.2.tgz", - "integrity": "sha512-wfI3pk7EE80lCIXprqh7ym48IHYdwmAAzESdbU8Q9l7pnRCk9LEhpbOTNKjz6FARLm/Bl5m+4F0ABxOkYUujSQ==", - "optional": true, - "dependencies": { - "debug": "^4.1.1", - "extend": "^3.0.2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "optional": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">= 6" } }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "optional": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "optional": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 4" } }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/retry-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz", + "integrity": "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==", "optional": true, "dependencies": { - "brace-expansion": "^1.1.7" + "@types/request": "^2.48.8", + "extend": "^3.0.2", + "teeny-request": "^9.0.0" }, "engines": { - "node": "*" + "node": ">=14" } }, "node_modules/safe-buffer": { @@ -2472,11 +2009,6 @@ "node": ">=4" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, "node_modules/serve-static": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", @@ -2537,15 +2069,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2564,9 +2087,9 @@ } }, "node_modules/stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", "optional": true }, "node_modules/string_decoder": { @@ -2604,22 +2127,16 @@ "node": ">=8" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "optional": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/strnum": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], "optional": true }, "node_modules/stubs": { @@ -2628,49 +2145,58 @@ "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", "optional": true }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "optional": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/teeny-request": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-8.0.3.tgz", - "integrity": "sha512-jJZpA5He2y52yUhA7pyAGZlgQpcB+xLjcN0eUFxr9c8hP/H7uOXbBNVo/O0C/xVfJLJs680jvkFgVJEEvk9+ww==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz", + "integrity": "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==", "optional": true, "dependencies": { "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.1", + "node-fetch": "^2.6.9", "stream-events": "^1.0.5", "uuid": "^9.0.0" }, "engines": { - "node": ">=12" + "node": ">=14" } }, - "node_modules/text-decoding": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-decoding/-/text-decoding-1.0.0.tgz", - "integrity": "sha512-/0TJD42KDnVwKmDK6jj3xP7E2MG7SHAOG4tyTgyUCRPdHwvkquYNLEQltmdMa3owq3TkddCVcTsoctJI8VQNKA==" + "node_modules/teeny-request/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "node_modules/teeny-request/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "optional": true, "dependencies": { - "rimraf": "^3.0.0" + "agent-base": "6", + "debug": "4" }, "engines": { - "node": ">=8.17.0" + "node": ">= 6" + } + }, + "node_modules/teeny-request/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" } }, "node_modules/toidentifier": { @@ -2684,25 +2210,12 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "optional": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "optional": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "node_modules/type-is": { "version": "1.6.18", @@ -2729,34 +2242,10 @@ "node": ">=4.2.0" } }, - "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "optional": true - }, - "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "optional": true - }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" }, "node_modules/unpipe": { "version": "1.0.0", @@ -2781,15 +2270,15 @@ } }, "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist/esm/bin/uuid" } }, "node_modules/vary": { @@ -2803,8 +2292,7 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "optional": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/websocket-driver": { "version": "0.7.4", @@ -2831,21 +2319,11 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "optional": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -2869,12 +2347,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "optional": true }, - "node_modules/xmlcreate": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", - "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", - "optional": true - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -2930,106 +2402,104 @@ } }, "dependencies": { - "@babel/parser": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", - "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", - "optional": true - }, "@fastify/busboy": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-1.2.1.tgz", - "integrity": "sha512-7PQA7EH43S0CxcOa9OeAnaeA0oQ+e/DHNPZwSQM9CQHW76jle5+OvLdibRp/Aafs9KXbLhxyjOTkRjWUbQEd3Q==", - "requires": { - "text-decoding": "^1.0.0" - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.1.1.tgz", + "integrity": "sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw==" + }, + "@firebase/app-check-interop-types": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz", + "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==" }, "@firebase/app-types": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", - "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==" + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz", + "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==" }, "@firebase/auth-interop-types": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz", - "integrity": "sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz", + "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==" }, "@firebase/component": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.4.tgz", - "integrity": "sha512-rLMyrXuO9jcAUCaQXCMjCMUsWrba5fzHlNK24xz5j2W6A/SRmK8mZJ/hn7V0fViLbxC0lPMtrK1eYzk6Fg03jA==", + "version": "0.6.13", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.13.tgz", + "integrity": "sha512-I/Eg1NpAtZ8AAfq8mpdfXnuUpcLxIDdCDtTzWSh+FXnp/9eCKJ3SNbOCKrUCyhLzNa2SiPJYruei0sxVjaOTeg==", "requires": { - "@firebase/util": "1.9.3", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" } }, "@firebase/database": { - "version": "0.14.4", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.14.4.tgz", - "integrity": "sha512-+Ea/IKGwh42jwdjCyzTmeZeLM3oy1h0mFPsTy6OqCWzcu/KFqRAr5Tt1HRCOBlNOdbh84JPZC47WLU18n2VbxQ==", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.14.tgz", + "integrity": "sha512-9nxYtkHAG02/Nh2Ssms1T4BbWPPjiwohCvkHDUl4hNxnki1kPgsLo5xe9kXNzbacOStmVys+RUXvwzynQSKmUQ==", "requires": { - "@firebase/auth-interop-types": "0.2.1", - "@firebase/component": "0.6.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.6.13", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.11.0", "faye-websocket": "0.11.4", "tslib": "^2.1.0" } }, "@firebase/database-compat": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.3.4.tgz", - "integrity": "sha512-kuAW+l+sLMUKBThnvxvUZ+Q1ZrF/vFJ58iUY9kAcbX48U03nVzIF6Tmkf0p3WVQwMqiXguSgtOPIB6ZCeF+5Gg==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.5.tgz", + "integrity": "sha512-CNf1UbvWh6qIaSf4sn6sx2DTDz/em/D7QxULH1LTxxDQHr9+CeYGvlAqrKnk4ZH0P0eIHyQFQU7RwkUJI0B9gQ==", "requires": { - "@firebase/component": "0.6.4", - "@firebase/database": "0.14.4", - "@firebase/database-types": "0.10.4", - "@firebase/logger": "0.4.0", - "@firebase/util": "1.9.3", + "@firebase/component": "0.6.13", + "@firebase/database": "1.0.14", + "@firebase/database-types": "1.0.10", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.11.0", "tslib": "^2.1.0" } }, "@firebase/database-types": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.10.4.tgz", - "integrity": "sha512-dPySn0vJ/89ZeBac70T+2tWWPiJXWbmRygYv0smT5TfE3hDrQ09eKMF3Y+vMlTdrMWq7mUdYW5REWPSGH4kAZQ==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.10.tgz", + "integrity": "sha512-mH6RC1E9/Pv8jf1/p+M8YFTX+iu+iHDN89hecvyO7wHrI4R1V0TXjxOHvX3nLJN1sfh0CWG6CHZ0VlrSmK/cwg==", "requires": { - "@firebase/app-types": "0.9.0", - "@firebase/util": "1.9.3" + "@firebase/app-types": "0.9.3", + "@firebase/util": "1.11.0" } }, "@firebase/logger": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.0.tgz", - "integrity": "sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.4.tgz", + "integrity": "sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g==", "requires": { "tslib": "^2.1.0" } }, "@firebase/util": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz", - "integrity": "sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.11.0.tgz", + "integrity": "sha512-PzSrhIr++KI6y4P6C/IdgBNMkEx0Ex6554/cYd0Hm+ovyFSJtJXqb/3OSIdnBoa2cpwZT1/GW56EmRc5qEc5fQ==", "requires": { "tslib": "^2.1.0" } }, "@google-cloud/firestore": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-6.8.0.tgz", - "integrity": "sha512-JRpk06SmZXLGz0pNx1x7yU3YhkUXheKgH5hbDZ4kMsdhtfV5qPLJLRI4wv69K0cZorIk+zTMOwptue7hizo0eA==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-7.11.0.tgz", + "integrity": "sha512-88uZ+jLsp1aVMj7gh3EKYH1aulTAMFAp8sH/v5a9w8q8iqSG27RiWLoxSAFr/XocZ9hGiWH1kEnBw+zl3xAgNA==", "optional": true, "requires": { + "@opentelemetry/api": "^1.3.0", "fast-deep-equal": "^3.1.1", "functional-red-black-tree": "^1.0.1", - "google-gax": "^3.5.7", - "protobufjs": "^7.2.5" + "google-gax": "^4.3.3", + "protobufjs": "^7.2.6" } }, "@google-cloud/paginator": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.7.tgz", - "integrity": "sha512-jJNutk0arIQhmpUUQJPJErsojqo834KcyB6X7a1mxuic8i1tKXxde8E69IZxNZawRIlZdIK2QY4WALvlK5MzYQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-5.0.2.tgz", + "integrity": "sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -3037,40 +2507,37 @@ } }, "@google-cloud/projectify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-3.0.0.tgz", - "integrity": "sha512-HRkZsNmjScY6Li8/kb70wjGlDDyLkVk3KvoEo9uIoxSjYLJasGiCch9+PqRVDOCGUFvEIqyogl+BeqILL4OJHA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-4.0.0.tgz", + "integrity": "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==", "optional": true }, "@google-cloud/promisify": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-3.0.1.tgz", - "integrity": "sha512-z1CjRjtQyBOYL+5Qr9DdYIfrdLBe746jRTYfaYU6MeXkqp7UfYs/jX16lFFVzZ7PGEJvqZNqYUEtb1mvDww4pA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-4.0.0.tgz", + "integrity": "sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==", "optional": true }, "@google-cloud/storage": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-6.12.0.tgz", - "integrity": "sha512-78nNAY7iiZ4O/BouWMWTD/oSF2YtYgYB3GZirn0To6eBOugjXVoK+GXgUXOl+HlqbAOyHxAVXOlsj3snfbQ1dw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-7.16.0.tgz", + "integrity": "sha512-7/5LRgykyOfQENcm6hDKP8SX/u9XxE5YOiWOkgkwcoO+cG8xT/cyOvp9wwN3IxfdYgpHs8CE7Nq2PKX2lNaEXw==", "optional": true, "requires": { - "@google-cloud/paginator": "^3.0.7", - "@google-cloud/projectify": "^3.0.0", - "@google-cloud/promisify": "^3.0.0", + "@google-cloud/paginator": "^5.0.0", + "@google-cloud/projectify": "^4.0.0", + "@google-cloud/promisify": "<4.1.0", "abort-controller": "^3.0.0", "async-retry": "^1.3.3", - "compressible": "^2.0.12", - "duplexify": "^4.0.0", - "ent": "^2.2.0", - "extend": "^3.0.2", - "fast-xml-parser": "^4.2.2", - "gaxios": "^5.0.0", - "google-auth-library": "^8.0.1", + "duplexify": "^4.1.3", + "fast-xml-parser": "^4.4.1", + "gaxios": "^6.0.2", + "google-auth-library": "^9.6.3", + "html-entities": "^2.5.2", "mime": "^3.0.0", - "mime-types": "^2.0.8", "p-limit": "^3.0.1", - "retry-request": "^5.0.0", - "teeny-request": "^8.0.0", + "retry-request": "^7.0.0", + "teeny-request": "^9.0.0", "uuid": "^8.0.0" }, "dependencies": { @@ -3083,35 +2550,38 @@ } }, "@grpc/grpc-js": { - "version": "1.8.22", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.22.tgz", - "integrity": "sha512-oAjDdN7fzbUi+4hZjKG96MR6KTEubAeMpQEb+77qy+3r0Ua5xTFuie6JOLr4ZZgl5g+W5/uRTS2M1V8mVAFPuA==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.13.2.tgz", + "integrity": "sha512-nnR5nmL6lxF8YBqb6gWvEgLdLh/Fn+kvAdX5hUOnt48sNSb0riz/93ASd2E5gvanPA41X6Yp25bIfGRp1SMb2g==", "optional": true, "requires": { - "@grpc/proto-loader": "^0.7.0", - "@types/node": ">=12.12.47" + "@grpc/proto-loader": "^0.7.13", + "@js-sdsl/ordered-map": "^4.4.2" } }, "@grpc/proto-loader": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", - "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", + "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", "optional": true, "requires": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", - "protobufjs": "^7.2.4", + "protobufjs": "^7.2.5", "yargs": "^17.7.2" } }, - "@jsdoc/salty": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.7.tgz", - "integrity": "sha512-mh8LbS9d4Jq84KLw8pzho7XC2q2/IJGiJss3xwRoLD1A+EE16SjN4PfaG4jRCzKegTFLlN0Zd8SdUPE6XdoPFg==", - "optional": true, - "requires": { - "lodash": "^4.17.21" - } + "@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "optional": true + }, + "@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "optional": true }, "@protobufjs/aspromise": { "version": "1.1.2", @@ -3182,6 +2652,12 @@ "@types/node": "*" } }, + "@types/caseless": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz", + "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", + "optional": true + }, "@types/connect": { "version": "3.4.33", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", @@ -3216,30 +2692,15 @@ "@types/range-parser": "*" } }, - "@types/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", - "optional": true, - "requires": { - "@types/minimatch": "^5.1.2", - "@types/node": "*" - } - }, "@types/jsonwebtoken": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz", - "integrity": "sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.9.tgz", + "integrity": "sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ==", "requires": { + "@types/ms": "*", "@types/node": "*" } }, - "@types/linkify-it": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", - "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", - "optional": true - }, "@types/lodash": { "version": "4.14.161", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz", @@ -3252,39 +2713,22 @@ "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", "optional": true }, - "@types/markdown-it": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", - "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", - "optional": true, - "requires": { - "@types/linkify-it": "*", - "@types/mdurl": "*" - } - }, - "@types/mdurl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", - "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", - "optional": true - }, "@types/mime": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" }, - "@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "optional": true + "@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" }, "@types/node": { - "version": "20.10.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz", - "integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==", + "version": "22.14.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", + "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", "requires": { - "undici-types": "~5.26.4" + "undici-types": "~6.21.0" } }, "@types/qs": { @@ -3297,14 +2741,16 @@ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" }, - "@types/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==", + "@types/request": { + "version": "2.48.12", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.12.tgz", + "integrity": "sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==", "optional": true, "requires": { - "@types/glob": "*", - "@types/node": "*" + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" } }, "@types/serve-static": { @@ -3316,6 +2762,12 @@ "@types/mime": "*" } }, + "@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "optional": true + }, "abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -3334,27 +2786,10 @@ "negotiator": "0.6.3" } }, - "acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "optional": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "optional": true, - "requires": {} - }, "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "optional": true, - "requires": { - "debug": "4" - } + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==" }, "ansi-regex": { "version": "5.0.1", @@ -3371,12 +2806,6 @@ "color-convert": "^2.0.1" } }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "optional": true - }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -3397,29 +2826,21 @@ "retry": "0.13.1" } }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "optional": true }, "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "optional": true + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "bignumber.js": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", - "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", - "optional": true - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "optional": true + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.2.0.tgz", + "integrity": "sha512-JocpCSOixzy5XFJi2ub6IMmV/G9i8Lrm2lZvwBv9xPdglmZM0ufDVBbjbrfU/zuLvBfD7Bv2eYxz9i+OHTgkew==" }, "body-parser": { "version": "1.20.3", @@ -3455,15 +2876,6 @@ } } }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "optional": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -3486,23 +2898,13 @@ "set-function-length": "^1.2.1" } }, - "catharsis": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", - "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", - "optional": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "optional": true, + "call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" } }, "cliui": { @@ -3531,21 +2933,15 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "optional": true }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "optional": true, "requires": { - "mime-db": ">= 1.43.0 < 2" + "delayed-stream": "~1.0.0" } }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "optional": true - }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -3579,19 +2975,13 @@ } }, "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "requires": { - "ms": "2.1.2" + "ms": "^2.1.3" } }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "optional": true - }, "define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -3602,6 +2992,12 @@ "gopd": "^1.0.1" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "optional": true + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -3612,16 +3008,26 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, "duplexify": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.2.tgz", - "integrity": "sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", "optional": true, "requires": { "end-of-stream": "^1.4.1", "inherits": "^2.0.3", "readable-stream": "^3.1.1", - "stream-shift": "^1.0.0" + "stream-shift": "^1.0.2" } }, "ecdsa-sig-formatter": { @@ -3657,103 +3063,46 @@ "once": "^1.4.0" } }, - "ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", - "optional": true - }, - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "optional": true - }, "es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "requires": { - "get-intrinsic": "^1.2.4" - } + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" }, "es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "optional": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "optional": true - }, - "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "optional": true, + "es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "optional": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "optional": true + "es-errors": "^1.3.0" + } }, - "espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "optional": true, "requires": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "optional": true - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "optional": true }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "optional": true + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "etag": { "version": "1.8.1", @@ -3827,8 +3176,12 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "optional": true + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "farmhash-modern": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/farmhash-modern/-/farmhash-modern-1.1.0.tgz", + "integrity": "sha512-6ypT4XfgqJk/F3Yuv4SX26I3doUjt0GTG4a+JgWxXQpxXzTBq8fPUeGHfcYMMDPHJHm3yPOSjaeBwBGAHWXCdA==" }, "fast-deep-equal": { "version": "3.1.3", @@ -3836,25 +3189,13 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "optional": true }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "optional": true - }, - "fast-text-encoding": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", - "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==", - "optional": true - }, "fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz", + "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==", "optional": true, "requires": { - "strnum": "^1.0.5" + "strnum": "^1.1.1" } }, "faye-websocket": { @@ -3900,20 +3241,22 @@ } }, "firebase-admin": { - "version": "11.11.1", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-11.11.1.tgz", - "integrity": "sha512-UyEbq+3u6jWzCYbUntv/HuJiTixwh36G1R9j0v71mSvGAx/YZEWEW7uSGLYxBYE6ckVRQoKMr40PYUEzrm/4dg==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-13.2.0.tgz", + "integrity": "sha512-qQBTKo0QWCDaWwISry989pr8YfZSSk00rNCKaucjOgltEm3cCYzEe4rODqBd1uUwma+Iu5jtAzg89Nfsjr3fGg==", "requires": { - "@fastify/busboy": "^1.2.1", - "@firebase/database-compat": "^0.3.4", - "@firebase/database-types": "^0.10.4", - "@google-cloud/firestore": "^6.8.0", - "@google-cloud/storage": "^6.9.5", - "@types/node": ">=12.12.47", + "@fastify/busboy": "^3.0.0", + "@firebase/database-compat": "^2.0.0", + "@firebase/database-types": "^1.0.6", + "@google-cloud/firestore": "^7.11.0", + "@google-cloud/storage": "^7.14.0", + "@types/node": "^22.8.7", + "farmhash-modern": "^1.1.0", + "google-auth-library": "^9.14.2", "jsonwebtoken": "^9.0.0", - "jwks-rsa": "^3.0.1", + "jwks-rsa": "^3.1.0", "node-forge": "^1.3.1", - "uuid": "^9.0.0" + "uuid": "^11.0.2" } }, "firebase-functions": { @@ -3938,6 +3281,19 @@ "lodash": "^4.17.5" } }, + "form-data": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.3.tgz", + "integrity": "sha512-XHIrMD0NpDrNM/Ckf7XJiBbLl57KEhT3+i3yY+eWm+cqYZJQTZrKo8Y8AWKnuV5GT4scfuUGt9LzNoIx3dU1nQ==", + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.35", + "safe-buffer": "^5.2.1" + } + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3948,12 +3304,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "optional": true - }, "function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -3966,24 +3316,31 @@ "optional": true }, "gaxios": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz", - "integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==", - "optional": true, + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", "requires": { "extend": "^3.0.2", - "https-proxy-agent": "^5.0.0", + "https-proxy-agent": "^7.0.1", "is-stream": "^2.0.0", - "node-fetch": "^2.6.9" + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "dependencies": { + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" + } } }, "gcp-metadata": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz", - "integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==", - "optional": true, + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", "requires": { - "gaxios": "^5.0.0", + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", "json-bigint": "^1.0.0" } }, @@ -3994,132 +3351,91 @@ "optional": true }, "get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "requires": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" } }, - "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "optional": true, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" } }, "google-auth-library": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz", - "integrity": "sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==", - "optional": true, + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", + "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", "requires": { - "arrify": "^2.0.0", "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", - "fast-text-encoding": "^1.0.0", - "gaxios": "^5.0.0", - "gcp-metadata": "^5.3.0", - "gtoken": "^6.1.0", - "jws": "^4.0.0", - "lru-cache": "^6.0.0" + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" } }, "google-gax": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-3.6.1.tgz", - "integrity": "sha512-g/lcUjGcB6DSw2HxgEmCDOrI/CByOwqRvsuUvNalHUK2iPPPlmAIpbMbl62u0YufGMr8zgE3JL7th6dCb1Ry+w==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.4.1.tgz", + "integrity": "sha512-Phyp9fMfA00J3sZbJxbbB4jC55b7DBjE3F6poyL3wKMEBVKA79q6BGuHcTiM28yOzVql0NDbRL8MLLh8Iwk9Dg==", "optional": true, "requires": { - "@grpc/grpc-js": "~1.8.0", - "@grpc/proto-loader": "^0.7.0", + "@grpc/grpc-js": "^1.10.9", + "@grpc/proto-loader": "^0.7.13", "@types/long": "^4.0.0", - "@types/rimraf": "^3.0.2", "abort-controller": "^3.0.0", "duplexify": "^4.0.0", - "fast-text-encoding": "^1.0.3", - "google-auth-library": "^8.0.2", - "is-stream-ended": "^0.1.4", - "node-fetch": "^2.6.1", + "google-auth-library": "^9.3.0", + "node-fetch": "^2.7.0", "object-hash": "^3.0.0", - "proto3-json-serializer": "^1.0.0", - "protobufjs": "7.2.4", - "protobufjs-cli": "1.1.1", - "retry-request": "^5.0.0" + "proto3-json-serializer": "^2.0.2", + "protobufjs": "^7.3.2", + "retry-request": "^7.0.0", + "uuid": "^9.0.1" }, "dependencies": { - "protobufjs": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz", - "integrity": "sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==", - "optional": true, - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - } + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "optional": true } } }, - "google-p12-pem": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-4.0.1.tgz", - "integrity": "sha512-WPkN4yGtz05WZ5EhtlxNDWPhC4JIic6G8ePitwUWy4l+XPVYec+a0j0Ts47PDtW59y3RwAhUd9/h9ZZ63px6RQ==", - "optional": true, - "requires": { - "node-forge": "^1.3.1" - } + "google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==" }, "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "optional": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" }, "gtoken": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-6.1.2.tgz", - "integrity": "sha512-4ccGpzz7YAr7lxrT2neugmXQ3hP9ho2gcaityLVkiUecAiwiy60Ii8gRbZeOsXV19fYaRjgBSshs8kXw+NKCPQ==", - "optional": true, + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", "requires": { - "gaxios": "^5.0.1", - "google-p12-pem": "^4.0.0", + "gaxios": "^6.0.0", "jws": "^4.0.0" } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "optional": true - }, "has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -4128,15 +3444,19 @@ "es-define-property": "^1.0.0" } }, - "has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" - }, "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + }, + "has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "optional": true, + "requires": { + "has-symbols": "^1.0.3" + } }, "hasown": { "version": "2.0.2", @@ -4146,6 +3466,12 @@ "function-bind": "^1.1.2" } }, + "html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "optional": true + }, "http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -4159,9 +3485,9 @@ } }, "http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.9.tgz", + "integrity": "sha512-n1XsPy3rXVxlqxVioEWdC+0+M+SQw0DpJynwtOPo1X+ZlvdzTLtDBIJJlDQTnwZIFJrZSzSGmIOUdP8tu+SgLw==" }, "http-proxy-agent": { "version": "5.0.0", @@ -4172,15 +3498,25 @@ "@tootallnate/once": "2", "agent-base": "6", "debug": "4" + }, + "dependencies": { + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "requires": { + "debug": "4" + } + } } }, "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "optional": true, + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "requires": { - "agent-base": "6", + "agent-base": "^7.1.2", "debug": "4" } }, @@ -4192,16 +3528,6 @@ "safer-buffer": ">= 2.1.2 < 3" } }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -4221,57 +3547,17 @@ "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "optional": true - }, - "is-stream-ended": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", - "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==", - "optional": true + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" }, "jose": { - "version": "4.15.5", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.5.tgz", - "integrity": "sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==" - }, - "js2xmlparser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", - "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", - "optional": true, - "requires": { - "xmlcreate": "^2.0.4" - } - }, - "jsdoc": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", - "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", - "optional": true, - "requires": { - "@babel/parser": "^7.20.15", - "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^12.2.3", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.2", - "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", - "marked": "^4.0.10", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "underscore": "~1.13.2" - } + "version": "4.15.9", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", + "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==" }, "json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "optional": true, "requires": { "bignumber.js": "^9.0.0" } @@ -4312,7 +3598,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "optional": true, "requires": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", @@ -4320,61 +3605,32 @@ } }, "jwks-rsa": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.0.1.tgz", - "integrity": "sha512-UUOZ0CVReK1QVU3rbi9bC7N5/le8ziUj0A2ef1Q0M7OPD2KvjEYizptqIxGIo6fSLYDkqBrazILS18tYuRc8gw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.2.0.tgz", + "integrity": "sha512-PwchfHcQK/5PSydeKCs1ylNym0w/SSv8a62DgHJ//7x2ZclCoinlsjAfDxAAbpoTPybOum/Jgy+vkvMmKz89Ww==", "requires": { - "@types/express": "^4.17.14", - "@types/jsonwebtoken": "^9.0.0", + "@types/express": "^4.17.20", + "@types/jsonwebtoken": "^9.0.4", "debug": "^4.3.4", - "jose": "^4.10.4", + "jose": "^4.15.4", "limiter": "^1.1.5", - "lru-memoizer": "^2.1.4" + "lru-memoizer": "^2.2.0" } }, "jws": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "optional": true, "requires": { "jwa": "^2.0.0", "safe-buffer": "^5.0.1" } }, - "klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", - "optional": true, - "requires": { - "graceful-fs": "^4.1.9" - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "optional": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, "limiter": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" }, - "linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "optional": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -4405,61 +3661,18 @@ } }, "lru-memoizer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.2.0.tgz", - "integrity": "sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.3.0.tgz", + "integrity": "sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==", "requires": { "lodash.clonedeep": "^4.5.0", - "lru-cache": "~4.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", - "integrity": "sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==", - "requires": { - "pseudomap": "^1.0.1", - "yallist": "^2.0.0" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" - } - } - }, - "markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "optional": true, - "requires": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "lru-cache": "6.0.0" } }, - "markdown-it-anchor": { - "version": "8.6.7", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", - "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", - "optional": true, - "requires": {} - }, - "marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "optional": true - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "optional": true + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" }, "media-typer": { "version": "0.3.0", @@ -4495,31 +3708,10 @@ "mime-db": "1.52.0" } }, - "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "optional": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "optional": true - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "optional": true - }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "negotiator": { "version": "0.6.3", @@ -4530,7 +3722,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "optional": true, "requires": { "whatwg-url": "^5.0.0" } @@ -4573,20 +3764,6 @@ "wrappy": "1" } }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "optional": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -4601,36 +3778,24 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "optional": true - }, "path-to-regexp": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "optional": true - }, "proto3-json-serializer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-1.1.1.tgz", - "integrity": "sha512-AwAuY4g9nxx0u52DnSMkqqgyLHaW/XaPLtaAo3y/ZCfeaQB/g4YDH4kb8Wc/mWzWvu0YjOznVnfn373MVZZrgw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz", + "integrity": "sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ==", "optional": true, "requires": { - "protobufjs": "^7.0.0" + "protobufjs": "^7.2.5" } }, "protobufjs": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", - "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -4646,24 +3811,6 @@ "long": "^5.0.0" } }, - "protobufjs-cli": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/protobufjs-cli/-/protobufjs-cli-1.1.1.tgz", - "integrity": "sha512-VPWMgIcRNyQwWUv8OLPyGQ/0lQY/QTQAVN5fh+XzfDwsVw1FZ2L3DM/bcBf8WPiRz2tNpaov9lPZfNcmNo6LXA==", - "optional": true, - "requires": { - "chalk": "^4.0.0", - "escodegen": "^1.13.0", - "espree": "^9.0.0", - "estraverse": "^5.1.0", - "glob": "^8.0.0", - "jsdoc": "^4.0.0", - "minimist": "^1.2.0", - "semver": "^7.1.2", - "tmp": "^0.2.1", - "uglify-js": "^3.7.7" - } - }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -4673,11 +3820,6 @@ "ipaddr.js": "1.9.1" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" - }, "qs": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", @@ -4719,15 +3861,6 @@ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "optional": true }, - "requizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", - "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", - "optional": true, - "requires": { - "lodash": "^4.17.21" - } - }, "retry": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", @@ -4735,57 +3868,14 @@ "optional": true }, "retry-request": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-5.0.2.tgz", - "integrity": "sha512-wfI3pk7EE80lCIXprqh7ym48IHYdwmAAzESdbU8Q9l7pnRCk9LEhpbOTNKjz6FARLm/Bl5m+4F0ABxOkYUujSQ==", - "optional": true, - "requires": { - "debug": "^4.1.1", - "extend": "^3.0.2" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz", + "integrity": "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==", "optional": true, "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } + "@types/request": "^2.48.8", + "extend": "^3.0.2", + "teeny-request": "^9.0.0" } }, "safe-buffer": { @@ -4845,11 +3935,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" } } }, @@ -4900,12 +3985,6 @@ "object-inspect": "^1.13.1" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "optional": true - }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -4921,9 +4000,9 @@ } }, "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", "optional": true }, "string_decoder": { @@ -4955,16 +4034,10 @@ "ansi-regex": "^5.0.1" } }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "optional": true - }, "strnum": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", "optional": true }, "stubs": { @@ -4973,40 +4046,44 @@ "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", "optional": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "optional": true, - "requires": { - "has-flag": "^4.0.0" - } - }, "teeny-request": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-8.0.3.tgz", - "integrity": "sha512-jJZpA5He2y52yUhA7pyAGZlgQpcB+xLjcN0eUFxr9c8hP/H7uOXbBNVo/O0C/xVfJLJs680jvkFgVJEEvk9+ww==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz", + "integrity": "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==", "optional": true, "requires": { "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.1", + "node-fetch": "^2.6.9", "stream-events": "^1.0.5", "uuid": "^9.0.0" - } - }, - "text-decoding": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-decoding/-/text-decoding-1.0.0.tgz", - "integrity": "sha512-/0TJD42KDnVwKmDK6jj3xP7E2MG7SHAOG4tyTgyUCRPdHwvkquYNLEQltmdMa3owq3TkddCVcTsoctJI8VQNKA==" - }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "optional": true, - "requires": { - "rimraf": "^3.0.0" + }, + "dependencies": { + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "requires": { + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "optional": true + } } }, "toidentifier": { @@ -5017,22 +4094,12 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "optional": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "optional": true, - "requires": { - "prelude-ls": "~1.1.2" - } + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "type-is": { "version": "1.6.18", @@ -5049,28 +4116,10 @@ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "optional": true - }, - "uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "optional": true - }, - "underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "optional": true - }, "undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" }, "unpipe": { "version": "1.0.0", @@ -5089,9 +4138,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==" }, "vary": { "version": "1.1.2", @@ -5101,8 +4150,7 @@ "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "optional": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "websocket-driver": { "version": "0.7.4", @@ -5123,18 +4171,11 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "optional": true, "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, - "word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "optional": true - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -5152,12 +4193,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "optional": true }, - "xmlcreate": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", - "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", - "optional": true - }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/.github/workflows/scripts/functions/package.json b/.github/workflows/scripts/functions/package.json index e1fcbdcf63be..15dbe63c1a59 100644 --- a/.github/workflows/scripts/functions/package.json +++ b/.github/workflows/scripts/functions/package.json @@ -14,7 +14,7 @@ }, "main": "lib/index.js", "dependencies": { - "firebase-admin": "^11.5.0", + "firebase-admin": "^13.2.0", "firebase-functions": "^6.3.2" }, "devDependencies": { diff --git a/.github/workflows/scripts/functions/src/index.ts b/.github/workflows/scripts/functions/src/index.ts index 6d6cc82951a5..458a7b107a57 100644 --- a/.github/workflows/scripts/functions/src/index.ts +++ b/.github/workflows/scripts/functions/src/index.ts @@ -1,8 +1,8 @@ import * as assert from 'assert'; import * as functions from 'firebase-functions'; -// import { onCall } from 'firebase-functions/https'; import * as functionsv2 from 'firebase-functions/v2'; + // For example app. // noinspection JSUnusedGlobalSymbols export const listFruit = functions.https.onCall(() => { @@ -15,13 +15,20 @@ export const listfruits2ndgen = functionsv2.https.onCall(() => { // For e2e testing a custom region. // noinspection JSUnusedGlobalSymbols -export const testFunctionCustomRegion = functions.https.onCall(() => 'europe-west1'); + +export const testFunctionCustomRegion = functions.https.onCall( + { + region: 'europe-west1' + }, + () => 'europe-west1' +); // For e2e testing timeouts. -export const testFunctionTimeout = functions.https.onCall((data) => { +export const testFunctionTimeout = functions.https.onCall((req, res) => { + const data = req.data console.log(JSON.stringify({ data })); return new Promise((resolve, reject) => { - if (data && data.rawRequest) { + if (data && data.testTimeout) { setTimeout( () => resolve({ timeLimit: 'exceeded' }), parseInt(data.rawRequest.body, 10) diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/CodecUtility.swift b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/CodecUtility.swift index 656393470a68..860f42d0621d 100644 --- a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/CodecUtility.swift +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/CodecUtility.swift @@ -1,6 +1,7 @@ // Copyright 2021 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import Foundation public struct AnyEncodable: Encodable { private let value: Any? diff --git a/packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/CodecUtility.swift b/packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/CodecUtility.swift new file mode 120000 index 000000000000..4dd991ad2c6f --- /dev/null +++ b/packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/CodecUtility.swift @@ -0,0 +1 @@ +../../../../ios/cloud_functions/Sources/cloud_functions/CodecUtility.swift \ No newline at end of file diff --git a/packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift b/packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift new file mode 120000 index 000000000000..f3d52d2d4e5e --- /dev/null +++ b/packages/cloud_functions/cloud_functions/macos/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift @@ -0,0 +1 @@ +../../../../ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift \ No newline at end of file diff --git a/packages/cloud_functions/cloud_functions_web/pubspec.yaml b/packages/cloud_functions/cloud_functions_web/pubspec.yaml index e5909d91500f..8ffd24852d51 100644 --- a/packages/cloud_functions/cloud_functions_web/pubspec.yaml +++ b/packages/cloud_functions/cloud_functions_web/pubspec.yaml @@ -13,11 +13,11 @@ dependencies: cloud_functions_platform_interface: ^5.6.5 firebase_core: ^3.13.0 firebase_core_web: ^2.22.0 - web: ^1.1.1 flutter: sdk: flutter flutter_web_plugins: sdk: flutter + web: ^1.1.1 dev_dependencies: firebase_core_platform_interface: ^5.3.1 From a9819dbf2fc0d058e68d5fccb1dc0c61d4700b16 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Thu, 3 Apr 2025 22:10:33 +0000 Subject: [PATCH 19/22] chore: fix ci --- .../Sources/cloud_functions/FunctionsStreamHandler.swift | 4 ++-- .../method_channel/method_channel_https_callable_streams.dart | 3 +-- .../platform_interface_https_callable_streams.dart | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift index a0f96c6ce844..a6e11962717c 100644 --- a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift @@ -58,7 +58,7 @@ class FunctionsStreamHandler: NSObject, FlutterStreamHandler { let options = HTTPSCallableOptions(requireLimitedUseAppCheckTokens: limitedUseAppCheckToken) // Stream handling for iOS 15+ - if #available(iOS 15.0, *) { + if #available(iOS 15.0, macOS 12.0, *) { var function: Callable> if let functionName { @@ -103,7 +103,7 @@ class FunctionsStreamHandler: NSObject, FlutterStreamHandler { } else { await MainActor.run { events(FlutterError(code: "unknown", - message: "Streaming requires iOS 15+", + message: "Streaming requires iOS 15+ or macOS 12+", details: nil)) } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart index 4647fb163363..4f1622f442f4 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart @@ -8,8 +8,7 @@ import 'package:cloud_functions_platform_interface/src/method_channel/utils/exce import 'package:flutter/services.dart'; import '../../cloud_functions_platform_interface.dart'; -class MethodChannelHttpsCallableStreams - extends HttpsCallableStreamsPlatform { +class MethodChannelHttpsCallableStreams extends HttpsCallableStreamsPlatform { MethodChannelHttpsCallableStreams(FirebaseFunctionsPlatform functions, String? origin, String? name, HttpsCallableOptions options, Uri? uri) : _transformedUri = uri?.pathSegments.join('_').replaceAll('.', '_'), diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart index 0b88221229a3..adee9d8e3fd5 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart @@ -6,7 +6,7 @@ import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -abstract class HttpsCallableStreamsPlatform extends PlatformInterface { +abstract class HttpsCallableStreamsPlatform extends PlatformInterface { HttpsCallableStreamsPlatform( this.functions, this.origin, From 295c6c61f39a6665aff691f814a1e2809f7ee0dc Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Thu, 3 Apr 2025 23:32:16 +0000 Subject: [PATCH 20/22] chore: fix cloud function test --- .github/workflows/scripts/functions/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scripts/functions/src/index.ts b/.github/workflows/scripts/functions/src/index.ts index 458a7b107a57..1ad25ab15c29 100644 --- a/.github/workflows/scripts/functions/src/index.ts +++ b/.github/workflows/scripts/functions/src/index.ts @@ -31,7 +31,7 @@ export const testFunctionTimeout = functions.https.onCall((req, res) => { if (data && data.testTimeout) { setTimeout( () => resolve({ timeLimit: 'exceeded' }), - parseInt(data.rawRequest.body, 10) + parseInt(data.testTimeout, 10) ); } else { reject( From 7a5ad4e80389c2cbc2aa7943767835e09725f5b7 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Fri, 4 Apr 2025 08:15:32 +0000 Subject: [PATCH 21/22] chore: add missing doc --- .../lib/src/firebase_functions.dart | 4 ++-- .../lib/src/https_callable_stream.dart | 14 ++++++++++++++ .../lib/src/https_callable_stream_result.dart | 2 ++ .../platform_interface_firebase_functions.dart | 2 ++ ...atform_interface_https_callable_streams.dart | 17 +++++++++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart b/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart index a85ae2d753a9..74387f829344 100644 --- a/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart @@ -109,7 +109,7 @@ class FirebaseFunctions extends FirebasePluginPlatform { delegate.httpsStreamCallable(_origin, name, options)); } - /// A reference to the streaming Callable HTTPS trigger with the given name. + /// A reference to the streaming Callable HTTPS trigger with the given URL. /// /// Should be URL of the 2nd gen Callable function in Firebase. HttpsCallableStream httpsCallableStreamFromUrl( @@ -122,7 +122,7 @@ class FirebaseFunctions extends FirebasePluginPlatform { delegate.httpsStreamCallableWithUri(_origin, uri, options)); } - /// A reference to the streaming Callable HTTPS trigger with the given name. + /// A reference to the streaming Callable HTTPS trigger with the given URI. /// /// Should be Uri of the 2nd gen Callable function in Firebase. HttpsCallableStream httpsCallableStreamFromUri( diff --git a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart index deaefbf9a889..3a6d47dedea1 100644 --- a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart +++ b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart @@ -13,6 +13,20 @@ class HttpsCallableStream { @visibleForTesting final HttpsCallableStreamsPlatform delegate; + /// Streams data to the specified HTTPS endpoint. + /// + /// The data passed into the trigger can be any of the following types: + /// + /// `null` + /// `String` + /// `num` + /// [List], where the contained objects are also one of these types. + /// [Map], where the values are also one of these types. + /// + /// The request to the Cloud Functions backend made by this method + /// automatically includes a Firebase Instance ID token to identify the app + /// instance. If a user is logged in with Firebase Auth, an auth ID token for + /// the user is also automatically included. Stream stream([Object? input]) async* { await for (final value in delegate.stream(input)) { if (value is Map) { diff --git a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart index 05e9a7aa7417..0bbece3d6b91 100644 --- a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart +++ b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream_result.dart @@ -10,12 +10,14 @@ sealed class StreamResponse {} /// A chunk received during the stream. class Chunk extends StreamResponse { + /// The intermediate data received from the server. final T partialData; Chunk(this.partialData); } /// The final result of the computation, marking the end of the stream. class Result extends StreamResponse { + /// The final computed result received from the server. final HttpsCallableResult result; Result(this.result); } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart index 7191ed40712d..1b26c476477d 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart @@ -73,11 +73,13 @@ abstract class FirebaseFunctionsPlatform extends PlatformInterface { throw UnimplementedError('httpsCallableWithUri() is not implemented'); } + /// Creates a [HttpsCallableStreamsPlatform] instance HttpsCallableStreamsPlatform httpsStreamCallable( String? origin, String name, HttpsCallableOptions options) { throw UnimplementedError('httpsStreamCallable() is not implemented'); } + /// Creates a [HttpsCallableStreamsPlatform] instance from [Uri] HttpsCallableStreamsPlatform httpsStreamCallableWithUri( String? origin, Uri uri, HttpsCallableOptions options) { throw UnimplementedError('httpsStreamCallableWithUri() is not implemented'); diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart index adee9d8e3fd5..09fa071826c2 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart @@ -6,6 +6,9 @@ import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +/// Interface for [HttpsCallableStream] implementations +/// +/// A reference to a particular Callable HTTPS trigger in Cloud Functions. abstract class HttpsCallableStreamsPlatform extends PlatformInterface { HttpsCallableStreamsPlatform( this.functions, @@ -37,5 +40,19 @@ abstract class HttpsCallableStreamsPlatform extends PlatformInterface { /// Used to set the options for this instance. HttpsCallableOptions options; + /// Streams data to the specified HTTPS endpoint. + /// + /// The data passed into the trigger can be any of the following types: + /// + /// `null` + /// `String` + /// `num` + /// [List], where the contained objects are also one of these types. + /// [Map], where the values are also one of these types. + /// + /// The request to the Cloud Functions backend made by this method + /// automatically includes a Firebase Instance ID token to identify the app + /// instance. If a user is logged in with Firebase Auth, an auth ID token for + /// the user is also automatically included. Stream stream(Object? parameters); } From 45fea6f3d97b0d03d10c9a585b109e8eb048ea69 Mon Sep 17 00:00:00 2001 From: Jude Kwashie Date: Wed, 9 Apr 2025 11:28:13 +0000 Subject: [PATCH 22/22] chore: fixes and clean up --- .../cloud_functions/example/lib/main.dart | 4 +- .../FunctionsStreamHandler.swift | 2 +- .../cloud_functions/lib/cloud_functions.dart | 1 - .../lib/src/firebase_functions.dart | 38 ------------ .../lib/src/https_callable.dart | 26 +++++++++ .../lib/src/https_callable_stream.dart | 41 ------------- .../cloud_functions_platform_interface.dart | 1 - .../method_channel_firebase_functions.dart | 13 ----- .../method_channel_https_callable.dart | 45 +++++++++++++- ...method_channel_https_callable_streams.dart | 56 ------------------ ...platform_interface_firebase_functions.dart | 12 ---- .../platform_interface_https_callable.dart | 18 ++++++ ...form_interface_https_callable_streams.dart | 58 ------------------- .../lib/cloud_functions_web.dart | 13 ----- .../lib/https_callable_stream_web.dart | 57 ------------------ .../lib/https_callable_web.dart | 33 +++++++++++ 16 files changed, 124 insertions(+), 294 deletions(-) delete mode 100644 packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart delete mode 100644 packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart delete mode 100644 packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart delete mode 100644 packages/cloud_functions/cloud_functions_web/lib/https_callable_stream_web.dart diff --git a/packages/cloud_functions/cloud_functions/example/lib/main.dart b/packages/cloud_functions/cloud_functions/example/lib/main.dart index 550532ffeba8..1a6fd84070ed 100644 --- a/packages/cloud_functions/cloud_functions/example/lib/main.dart +++ b/packages/cloud_functions/cloud_functions/example/lib/main.dart @@ -43,7 +43,7 @@ class _MyAppState extends State { void streamFunction() { fruit.clear(); - FirebaseFunctions.instance.httpsStreamCallable('getFruits').stream().listen( + FirebaseFunctions.instance.httpsCallable('getFruits').stream().listen( (data) { if (data is Chunk) { setState(() { @@ -53,7 +53,7 @@ class _MyAppState extends State { } else if (data is Result) { setState(() { // stores complete stream result - streamResult = data.result.data; + streamResult = List.from(data.result.data); }); } }, diff --git a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift index a6e11962717c..edaea7795815 100644 --- a/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift +++ b/packages/cloud_functions/cloud_functions/ios/cloud_functions/Sources/cloud_functions/FunctionsStreamHandler.swift @@ -44,7 +44,7 @@ class FunctionsStreamHandler: NSObject, FlutterStreamHandler { let functionName = arguments["functionName"] as? String let functionUri = arguments["functionUri"] as? String let origin = arguments["origin"] as? String - let parameters = arguments["arguments"] + let parameters = arguments["parameters"] let timeout = arguments["timeout"] as? Double let limitedUseAppCheckToken = arguments["limitedUseAppCheckToken"] as? Bool ?? false diff --git a/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart b/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart index a316dc7afcb2..9249ca5e3e9b 100644 --- a/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart +++ b/packages/cloud_functions/cloud_functions/lib/cloud_functions.dart @@ -20,5 +20,4 @@ export 'package:cloud_functions_platform_interface/cloud_functions_platform_inte part 'src/firebase_functions.dart'; part 'src/https_callable.dart'; part 'src/https_callable_result.dart'; -part 'src/https_callable_stream.dart'; part 'src/https_callable_stream_result.dart'; diff --git a/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart b/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart index 74387f829344..94a3e25e85d1 100644 --- a/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions/lib/src/firebase_functions.dart @@ -96,44 +96,6 @@ class FirebaseFunctions extends FirebasePluginPlatform { delegate.httpsCallableWithUri(_origin, uri, options)); } - /// A reference to the streaming Callable HTTPS trigger with the given name. - /// - /// Should be the name of the Callable function in Firebase that supports streaming. - HttpsCallableStream httpsStreamCallable( - String name, { - HttpsCallableOptions? options, - }) { - options ??= HttpsCallableOptions(); - assert(name.isNotEmpty); - return HttpsCallableStream._( - delegate.httpsStreamCallable(_origin, name, options)); - } - - /// A reference to the streaming Callable HTTPS trigger with the given URL. - /// - /// Should be URL of the 2nd gen Callable function in Firebase. - HttpsCallableStream httpsCallableStreamFromUrl( - String url, { - HttpsCallableOptions? options, - }) { - options ??= HttpsCallableOptions(); - final uri = Uri.parse(url); - return HttpsCallableStream._( - delegate.httpsStreamCallableWithUri(_origin, uri, options)); - } - - /// A reference to the streaming Callable HTTPS trigger with the given URI. - /// - /// Should be Uri of the 2nd gen Callable function in Firebase. - HttpsCallableStream httpsCallableStreamFromUri( - Uri uri, { - HttpsCallableOptions? options, - }) { - options ??= HttpsCallableOptions(); - return HttpsCallableStream._( - delegate.httpsStreamCallableWithUri(_origin, uri, options)); - } - /// Changes this instance to point to a Cloud Functions emulator running locally. /// /// Set the [host] of the local emulator, such as "localhost" diff --git a/packages/cloud_functions/cloud_functions/lib/src/https_callable.dart b/packages/cloud_functions/cloud_functions/lib/src/https_callable.dart index 61e66c65b061..b2fc2b378835 100644 --- a/packages/cloud_functions/cloud_functions/lib/src/https_callable.dart +++ b/packages/cloud_functions/cloud_functions/lib/src/https_callable.dart @@ -48,6 +48,32 @@ class HttpsCallable { } return HttpsCallableResult._(await delegate.call(updatedParameters)); } + + /// Streams data to the specified HTTPS endpoint. + /// + /// The data passed into the trigger can be any of the following types: + /// + /// `null` + /// `String` + /// `num` + /// [List], where the contained objects are also one of these types. + /// [Map], where the values are also one of these types. + /// + /// The request to the Cloud Functions backend made by this method + /// automatically includes a Firebase Instance ID token to identify the app + /// instance. If a user is logged in with Firebase Auth, an auth ID token for + /// the user is also automatically included. + Stream stream([Object? input]) async* { + await for (final value in delegate.stream(input)) { + if (value is Map) { + if (value.containsKey('message')) { + yield Chunk(value['message'] as T); + } else if (value.containsKey('result')) { + yield Result(HttpsCallableResult._(value['result'] as R)); + } + } + } + } } dynamic _updateRawDataToList(dynamic value) { diff --git a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart b/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart deleted file mode 100644 index 3a6d47dedea1..000000000000 --- a/packages/cloud_functions/cloud_functions/lib/src/https_callable_stream.dart +++ /dev/null @@ -1,41 +0,0 @@ -// ignore_for_file: require_trailing_commas -// Copyright 2020, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -part of '../cloud_functions.dart'; - -class HttpsCallableStream { - HttpsCallableStream._(this.delegate); - - /// Returns the underlying [HttpsCallableStream] delegate for this - /// [HttpsCallableStreamsPlatform] instance. This is useful for testing purposes only. - @visibleForTesting - final HttpsCallableStreamsPlatform delegate; - - /// Streams data to the specified HTTPS endpoint. - /// - /// The data passed into the trigger can be any of the following types: - /// - /// `null` - /// `String` - /// `num` - /// [List], where the contained objects are also one of these types. - /// [Map], where the values are also one of these types. - /// - /// The request to the Cloud Functions backend made by this method - /// automatically includes a Firebase Instance ID token to identify the app - /// instance. If a user is logged in with Firebase Auth, an auth ID token for - /// the user is also automatically included. - Stream stream([Object? input]) async* { - await for (final value in delegate.stream(input)) { - if (value is Map) { - if (value.containsKey('message')) { - yield Chunk(value['message'] as T); - } else if (value.containsKey('result')) { - yield Result(HttpsCallableResult._(value['result'] as R)); - } - } - } - } -} diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/cloud_functions_platform_interface.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/cloud_functions_platform_interface.dart index 60f8ea822179..81b3072393df 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/cloud_functions_platform_interface.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/cloud_functions_platform_interface.dart @@ -7,4 +7,3 @@ export 'src/firebase_functions_exception.dart'; export 'src/https_callable_options.dart'; export 'src/platform_interface/platform_interface_firebase_functions.dart'; export 'src/platform_interface/platform_interface_https_callable.dart'; -export 'src/platform_interface/platform_interface_https_callable_streams.dart'; diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart index 78f0e8cdae94..8f27e436e1ff 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_firebase_functions.dart @@ -3,7 +3,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:cloud_functions_platform_interface/src/method_channel/method_channel_https_callable_streams.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/services.dart'; @@ -51,16 +50,4 @@ class MethodChannelFirebaseFunctions extends FirebaseFunctionsPlatform { String? origin, Uri uri, HttpsCallableOptions options) { return MethodChannelHttpsCallable(this, origin, null, options, uri); } - - @override - HttpsCallableStreamsPlatform httpsStreamCallable( - String? origin, String name, HttpsCallableOptions options) { - return MethodChannelHttpsCallableStreams(this, origin, name, options, null); - } - - @override - HttpsCallableStreamsPlatform httpsStreamCallableWithUri( - String? origin, Uri uri, HttpsCallableOptions options) { - return MethodChannelHttpsCallableStreams(this, origin, null, options, uri); - } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable.dart index fb17e3e5b706..c4eddec24e03 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable.dart @@ -5,6 +5,8 @@ import 'dart:async'; +import 'package:flutter/services.dart'; + import '../../cloud_functions_platform_interface.dart'; import 'method_channel_firebase_functions.dart'; import 'utils/exception.dart'; @@ -14,7 +16,16 @@ class MethodChannelHttpsCallable extends HttpsCallablePlatform { /// Creates a new [MethodChannelHttpsCallable] instance. MethodChannelHttpsCallable(FirebaseFunctionsPlatform functions, String? origin, String? name, HttpsCallableOptions options, Uri? uri) - : super(functions, origin, name, options, uri); + : _transformedUri = uri?.pathSegments.join('_').replaceAll('.', '_'), + super(functions, origin, name, options, uri) { + _eventChannelId = name ?? _transformedUri ?? ''; + _channel = + EventChannel('plugins.flutter.io/firebase_functions/$_eventChannelId'); + } + + late final EventChannel _channel; + final String? _transformedUri; + late String _eventChannelId; @override Future call([Object? parameters]) async { @@ -40,4 +51,36 @@ class MethodChannelHttpsCallable extends HttpsCallablePlatform { convertPlatformException(e, s); } } + + @override + Stream stream(Object? parameters) async* { + try { + await _registerEventChannelOnNative(); + final eventData = { + 'functionName': name, + 'functionUri': uri?.toString(), + 'origin': origin, + 'parameters': parameters, + 'limitedUseAppCheckToken': options.limitedUseAppCheckToken, + 'timeout': options.timeout.inMilliseconds, + }; + yield* _channel.receiveBroadcastStream(eventData).map((message) { + if (message is Map) { + return Map.from(message); + } + return message; + }); + } catch (e, s) { + convertPlatformException(e, s); + } + } + + Future _registerEventChannelOnNative() async { + await MethodChannelFirebaseFunctions.channel.invokeMethod( + 'FirebaseFunctions#registerEventChannel', { + 'eventChannelId': _eventChannelId, + 'appName': functions.app!.name, + 'region': functions.region, + }); + } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart deleted file mode 100644 index 4f1622f442f4..000000000000 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/method_channel/method_channel_https_callable_streams.dart +++ /dev/null @@ -1,56 +0,0 @@ -// ignore_for_file: require_trailing_commas -// Copyright 2020, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:cloud_functions_platform_interface/src/method_channel/method_channel_firebase_functions.dart'; -import 'package:cloud_functions_platform_interface/src/method_channel/utils/exception.dart'; -import 'package:flutter/services.dart'; -import '../../cloud_functions_platform_interface.dart'; - -class MethodChannelHttpsCallableStreams extends HttpsCallableStreamsPlatform { - MethodChannelHttpsCallableStreams(FirebaseFunctionsPlatform functions, - String? origin, String? name, HttpsCallableOptions options, Uri? uri) - : _transformedUri = uri?.pathSegments.join('_').replaceAll('.', '_'), - super(functions, origin, name, options, uri) { - _eventChannelId = name ?? _transformedUri ?? ''; - _channel = - EventChannel('plugins.flutter.io/firebase_functions/$_eventChannelId'); - } - - late final EventChannel _channel; - final String? _transformedUri; - late String _eventChannelId; - - @override - Stream stream(Object? parameters) async* { - try { - await _registerEventChannelOnNative(); - final eventData = { - 'functionName': name, - 'functionUri': uri?.toString(), - 'origin': origin, - 'parameters': parameters, - 'limitedUseAppCheckToken': options.limitedUseAppCheckToken, - 'timeout': options.timeout.inMilliseconds, - }; - yield* _channel.receiveBroadcastStream(eventData).map((message) { - if (message is Map) { - return Map.from(message); - } - return message; - }); - } catch (e, s) { - convertPlatformException(e, s); - } - } - - Future _registerEventChannelOnNative() async { - await MethodChannelFirebaseFunctions.channel.invokeMethod( - 'FirebaseFunctions#registerEventChannel', { - 'eventChannelId': _eventChannelId, - 'appName': functions.app!.name, - 'region': functions.region, - }); - } -} diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart index 1b26c476477d..d9eac236d341 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_firebase_functions.dart @@ -72,16 +72,4 @@ abstract class FirebaseFunctionsPlatform extends PlatformInterface { String? origin, Uri uri, HttpsCallableOptions options) { throw UnimplementedError('httpsCallableWithUri() is not implemented'); } - - /// Creates a [HttpsCallableStreamsPlatform] instance - HttpsCallableStreamsPlatform httpsStreamCallable( - String? origin, String name, HttpsCallableOptions options) { - throw UnimplementedError('httpsStreamCallable() is not implemented'); - } - - /// Creates a [HttpsCallableStreamsPlatform] instance from [Uri] - HttpsCallableStreamsPlatform httpsStreamCallableWithUri( - String? origin, Uri uri, HttpsCallableOptions options) { - throw UnimplementedError('httpsStreamCallableWithUri() is not implemented'); - } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable.dart index ec5c2c22c9c1..be287c7a9571 100644 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable.dart +++ b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable.dart @@ -67,4 +67,22 @@ abstract class HttpsCallablePlatform extends PlatformInterface { Future call([dynamic parameters]) { throw UnimplementedError('call() is not implemented'); } + + /// Streams data to the specified HTTPS endpoint. + /// + /// The data passed into the trigger can be any of the following types: + /// + /// `null` + /// `String` + /// `num` + /// [List], where the contained objects are also one of these types. + /// [Map], where the values are also one of these types. + /// + /// The request to the Cloud Functions backend made by this method + /// automatically includes a Firebase Instance ID token to identify the app + /// instance. If a user is logged in with Firebase Auth, an auth ID token for + /// the user is also automatically included. + Stream stream(Object? parameters) { + throw UnimplementedError('stream() is not implemented'); + } } diff --git a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart b/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart deleted file mode 100644 index 09fa071826c2..000000000000 --- a/packages/cloud_functions/cloud_functions_platform_interface/lib/src/platform_interface/platform_interface_https_callable_streams.dart +++ /dev/null @@ -1,58 +0,0 @@ -// ignore_for_file: require_trailing_commas -// Copyright 2020 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; - -/// Interface for [HttpsCallableStream] implementations -/// -/// A reference to a particular Callable HTTPS trigger in Cloud Functions. -abstract class HttpsCallableStreamsPlatform extends PlatformInterface { - HttpsCallableStreamsPlatform( - this.functions, - this.origin, - this.name, - this.options, - this.uri, - ) : assert(name != null || uri != null), - super(token: _token); - - static final Object _token = Object(); - - static void verify(HttpsCallableStreamsPlatform instance) { - PlatformInterface.verify(instance, _token); - } - - /// The [FirebaseFunctionsPlatform] instance. - final FirebaseFunctionsPlatform functions; - - /// The [origin] of the local emulator, such as "http://localhost:5001" - final String? origin; - - /// The name of the function (required, non-nullable) - final String? name; - - /// The URI of the function for 2nd gen functions - final Uri? uri; - - /// Used to set the options for this instance. - HttpsCallableOptions options; - - /// Streams data to the specified HTTPS endpoint. - /// - /// The data passed into the trigger can be any of the following types: - /// - /// `null` - /// `String` - /// `num` - /// [List], where the contained objects are also one of these types. - /// [Map], where the values are also one of these types. - /// - /// The request to the Cloud Functions backend made by this method - /// automatically includes a Firebase Instance ID token to identify the app - /// instance. If a user is logged in with Firebase Auth, an auth ID token for - /// the user is also automatically included. - Stream stream(Object? parameters); -} diff --git a/packages/cloud_functions/cloud_functions_web/lib/cloud_functions_web.dart b/packages/cloud_functions/cloud_functions_web/lib/cloud_functions_web.dart index fcee4552424a..594c90a56985 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/cloud_functions_web.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/cloud_functions_web.dart @@ -4,7 +4,6 @@ // found in the LICENSE file. import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; -import 'package:cloud_functions_web/https_callable_stream_web.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core_web/firebase_core_web.dart'; import 'package:firebase_core_web/firebase_core_web_interop.dart' @@ -63,16 +62,4 @@ class FirebaseFunctionsWeb extends FirebaseFunctionsPlatform { String? origin, Uri uri, HttpsCallableOptions options) { return HttpsCallableWeb(this, _delegate, origin, null, options, uri); } - - @override - HttpsCallableStreamsPlatform httpsStreamCallable( - String? origin, String name, HttpsCallableOptions options) { - return HttpsCallableStreamWeb(this, _delegate, origin, name, options, null); - } - - @override - HttpsCallableStreamsPlatform httpsStreamCallableWithUri( - String? origin, Uri uri, HttpsCallableOptions options) { - return HttpsCallableStreamWeb(this, _delegate, origin, null, options, null); - } } diff --git a/packages/cloud_functions/cloud_functions_web/lib/https_callable_stream_web.dart b/packages/cloud_functions/cloud_functions_web/lib/https_callable_stream_web.dart deleted file mode 100644 index f79ab210cb85..000000000000 --- a/packages/cloud_functions/cloud_functions_web/lib/https_callable_stream_web.dart +++ /dev/null @@ -1,57 +0,0 @@ -// ignore_for_file: require_trailing_commas -// Copyright 2020, the Chromium project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'dart:js_interop'; - -import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; -import 'package:cloud_functions_web/interop/functions_interop.dart' as interop; - -import 'interop/functions.dart' as functions_interop; -import 'utils.dart'; - -class HttpsCallableStreamWeb extends HttpsCallableStreamsPlatform { - HttpsCallableStreamWeb( - FirebaseFunctionsPlatform functions, - this._webFunctions, - String? origin, - String? name, - HttpsCallableOptions options, - Uri? uri) - : super(functions, origin, name, options, uri); - - final functions_interop.Functions _webFunctions; - - @override - Stream stream(Object? parameters) async* { - if (origin != null) { - final uri = Uri.parse(origin!); - - _webFunctions.useFunctionsEmulator(uri.host, uri.port); - } - - late functions_interop.HttpsCallable callable; - - if (name != null) { - callable = _webFunctions.httpsCallable(name!); - } else if (uri != null) { - callable = _webFunctions.httpsCallableUri(uri!); - } else { - throw ArgumentError('Either name or uri must be provided'); - } - - final JSAny? parametersJS = parameters?.jsify(); - interop.HttpsCallableStreamOptions callableStreamOptions = - interop.HttpsCallableStreamOptions( - limitedUseAppCheckTokens: options.limitedUseAppCheckToken.toJS); - try { - await for (final value - in callable.stream(parametersJS, callableStreamOptions)) { - yield value; - } - } catch (e, s) { - throw convertFirebaseFunctionsException(e as JSObject, s); - } - } -} diff --git a/packages/cloud_functions/cloud_functions_web/lib/https_callable_web.dart b/packages/cloud_functions/cloud_functions_web/lib/https_callable_web.dart index c85f7a17d564..fa21e07469f9 100644 --- a/packages/cloud_functions/cloud_functions_web/lib/https_callable_web.dart +++ b/packages/cloud_functions/cloud_functions_web/lib/https_callable_web.dart @@ -7,6 +7,7 @@ import 'dart:async'; import 'dart:js_interop'; import 'package:cloud_functions_platform_interface/cloud_functions_platform_interface.dart'; +import 'package:cloud_functions_web/interop/functions_interop.dart' as interop; import 'interop/functions.dart' as functions_interop; import 'utils.dart'; @@ -56,4 +57,36 @@ class HttpsCallableWeb extends HttpsCallablePlatform { return response.data; } + + @override + Stream stream(Object? parameters) async* { + if (origin != null) { + final uri = Uri.parse(origin!); + + _webFunctions.useFunctionsEmulator(uri.host, uri.port); + } + + late functions_interop.HttpsCallable callable; + + if (name != null) { + callable = _webFunctions.httpsCallable(name!); + } else if (uri != null) { + callable = _webFunctions.httpsCallableUri(uri!); + } else { + throw ArgumentError('Either name or uri must be provided'); + } + + final JSAny? parametersJS = parameters?.jsify(); + interop.HttpsCallableStreamOptions callableStreamOptions = + interop.HttpsCallableStreamOptions( + limitedUseAppCheckTokens: options.limitedUseAppCheckToken.toJS); + try { + await for (final value + in callable.stream(parametersJS, callableStreamOptions)) { + yield value; + } + } catch (e, s) { + throw convertFirebaseFunctionsException(e as JSObject, s); + } + } }