@dittolive/ditto 4.4.4 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DittoReactNative.podspec +27 -0
- package/README.md +68 -51
- package/node/ditto.cjs.js +1639 -851
- package/node/ditto.darwin-arm64.node +0 -0
- package/node/ditto.darwin-x64.node +0 -0
- package/node/ditto.linux-arm.node +0 -0
- package/node/ditto.linux-x64.node +0 -0
- package/node/ditto.win32-x64.node +0 -0
- package/node/transports.darwin-arm64.node +0 -0
- package/node/transports.darwin-x64.node +0 -0
- package/package.json +34 -38
- package/react-native/android/CMakeLists.txt +37 -0
- package/react-native/android/build.gradle +203 -0
- package/react-native/android/cpp-adapter.cpp +254 -0
- package/react-native/android/gradle.properties +5 -0
- package/react-native/android/src/main/AndroidManifest.xml +4 -0
- package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.java +85 -0
- package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKPackage.java +28 -0
- package/react-native/boost/boost/assert.hpp +85 -0
- package/react-native/boost/boost/config/abi/borland_prefix.hpp +27 -0
- package/react-native/boost/boost/config/abi/borland_suffix.hpp +12 -0
- package/react-native/boost/boost/config/abi/msvc_prefix.hpp +22 -0
- package/react-native/boost/boost/config/abi/msvc_suffix.hpp +8 -0
- package/react-native/boost/boost/config/abi_prefix.hpp +25 -0
- package/react-native/boost/boost/config/abi_suffix.hpp +25 -0
- package/react-native/boost/boost/config/assert_cxx03.hpp +211 -0
- package/react-native/boost/boost/config/assert_cxx11.hpp +209 -0
- package/react-native/boost/boost/config/assert_cxx14.hpp +47 -0
- package/react-native/boost/boost/config/assert_cxx17.hpp +62 -0
- package/react-native/boost/boost/config/assert_cxx20.hpp +59 -0
- package/react-native/boost/boost/config/assert_cxx98.hpp +23 -0
- package/react-native/boost/boost/config/auto_link.hpp +525 -0
- package/react-native/boost/boost/config/compiler/borland.hpp +339 -0
- package/react-native/boost/boost/config/compiler/clang.hpp +366 -0
- package/react-native/boost/boost/config/compiler/clang_version.hpp +83 -0
- package/react-native/boost/boost/config/compiler/codegear.hpp +385 -0
- package/react-native/boost/boost/config/compiler/comeau.hpp +59 -0
- package/react-native/boost/boost/config/compiler/common_edg.hpp +183 -0
- package/react-native/boost/boost/config/compiler/compaq_cxx.hpp +19 -0
- package/react-native/boost/boost/config/compiler/cray.hpp +446 -0
- package/react-native/boost/boost/config/compiler/diab.hpp +26 -0
- package/react-native/boost/boost/config/compiler/digitalmars.hpp +143 -0
- package/react-native/boost/boost/config/compiler/gcc.hpp +383 -0
- package/react-native/boost/boost/config/compiler/gcc_xml.hpp +114 -0
- package/react-native/boost/boost/config/compiler/greenhills.hpp +28 -0
- package/react-native/boost/boost/config/compiler/hp_acc.hpp +149 -0
- package/react-native/boost/boost/config/compiler/intel.hpp +577 -0
- package/react-native/boost/boost/config/compiler/kai.hpp +33 -0
- package/react-native/boost/boost/config/compiler/metrowerks.hpp +198 -0
- package/react-native/boost/boost/config/compiler/mpw.hpp +140 -0
- package/react-native/boost/boost/config/compiler/nvcc.hpp +61 -0
- package/react-native/boost/boost/config/compiler/pathscale.hpp +138 -0
- package/react-native/boost/boost/config/compiler/pgi.hpp +23 -0
- package/react-native/boost/boost/config/compiler/sgi_mipspro.hpp +29 -0
- package/react-native/boost/boost/config/compiler/sunpro_cc.hpp +222 -0
- package/react-native/boost/boost/config/compiler/vacpp.hpp +186 -0
- package/react-native/boost/boost/config/compiler/visualc.hpp +391 -0
- package/react-native/boost/boost/config/compiler/xlcpp.hpp +299 -0
- package/react-native/boost/boost/config/compiler/xlcpp_zos.hpp +173 -0
- package/react-native/boost/boost/config/detail/cxx_composite.hpp +203 -0
- package/react-native/boost/boost/config/detail/posix_features.hpp +95 -0
- package/react-native/boost/boost/config/detail/select_compiler_config.hpp +157 -0
- package/react-native/boost/boost/config/detail/select_platform_config.hpp +147 -0
- package/react-native/boost/boost/config/detail/select_stdlib_config.hpp +121 -0
- package/react-native/boost/boost/config/detail/suffix.hpp +1294 -0
- package/react-native/boost/boost/config/header_deprecated.hpp +26 -0
- package/react-native/boost/boost/config/helper_macros.hpp +37 -0
- package/react-native/boost/boost/config/no_tr1/cmath.hpp +28 -0
- package/react-native/boost/boost/config/no_tr1/complex.hpp +28 -0
- package/react-native/boost/boost/config/no_tr1/functional.hpp +28 -0
- package/react-native/boost/boost/config/no_tr1/memory.hpp +28 -0
- package/react-native/boost/boost/config/no_tr1/utility.hpp +28 -0
- package/react-native/boost/boost/config/platform/aix.hpp +33 -0
- package/react-native/boost/boost/config/platform/amigaos.hpp +15 -0
- package/react-native/boost/boost/config/platform/beos.hpp +26 -0
- package/react-native/boost/boost/config/platform/bsd.hpp +83 -0
- package/react-native/boost/boost/config/platform/cloudabi.hpp +18 -0
- package/react-native/boost/boost/config/platform/cray.hpp +18 -0
- package/react-native/boost/boost/config/platform/cygwin.hpp +71 -0
- package/react-native/boost/boost/config/platform/haiku.hpp +31 -0
- package/react-native/boost/boost/config/platform/hpux.hpp +87 -0
- package/react-native/boost/boost/config/platform/irix.hpp +31 -0
- package/react-native/boost/boost/config/platform/linux.hpp +106 -0
- package/react-native/boost/boost/config/platform/macos.hpp +87 -0
- package/react-native/boost/boost/config/platform/qnxnto.hpp +31 -0
- package/react-native/boost/boost/config/platform/solaris.hpp +31 -0
- package/react-native/boost/boost/config/platform/symbian.hpp +97 -0
- package/react-native/boost/boost/config/platform/vms.hpp +25 -0
- package/react-native/boost/boost/config/platform/vxworks.hpp +422 -0
- package/react-native/boost/boost/config/platform/wasm.hpp +23 -0
- package/react-native/boost/boost/config/platform/win32.hpp +90 -0
- package/react-native/boost/boost/config/platform/zos.hpp +32 -0
- package/react-native/boost/boost/config/pragma_message.hpp +31 -0
- package/react-native/boost/boost/config/requires_threads.hpp +92 -0
- package/react-native/boost/boost/config/stdlib/dinkumware.hpp +324 -0
- package/react-native/boost/boost/config/stdlib/libcomo.hpp +93 -0
- package/react-native/boost/boost/config/stdlib/libcpp.hpp +180 -0
- package/react-native/boost/boost/config/stdlib/libstdcpp3.hpp +482 -0
- package/react-native/boost/boost/config/stdlib/modena.hpp +79 -0
- package/react-native/boost/boost/config/stdlib/msl.hpp +98 -0
- package/react-native/boost/boost/config/stdlib/roguewave.hpp +208 -0
- package/react-native/boost/boost/config/stdlib/sgi.hpp +168 -0
- package/react-native/boost/boost/config/stdlib/stlport.hpp +258 -0
- package/react-native/boost/boost/config/stdlib/vacpp.hpp +74 -0
- package/react-native/boost/boost/config/stdlib/xlcpp_zos.hpp +61 -0
- package/react-native/boost/boost/config/user.hpp +133 -0
- package/react-native/boost/boost/config/warning_disable.hpp +47 -0
- package/react-native/boost/boost/config/workaround.hpp +305 -0
- package/react-native/boost/boost/config.hpp +67 -0
- package/react-native/boost/boost/cstdint.hpp +556 -0
- package/react-native/boost/boost/intrusive_ptr.hpp +18 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count.hpp +103 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_gcc.hpp +79 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_gcc_atomic.hpp +63 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_gcc_x86.hpp +88 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_nt.hpp +66 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_pt.hpp +104 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_spin.hpp +69 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_std_atomic.hpp +67 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_sync.hpp +72 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_win32.hpp +70 -0
- package/react-native/boost/boost/smart_ptr/detail/local_counted_base.hpp +148 -0
- package/react-native/boost/boost/smart_ptr/detail/local_sp_deleter.hpp +91 -0
- package/react-native/boost/boost/smart_ptr/detail/operator_bool.hpp +64 -0
- package/react-native/boost/boost/smart_ptr/detail/requires_cxx11.hpp +23 -0
- package/react-native/boost/boost/smart_ptr/detail/shared_count.hpp +707 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_convertible.hpp +92 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base.hpp +92 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp +163 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_aix.hpp +152 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp +185 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_atomic.hpp +148 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp +170 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp +200 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp +194 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp +179 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp +186 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_nt.hpp +119 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_pt.hpp +147 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_snc_ps3.hpp +174 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_spin.hpp +141 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp +147 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_sync.hpp +165 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_vacpp_ppc.hpp +163 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_w32.hpp +140 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_impl.hpp +309 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_disable_deprecated.hpp +40 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_forward.hpp +52 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_has_gcc_intrinsics.hpp +27 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_has_sync_intrinsics.hpp +69 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_interlocked.hpp +173 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_noexcept.hpp +48 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_nullptr_t.hpp +45 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_obsolete.hpp +32 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_thread_pause.hpp +51 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_thread_sleep.hpp +104 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_thread_yield.hpp +100 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_typeinfo_.hpp +58 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_win32_sleep.hpp +49 -0
- package/react-native/boost/boost/smart_ptr/intrusive_ptr.hpp +409 -0
- package/react-native/boost/boost/smart_ptr/intrusive_ref_counter.hpp +188 -0
- package/react-native/cpp/include/Attachment.h +16 -0
- package/react-native/cpp/include/Authentication.h +23 -0
- package/react-native/cpp/include/Collection.h +13 -0
- package/react-native/cpp/include/DQL.h +21 -0
- package/react-native/cpp/include/Document.h +17 -0
- package/react-native/cpp/include/Identity.h +17 -0
- package/react-native/cpp/include/Lifecycle.h +16 -0
- package/react-native/cpp/include/LiveQuery.h +17 -0
- package/react-native/cpp/include/Logger.h +22 -0
- package/react-native/cpp/include/Misc.h +26 -0
- package/react-native/cpp/include/Presence.h +14 -0
- package/react-native/cpp/include/RetainableState.h +24 -0
- package/react-native/cpp/include/SmallPeerInfo.h +17 -0
- package/react-native/cpp/include/Transports.h +25 -0
- package/react-native/cpp/include/TypedArray.hpp +167 -0
- package/react-native/cpp/include/Utils.h +61 -0
- package/react-native/cpp/include/main.h +10 -0
- package/react-native/cpp/src/Attachment.cpp +86 -0
- package/react-native/cpp/src/Authentication.cpp +224 -0
- package/react-native/cpp/src/Collection.cpp +54 -0
- package/react-native/cpp/src/DQL.cpp +254 -0
- package/react-native/cpp/src/Document.cpp +146 -0
- package/react-native/cpp/src/Identity.cpp +123 -0
- package/react-native/cpp/src/Lifecycle.cpp +75 -0
- package/react-native/cpp/src/LiveQuery.cpp +64 -0
- package/react-native/cpp/src/Logger.cpp +200 -0
- package/react-native/cpp/src/Misc.cpp +271 -0
- package/react-native/cpp/src/Presence.cpp +77 -0
- package/react-native/cpp/src/RetainableState.cpp +15 -0
- package/react-native/cpp/src/SmallPeerInfo.cpp +108 -0
- package/react-native/cpp/src/Transports.cpp +270 -0
- package/react-native/cpp/src/TypedArray.cpp +303 -0
- package/react-native/cpp/src/Utils.cpp +138 -0
- package/react-native/cpp/src/main.cpp +149 -0
- package/react-native/dittoffi/dittoffi.h +4698 -0
- package/react-native/dittoffi/ifaddrs.cpp +385 -0
- package/react-native/dittoffi/ifaddrs.h +206 -0
- package/react-native/ios/DittoRNSDK.h +7 -0
- package/react-native/ios/DittoRNSDK.mm +107 -0
- package/react-native/ios/YeetJSIUtils.h +60 -0
- package/react-native/ios/YeetJSIUtils.mm +196 -0
- package/react-native/lib/commonjs/ditto.rn.js +93 -0
- package/react-native/lib/commonjs/ditto.rn.js.map +1 -0
- package/react-native/lib/commonjs/index.js +14 -0
- package/react-native/lib/commonjs/index.js.map +1 -0
- package/react-native/lib/module/ditto.rn.js +83 -0
- package/react-native/lib/module/ditto.rn.js.map +1 -0
- package/react-native/lib/module/index.js +13 -0
- package/react-native/lib/module/index.js.map +1 -0
- package/react-native/lib/typescript/ditto.rn.d.ts +15 -0
- package/react-native/lib/typescript/ditto.rn.d.ts.map +1 -0
- package/react-native/lib/typescript/index.d.ts +1 -0
- package/react-native/lib/typescript/index.d.ts.map +1 -0
- package/react-native/scripts/ruby/include_local_boost.rb +78 -0
- package/react-native/src/ditto.rn.ts +91 -0
- package/react-native/src/environment/environment.fallback.ts +4 -0
- package/react-native/src/index.ts +26 -0
- package/react-native/src/sources/@cbor-redux.ts +2 -0
- package/react-native/src/sources/@ditto.core.ts +1 -0
- package/react-native/src/sources/@environment.ts +2 -0
- package/react-native/src/sources/attachment-fetch-event.ts +54 -0
- package/react-native/src/sources/attachment-fetcher-manager.ts +129 -0
- package/react-native/src/sources/attachment-fetcher.ts +124 -0
- package/react-native/src/sources/attachment-token.ts +48 -0
- package/react-native/src/sources/attachment.ts +59 -0
- package/react-native/src/sources/augment.ts +89 -0
- package/react-native/src/sources/authenticator.ts +314 -0
- package/react-native/src/sources/base-pending-cursor-operation.ts +237 -0
- package/react-native/src/sources/base-pending-id-specific-operation.ts +109 -0
- package/react-native/src/sources/bridge.ts +549 -0
- package/react-native/src/sources/build-time-constants.ts +4 -0
- package/react-native/src/sources/cbor.ts +35 -0
- package/react-native/src/sources/collection-interface.ts +67 -0
- package/react-native/src/sources/collection.ts +212 -0
- package/react-native/src/sources/collections-event.ts +99 -0
- package/react-native/src/sources/counter.ts +77 -0
- package/react-native/src/sources/ditto.ts +945 -0
- package/react-native/src/sources/document-id.ts +159 -0
- package/react-native/src/sources/document-path.ts +303 -0
- package/react-native/src/sources/document.ts +192 -0
- package/react-native/src/sources/epilogue.ts +24 -0
- package/react-native/src/sources/error-codes.ts +52 -0
- package/react-native/src/sources/error.ts +203 -0
- package/react-native/src/sources/essentials.ts +53 -0
- package/react-native/src/sources/ffi-error.ts +117 -0
- package/react-native/src/sources/ffi.ts +1972 -0
- package/react-native/src/sources/identity.ts +163 -0
- package/react-native/src/sources/init.ts +70 -0
- package/react-native/src/sources/internal.ts +113 -0
- package/react-native/src/sources/keep-alive.ts +69 -0
- package/react-native/src/sources/key-path.ts +195 -0
- package/react-native/src/sources/live-query-event.ts +208 -0
- package/react-native/src/sources/live-query-manager.ts +101 -0
- package/react-native/src/sources/live-query.ts +164 -0
- package/react-native/src/sources/logger.ts +196 -0
- package/react-native/src/sources/observer-manager.ts +175 -0
- package/react-native/src/sources/observer.ts +77 -0
- package/react-native/src/sources/pending-collections-operation.ts +232 -0
- package/react-native/src/sources/pending-cursor-operation.ts +218 -0
- package/react-native/src/sources/pending-id-specific-operation.ts +216 -0
- package/react-native/src/sources/presence-manager.ts +160 -0
- package/react-native/src/sources/presence.ts +238 -0
- package/react-native/src/sources/query-result-item.ts +116 -0
- package/react-native/src/sources/query-result.ts +55 -0
- package/react-native/src/sources/register.ts +92 -0
- package/react-native/src/sources/small-peer-info.ts +176 -0
- package/react-native/src/sources/static-tcp-client.ts +6 -0
- package/react-native/src/sources/store-observer.ts +176 -0
- package/react-native/src/sources/store.ts +365 -0
- package/react-native/src/sources/subscription-manager.ts +98 -0
- package/react-native/src/sources/subscription.ts +88 -0
- package/react-native/src/sources/sync-subscription.ts +90 -0
- package/react-native/src/sources/sync.ts +495 -0
- package/react-native/src/sources/test-helpers.ts +24 -0
- package/react-native/src/sources/transport-conditions-manager.ts +104 -0
- package/react-native/src/sources/transport-config.ts +428 -0
- package/react-native/src/sources/update-result.ts +66 -0
- package/react-native/src/sources/update-results-map.ts +57 -0
- package/react-native/src/sources/websocket-client.ts +6 -0
- package/react-native/src/sources/write-transaction-collection.ts +122 -0
- package/react-native/src/sources/write-transaction-pending-cursor-operation.ts +101 -0
- package/react-native/src/sources/write-transaction-pending-id-specific-operation.ts +72 -0
- package/react-native/src/sources/write-transaction.ts +119 -0
- package/react-native.config.js +9 -0
- package/types/ditto.d.ts +1230 -798
- package/web/ditto.es6.js +1 -1
- package/web/ditto.umd.js +1 -1
- package/web/ditto.wasm +0 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright © 2021 DittoLive Incorporated. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import type { AuthenticationHandler } from './authenticator'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* An identity to be used while in development when you want to control the app
|
|
9
|
+
* name and the site ID of the peer.
|
|
10
|
+
*/
|
|
11
|
+
export interface IdentityOfflinePlayground {
|
|
12
|
+
type: 'offlinePlayground'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The app ID for the Ditto instance.
|
|
16
|
+
*/
|
|
17
|
+
appID: string
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The `siteID` needs to be an unsigned 64 bit integer >= 0, i.e. either a
|
|
21
|
+
* regular non-fractional `number` or a `BigInt` in the range between 0 and
|
|
22
|
+
* 2^64 - 1 (inclusive). If `siteID` is `0`, Ditto will generate an
|
|
23
|
+
* appropriate site ID and persist it when needed. Default is `0`.
|
|
24
|
+
*/
|
|
25
|
+
siteID?: number | BigInt
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* An identity with intermediate level of security where all users and devices
|
|
30
|
+
* are trusted and a single shared secret (key) between all peers satisfies the
|
|
31
|
+
* security requirements.
|
|
32
|
+
*
|
|
33
|
+
* **NOTE**: This identity type is only supported for Node environments, using
|
|
34
|
+
* this to create a Ditto instance in the web browser will throw an exception.
|
|
35
|
+
*/
|
|
36
|
+
export interface IdentitySharedKey {
|
|
37
|
+
type: 'sharedKey'
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The app ID for the Ditto instance.
|
|
41
|
+
*/
|
|
42
|
+
appID: string
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The `siteID` needs to be an unsigned 64 bit integer >= 0, i.e. either a
|
|
46
|
+
* regular non-fractional `number` or a `BigInt` in the range between 0 and
|
|
47
|
+
* 2^64 - 1 (inclusive). If `siteID` is `0`, Ditto will generate an
|
|
48
|
+
* appropriate site ID and persist it when needed. Default is `0`.
|
|
49
|
+
*/
|
|
50
|
+
siteID?: number | BigInt
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* A base64 encoded DER representation of a private key, which is shared
|
|
54
|
+
* between devices for a single app.
|
|
55
|
+
*/
|
|
56
|
+
sharedKey: string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A manually-provided certificate identity. This accepts a
|
|
61
|
+
* base64-encoded bundle.
|
|
62
|
+
*
|
|
63
|
+
* A manual identity's `appID` is encoded in its certificate.
|
|
64
|
+
*/
|
|
65
|
+
export interface IdentityManual {
|
|
66
|
+
type: 'manual'
|
|
67
|
+
certificate: string
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Test a Ditto Cloud app with weak shared token authentication ("Playground
|
|
72
|
+
* mode"). This mode is not secure and must only be used for development.
|
|
73
|
+
*/
|
|
74
|
+
export interface IdentityOnlinePlayground {
|
|
75
|
+
type: 'onlinePlayground'
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* An ID identifying this app registration on the Ditto portal, which can be
|
|
79
|
+
* found at https://portal.ditto.live.
|
|
80
|
+
*/
|
|
81
|
+
appID: string
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* A shared token used to set up the OnlinePlayground session. This token is
|
|
85
|
+
* provided by the Ditto Portal when setting up the application.
|
|
86
|
+
*/
|
|
87
|
+
token: string
|
|
88
|
+
|
|
89
|
+
/** If true, auto-configure sync with Ditto Cloud. Default is `true`. */
|
|
90
|
+
enableDittoCloudSync?: boolean
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* If specified, use a custom authentication service instead of Ditto Cloud.
|
|
94
|
+
* @internal
|
|
95
|
+
*/
|
|
96
|
+
customAuthURL?: string
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* A custom Ditto Cloud URL.
|
|
100
|
+
* @internal
|
|
101
|
+
*/
|
|
102
|
+
customDittoCloudURL?: string
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Run Ditto in secure production mode, logging on to Ditto Cloud or an
|
|
107
|
+
* on-premises authentication server. User permissions are centrally managed.
|
|
108
|
+
* Sync will not work until a successful login has occurred.
|
|
109
|
+
*
|
|
110
|
+
* The only required configuration is the application's UUID, which can be found
|
|
111
|
+
* on the Ditto portal where the app is registered.
|
|
112
|
+
*
|
|
113
|
+
* By default cloud sync is enabled. This means the SDK will sync to a Big Peer
|
|
114
|
+
* in Ditto's cloud when an internet connection is available. This is controlled
|
|
115
|
+
* by the `enableCloudSync` parameter. If `true` (default), a suitable wss://
|
|
116
|
+
* URL will be added to the `TransportConfig`. To prevent cloud sync, or to
|
|
117
|
+
* specify your own URL later, pass `false`.
|
|
118
|
+
*
|
|
119
|
+
* Authentication requests are handled by Ditto's cloud by default, configured
|
|
120
|
+
* in the portal at https://portal.ditto.live.
|
|
121
|
+
*
|
|
122
|
+
* To use a different or on-premises authentication service, pass a custom HTTPS
|
|
123
|
+
* base URL as the `customAuthUrl` parameter.
|
|
124
|
+
*/
|
|
125
|
+
export interface IdentityOnlineWithAuthentication {
|
|
126
|
+
type: 'onlineWithAuthentication'
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* An ID identifying this app registration on the Ditto portal, which can be
|
|
130
|
+
* found at https://portal.ditto.live.
|
|
131
|
+
*/
|
|
132
|
+
appID: string
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* If true, auto-configure sync with Ditto Cloud. Default is `true`.
|
|
136
|
+
*/
|
|
137
|
+
enableDittoCloudSync?: boolean
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* A handler for when Ditto requires (re)authentication.
|
|
141
|
+
*/
|
|
142
|
+
authHandler: AuthenticationHandler
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* If specified, use a custom authentication service instead of Ditto Cloud.
|
|
146
|
+
*/
|
|
147
|
+
customAuthURL?: string
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* A custom Ditto Cloud URL.
|
|
151
|
+
* @internal
|
|
152
|
+
*/
|
|
153
|
+
customDittoCloudURL?: string
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The various identity configurations that you can use when initializing a
|
|
158
|
+
* `Ditto` instance.
|
|
159
|
+
*/
|
|
160
|
+
export type Identity = IdentityOfflinePlayground | IdentitySharedKey | IdentityManual | IdentityOnlinePlayground | IdentityOnlineWithAuthentication
|
|
161
|
+
|
|
162
|
+
/** The list of identity types that require activation through an offlineLicenseToken */
|
|
163
|
+
export const IdentityTypesRequiringOfflineLicenseToken = ['manual', 'sharedKey', 'offlinePlayground']
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright © 2021 DittoLive Incorporated. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as FFI from './ffi'
|
|
6
|
+
import * as Environment from './@environment'
|
|
7
|
+
|
|
8
|
+
import { fullBuildVersionString, defaultDittoWasmFileURL } from './build-time-constants'
|
|
9
|
+
import type { WebAssemblyModule } from './ffi'
|
|
10
|
+
|
|
11
|
+
let isInitialized = false
|
|
12
|
+
|
|
13
|
+
export { WebAssemblyModule }
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Available options for {@link init | init()}.
|
|
17
|
+
*/
|
|
18
|
+
export type InitOptions = {
|
|
19
|
+
/**
|
|
20
|
+
* You can explicitly pass the WebAssembly module or its location via the
|
|
21
|
+
* `webAssemblyModule` option. By default, Ditto tries to load the WebAssembly
|
|
22
|
+
* module from the same path where this JavaScript is served.
|
|
23
|
+
*/
|
|
24
|
+
webAssemblyModule?: WebAssemblyModule
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Initializes the whole Ditto module. Needs to be called and complete before
|
|
29
|
+
* any of the Ditto API is used.
|
|
30
|
+
*
|
|
31
|
+
* @param options - Dictionary with global {@link InitOptions | initialization options}.
|
|
32
|
+
*/
|
|
33
|
+
export async function init(options: InitOptions = {}): Promise<void> {
|
|
34
|
+
if (!isInitialized) {
|
|
35
|
+
if (Environment.isWebBuild) {
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
const webAssemblyModule = options.webAssemblyModule || defaultDittoWasmFileURL
|
|
39
|
+
|
|
40
|
+
await FFI.init(webAssemblyModule)
|
|
41
|
+
|
|
42
|
+
FFI.initSDKVersion('Web', 'JavaScript', fullBuildVersionString)
|
|
43
|
+
FFI.loggerInit()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
isInitialized = true
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (Environment.isNodeBuild) {
|
|
51
|
+
switch (process.platform) {
|
|
52
|
+
case 'android':
|
|
53
|
+
FFI.initSDKVersion('Android', 'JavaScript', fullBuildVersionString)
|
|
54
|
+
break
|
|
55
|
+
case 'darwin':
|
|
56
|
+
FFI.initSDKVersion('Mac', 'JavaScript', fullBuildVersionString)
|
|
57
|
+
break
|
|
58
|
+
case 'linux':
|
|
59
|
+
FFI.initSDKVersion('Linux', 'JavaScript', fullBuildVersionString)
|
|
60
|
+
break
|
|
61
|
+
case 'win32':
|
|
62
|
+
FFI.initSDKVersion('Windows', 'JavaScript', fullBuildVersionString)
|
|
63
|
+
break
|
|
64
|
+
default:
|
|
65
|
+
FFI.initSDKVersion('Unknown', 'JavaScript', fullBuildVersionString)
|
|
66
|
+
break
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
FFI.loggerInit()
|
|
70
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright © 2021 DittoLive Incorporated. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as FFI from './ffi'
|
|
6
|
+
import * as Environment from './@environment'
|
|
7
|
+
|
|
8
|
+
// ------------------------------------------------------------ Constants ------
|
|
9
|
+
|
|
10
|
+
export const defaultDittoCloudDomain = `cloud.ditto.live`
|
|
11
|
+
|
|
12
|
+
// ------------------------------------------------------------- Defaults ------
|
|
13
|
+
|
|
14
|
+
/** @internal */
|
|
15
|
+
export function defaultAuthURL(appID: string): string {
|
|
16
|
+
return `https://${appID}.${defaultDittoCloudDomain}`
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** @internal */
|
|
20
|
+
export function defaultDittoCloudURL(appID: string): string {
|
|
21
|
+
return `wss://${appID}.${defaultDittoCloudDomain}`
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ---------------------------------------------------------- Validations ------
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Validates a number and returns it as-is if all requirements are met,
|
|
28
|
+
* otherwise throws an exception. Options:
|
|
29
|
+
*
|
|
30
|
+
* - `integer`: if `true`, requires the number to be an integer
|
|
31
|
+
*
|
|
32
|
+
* - `min`: if given, requires the number to be >= `min`
|
|
33
|
+
* - `max`: if given, requires the number to be <= `max`
|
|
34
|
+
*
|
|
35
|
+
* - `minX`: if given, requires the number to be > `minX` (x stands for "exclusive")
|
|
36
|
+
* - `maxX`: if given, requires the number to be < `maxX` (x stands for "exclusive")
|
|
37
|
+
*
|
|
38
|
+
* You can also customize the error message by providing a prefix via
|
|
39
|
+
* `errorMessagePrefix`, which defaults to `"Number validation failed:"`.
|
|
40
|
+
*
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
export function validateNumber(value, options = {}): number {
|
|
44
|
+
const errorMessagePrefix = options['errorMessagePrefix'] ?? 'Number validation failed:'
|
|
45
|
+
const integer = !!options['integer']
|
|
46
|
+
|
|
47
|
+
const min = options['min']
|
|
48
|
+
const max = options['max']
|
|
49
|
+
|
|
50
|
+
const minX = options['minX']
|
|
51
|
+
const maxX = options['maxX']
|
|
52
|
+
|
|
53
|
+
if (typeof value !== 'number') throw new Error(`${errorMessagePrefix} '${value}' is not a number.`)
|
|
54
|
+
if (integer && Math.floor(value) !== value) throw new Error(`${errorMessagePrefix} '${value}' is not an integer.`)
|
|
55
|
+
|
|
56
|
+
if (typeof min !== 'undefined' && value < min) throw new Error(`${errorMessagePrefix} '${value}' must be >= ${min}.`)
|
|
57
|
+
if (typeof max !== 'undefined' && value > max) throw new Error(`${errorMessagePrefix} '${value}' must be <= ${max}.`)
|
|
58
|
+
|
|
59
|
+
if (typeof minX !== 'undefined' && value <= minX) throw new Error(`${errorMessagePrefix} '${value}' must be > ${minX}.`)
|
|
60
|
+
if (typeof maxX !== 'undefined' && value >= maxX) throw new Error(`${errorMessagePrefix} '${value}' must be < ${maxX}.`)
|
|
61
|
+
|
|
62
|
+
return value
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function validateQuery(query, options = {}): string {
|
|
66
|
+
const errorMessagePrefix = options['errorMessagePrefix'] ?? 'Query validation failed,'
|
|
67
|
+
|
|
68
|
+
if (typeof query !== 'string') throw new Error(`${errorMessagePrefix} query is not a string: ${query}`)
|
|
69
|
+
if (query === '') throw new Error(`${errorMessagePrefix} query is an empty string.`)
|
|
70
|
+
|
|
71
|
+
const validatedQuery = query.trim()
|
|
72
|
+
if (validatedQuery === '') throw new Error(`${errorMessagePrefix} query contains only whitespace characters.`)
|
|
73
|
+
return validatedQuery
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// -------------------------------------------------------------- Helpers ------
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Generate a random hex-encoded token using the WebCrypto API.
|
|
80
|
+
*
|
|
81
|
+
* @internal */
|
|
82
|
+
export function generateEphemeralToken(): string {
|
|
83
|
+
let webcrypto = undefined
|
|
84
|
+
|
|
85
|
+
let data = new Uint16Array(16)
|
|
86
|
+
if (Environment.isReactNativeBuild) {
|
|
87
|
+
data = FFI.getRandomValues(data) as Uint16Array
|
|
88
|
+
} else {
|
|
89
|
+
throw new Error('Internal inconsistency, incorrect environment to run getRandomValues()')
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const doublets = Array.from(data)
|
|
93
|
+
return doublets.map((doublet) => doublet.toString(16)).join('')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// --------------------------------------------------------------- System ------
|
|
97
|
+
|
|
98
|
+
/** @internal */
|
|
99
|
+
export function sleep(milliseconds: number): Promise<void> {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
setTimeout(resolve, milliseconds)
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** @internal use this to asyncify chunks of code. */
|
|
106
|
+
export async function step<T>(closure: () => T): Promise<T> {
|
|
107
|
+
await sleep(0)
|
|
108
|
+
return closure()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** @internal */
|
|
112
|
+
|
|
113
|
+
export const performAsyncToWorkaroundNonAsyncFFIAPI = step
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright © 2021 DittoLive Incorporated. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
/** @internal */
|
|
6
|
+
export class KeepAlive {
|
|
7
|
+
/** @internal */
|
|
8
|
+
get isActive(): boolean {
|
|
9
|
+
return this.intervalID !== null
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** @internal */
|
|
13
|
+
constructor() {
|
|
14
|
+
this.countsByID = {}
|
|
15
|
+
this.intervalID = null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** @internal */
|
|
19
|
+
retain(id: string): void {
|
|
20
|
+
if (typeof this.countsByID[id] === 'undefined') {
|
|
21
|
+
this.countsByID[id] = 0
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
this.countsByID[id] += 1
|
|
25
|
+
|
|
26
|
+
if (this.intervalID === null) {
|
|
27
|
+
const maxDelay = 2147483647
|
|
28
|
+
this.intervalID = setInterval(() => {
|
|
29
|
+
/* no-op */
|
|
30
|
+
}, maxDelay)
|
|
31
|
+
KeepAlive.finalizationRegistry.register(this, this.intervalID, this)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** @internal */
|
|
36
|
+
release(id: string): void {
|
|
37
|
+
if (typeof this.countsByID[id] === 'undefined') {
|
|
38
|
+
throw new Error(`Internal inconsistency, trying to release a keep-alive ID that hasn't been retained before or isn't tracked anymore: ${id}`)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.countsByID[id] -= 1
|
|
42
|
+
|
|
43
|
+
if (this.countsByID[id] === 0) {
|
|
44
|
+
delete this.countsByID[id]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (Object.keys(this.countsByID).length === 0) {
|
|
48
|
+
|
|
49
|
+
KeepAlive.finalizationRegistry.unregister(this)
|
|
50
|
+
clearInterval(this.intervalID)
|
|
51
|
+
this.intervalID = null
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** @internal */
|
|
56
|
+
currentIDs(): string[] {
|
|
57
|
+
return Object.keys(this.countsByID)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** @internal */
|
|
61
|
+
countForID(id: string): number | null {
|
|
62
|
+
return this.countsByID[id] ?? null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private static finalizationRegistry = new FinalizationRegistry(clearInterval)
|
|
66
|
+
|
|
67
|
+
private intervalID
|
|
68
|
+
private countsByID
|
|
69
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright © 2021 DittoLive Incorporated. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
const regularKeyPattern = /\.([A-Za-z_]\w*)/.source
|
|
6
|
+
const subscriptIndexPattern = /\[(\d+)\]/.source
|
|
7
|
+
const subscriptSingleQuoteKeyPattern = /\[\'(.+?)\'\]/.source
|
|
8
|
+
const subscriptDoubleQuoteKeyPattern = /\[\"(.+?)\"\]/.source
|
|
9
|
+
const validKeyPathPattern = `((${regularKeyPattern})|(${subscriptIndexPattern})|(${subscriptSingleQuoteKeyPattern})|(${subscriptDoubleQuoteKeyPattern}))*`
|
|
10
|
+
|
|
11
|
+
const regularKeyRegExp = new RegExp(`^${regularKeyPattern}`)
|
|
12
|
+
const subscriptIndexRegExp = new RegExp(`^${subscriptIndexPattern}`)
|
|
13
|
+
const subscriptSingleQuoteKeyRegExp = new RegExp(`^${subscriptSingleQuoteKeyPattern}`)
|
|
14
|
+
const subscriptDoubleQuoteKeyRegExp = new RegExp(`^${subscriptDoubleQuoteKeyPattern}`)
|
|
15
|
+
const validKeyPathRegExp = new RegExp(`^${validKeyPathPattern}$`)
|
|
16
|
+
|
|
17
|
+
export type KeyPathValidateOptions = {
|
|
18
|
+
isInitial?: boolean // default: false
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type KeyPathEvaluateOptions = {
|
|
22
|
+
stopAtLastContainer?: boolean // default: false
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type KeyPathEvaluationResult = {
|
|
26
|
+
keyPath: string | number
|
|
27
|
+
object: any
|
|
28
|
+
options: KeyPathEvaluateOptions
|
|
29
|
+
coveredPath: string | number
|
|
30
|
+
nextPathComponent: string | number | null
|
|
31
|
+
remainingPath: string | number
|
|
32
|
+
value: any
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Namespace for key-path related functions.
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
export class KeyPath {
|
|
40
|
+
/**
|
|
41
|
+
* Returns the key-path by prefixing it with a leading dot if first key
|
|
42
|
+
* starts with a character or an underscore.
|
|
43
|
+
*/
|
|
44
|
+
static withLeadingDot(keyPath: string | number): any /* string | number */ {
|
|
45
|
+
if (typeof keyPath === 'number') {
|
|
46
|
+
return keyPath
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (typeof keyPath !== 'string') {
|
|
50
|
+
throw new Error(`Key-path must be a string or a number but is ${typeof keyPath}: ${keyPath}`)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const needsLeadingDot = typeof keyPath === 'string' && !!keyPath.match(/^[A-Za-z_]/)
|
|
54
|
+
return needsLeadingDot ? `.${keyPath}` : keyPath
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns the key-path by removing the leading dot if it starts with one.
|
|
59
|
+
*/
|
|
60
|
+
static withoutLeadingDot(keyPath: string | number): any /* string | number */ {
|
|
61
|
+
if (typeof keyPath === 'number') {
|
|
62
|
+
return keyPath
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (typeof keyPath !== 'string') {
|
|
66
|
+
throw new Error(`Key-path must be a string or a number but is ${typeof keyPath}: ${keyPath}`)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const hasLeadingDot = typeof keyPath === 'string' && !!keyPath.match(/^\./)
|
|
70
|
+
return hasLeadingDot ? keyPath.slice(1) : keyPath
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Validates a key-path by adding a leading dot if appropriate and checking
|
|
75
|
+
* its syntax. Throws if syntax is invalid.
|
|
76
|
+
*/
|
|
77
|
+
static validate(keyPath: string | number, options: KeyPathValidateOptions = {}): any /* string | number */ {
|
|
78
|
+
const isInitial = options.isInitial ?? false
|
|
79
|
+
|
|
80
|
+
if (typeof keyPath === 'number') {
|
|
81
|
+
return Math.floor(Math.abs(keyPath))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (typeof keyPath !== 'string') {
|
|
85
|
+
throw new Error(`Key-path must be a string or a number but is ${typeof keyPath}: ${keyPath}`)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const keyPathWithLeadingDot = this.withLeadingDot(keyPath) as string
|
|
89
|
+
|
|
90
|
+
if (!validKeyPathRegExp.test(keyPathWithLeadingDot)) {
|
|
91
|
+
throw new Error(`Key-path is not valid: ${keyPath}`)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return isInitial ? keyPath : keyPathWithLeadingDot
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Follows the `keyPath`, boring down through `object` recursively until the
|
|
99
|
+
* final key-path is reached. Implemented as a free function to help ensure it's
|
|
100
|
+
* purely functional in nature and that no modifications are made to a
|
|
101
|
+
* `Document{ID}` or `DocumentPath` where similarly named variables are at play.
|
|
102
|
+
* @internal
|
|
103
|
+
*/
|
|
104
|
+
static evaluate(keyPath: string | number, object: any, options: KeyPathEvaluateOptions = {}): KeyPathEvaluationResult {
|
|
105
|
+
const stopAtLastContainer = options.stopAtLastContainer ?? false
|
|
106
|
+
|
|
107
|
+
const evaluationResult = {
|
|
108
|
+
keyPath: keyPath,
|
|
109
|
+
object: object,
|
|
110
|
+
options: { ...options },
|
|
111
|
+
coveredPath: null,
|
|
112
|
+
nextPathComponent: null,
|
|
113
|
+
remainingPath: keyPath,
|
|
114
|
+
value: object,
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function advance(keyPath: string | number): { nextPathComponentRaw: string | number; nextPathComponent: string | number; remainingPath: string } {
|
|
118
|
+
if (typeof keyPath === 'number') {
|
|
119
|
+
return { nextPathComponentRaw: keyPath, nextPathComponent: keyPath, remainingPath: '' }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (typeof keyPath !== 'string') {
|
|
123
|
+
throw new Error(`Can't return value at given keyPath, expected keyPath to be a string or a number but got ${typeof keyPath}: ${keyPath}`)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
const regularKeyMatch = keyPath.match(regularKeyRegExp)
|
|
129
|
+
if (regularKeyMatch !== null) {
|
|
130
|
+
const nextPathComponentRaw = regularKeyMatch[0]
|
|
131
|
+
const nextPathComponent = regularKeyMatch[1]
|
|
132
|
+
const remainingPath = keyPath.slice(nextPathComponent.length + /* stripped out . */ 1)
|
|
133
|
+
return { nextPathComponentRaw, nextPathComponent, remainingPath }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const subscriptIndexMatch = keyPath.match(subscriptIndexRegExp)
|
|
137
|
+
if (subscriptIndexMatch !== null) {
|
|
138
|
+
const nextPathComponentRaw = subscriptIndexMatch[0]
|
|
139
|
+
const nextPathComponentString = subscriptIndexMatch[1]
|
|
140
|
+
const nextPathComponent = parseInt(nextPathComponentString)
|
|
141
|
+
const remainingPath = keyPath.slice(nextPathComponentString.length + /* stripped out [] */ 2)
|
|
142
|
+
return { nextPathComponentRaw, nextPathComponent, remainingPath }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const subscriptSingleQuoteMatch = keyPath.match(subscriptSingleQuoteKeyRegExp)
|
|
146
|
+
if (subscriptSingleQuoteMatch !== null) {
|
|
147
|
+
const nextPathComponentRaw = subscriptSingleQuoteMatch[0]
|
|
148
|
+
const nextPathComponent = subscriptSingleQuoteMatch[1]
|
|
149
|
+
const remainingPath = keyPath.slice(nextPathComponent.length + /* stripped out [''] */ 4)
|
|
150
|
+
return { nextPathComponentRaw, nextPathComponent, remainingPath }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const subscriptDoubleQuoteMatch = keyPath.match(subscriptDoubleQuoteKeyRegExp)
|
|
154
|
+
if (subscriptDoubleQuoteMatch !== null) {
|
|
155
|
+
const nextPathComponentRaw = subscriptDoubleQuoteMatch[0]
|
|
156
|
+
const nextPathComponent = subscriptDoubleQuoteMatch[1]
|
|
157
|
+
const remainingPath = keyPath.slice(nextPathComponent.length + /* stripped out [""] */ 4)
|
|
158
|
+
return { nextPathComponentRaw, nextPathComponent, remainingPath }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
throw new Error(`Can't return value at keyPath because the following part of the keyPath is invalid: ${keyPath}`)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function recurse(object: any, keyPath: string | number): KeyPathEvaluationResult {
|
|
165
|
+
if (keyPath === '') {
|
|
166
|
+
evaluationResult.value = object
|
|
167
|
+
return evaluationResult
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const { nextPathComponentRaw, nextPathComponent, remainingPath } = advance(keyPath)
|
|
171
|
+
|
|
172
|
+
evaluationResult.nextPathComponent = nextPathComponent
|
|
173
|
+
evaluationResult.remainingPath = remainingPath
|
|
174
|
+
|
|
175
|
+
if (evaluationResult.coveredPath === null || typeof nextPathComponentRaw === 'number') {
|
|
176
|
+
evaluationResult.coveredPath = nextPathComponentRaw
|
|
177
|
+
} else {
|
|
178
|
+
evaluationResult.coveredPath += nextPathComponentRaw
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (remainingPath === '' && stopAtLastContainer) {
|
|
182
|
+
evaluationResult.value = object
|
|
183
|
+
return evaluationResult
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const nextObject = object[nextPathComponent]
|
|
187
|
+
return recurse(nextObject, remainingPath)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const keyPathWithLeadingDot = this.withLeadingDot(keyPath)
|
|
191
|
+
return recurse(object, keyPathWithLeadingDot)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private constructor() {}
|
|
195
|
+
}
|