@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.
Files changed (186) hide show
  1. package/LICENSE +201 -0
  2. package/NarsilReactNative.podspec +57 -0
  3. package/README.md +46 -2
  4. package/android/CMakeLists.txt +48 -0
  5. package/android/build.gradle +151 -0
  6. package/android/gradle.properties +5 -0
  7. package/android/src/main/AndroidManifest.xml +2 -0
  8. package/android/src/main/cpp/AndroidEnvironment.cpp +44 -0
  9. package/android/src/main/cpp/AndroidEnvironment.hpp +11 -0
  10. package/android/src/main/cpp/cpp-adapter.cpp +11 -0
  11. package/android/src/main/java/com/margelo/nitro/narsil/NarsilAndroidEnvironment.kt +29 -0
  12. package/android/src/main/java/com/margelo/nitro/narsil/NarsilReactNativePackage.kt +22 -0
  13. package/app.plugin.js +25 -0
  14. package/cpp/AttachedField.cpp +234 -0
  15. package/cpp/AttachedField.hpp +61 -0
  16. package/cpp/Compression.cpp +113 -0
  17. package/cpp/Compression.hpp +16 -0
  18. package/cpp/GraphHeldAlone.cpp +29 -0
  19. package/cpp/GraphHeldAlone.hpp +25 -0
  20. package/cpp/HostMemory.cpp +123 -0
  21. package/cpp/HostMemory.hpp +53 -0
  22. package/cpp/HybridNarsilCoreImpl.cpp +390 -0
  23. package/cpp/HybridNarsilCoreImpl.hpp +68 -0
  24. package/cpp/HybridNarsilFilesImpl.cpp +245 -0
  25. package/cpp/HybridNarsilFilesImpl.hpp +34 -0
  26. package/cpp/HybridNarsilHostImpl.cpp +126 -0
  27. package/cpp/HybridNarsilHostImpl.hpp +42 -0
  28. package/cpp/NativeAtomics.cpp +110 -0
  29. package/cpp/NativeAtomics.hpp +11 -0
  30. package/cpp/ProcessInfo.cpp +83 -0
  31. package/cpp/ProcessInfo.hpp +11 -0
  32. package/cpp/ThreadPriority.cpp +77 -0
  33. package/cpp/ThreadPriority.hpp +8 -0
  34. package/cpp/WorkletRuntimeDispatcher.cpp +61 -0
  35. package/cpp/WorkletRuntimeDispatcher.hpp +9 -0
  36. package/cpp/core/include/narsil_core.h +208 -0
  37. package/cpp/core/src/connect.c +213 -0
  38. package/cpp/core/src/distance.c +103 -0
  39. package/cpp/core/src/files.c +99 -0
  40. package/cpp/core/src/heap.c +84 -0
  41. package/cpp/core/src/internal.h +284 -0
  42. package/cpp/core/src/kernels_code.c +209 -0
  43. package/cpp/core/src/kernels_float.c +197 -0
  44. package/cpp/core/src/kernels_pair.c +133 -0
  45. package/cpp/core/src/last_links.c +145 -0
  46. package/cpp/core/src/links.c +195 -0
  47. package/cpp/core/src/locks.c +168 -0
  48. package/cpp/core/src/nearest_links.c +147 -0
  49. package/cpp/core/src/place.c +215 -0
  50. package/cpp/core/src/quantize.c +226 -0
  51. package/cpp/core/src/records.c +97 -0
  52. package/cpp/core/src/remove.c +205 -0
  53. package/cpp/core/src/vectors.c +139 -0
  54. package/cpp/core/src/walk.c +231 -0
  55. package/cpp/core/src/workspace.c +167 -0
  56. package/ios/PrivacyInfo.xcprivacy +23 -0
  57. package/lib/client.d.ts +19 -0
  58. package/lib/client.js +41 -0
  59. package/lib/constants.d.ts +9 -0
  60. package/lib/constants.js +9 -0
  61. package/lib/engine/byte-files.d.ts +5 -0
  62. package/lib/engine/byte-files.js +97 -0
  63. package/lib/engine/core.d.ts +3 -0
  64. package/lib/engine/core.js +113 -0
  65. package/lib/engine/files.d.ts +3 -0
  66. package/lib/engine/files.js +188 -0
  67. package/lib/engine/host.d.ts +13 -0
  68. package/lib/engine/host.js +102 -0
  69. package/lib/engine/install.d.ts +4 -0
  70. package/lib/engine/install.js +29 -0
  71. package/lib/engine/native-error.d.ts +1 -0
  72. package/lib/engine/native-error.js +12 -0
  73. package/lib/engine/stand-ins/atomics.d.ts +5 -0
  74. package/lib/engine/stand-ins/atomics.js +236 -0
  75. package/lib/engine/stand-ins/crypto.d.ts +2 -0
  76. package/lib/engine/stand-ins/crypto.js +65 -0
  77. package/lib/engine/stand-ins/process.d.ts +2 -0
  78. package/lib/engine/stand-ins/process.js +22 -0
  79. package/lib/engine/stand-ins/streams.d.ts +1 -0
  80. package/lib/engine/stand-ins/streams.js +31 -0
  81. package/lib/engine/stand-ins/structured-clone.d.ts +1 -0
  82. package/lib/engine/stand-ins/structured-clone.js +121 -0
  83. package/lib/engine/streamed.d.ts +6 -0
  84. package/lib/engine/streamed.js +29 -0
  85. package/lib/engine/transfer.d.ts +3 -0
  86. package/lib/engine/transfer.js +77 -0
  87. package/lib/errors.d.ts +25 -0
  88. package/lib/errors.js +59 -0
  89. package/lib/index.d.ts +3 -0
  90. package/lib/index.js +2 -0
  91. package/lib/methods.d.ts +5 -0
  92. package/lib/methods.js +47 -0
  93. package/lib/native-objects.d.ts +2 -0
  94. package/lib/native-objects.js +24 -0
  95. package/lib/specs/core.nitro.d.ts +79 -0
  96. package/lib/specs/core.nitro.js +1 -0
  97. package/lib/specs/files.nitro.d.ts +36 -0
  98. package/lib/specs/files.nitro.js +1 -0
  99. package/lib/specs/host.nitro.d.ts +24 -0
  100. package/lib/specs/host.nitro.js +1 -0
  101. package/lib/transferred.d.ts +15 -0
  102. package/lib/transferred.js +6 -0
  103. package/lib/types.d.ts +136 -0
  104. package/lib/types.js +1 -0
  105. package/lib/worklets/app-turns.d.ts +1 -0
  106. package/lib/worklets/app-turns.js +44 -0
  107. package/lib/worklets/client.d.ts +30 -0
  108. package/lib/worklets/client.js +144 -0
  109. package/lib/worklets/index.d.ts +4 -0
  110. package/lib/worklets/index.js +2 -0
  111. package/lib/worklets/instances.d.ts +15 -0
  112. package/lib/worklets/instances.js +194 -0
  113. package/lib/worklets/json-part.d.ts +1 -0
  114. package/lib/worklets/json-part.js +42 -0
  115. package/lib/worklets/runtime.d.ts +25 -0
  116. package/lib/worklets/runtime.js +80 -0
  117. package/lib/worklets/transfer-queue.d.ts +7 -0
  118. package/lib/worklets/transfer-queue.js +79 -0
  119. package/lib/worklets/types.d.ts +26 -0
  120. package/lib/worklets/types.js +1 -0
  121. package/nitro.json +32 -0
  122. package/nitrogen/generated/.gitattributes +1 -0
  123. package/nitrogen/generated/android/NarsilReactNative+autolinking.cmake +85 -0
  124. package/nitrogen/generated/android/NarsilReactNative+autolinking.gradle +27 -0
  125. package/nitrogen/generated/android/NarsilReactNativeOnLoad.cpp +69 -0
  126. package/nitrogen/generated/android/NarsilReactNativeOnLoad.hpp +34 -0
  127. package/nitrogen/generated/android/kotlin/com/margelo/nitro/narsil/NarsilReactNativeOnLoad.kt +35 -0
  128. package/nitrogen/generated/ios/NarsilReactNative+autolinking.rb +62 -0
  129. package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Bridge.cpp +17 -0
  130. package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Bridge.hpp +27 -0
  131. package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Umbrella.hpp +38 -0
  132. package/nitrogen/generated/ios/NarsilReactNativeAutolinking.mm +55 -0
  133. package/nitrogen/generated/ios/NarsilReactNativeAutolinking.swift +16 -0
  134. package/nitrogen/generated/shared/c++/DirectoryEntry.hpp +91 -0
  135. package/nitrogen/generated/shared/c++/FileStatus.hpp +103 -0
  136. package/nitrogen/generated/shared/c++/GraphMemory.hpp +120 -0
  137. package/nitrogen/generated/shared/c++/HybridNarsilAttachedGraphSpec.cpp +21 -0
  138. package/nitrogen/generated/shared/c++/HybridNarsilAttachedGraphSpec.hpp +62 -0
  139. package/nitrogen/generated/shared/c++/HybridNarsilAttachedStoreSpec.cpp +21 -0
  140. package/nitrogen/generated/shared/c++/HybridNarsilAttachedStoreSpec.hpp +62 -0
  141. package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.cpp +35 -0
  142. package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.hpp +100 -0
  143. package/nitrogen/generated/shared/c++/HybridNarsilFilesSpec.cpp +37 -0
  144. package/nitrogen/generated/shared/c++/HybridNarsilFilesSpec.hpp +86 -0
  145. package/nitrogen/generated/shared/c++/HybridNarsilHostSpec.cpp +34 -0
  146. package/nitrogen/generated/shared/c++/HybridNarsilHostSpec.hpp +78 -0
  147. package/nitrogen/generated/shared/c++/MemoryView.hpp +91 -0
  148. package/nitrogen/generated/shared/c++/NativeConnectOutcome.hpp +87 -0
  149. package/nitrogen/generated/shared/c++/NativeScores.hpp +87 -0
  150. package/nitrogen/generated/shared/c++/NativeSearchHits.hpp +91 -0
  151. package/nitrogen/generated/shared/c++/ProcessMemory.hpp +87 -0
  152. package/nitrogen/generated/shared/c++/StoreMemory.hpp +142 -0
  153. package/package.json +87 -3
  154. package/react-native.config.js +8 -0
  155. package/src/client.ts +44 -0
  156. package/src/constants.ts +9 -0
  157. package/src/engine/byte-files.ts +99 -0
  158. package/src/engine/core.ts +162 -0
  159. package/src/engine/files.ts +186 -0
  160. package/src/engine/host.ts +111 -0
  161. package/src/engine/install.ts +31 -0
  162. package/src/engine/native-error.ts +10 -0
  163. package/src/engine/stand-ins/atomics.ts +288 -0
  164. package/src/engine/stand-ins/crypto.ts +81 -0
  165. package/src/engine/stand-ins/process.ts +30 -0
  166. package/src/engine/stand-ins/streams.ts +45 -0
  167. package/src/engine/stand-ins/structured-clone.ts +118 -0
  168. package/src/engine/streamed.ts +40 -0
  169. package/src/engine/transfer.ts +72 -0
  170. package/src/errors.ts +73 -0
  171. package/src/index.ts +3 -0
  172. package/src/methods.ts +52 -0
  173. package/src/native-objects.ts +30 -0
  174. package/src/specs/core.nitro.ts +140 -0
  175. package/src/specs/files.nitro.ts +42 -0
  176. package/src/specs/host.nitro.ts +30 -0
  177. package/src/transferred.ts +18 -0
  178. package/src/types.ts +164 -0
  179. package/src/worklets/app-turns.ts +48 -0
  180. package/src/worklets/client.ts +165 -0
  181. package/src/worklets/index.ts +4 -0
  182. package/src/worklets/instances.ts +231 -0
  183. package/src/worklets/json-part.ts +38 -0
  184. package/src/worklets/runtime.ts +190 -0
  185. package/src/worklets/transfer-queue.ts +98 -0
  186. 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
@@ -0,0 +1,3 @@
1
+ export { createNarsil } from './client'
2
+ export { isNarsilError, type PhoneNarsilError } from './errors'
3
+ export type { PhoneEventHandler, PhoneNarsil, PhoneNarsilConfig } from './types'
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
+ }