@delali/narsil-react-native 0.0.0-stage → 0.3.1-next.146
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/LICENSE +201 -0
- package/NarsilReactNative.podspec +57 -0
- package/README.md +46 -2
- package/android/CMakeLists.txt +48 -0
- package/android/build.gradle +151 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/AndroidEnvironment.cpp +44 -0
- package/android/src/main/cpp/AndroidEnvironment.hpp +11 -0
- package/android/src/main/cpp/cpp-adapter.cpp +11 -0
- package/android/src/main/java/com/margelo/nitro/narsil/NarsilAndroidEnvironment.kt +29 -0
- package/android/src/main/java/com/margelo/nitro/narsil/NarsilReactNativePackage.kt +22 -0
- package/app.plugin.js +25 -0
- package/cpp/AttachedField.cpp +234 -0
- package/cpp/AttachedField.hpp +61 -0
- package/cpp/Compression.cpp +113 -0
- package/cpp/Compression.hpp +16 -0
- package/cpp/GraphHeldAlone.cpp +29 -0
- package/cpp/GraphHeldAlone.hpp +25 -0
- package/cpp/HostMemory.cpp +123 -0
- package/cpp/HostMemory.hpp +53 -0
- package/cpp/HybridNarsilCoreImpl.cpp +390 -0
- package/cpp/HybridNarsilCoreImpl.hpp +68 -0
- package/cpp/HybridNarsilFilesImpl.cpp +245 -0
- package/cpp/HybridNarsilFilesImpl.hpp +34 -0
- package/cpp/HybridNarsilHostImpl.cpp +126 -0
- package/cpp/HybridNarsilHostImpl.hpp +42 -0
- package/cpp/NativeAtomics.cpp +110 -0
- package/cpp/NativeAtomics.hpp +11 -0
- package/cpp/ProcessInfo.cpp +83 -0
- package/cpp/ProcessInfo.hpp +11 -0
- package/cpp/ThreadPriority.cpp +77 -0
- package/cpp/ThreadPriority.hpp +8 -0
- package/cpp/WorkletRuntimeDispatcher.cpp +61 -0
- package/cpp/WorkletRuntimeDispatcher.hpp +9 -0
- package/cpp/core/include/narsil_core.h +208 -0
- package/cpp/core/src/connect.c +213 -0
- package/cpp/core/src/distance.c +103 -0
- package/cpp/core/src/files.c +99 -0
- package/cpp/core/src/heap.c +84 -0
- package/cpp/core/src/internal.h +284 -0
- package/cpp/core/src/kernels_code.c +209 -0
- package/cpp/core/src/kernels_float.c +197 -0
- package/cpp/core/src/kernels_pair.c +133 -0
- package/cpp/core/src/last_links.c +145 -0
- package/cpp/core/src/links.c +195 -0
- package/cpp/core/src/locks.c +168 -0
- package/cpp/core/src/nearest_links.c +147 -0
- package/cpp/core/src/place.c +215 -0
- package/cpp/core/src/quantize.c +226 -0
- package/cpp/core/src/records.c +97 -0
- package/cpp/core/src/remove.c +205 -0
- package/cpp/core/src/vectors.c +139 -0
- package/cpp/core/src/walk.c +231 -0
- package/cpp/core/src/workspace.c +167 -0
- package/ios/PrivacyInfo.xcprivacy +23 -0
- package/lib/client.d.ts +19 -0
- package/lib/client.js +41 -0
- package/lib/constants.d.ts +9 -0
- package/lib/constants.js +9 -0
- package/lib/engine/byte-files.d.ts +5 -0
- package/lib/engine/byte-files.js +97 -0
- package/lib/engine/core.d.ts +3 -0
- package/lib/engine/core.js +113 -0
- package/lib/engine/files.d.ts +3 -0
- package/lib/engine/files.js +188 -0
- package/lib/engine/host.d.ts +13 -0
- package/lib/engine/host.js +102 -0
- package/lib/engine/install.d.ts +4 -0
- package/lib/engine/install.js +29 -0
- package/lib/engine/native-error.d.ts +1 -0
- package/lib/engine/native-error.js +12 -0
- package/lib/engine/stand-ins/atomics.d.ts +5 -0
- package/lib/engine/stand-ins/atomics.js +236 -0
- package/lib/engine/stand-ins/crypto.d.ts +2 -0
- package/lib/engine/stand-ins/crypto.js +65 -0
- package/lib/engine/stand-ins/process.d.ts +2 -0
- package/lib/engine/stand-ins/process.js +22 -0
- package/lib/engine/stand-ins/streams.d.ts +1 -0
- package/lib/engine/stand-ins/streams.js +31 -0
- package/lib/engine/stand-ins/structured-clone.d.ts +1 -0
- package/lib/engine/stand-ins/structured-clone.js +121 -0
- package/lib/engine/streamed.d.ts +6 -0
- package/lib/engine/streamed.js +29 -0
- package/lib/engine/transfer.d.ts +3 -0
- package/lib/engine/transfer.js +77 -0
- package/lib/errors.d.ts +25 -0
- package/lib/errors.js +59 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +2 -0
- package/lib/methods.d.ts +5 -0
- package/lib/methods.js +47 -0
- package/lib/native-objects.d.ts +2 -0
- package/lib/native-objects.js +24 -0
- package/lib/specs/core.nitro.d.ts +79 -0
- package/lib/specs/core.nitro.js +1 -0
- package/lib/specs/files.nitro.d.ts +36 -0
- package/lib/specs/files.nitro.js +1 -0
- package/lib/specs/host.nitro.d.ts +24 -0
- package/lib/specs/host.nitro.js +1 -0
- package/lib/transferred.d.ts +15 -0
- package/lib/transferred.js +6 -0
- package/lib/types.d.ts +136 -0
- package/lib/types.js +1 -0
- package/lib/worklets/app-turns.d.ts +1 -0
- package/lib/worklets/app-turns.js +44 -0
- package/lib/worklets/client.d.ts +30 -0
- package/lib/worklets/client.js +144 -0
- package/lib/worklets/index.d.ts +4 -0
- package/lib/worklets/index.js +2 -0
- package/lib/worklets/instances.d.ts +15 -0
- package/lib/worklets/instances.js +194 -0
- package/lib/worklets/json-part.d.ts +1 -0
- package/lib/worklets/json-part.js +42 -0
- package/lib/worklets/runtime.d.ts +25 -0
- package/lib/worklets/runtime.js +80 -0
- package/lib/worklets/transfer-queue.d.ts +7 -0
- package/lib/worklets/transfer-queue.js +79 -0
- package/lib/worklets/types.d.ts +26 -0
- package/lib/worklets/types.js +1 -0
- package/nitro.json +32 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/NarsilReactNative+autolinking.cmake +85 -0
- package/nitrogen/generated/android/NarsilReactNative+autolinking.gradle +27 -0
- package/nitrogen/generated/android/NarsilReactNativeOnLoad.cpp +69 -0
- package/nitrogen/generated/android/NarsilReactNativeOnLoad.hpp +34 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/narsil/NarsilReactNativeOnLoad.kt +35 -0
- package/nitrogen/generated/ios/NarsilReactNative+autolinking.rb +62 -0
- package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Bridge.cpp +17 -0
- package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Bridge.hpp +27 -0
- package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Umbrella.hpp +38 -0
- package/nitrogen/generated/ios/NarsilReactNativeAutolinking.mm +55 -0
- package/nitrogen/generated/ios/NarsilReactNativeAutolinking.swift +16 -0
- package/nitrogen/generated/shared/c++/DirectoryEntry.hpp +91 -0
- package/nitrogen/generated/shared/c++/FileStatus.hpp +103 -0
- package/nitrogen/generated/shared/c++/GraphMemory.hpp +120 -0
- package/nitrogen/generated/shared/c++/HybridNarsilAttachedGraphSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridNarsilAttachedGraphSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/HybridNarsilAttachedStoreSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridNarsilAttachedStoreSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.cpp +35 -0
- package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.hpp +100 -0
- package/nitrogen/generated/shared/c++/HybridNarsilFilesSpec.cpp +37 -0
- package/nitrogen/generated/shared/c++/HybridNarsilFilesSpec.hpp +86 -0
- package/nitrogen/generated/shared/c++/HybridNarsilHostSpec.cpp +34 -0
- package/nitrogen/generated/shared/c++/HybridNarsilHostSpec.hpp +78 -0
- package/nitrogen/generated/shared/c++/MemoryView.hpp +91 -0
- package/nitrogen/generated/shared/c++/NativeConnectOutcome.hpp +87 -0
- package/nitrogen/generated/shared/c++/NativeScores.hpp +87 -0
- package/nitrogen/generated/shared/c++/NativeSearchHits.hpp +91 -0
- package/nitrogen/generated/shared/c++/ProcessMemory.hpp +87 -0
- package/nitrogen/generated/shared/c++/StoreMemory.hpp +142 -0
- package/package.json +87 -3
- package/react-native.config.js +8 -0
- package/src/client.ts +44 -0
- package/src/constants.ts +9 -0
- package/src/engine/byte-files.ts +99 -0
- package/src/engine/core.ts +162 -0
- package/src/engine/files.ts +186 -0
- package/src/engine/host.ts +111 -0
- package/src/engine/install.ts +31 -0
- package/src/engine/native-error.ts +10 -0
- package/src/engine/stand-ins/atomics.ts +288 -0
- package/src/engine/stand-ins/crypto.ts +81 -0
- package/src/engine/stand-ins/process.ts +30 -0
- package/src/engine/stand-ins/streams.ts +45 -0
- package/src/engine/stand-ins/structured-clone.ts +118 -0
- package/src/engine/streamed.ts +40 -0
- package/src/engine/transfer.ts +72 -0
- package/src/errors.ts +73 -0
- package/src/index.ts +3 -0
- package/src/methods.ts +52 -0
- package/src/native-objects.ts +30 -0
- package/src/specs/core.nitro.ts +140 -0
- package/src/specs/files.nitro.ts +42 -0
- package/src/specs/host.nitro.ts +30 -0
- package/src/transferred.ts +18 -0
- package/src/types.ts +164 -0
- package/src/worklets/app-turns.ts +48 -0
- package/src/worklets/client.ts +165 -0
- package/src/worklets/index.ts +4 -0
- package/src/worklets/instances.ts +231 -0
- package/src/worklets/json-part.ts +38 -0
- package/src/worklets/runtime.ts +190 -0
- package/src/worklets/transfer-queue.ts +98 -0
- package/src/worklets/types.ts +37 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
type TypedArrayConstructor = new (buffer: ArrayBuffer, byteOffset: number, length: number) => ArrayBufferView
|
|
2
|
+
|
|
3
|
+
const ERROR_CONSTRUCTORS: Record<string, ErrorConstructor> = {
|
|
4
|
+
Error,
|
|
5
|
+
EvalError,
|
|
6
|
+
RangeError,
|
|
7
|
+
ReferenceError,
|
|
8
|
+
SyntaxError,
|
|
9
|
+
TypeError,
|
|
10
|
+
URIError,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function dataCloneError(message: string): Error {
|
|
14
|
+
const DomException = (globalThis as { DOMException?: new (message: string, name: string) => Error }).DOMException
|
|
15
|
+
if (DomException !== undefined) return new DomException(message, 'DataCloneError')
|
|
16
|
+
const error = new Error(message)
|
|
17
|
+
error.name = 'DataCloneError'
|
|
18
|
+
return error
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function typedArrayConstructorOf(view: ArrayBufferView): TypedArrayConstructor | null {
|
|
22
|
+
const viewType = (view as { constructor?: unknown }).constructor
|
|
23
|
+
if (typeof viewType !== 'function') return null
|
|
24
|
+
const scope = globalThis as Record<string, unknown>
|
|
25
|
+
const name = (viewType as { name?: unknown }).name
|
|
26
|
+
if (typeof name !== 'string' || scope[name] !== viewType) return null
|
|
27
|
+
return viewType as TypedArrayConstructor
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function cloneValue(value: unknown, memory: Map<object, unknown>): unknown {
|
|
31
|
+
if (typeof value === 'symbol') throw dataCloneError('A symbol cannot be cloned')
|
|
32
|
+
if (typeof value === 'function') throw dataCloneError('A function cannot be cloned')
|
|
33
|
+
if (value === null || typeof value !== 'object') return value
|
|
34
|
+
|
|
35
|
+
const remembered = memory.get(value)
|
|
36
|
+
if (remembered !== undefined || memory.has(value)) return remembered
|
|
37
|
+
|
|
38
|
+
if (value instanceof Date) {
|
|
39
|
+
const copy = new Date(value.getTime())
|
|
40
|
+
memory.set(value, copy)
|
|
41
|
+
return copy
|
|
42
|
+
}
|
|
43
|
+
if (value instanceof RegExp) {
|
|
44
|
+
const copy = new RegExp(value.source, value.flags)
|
|
45
|
+
memory.set(value, copy)
|
|
46
|
+
return copy
|
|
47
|
+
}
|
|
48
|
+
if (value instanceof Boolean || value instanceof Number || value instanceof String) {
|
|
49
|
+
const copy = Object(value.valueOf())
|
|
50
|
+
memory.set(value, copy)
|
|
51
|
+
return copy
|
|
52
|
+
}
|
|
53
|
+
if (typeof BigInt !== 'undefined' && Object.prototype.toString.call(value) === '[object BigInt]') {
|
|
54
|
+
const copy = Object((value as { valueOf(): bigint }).valueOf())
|
|
55
|
+
memory.set(value, copy)
|
|
56
|
+
return copy
|
|
57
|
+
}
|
|
58
|
+
if (value instanceof ArrayBuffer) {
|
|
59
|
+
const copy = value.slice(0, value.byteLength)
|
|
60
|
+
memory.set(value, copy)
|
|
61
|
+
return copy
|
|
62
|
+
}
|
|
63
|
+
if (ArrayBuffer.isView(value)) {
|
|
64
|
+
const buffer = cloneValue(value.buffer, memory) as ArrayBuffer
|
|
65
|
+
if (value instanceof DataView) {
|
|
66
|
+
const copy = new DataView(buffer, value.byteOffset, value.byteLength)
|
|
67
|
+
memory.set(value, copy)
|
|
68
|
+
return copy
|
|
69
|
+
}
|
|
70
|
+
const ViewType = typedArrayConstructorOf(value)
|
|
71
|
+
if (ViewType === null) throw dataCloneError('This kind of array buffer view cannot be cloned')
|
|
72
|
+
const length = (value as unknown as { length: number }).length
|
|
73
|
+
const copy = new ViewType(buffer, value.byteOffset, length)
|
|
74
|
+
memory.set(value, copy)
|
|
75
|
+
return copy
|
|
76
|
+
}
|
|
77
|
+
if (value instanceof Map) {
|
|
78
|
+
const copy = new Map<unknown, unknown>()
|
|
79
|
+
memory.set(value, copy)
|
|
80
|
+
for (const [key, entry] of value) copy.set(cloneValue(key, memory), cloneValue(entry, memory))
|
|
81
|
+
return copy
|
|
82
|
+
}
|
|
83
|
+
if (value instanceof Set) {
|
|
84
|
+
const copy = new Set<unknown>()
|
|
85
|
+
memory.set(value, copy)
|
|
86
|
+
for (const entry of value) copy.add(cloneValue(entry, memory))
|
|
87
|
+
return copy
|
|
88
|
+
}
|
|
89
|
+
if (value instanceof Error) {
|
|
90
|
+
const ErrorType = ERROR_CONSTRUCTORS[value.name] ?? Error
|
|
91
|
+
const copy = new ErrorType(value.message)
|
|
92
|
+
memory.set(value, copy)
|
|
93
|
+
if (typeof value.stack === 'string') copy.stack = value.stack
|
|
94
|
+
if ('cause' in value) (copy as { cause?: unknown }).cause = cloneValue(value.cause, memory)
|
|
95
|
+
return copy
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const copy = (Array.isArray(value) ? new Array<unknown>(value.length) : {}) as Record<string, unknown>
|
|
99
|
+
memory.set(value, copy)
|
|
100
|
+
for (const key of Object.keys(value)) {
|
|
101
|
+
copy[key] = cloneValue((value as Record<string, unknown>)[key], memory)
|
|
102
|
+
}
|
|
103
|
+
return copy
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function structuredCloneStandIn<T>(value: T): T {
|
|
107
|
+
return cloneValue(value, new Map()) as T
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function installStructuredClone(): void {
|
|
111
|
+
if (typeof (globalThis as { structuredClone?: unknown }).structuredClone === 'function') return
|
|
112
|
+
Object.defineProperty(globalThis, 'structuredClone', {
|
|
113
|
+
value: structuredCloneStandIn,
|
|
114
|
+
writable: true,
|
|
115
|
+
configurable: true,
|
|
116
|
+
enumerable: false,
|
|
117
|
+
})
|
|
118
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { DurabilityConfig, Narsil, NarsilConfig, ReactNativeHost } from '@delali/narsil'
|
|
2
|
+
import { DEFAULT_DURABILITY_DIRECTORY } from '../constants'
|
|
3
|
+
import type { StreamedMethod } from '../methods'
|
|
4
|
+
import { collectStream, fileChunks, resolveAppPath, writeStreamToFile } from './byte-files'
|
|
5
|
+
|
|
6
|
+
export function withPhoneDurability<T extends { durability?: DurabilityConfig | null }>(
|
|
7
|
+
config: T,
|
|
8
|
+
durabilitySetElsewhere = false,
|
|
9
|
+
): Omit<T, 'durability'> & Pick<NarsilConfig, 'durability'> {
|
|
10
|
+
const { durability, ...rest } = config
|
|
11
|
+
if (durability === null || durabilitySetElsewhere) return rest
|
|
12
|
+
return { ...rest, durability: { directory: DEFAULT_DURABILITY_DIRECTORY, ...durability } }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function callStreamed(
|
|
16
|
+
narsil: Narsil,
|
|
17
|
+
host: ReactNativeHost,
|
|
18
|
+
method: StreamedMethod,
|
|
19
|
+
args: readonly unknown[],
|
|
20
|
+
): Promise<unknown> {
|
|
21
|
+
const indexName = args[0] as string
|
|
22
|
+
switch (method) {
|
|
23
|
+
case 'snapshot':
|
|
24
|
+
return narsil.snapshot(indexName).then(collectStream)
|
|
25
|
+
case 'exportDocuments':
|
|
26
|
+
return narsil.exportDocuments(indexName).then(collectStream)
|
|
27
|
+
case 'snapshotToFile':
|
|
28
|
+
return narsil
|
|
29
|
+
.snapshot(indexName)
|
|
30
|
+
.then(stream => writeStreamToFile(host.files, stream, resolveAppPath(host, args[1] as string)))
|
|
31
|
+
case 'exportDocumentsToFile':
|
|
32
|
+
return narsil
|
|
33
|
+
.exportDocuments(indexName)
|
|
34
|
+
.then(stream => writeStreamToFile(host.files, stream, resolveAppPath(host, args[1] as string)))
|
|
35
|
+
case 'restoreFromFile':
|
|
36
|
+
return narsil.restore(indexName, fileChunks(host.files, resolveAppPath(host, args[1] as string)))
|
|
37
|
+
case 'importDocumentExportFromFile':
|
|
38
|
+
return narsil.importDocumentExport(indexName, fileChunks(host.files, resolveAppPath(host, args[1] as string)))
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { TransferredError } from '../transferred'
|
|
2
|
+
|
|
3
|
+
function isPlainObject(value: object): boolean {
|
|
4
|
+
const prototype = Object.getPrototypeOf(value)
|
|
5
|
+
return prototype === Object.prototype || prototype === null
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function viewCopy(view: ArrayBufferView): ArrayBufferView {
|
|
9
|
+
if (view.byteOffset === 0 && view.byteLength === view.buffer.byteLength) return view
|
|
10
|
+
const copy = new Uint8Array(view.byteLength)
|
|
11
|
+
copy.set(new Uint8Array(view.buffer, view.byteOffset, view.byteLength))
|
|
12
|
+
if (view instanceof DataView) return new DataView(copy.buffer)
|
|
13
|
+
const Constructor = view.constructor as new (buffer: ArrayBuffer) => ArrayBufferView
|
|
14
|
+
return new Constructor(copy.buffer)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function transferredError(error: unknown, seen = new Map<object, unknown>()): TransferredError {
|
|
18
|
+
if (!(error instanceof Error)) {
|
|
19
|
+
return { transferredError: true, name: 'Error', message: String(error), code: undefined, details: undefined }
|
|
20
|
+
}
|
|
21
|
+
const coded = error as Error & { code?: unknown; details?: unknown }
|
|
22
|
+
return {
|
|
23
|
+
transferredError: true,
|
|
24
|
+
name: error.name,
|
|
25
|
+
message: error.message,
|
|
26
|
+
code: typeof coded.code === 'string' ? coded.code : undefined,
|
|
27
|
+
details: coded.details === undefined ? undefined : transferable(coded.details, seen),
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function transferable(value: unknown, seen = new Map<object, unknown>()): unknown {
|
|
32
|
+
if (value === null || typeof value !== 'object') return typeof value === 'function' ? undefined : value
|
|
33
|
+
const known = seen.get(value)
|
|
34
|
+
if (known !== undefined) return known
|
|
35
|
+
if (ArrayBuffer.isView(value)) {
|
|
36
|
+
const copy = viewCopy(value)
|
|
37
|
+
seen.set(value, copy)
|
|
38
|
+
return copy
|
|
39
|
+
}
|
|
40
|
+
if (value instanceof Error) {
|
|
41
|
+
const copy = transferredError(value, seen)
|
|
42
|
+
seen.set(value, copy)
|
|
43
|
+
return copy
|
|
44
|
+
}
|
|
45
|
+
if (Array.isArray(value)) {
|
|
46
|
+
const copy: unknown[] = new Array(value.length)
|
|
47
|
+
seen.set(value, copy)
|
|
48
|
+
for (let index = 0; index < value.length; index++) copy[index] = transferable(value[index], seen)
|
|
49
|
+
return copy
|
|
50
|
+
}
|
|
51
|
+
if (value instanceof Map) {
|
|
52
|
+
const copy = new Map<unknown, unknown>()
|
|
53
|
+
seen.set(value, copy)
|
|
54
|
+
for (const [key, entry] of value) copy.set(transferable(key, seen), transferable(entry, seen))
|
|
55
|
+
return copy
|
|
56
|
+
}
|
|
57
|
+
if (value instanceof Set) {
|
|
58
|
+
const copy = new Set<unknown>()
|
|
59
|
+
seen.set(value, copy)
|
|
60
|
+
for (const entry of value) copy.add(transferable(entry, seen))
|
|
61
|
+
return copy
|
|
62
|
+
}
|
|
63
|
+
if (value instanceof Date || value instanceof RegExp || value instanceof ArrayBuffer) return value
|
|
64
|
+
if (!isPlainObject(value)) return value
|
|
65
|
+
const copy: Record<string, unknown> = {}
|
|
66
|
+
seen.set(value, copy)
|
|
67
|
+
for (const key of Object.keys(value)) {
|
|
68
|
+
const entry = transferable((value as Record<string, unknown>)[key], seen)
|
|
69
|
+
if (entry !== undefined) copy[key] = entry
|
|
70
|
+
}
|
|
71
|
+
return copy
|
|
72
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { isTransferredError, type TransferredError } from './transferred'
|
|
2
|
+
|
|
3
|
+
const NARSIL_ERROR_MARKER = Symbol.for('@delali/narsil.NarsilError')
|
|
4
|
+
const NARSIL_ERROR_NAME = 'NarsilError'
|
|
5
|
+
const NATIVE_DEPENDENCY_MISSING = 'NATIVE_DEPENDENCY_MISSING'
|
|
6
|
+
|
|
7
|
+
const NATIVE_DEPENDENCY_MISSING_MESSAGE =
|
|
8
|
+
'This app build does not include the Narsil native module, as happens in Expo Go and on 32-bit Android. Install `@delali/narsil-react-native` and `react-native-nitro-modules`, then make a development build with `npx expo run:ios` or `npx expo run:android`, or, in an app without Expo, run `pod install` in the `ios` folder and rebuild the app for each platform.'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* An error that the engine raised, as it reaches the app's JS thread. `code`
|
|
12
|
+
* holds the engine's error code, such as `INDEX_NOT_FOUND`, and `details`
|
|
13
|
+
* holds the values behind the failure.
|
|
14
|
+
*
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export interface PhoneNarsilError extends Error {
|
|
18
|
+
readonly code: string
|
|
19
|
+
readonly details: Record<string, unknown>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Reports whether a value is an error that the Narsil engine raised, whether
|
|
24
|
+
* it reached the app from the engine's runtime or from this package.
|
|
25
|
+
*
|
|
26
|
+
* @param value - Anything that a rejected promise or a `catch` block holds.
|
|
27
|
+
* @returns True when the value carries a Narsil error code.
|
|
28
|
+
*
|
|
29
|
+
* @public
|
|
30
|
+
*/
|
|
31
|
+
export function isNarsilError(value: unknown): value is PhoneNarsilError {
|
|
32
|
+
return typeof value === 'object' && value !== null && NARSIL_ERROR_MARKER in value
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function narsilError(message: string, code: string, details: Record<string, unknown>): PhoneNarsilError {
|
|
36
|
+
const error = new Error(message)
|
|
37
|
+
error.name = NARSIL_ERROR_NAME
|
|
38
|
+
Object.defineProperty(error, 'code', { value: code, enumerable: true })
|
|
39
|
+
Object.defineProperty(error, 'details', { value: details, enumerable: true })
|
|
40
|
+
Object.defineProperty(error, NARSIL_ERROR_MARKER, { value: true })
|
|
41
|
+
return error as PhoneNarsilError
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function nativeDependencyMissing(cause: unknown): PhoneNarsilError {
|
|
45
|
+
return narsilError(NATIVE_DEPENDENCY_MISSING_MESSAGE, NATIVE_DEPENDENCY_MISSING, {
|
|
46
|
+
cause: cause instanceof Error ? cause.message : String(cause),
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function rebuiltError(transferred: TransferredError): Error {
|
|
51
|
+
const details = rebuiltValue(transferred.details)
|
|
52
|
+
if (transferred.name === NARSIL_ERROR_NAME && transferred.code !== undefined) {
|
|
53
|
+
const record = typeof details === 'object' && details !== null ? (details as Record<string, unknown>) : {}
|
|
54
|
+
return narsilError(transferred.message, transferred.code, record)
|
|
55
|
+
}
|
|
56
|
+
const error = new Error(transferred.message)
|
|
57
|
+
error.name = transferred.name
|
|
58
|
+
if (transferred.code !== undefined)
|
|
59
|
+
Object.defineProperty(error, 'code', { value: transferred.code, enumerable: true })
|
|
60
|
+
if (details !== undefined) Object.defineProperty(error, 'details', { value: details, enumerable: true })
|
|
61
|
+
return error
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function rebuiltValue(value: unknown): unknown {
|
|
65
|
+
if (value === null || typeof value !== 'object') return value
|
|
66
|
+
if (isTransferredError(value)) return rebuiltError(value)
|
|
67
|
+
const prototype = Object.getPrototypeOf(value)
|
|
68
|
+
if (!Array.isArray(value) && prototype !== Object.prototype && prototype !== null) return value
|
|
69
|
+
if (Array.isArray(value)) return value.map(rebuiltValue)
|
|
70
|
+
const record: Record<string, unknown> = {}
|
|
71
|
+
for (const key of Object.keys(value)) record[key] = rebuiltValue((value as Record<string, unknown>)[key])
|
|
72
|
+
return record
|
|
73
|
+
}
|
package/src/index.ts
ADDED
package/src/methods.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export const FORWARDED_METHODS = [
|
|
2
|
+
'createIndex',
|
|
3
|
+
'dropIndex',
|
|
4
|
+
'listIndexes',
|
|
5
|
+
'getStats',
|
|
6
|
+
'getPartitionStats',
|
|
7
|
+
'get',
|
|
8
|
+
'getMultiple',
|
|
9
|
+
'has',
|
|
10
|
+
'countDocuments',
|
|
11
|
+
'listDocuments',
|
|
12
|
+
'query',
|
|
13
|
+
'preflight',
|
|
14
|
+
'suggest',
|
|
15
|
+
'rebuildAnalysis',
|
|
16
|
+
'restore',
|
|
17
|
+
'importDocumentExport',
|
|
18
|
+
'checkpoint',
|
|
19
|
+
'clear',
|
|
20
|
+
'rebalance',
|
|
21
|
+
'updatePartitionConfig',
|
|
22
|
+
'getMemoryStats',
|
|
23
|
+
'compactVectors',
|
|
24
|
+
'optimizeVectors',
|
|
25
|
+
'vectorMaintenanceStatus',
|
|
26
|
+
'open',
|
|
27
|
+
'close',
|
|
28
|
+
'insert',
|
|
29
|
+
'insertBatch',
|
|
30
|
+
'remove',
|
|
31
|
+
'removeBatch',
|
|
32
|
+
'update',
|
|
33
|
+
'updateBatch',
|
|
34
|
+
'waitForWrites',
|
|
35
|
+
'updateSynonyms',
|
|
36
|
+
'getSynonyms',
|
|
37
|
+
'changeAnalysis',
|
|
38
|
+
'updateBM25',
|
|
39
|
+
] as const
|
|
40
|
+
|
|
41
|
+
export const STREAMED_METHODS = [
|
|
42
|
+
'snapshot',
|
|
43
|
+
'exportDocuments',
|
|
44
|
+
'snapshotToFile',
|
|
45
|
+
'exportDocumentsToFile',
|
|
46
|
+
'restoreFromFile',
|
|
47
|
+
'importDocumentExportFromFile',
|
|
48
|
+
] as const
|
|
49
|
+
|
|
50
|
+
export type ForwardedMethod = (typeof FORWARDED_METHODS)[number]
|
|
51
|
+
export type StreamedMethod = (typeof STREAMED_METHODS)[number]
|
|
52
|
+
export type EngineMethod = ForwardedMethod | StreamedMethod | 'shutdown'
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { NativeObjects } from './engine/host'
|
|
2
|
+
import { nativeDependencyMissing } from './errors'
|
|
3
|
+
import type { NarsilCore } from './specs/core.nitro'
|
|
4
|
+
import type { NarsilFiles } from './specs/files.nitro'
|
|
5
|
+
import type { NarsilHost } from './specs/host.nitro'
|
|
6
|
+
|
|
7
|
+
let loading: Promise<NativeObjects> | null = null
|
|
8
|
+
|
|
9
|
+
async function createNativeObjects(): Promise<NativeObjects> {
|
|
10
|
+
try {
|
|
11
|
+
const { NitroModules } = await import('react-native-nitro-modules')
|
|
12
|
+
return {
|
|
13
|
+
host: NitroModules.createHybridObject<NarsilHost>('NarsilHost'),
|
|
14
|
+
files: NitroModules.createHybridObject<NarsilFiles>('NarsilFiles'),
|
|
15
|
+
core: NitroModules.createHybridObject<NarsilCore>('NarsilCore'),
|
|
16
|
+
}
|
|
17
|
+
} catch (error) {
|
|
18
|
+
throw nativeDependencyMissing(error)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function loadNativeObjects(): Promise<NativeObjects> {
|
|
23
|
+
if (loading === null) {
|
|
24
|
+
loading = createNativeObjects()
|
|
25
|
+
loading.catch(() => {
|
|
26
|
+
loading = null
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
return loading
|
|
30
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type { HybridObject } from 'react-native-nitro-modules'
|
|
2
|
+
|
|
3
|
+
export interface MemoryView {
|
|
4
|
+
buffer: ArrayBuffer
|
|
5
|
+
byteOffset: number
|
|
6
|
+
byteLength: number
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface GraphMemory {
|
|
10
|
+
graphHeader: MemoryView
|
|
11
|
+
nodeLevels: MemoryView
|
|
12
|
+
level0: MemoryView
|
|
13
|
+
upperBase: MemoryView
|
|
14
|
+
upper: MemoryView
|
|
15
|
+
locks: MemoryView
|
|
16
|
+
tombstones: MemoryView
|
|
17
|
+
incoming: MemoryView
|
|
18
|
+
nearestLinkDue: MemoryView
|
|
19
|
+
heldLocks: MemoryView
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface StoreMemory {
|
|
23
|
+
storeHeader: MemoryView
|
|
24
|
+
dimension: number
|
|
25
|
+
bits: number
|
|
26
|
+
recordsPerBlock: number
|
|
27
|
+
vectorsPerBlock: number
|
|
28
|
+
vectorStrideBytes: number
|
|
29
|
+
codePresent: MemoryView
|
|
30
|
+
centroid: MemoryView
|
|
31
|
+
magnitudes: MemoryView
|
|
32
|
+
present: MemoryView
|
|
33
|
+
vectorFile: MemoryView
|
|
34
|
+
vectorOffset: MemoryView
|
|
35
|
+
vectorFiles: string[]
|
|
36
|
+
codeBlocks: MemoryView[]
|
|
37
|
+
vectorBlocks: MemoryView[]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface NativeSearchHits {
|
|
41
|
+
count: number
|
|
42
|
+
ordinals: ArrayBuffer
|
|
43
|
+
distances: ArrayBuffer
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface NativeScores {
|
|
47
|
+
status: number
|
|
48
|
+
distances: ArrayBuffer
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface NativeConnectOutcome {
|
|
52
|
+
status: number
|
|
53
|
+
wakes: ArrayBuffer
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface NarsilAttachedGraph extends HybridObject<{ ios: 'c++'; android: 'c++' }> {}
|
|
57
|
+
|
|
58
|
+
export interface NarsilAttachedStore extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
59
|
+
detach(): number
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface NarsilCore extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
63
|
+
abiVersion(): number
|
|
64
|
+
workspaceBytes(): number
|
|
65
|
+
attachGraph(memory: GraphMemory): NarsilAttachedGraph
|
|
66
|
+
attachStore(memory: StoreMemory): NarsilAttachedStore
|
|
67
|
+
search(
|
|
68
|
+
graph: NarsilAttachedGraph,
|
|
69
|
+
store: NarsilAttachedStore,
|
|
70
|
+
query: MemoryView,
|
|
71
|
+
metric: number,
|
|
72
|
+
candidateCount: number,
|
|
73
|
+
threadSlot: number,
|
|
74
|
+
ordinals: MemoryView,
|
|
75
|
+
distances: MemoryView,
|
|
76
|
+
accepted: MemoryView,
|
|
77
|
+
filtered: boolean,
|
|
78
|
+
): number
|
|
79
|
+
searchAsync(
|
|
80
|
+
graph: NarsilAttachedGraph,
|
|
81
|
+
store: NarsilAttachedStore,
|
|
82
|
+
query: MemoryView,
|
|
83
|
+
metric: number,
|
|
84
|
+
candidateCount: number,
|
|
85
|
+
threadSlot: number,
|
|
86
|
+
accepted: MemoryView,
|
|
87
|
+
filtered: boolean,
|
|
88
|
+
): Promise<NativeSearchHits>
|
|
89
|
+
scoreAsync(
|
|
90
|
+
store: NarsilAttachedStore,
|
|
91
|
+
query: MemoryView,
|
|
92
|
+
metric: number,
|
|
93
|
+
ordinals: MemoryView,
|
|
94
|
+
count: number,
|
|
95
|
+
threadSlot: number,
|
|
96
|
+
): Promise<NativeScores>
|
|
97
|
+
score(
|
|
98
|
+
store: NarsilAttachedStore,
|
|
99
|
+
query: MemoryView,
|
|
100
|
+
metric: number,
|
|
101
|
+
ordinals: MemoryView,
|
|
102
|
+
count: number,
|
|
103
|
+
distances: MemoryView,
|
|
104
|
+
): number
|
|
105
|
+
place(
|
|
106
|
+
graph: NarsilAttachedGraph,
|
|
107
|
+
store: NarsilAttachedStore,
|
|
108
|
+
metric: number,
|
|
109
|
+
ordinal: number,
|
|
110
|
+
topLayer: number,
|
|
111
|
+
graphHeldAlone: number,
|
|
112
|
+
threadSlot: number,
|
|
113
|
+
wakes: MemoryView,
|
|
114
|
+
): number
|
|
115
|
+
remove(graph: NarsilAttachedGraph, ordinal: number, threadSlot: number, wakes: MemoryView): number
|
|
116
|
+
compact(
|
|
117
|
+
graph: NarsilAttachedGraph,
|
|
118
|
+
store: NarsilAttachedStore,
|
|
119
|
+
metric: number,
|
|
120
|
+
threadSlot: number,
|
|
121
|
+
wakes: MemoryView,
|
|
122
|
+
): number
|
|
123
|
+
connectUnreached(
|
|
124
|
+
graph: NarsilAttachedGraph,
|
|
125
|
+
store: NarsilAttachedStore,
|
|
126
|
+
metric: number,
|
|
127
|
+
nearby: MemoryView,
|
|
128
|
+
threadSlot: number,
|
|
129
|
+
wakes: MemoryView,
|
|
130
|
+
): number
|
|
131
|
+
connectUnreachedAsync(
|
|
132
|
+
graph: NarsilAttachedGraph,
|
|
133
|
+
store: NarsilAttachedStore,
|
|
134
|
+
metric: number,
|
|
135
|
+
nearby: MemoryView,
|
|
136
|
+
threadSlot: number,
|
|
137
|
+
): Promise<NativeConnectOutcome>
|
|
138
|
+
measure(store: NarsilAttachedStore, metric: number, ordinals: MemoryView, count: number, totals: MemoryView): number
|
|
139
|
+
quantise(store: NarsilAttachedStore, metric: number, ordinals: MemoryView, count: number): number
|
|
140
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { HybridObject } from 'react-native-nitro-modules'
|
|
2
|
+
|
|
3
|
+
export interface FileStatus {
|
|
4
|
+
size: number
|
|
5
|
+
isDirectory: boolean
|
|
6
|
+
isFile: boolean
|
|
7
|
+
device: string
|
|
8
|
+
inode: string
|
|
9
|
+
modifiedMs: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface DirectoryEntry {
|
|
13
|
+
name: string
|
|
14
|
+
isDirectory: boolean
|
|
15
|
+
isFile: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface NarsilFiles extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
19
|
+
open(path: string, flags: string): number
|
|
20
|
+
close(descriptor: number): void
|
|
21
|
+
read(descriptor: number, target: ArrayBuffer, byteOffset: number, byteLength: number, position: number): number
|
|
22
|
+
write(descriptor: number, source: ArrayBuffer, byteOffset: number, byteLength: number, position: number): number
|
|
23
|
+
sync(descriptor: number): void
|
|
24
|
+
readAsync(descriptor: number, byteLength: number, position: number): Promise<ArrayBuffer>
|
|
25
|
+
writeAsync(
|
|
26
|
+
descriptor: number,
|
|
27
|
+
source: ArrayBuffer,
|
|
28
|
+
byteOffset: number,
|
|
29
|
+
byteLength: number,
|
|
30
|
+
position: number,
|
|
31
|
+
): Promise<number>
|
|
32
|
+
syncAsync(descriptor: number): Promise<void>
|
|
33
|
+
truncate(descriptor: number, byteLength: number): void
|
|
34
|
+
descriptorStatus(descriptor: number): FileStatus
|
|
35
|
+
pathStatus(path: string): FileStatus
|
|
36
|
+
makeDirectory(path: string): void
|
|
37
|
+
readDirectory(path: string): DirectoryEntry[]
|
|
38
|
+
rename(from: string, to: string): void
|
|
39
|
+
unlink(path: string): void
|
|
40
|
+
removeDirectory(path: string): void
|
|
41
|
+
link(existingPath: string, newPath: string): void
|
|
42
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { HybridObject } from 'react-native-nitro-modules'
|
|
2
|
+
|
|
3
|
+
export interface ProcessMemory {
|
|
4
|
+
residentBytes: number
|
|
5
|
+
availableBytes: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface NarsilHost extends HybridObject<{ ios: 'c++'; android: 'c++' }> {
|
|
9
|
+
reserveMemory(bytes: number): ArrayBuffer
|
|
10
|
+
allocateMemory(bytes: number): ArrayBuffer
|
|
11
|
+
ownsMemory(buffer: ArrayBuffer): boolean
|
|
12
|
+
atomic(
|
|
13
|
+
operation: number,
|
|
14
|
+
elementKind: number,
|
|
15
|
+
buffer: ArrayBuffer,
|
|
16
|
+
byteIndex: number,
|
|
17
|
+
value: number,
|
|
18
|
+
replacement: number,
|
|
19
|
+
): number
|
|
20
|
+
fillRandom(target: ArrayBuffer, byteOffset: number, byteLength: number): void
|
|
21
|
+
processId(): number
|
|
22
|
+
processStartedAtMs(): number
|
|
23
|
+
processIsAlive(processId: number): boolean
|
|
24
|
+
processMemory(): ProcessMemory
|
|
25
|
+
appStorageDirectory(): string
|
|
26
|
+
deflateRaw(source: ArrayBuffer, byteOffset: number, byteLength: number): ArrayBuffer
|
|
27
|
+
inflateRaw(source: ArrayBuffer, byteOffset: number, byteLength: number, rawByteLength: number): ArrayBuffer
|
|
28
|
+
gzip(source: ArrayBuffer, byteOffset: number, byteLength: number): ArrayBuffer
|
|
29
|
+
gunzip(source: ArrayBuffer, byteOffset: number, byteLength: number, maxByteLength: number): ArrayBuffer
|
|
30
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface TransferredError {
|
|
2
|
+
transferredError: true
|
|
3
|
+
name: string
|
|
4
|
+
message: string
|
|
5
|
+
code: string | undefined
|
|
6
|
+
details: unknown
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type CallOutcome = { ok: true; value: unknown } | { ok: false; error: TransferredError }
|
|
10
|
+
|
|
11
|
+
export function isTransferredError(value: unknown): value is TransferredError {
|
|
12
|
+
return (
|
|
13
|
+
typeof value === 'object' &&
|
|
14
|
+
value !== null &&
|
|
15
|
+
(value as { transferredError?: unknown }).transferredError === true &&
|
|
16
|
+
typeof (value as { message?: unknown }).message === 'string'
|
|
17
|
+
)
|
|
18
|
+
}
|