react-native-nitro-cookies 1.0.0 → 1.0.2

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 (37) hide show
  1. package/android/AGENTS.md +62 -0
  2. package/android/src/main/java/com/margelo/nitro/nitrocookies/NitroCookies.kt +37 -21
  3. package/ios/AGENTS.md +49 -0
  4. package/ios/NitroCookies.swift +63 -16
  5. package/lib/module/AGENTS.md +50 -0
  6. package/lib/typescript/src/NitroCookies.nitro.d.ts.map +1 -1
  7. package/nitrogen/generated/android/c++/JCookie.hpp +1 -1
  8. package/nitrogen/generated/android/c++/JHybridNitroCookiesSpec.cpp +9 -1
  9. package/nitrogen/generated/android/c++/JHybridNitroCookiesSpec.hpp +2 -1
  10. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrocookies/Cookie.kt +2 -2
  11. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrocookies/HybridNitroCookiesSpec.kt +1 -1
  12. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrocookies/nitrocookiesOnLoad.kt +1 -1
  13. package/nitrogen/generated/android/nitrocookies+autolinking.cmake +1 -1
  14. package/nitrogen/generated/android/nitrocookies+autolinking.gradle +1 -1
  15. package/nitrogen/generated/android/nitrocookiesOnLoad.cpp +1 -1
  16. package/nitrogen/generated/android/nitrocookiesOnLoad.hpp +1 -1
  17. package/nitrogen/generated/ios/NitroCookies+autolinking.rb +2 -2
  18. package/nitrogen/generated/ios/NitroCookies-Swift-Cxx-Bridge.cpp +2 -1
  19. package/nitrogen/generated/ios/NitroCookies-Swift-Cxx-Bridge.hpp +3 -3
  20. package/nitrogen/generated/ios/NitroCookies-Swift-Cxx-Umbrella.hpp +1 -1
  21. package/nitrogen/generated/ios/NitroCookiesAutolinking.mm +1 -1
  22. package/nitrogen/generated/ios/NitroCookiesAutolinking.swift +9 -8
  23. package/nitrogen/generated/ios/c++/HybridNitroCookiesSpecSwift.cpp +1 -1
  24. package/nitrogen/generated/ios/c++/HybridNitroCookiesSpecSwift.hpp +7 -1
  25. package/nitrogen/generated/ios/swift/Cookie.swift +59 -143
  26. package/nitrogen/generated/ios/swift/Func_void.swift +1 -2
  27. package/nitrogen/generated/ios/swift/Func_void_bool.swift +1 -2
  28. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +1 -2
  29. package/nitrogen/generated/ios/swift/Func_void_std__vector_Cookie_.swift +1 -2
  30. package/nitrogen/generated/ios/swift/HybridNitroCookiesSpec.swift +3 -5
  31. package/nitrogen/generated/ios/swift/HybridNitroCookiesSpec_cxx.swift +9 -3
  32. package/nitrogen/generated/shared/c++/Cookie.hpp +34 -26
  33. package/nitrogen/generated/shared/c++/HybridNitroCookiesSpec.cpp +1 -1
  34. package/nitrogen/generated/shared/c++/HybridNitroCookiesSpec.hpp +1 -1
  35. package/package.json +13 -13
  36. package/src/AGENTS.md +50 -0
  37. package/src/NitroCookies.nitro.ts +4 -2
@@ -0,0 +1,62 @@
1
+ <!-- Parent: ../AGENTS.md -->
2
+ <!-- Generated: 2026-02-13 | Updated: 2026-02-13 -->
3
+
4
+ # android
5
+
6
+ ## Purpose
7
+ Android native implementation of the NitroCookies HybridObject in Kotlin, plus JNI/C++ adapter for Nitro Modules initialization. Uses Android's `CookieManager` (WebView-based) for all cookie operations. Includes Gradle build configuration and CMake native build.
8
+
9
+ ## Key Files
10
+
11
+ | File | Description |
12
+ |------|-------------|
13
+ | `build.gradle` | Android Gradle build config (Kotlin, CMake, dependencies) |
14
+ | `CMakeLists.txt` | CMake config for building the C++ JNI adapter |
15
+
16
+ ## Subdirectories
17
+
18
+ | Directory | Purpose |
19
+ |-----------|---------|
20
+ | `src/main/java/com/margelo/nitro/nitrocookies/` | Kotlin source files |
21
+ | `src/main/cpp/` | C++ JNI adapter for Nitro module loading |
22
+ | `.gradle/` | Gradle cache (gitignored, auto-generated) |
23
+ | `.cxx/` | CMake build output (gitignored, auto-generated) |
24
+
25
+ ## For AI Agents
26
+
27
+ ### Working In This Directory
28
+ - `NitroCookies.kt` is the main implementation file -- extends `HybridNitroCookiesSpec()` generated by Nitrogen
29
+ - `NitroCookiesPackage.kt` is the React Native package registration (loads `libnitrocookies` native library)
30
+ - `cpp-adapter.cpp` is the JNI entry point that calls `margelo::nitro::nitrocookies::initialize(vm)`
31
+ - Android uses `android.webkit.CookieManager` for all cookie operations (single storage backend, no WebKit/non-WebKit distinction)
32
+ - `useWebKit` parameter is accepted but ignored on Android (API compatibility with iOS)
33
+ - Cookie deletion works by setting an expired cookie (Android `CookieManager` limitation)
34
+ - `getAll()` throws `PLATFORM_UNSUPPORTED` on Android (iOS-only feature)
35
+ - Date formatting: converts between ISO 8601 and RFC 1123 for cookie headers
36
+ - Some async operations (`clearAll`, `removeSessionCookies`) require `Dispatchers.Main` because `CookieManager` callbacks run on the main thread
37
+
38
+ ### Testing Requirements
39
+ - No unit tests in this directory -- test via the `example/` Android app
40
+ - Test on various Android API levels (min API 21+)
41
+ - Verify cookie persistence across app restarts (test `flush()`)
42
+
43
+ ### Common Patterns
44
+ - `Promise.async { ... }` for async operations
45
+ - `suspendCancellableCoroutine` to bridge callback-based `CookieManager` APIs to coroutines
46
+ - `toRFC6265String()` serializes Cookie struct to Set-Cookie header format
47
+ - `createCookieData()` parses Set-Cookie header string back to Cookie struct
48
+ - `validateURL()` / `validateDomain()` for input validation
49
+
50
+ ## Dependencies
51
+
52
+ ### Internal
53
+ - `nitrogen/generated/android/` -- `HybridNitroCookiesSpec`, `Cookie` data class, JNI bridges
54
+ - `nitrogen/generated/shared/c++/` -- C++ spec and Cookie struct
55
+
56
+ ### External
57
+ - `android.webkit.CookieManager` -- Cookie storage (WebView-based)
58
+ - `java.net.HttpURLConnection` -- HTTP requests for `getFromResponse()`
59
+ - `com.margelo.nitro.core.Promise` -- Nitro async return type
60
+ - `kotlinx.coroutines` -- Coroutine support for async callbacks
61
+
62
+ <!-- MANUAL: Any manually added notes below this line are preserved on regeneration -->
@@ -1,5 +1,7 @@
1
1
  package com.margelo.nitro.nitrocookies
2
2
 
3
+ import android.os.Handler
4
+ import android.os.Looper
3
5
  import android.webkit.CookieManager
4
6
  import com.facebook.proguard.annotations.DoNotStrip
5
7
  import com.margelo.nitro.core.Promise
@@ -8,8 +10,6 @@ import java.net.URL
8
10
  import java.text.SimpleDateFormat
9
11
  import java.util.Locale
10
12
  import java.util.TimeZone
11
- import kotlin.coroutines.resume
12
- import kotlin.coroutines.suspendCoroutine
13
13
 
14
14
  /** HybridNitroCookies - Android implementation of cookie management */
15
15
  @DoNotStrip
@@ -31,9 +31,14 @@ class NitroCookies : HybridNitroCookiesSpec() {
31
31
  // Expires attribute (convert ISO 8601 to RFC 1123)
32
32
  cookie.expires?.let { expiresISO ->
33
33
  try {
34
- val date = iso8601Formatter.parse(expiresISO)
34
+ val normalizedISO = if (expiresISO.endsWith("Z")) {
35
+ expiresISO.dropLast(1) + "+00:00"
36
+ } else {
37
+ expiresISO
38
+ }
39
+ val date = iso8601Formatter.get()!!.parse(normalizedISO)
35
40
  date?.let {
36
- val expiresRFC = rfc1123Formatter.format(it)
41
+ val expiresRFC = rfc1123Formatter.get()!!.format(it)
37
42
  parts.add("Expires=$expiresRFC")
38
43
  }
39
44
  } catch (e: Exception) {
@@ -87,8 +92,8 @@ class NitroCookies : HybridNitroCookiesSpec() {
87
92
  part.startsWith("Expires=", ignoreCase = true) -> {
88
93
  val expiresRFC = part.substring(8).trim()
89
94
  try {
90
- val date = rfc1123Formatter.parse(expiresRFC)
91
- date?.let { expires = iso8601Formatter.format(it) }
95
+ val date = rfc1123Formatter.get()!!.parse(expiresRFC)
96
+ date?.let { expires = iso8601Formatter.get()!!.format(it) }
92
97
  } catch (e: Exception) {
93
98
  // Invalid date, skip
94
99
  }
@@ -130,7 +135,7 @@ class NitroCookies : HybridNitroCookiesSpec() {
130
135
  // Wildcard match (.example.com matches api.example.com)
131
136
  if (cookieDomain.startsWith(".")) {
132
137
  val domain = cookieDomain.substring(1)
133
- return urlHost.endsWith(domain) || urlHost == domain
138
+ return urlHost.endsWith(".$domain") || urlHost == domain
134
139
  }
135
140
 
136
141
  // Subdomain match (example.com matches api.example.com)
@@ -324,12 +329,16 @@ class NitroCookies : HybridNitroCookiesSpec() {
324
329
 
325
330
  /** Clear all cookies */
326
331
  override fun clearAll(useWebKit: Boolean?): Promise<Boolean> {
327
- return Promise.async {
328
- val cookieManager = CookieManager.getInstance()
329
- suspendCoroutine { continuation ->
330
- cookieManager.removeAllCookies { success -> continuation.resume(success) }
332
+ val promise = Promise<Boolean>()
333
+ Handler(Looper.getMainLooper()).post {
334
+ try {
335
+ val cookieManager = CookieManager.getInstance()
336
+ cookieManager.removeAllCookies { removed -> promise.resolve(removed) }
337
+ } catch (e: Exception) {
338
+ promise.reject(e)
331
339
  }
332
340
  }
341
+ return promise
333
342
  }
334
343
 
335
344
  /** Parse and set cookies from Set-Cookie header */
@@ -354,9 +363,9 @@ class NitroCookies : HybridNitroCookiesSpec() {
354
363
  /** Make HTTP request and get cookies from response */
355
364
  override fun getFromResponse(url: String): Promise<Array<Cookie>> {
356
365
  return Promise.async {
366
+ val urlObj = validateURL(url)
367
+ val connection = urlObj.openConnection() as HttpURLConnection
357
368
  try {
358
- val urlObj = validateURL(url)
359
- val connection = urlObj.openConnection() as HttpURLConnection
360
369
  connection.requestMethod = "GET"
361
370
  connection.connect()
362
371
 
@@ -368,10 +377,11 @@ class NitroCookies : HybridNitroCookiesSpec() {
368
377
  cookie?.let { cookies.add(it) }
369
378
  }
370
379
 
371
- connection.disconnect()
372
380
  cookies.toTypedArray()
373
381
  } catch (e: Exception) {
374
- throw Exception("NETWORK_ERROR: ${e.message}")
382
+ throw Exception("NETWORK_ERROR: ${e.message}", e)
383
+ } finally {
384
+ connection.disconnect()
375
385
  }
376
386
  }
377
387
  }
@@ -418,25 +428,31 @@ class NitroCookies : HybridNitroCookiesSpec() {
418
428
 
419
429
  /** Remove session cookies (Android only) */
420
430
  override fun removeSessionCookies(): Promise<Boolean> {
421
- return Promise.async {
422
- val cookieManager = CookieManager.getInstance()
423
- suspendCoroutine { continuation ->
424
- cookieManager.removeSessionCookies { success -> continuation.resume(success) }
431
+ val promise = Promise<Boolean>()
432
+ Handler(Looper.getMainLooper()).post {
433
+ try {
434
+ val cookieManager = CookieManager.getInstance()
435
+ cookieManager.removeSessionCookies { removed -> promise.resolve(removed) }
436
+ } catch (e: Exception) {
437
+ promise.reject(e)
425
438
  }
426
439
  }
440
+ return promise
427
441
  }
428
442
 
429
443
  companion object {
430
444
  /** ISO 8601 date formatter for cookie expires (yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ) */
431
- private val iso8601Formatter =
445
+ private val iso8601Formatter = ThreadLocal.withInitial {
432
446
  SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ", Locale.US).apply {
433
447
  timeZone = TimeZone.getTimeZone("UTC")
434
448
  }
449
+ }
435
450
 
436
451
  /** RFC 1123 date formatter for Set-Cookie headers (EEE, dd MMM yyyy HH:mm:ss z) */
437
- private val rfc1123Formatter =
452
+ private val rfc1123Formatter = ThreadLocal.withInitial {
438
453
  SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US).apply {
439
454
  timeZone = TimeZone.getTimeZone("GMT")
440
455
  }
456
+ }
441
457
  }
442
458
  }
package/ios/AGENTS.md ADDED
@@ -0,0 +1,49 @@
1
+ <!-- Parent: ../AGENTS.md -->
2
+ <!-- Generated: 2026-02-13 | Updated: 2026-02-13 -->
3
+
4
+ # ios
5
+
6
+ ## Purpose
7
+ iOS native implementation of the NitroCookies HybridObject in Swift. Provides cookie management using `NSHTTPCookieStorage` (synchronous/default) and `WKHTTPCookieStore` (async WebKit operations). Conforms to the Nitrogen-generated `HybridNitroCookiesSpec`.
8
+
9
+ ## Key Files
10
+
11
+ | File | Description |
12
+ |------|-------------|
13
+ | `NitroCookies.swift` | Full iOS implementation: `HybridNitroCookies` class extending `HybridNitroCookiesSpec` with sync + async cookie CRUD, URL validation, domain matching, WebKit support |
14
+
15
+ ## For AI Agents
16
+
17
+ ### Working In This Directory
18
+ - The class `HybridNitroCookies` extends the generated `HybridNitroCookiesSpec` (from `nitrogen/generated/ios/`)
19
+ - Two cookie storage backends:
20
+ - **NSHTTPCookieStorage** (shared): used for all sync methods and async methods when `useWebKit == false`
21
+ - **WKHTTPCookieStore**: used for async methods when `useWebKit == true` (iOS 11+ required)
22
+ - WebKit operations require `MainActor.run` to access `WKWebsiteDataStore.default().httpCookieStore` safely across iOS versions
23
+ - Date conversion uses `ISO8601DateFormatter` with fractional seconds for cookie `expires` fields
24
+ - Platform-only methods (`flush`, `removeSessionCookies`) throw `PLATFORM_UNSUPPORTED` errors on iOS
25
+ - Domain matching logic: exact match, wildcard (`.example.com`), and subdomain matching
26
+
27
+ ### Testing Requirements
28
+ - No unit tests in this directory -- test via the `example/` iOS app
29
+ - Test both NSHTTPCookieStorage and WKHTTPCookieStore paths
30
+ - Verify iOS 11+ availability checks for WebKit operations
31
+
32
+ ### Common Patterns
33
+ - `Promise.async { ... }` wraps async work into Nitro Promises
34
+ - `withCheckedContinuation` bridges callback-based WebKit APIs to Swift concurrency
35
+ - `validateURL()` and `validateDomain()` are called at the start of every operation
36
+ - Cookie struct conversion: `makeHTTPCookie(from:url:)` and `createCookieData(from:)`
37
+
38
+ ## Dependencies
39
+
40
+ ### Internal
41
+ - `nitrogen/generated/ios/` -- `HybridNitroCookiesSpec`, `Cookie` type bridges
42
+ - `nitrogen/generated/shared/c++/` -- C++ spec and Cookie struct
43
+
44
+ ### External
45
+ - `Foundation` -- `HTTPCookieStorage`, `HTTPCookie`, `URLSession`
46
+ - `WebKit` -- `WKWebsiteDataStore`, `WKHTTPCookieStore`
47
+ - `NitroModules` -- `HybridObject` base, `Promise`
48
+
49
+ <!-- MANUAL: Any manually added notes below this line are preserved on regeneration -->
@@ -25,6 +25,27 @@ public class HybridNitroCookies: HybridNitroCookiesSpec {
25
25
  return formatter
26
26
  }()
27
27
 
28
+ /// RFC 1123 date formatter for Set-Cookie Expires attribute
29
+ private static let rfc1123Formatter: DateFormatter = {
30
+ let formatter = DateFormatter()
31
+ formatter.locale = Locale(identifier: "en_US_POSIX")
32
+ formatter.timeZone = TimeZone(abbreviation: "GMT")
33
+ formatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss zzz"
34
+ return formatter
35
+ }()
36
+
37
+ /// Remove CR, LF, and NUL characters that could enable header injection
38
+ private static func sanitizeCookieToken(_ value: String) -> String {
39
+ var result = ""
40
+ result.reserveCapacity(value.count)
41
+ for scalar in value.unicodeScalars {
42
+ if scalar != "\r" && scalar != "\n" && scalar != "\0" {
43
+ result.append(String(scalar))
44
+ }
45
+ }
46
+ return result
47
+ }
48
+
28
49
  // MARK: - Helper Functions
29
50
 
30
51
  /**
@@ -42,24 +63,49 @@ public class HybridNitroCookies: HybridNitroCookiesSpec {
42
63
  .path: cookiePath
43
64
  ]
44
65
 
45
- // Add expires if provided
46
66
  if let expiresString = cookie.expires,
47
67
  let expiresDate = Self.iso8601Formatter.date(from: expiresString) {
48
68
  properties[.expires] = expiresDate
49
69
  }
50
70
 
51
- // Add secure flag
52
71
  if cookie.secure == true {
53
72
  properties[.secure] = "TRUE"
54
73
  }
55
74
 
56
- // Note: HttpOnly is handled via the isHTTPOnly property, not in properties dict
57
-
58
75
  guard let httpCookie = HTTPCookie(properties: properties) else {
59
76
  throw NSError(domain: "NitroCookies", code: 1,
60
77
  userInfo: [NSLocalizedDescriptionKey: "Failed to create HTTPCookie"])
61
78
  }
62
79
 
80
+ // HTTPCookie(properties:) ignores httpOnly — there is no property key for it.
81
+ // When httpOnly is requested, rebuild via Set-Cookie header parsing which
82
+ // correctly handles the HttpOnly attribute, while preserving the original domain.
83
+ if cookie.httpOnly == true {
84
+ let originalDomain = httpCookie.domain
85
+ let safeName = Self.sanitizeCookieToken(httpCookie.name)
86
+ let safeValue = Self.sanitizeCookieToken(httpCookie.value)
87
+ var parts: [String] = ["\(safeName)=\(safeValue)"]
88
+ parts.append("Domain=\(originalDomain)")
89
+ parts.append("Path=\(httpCookie.path)")
90
+ if let expires = httpCookie.expiresDate {
91
+ parts.append("Expires=\(Self.rfc1123Formatter.string(from: expires))")
92
+ }
93
+ if httpCookie.isSecure {
94
+ parts.append("Secure")
95
+ }
96
+ parts.append("HttpOnly")
97
+
98
+ let setCookieHeader = parts.joined(separator: "; ")
99
+ let headerFields = ["Set-Cookie": setCookieHeader]
100
+ let parsed = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url)
101
+
102
+ guard let httpOnlyCookie = parsed.first else {
103
+ throw NSError(domain: "NitroCookies", code: 1,
104
+ userInfo: [NSLocalizedDescriptionKey: "Failed to create HTTPCookie with HttpOnly"])
105
+ }
106
+ return httpOnlyCookie
107
+ }
108
+
63
109
  return httpCookie
64
110
  }
65
111
 
@@ -71,11 +117,18 @@ public class HybridNitroCookies: HybridNitroCookiesSpec {
71
117
  Self.iso8601Formatter.string(from: $0)
72
118
  }
73
119
 
120
+ // Strip leading dot from domain — NSHTTPCookieStorage and Set-Cookie
121
+ // parsing add a dot prefix per RFC 6265, but callers expect the bare domain.
122
+ var domain = httpCookie.domain
123
+ if domain.hasPrefix(".") {
124
+ domain = String(domain.dropFirst())
125
+ }
126
+
74
127
  return Cookie(
75
128
  name: httpCookie.name,
76
129
  value: httpCookie.value,
77
130
  path: httpCookie.path,
78
- domain: httpCookie.domain,
131
+ domain: domain,
79
132
  version: String(httpCookie.version),
80
133
  expires: expiresString,
81
134
  secure: httpCookie.isSecure,
@@ -95,7 +148,7 @@ public class HybridNitroCookies: HybridNitroCookiesSpec {
95
148
  // Wildcard match (.example.com matches api.example.com)
96
149
  if cookieDomain.hasPrefix(".") {
97
150
  let domain = String(cookieDomain.dropFirst())
98
- return urlHost.hasSuffix(domain) || urlHost == domain
151
+ return urlHost.hasSuffix("." + domain) || urlHost == domain
99
152
  }
100
153
 
101
154
  // Subdomain match (example.com matches api.example.com)
@@ -367,10 +420,8 @@ public class HybridNitroCookies: HybridNitroCookiesSpec {
367
420
  userInfo: [NSLocalizedDescriptionKey: "Not HTTP response"])
368
421
  }
369
422
 
370
- let cookies = HTTPCookie.cookies(
371
- withResponseHeaderFields: httpResponse.allHeaderFields as! [String: String],
372
- for: url
373
- )
423
+ let headerFields = httpResponse.allHeaderFields as? [String: String] ?? [:]
424
+ let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url)
374
425
 
375
426
  return cookies.map { self.createCookieData(from: $0) }
376
427
  }
@@ -466,9 +517,7 @@ public class HybridNitroCookies: HybridNitroCookiesSpec {
466
517
  */
467
518
  public func flush() throws -> Promise<Void> {
468
519
  return Promise.async {
469
- throw NSError(domain: "PLATFORM_UNSUPPORTED", code: 5,
470
- userInfo: [NSLocalizedDescriptionKey:
471
- "flush() is only available on Android"])
520
+ // No-op on iOS - cookies are automatically persisted
472
521
  }
473
522
  }
474
523
 
@@ -477,9 +526,7 @@ public class HybridNitroCookies: HybridNitroCookiesSpec {
477
526
  */
478
527
  public func removeSessionCookies() throws -> Promise<Bool> {
479
528
  return Promise.async {
480
- throw NSError(domain: "PLATFORM_UNSUPPORTED", code: 5,
481
- userInfo: [NSLocalizedDescriptionKey:
482
- "removeSessionCookies() is only available on Android"])
529
+ return false
483
530
  }
484
531
  }
485
532
  }
@@ -0,0 +1,50 @@
1
+ <!-- Parent: ../AGENTS.md -->
2
+ <!-- Generated: 2026-02-13 | Updated: 2026-02-13 -->
3
+
4
+ # src
5
+
6
+ ## Purpose
7
+ TypeScript source code for the `react-native-nitro-cookies` npm package. Contains the public API, Nitro HybridObject interface contract, type definitions, and tests. This is the entry point consumers import from.
8
+
9
+ ## Key Files
10
+
11
+ | File | Description |
12
+ |------|-------------|
13
+ | `index.tsx` | Public API -- exports `NitroCookies` object wrapping the HybridObject with sync/async methods; converts Cookie arrays to Record dictionaries |
14
+ | `NitroCookies.nitro.ts` | Nitro HybridObject interface -- the **contract** that drives Nitrogen code generation for C++/Swift/Kotlin bridges |
15
+ | `types.ts` | Type definitions: `Cookie` interface (RFC 6265), `Cookies` type alias, `CookieErrorCode` enum, `CookieError` interface |
16
+
17
+ ## Subdirectories
18
+
19
+ | Directory | Purpose |
20
+ |-----------|---------|
21
+ | `__tests__/` | Jest test suite (currently placeholder) |
22
+
23
+ ## For AI Agents
24
+
25
+ ### Working In This Directory
26
+ - `NitroCookies.nitro.ts` is the **single source of truth** for the native interface. Changing it requires running `yarn nitrogen` to regenerate all C++/Swift/Kotlin bridge code
27
+ - `index.tsx` is the **public API layer** that wraps the raw HybridObject. It converts `Cookie[]` arrays from native into `Cookies` (Record) dictionaries for backward compatibility with `@react-native-cookies/cookies`
28
+ - `types.ts` defines types used both by the public API and the Nitro interface
29
+ - The `useWebKit` parameter defaults to `false` in the public API (via `?? false`); the Nitro interface uses `optional<bool>`
30
+
31
+ ### Testing Requirements
32
+ - Run `yarn test` to execute Jest tests
33
+ - The test suite is currently a placeholder -- add real unit tests when modifying the TypeScript API
34
+ - Platform-specific behavior must be tested in the `example/` app on real devices/simulators
35
+
36
+ ### Common Patterns
37
+ - Sync methods: direct JSI calls returning values immediately (no Promise)
38
+ - Async methods: return `Promise` from the HybridObject, public API wraps with `async`
39
+ - Cookie conversion: `cookiesToDictionary()` helper converts `Cookie[]` to `Record<string, Cookie>`
40
+ - Default exports: both named (`NitroCookies`) and default export for consumer flexibility
41
+
42
+ ## Dependencies
43
+
44
+ ### Internal
45
+ - `react-native-nitro-modules` -- `NitroModules.createHybridObject`, `HybridObject` types
46
+
47
+ ### External
48
+ - `react-native-nitro-modules` ^0.31.4
49
+
50
+ <!-- MANUAL: Any manually added notes below this line are preserved on regeneration -->
@@ -1 +1 @@
1
- {"version":3,"file":"NitroCookies.nitro.d.ts","sourceRoot":"","sources":["../../../src/NitroCookies.nitro.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAKtC;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YACf,SAAQ,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;IAKzD;;;;;;;;;OASG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE/B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAE9C;;;;;;;OAOG;IACH,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAEzD;;;;;;;OAOG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAMpD;;;;;;;OAOG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAExE;;;;;;OAMG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEzD;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEhD;;;;;;OAMG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE9D;;;;;OAKG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEhD;;;;;OAKG;IACH,MAAM,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAE/C;;;;;;;OAOG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE9E;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;;OAIG;IACH,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1C"}
1
+ {"version":3,"file":"NitroCookies.nitro.d.ts","sourceRoot":"","sources":["../../../src/NitroCookies.nitro.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAKtC;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YAAa,SAAQ,YAAY,CAAC;IACjD,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;CACnB,CAAC;IAKA;;;;;;;;;OASG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE/B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAE9C;;;;;;;OAOG;IACH,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IAEzD;;;;;;;OAOG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAMpD;;;;;;;OAOG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAExE;;;;;;OAMG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEzD;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEhD;;;;;;OAMG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE9D;;;;;OAKG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEhD;;;;;OAKG;IACH,MAAM,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAE/C;;;;;;;OAOG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE9E;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;;OAIG;IACH,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1C"}
@@ -2,7 +2,7 @@
2
2
  /// JCookie.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -2,7 +2,7 @@
2
2
  /// JHybridNitroCookiesSpec.cpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #include "JHybridNitroCookiesSpec.hpp"
@@ -17,6 +17,7 @@ namespace margelo::nitro::nitrocookies { struct Cookie; }
17
17
  #include <optional>
18
18
  #include <NitroModules/Promise.hpp>
19
19
  #include <NitroModules/JPromise.hpp>
20
+ #include <NitroModules/JUnit.hpp>
20
21
 
21
22
  namespace margelo::nitro::nitrocookies {
22
23
 
@@ -35,6 +36,13 @@ namespace margelo::nitro::nitrocookies {
35
36
  return method(_javaPart);
36
37
  }
37
38
 
39
+ bool JHybridNitroCookiesSpec::equals(const std::shared_ptr<HybridObject>& other) {
40
+ if (auto otherCast = std::dynamic_pointer_cast<JHybridNitroCookiesSpec>(other)) {
41
+ return _javaPart == otherCast->_javaPart;
42
+ }
43
+ return false;
44
+ }
45
+
38
46
  void JHybridNitroCookiesSpec::dispose() noexcept {
39
47
  static const auto method = javaClassStatic()->getMethod<void()>("dispose");
40
48
  method(_javaPart);
@@ -2,7 +2,7 @@
2
2
  /// HybridNitroCookiesSpec.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -40,6 +40,7 @@ namespace margelo::nitro::nitrocookies {
40
40
 
41
41
  public:
42
42
  size_t getExternalMemorySize() noexcept override;
43
+ bool equals(const std::shared_ptr<HybridObject>& other) override;
43
44
  void dispose() noexcept override;
44
45
  std::string toString() override;
45
46
 
@@ -2,7 +2,7 @@
2
2
  /// Cookie.kt
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  package com.margelo.nitro.nitrocookies
@@ -44,7 +44,7 @@ data class Cookie(
44
44
  ) {
45
45
  /* primary constructor */
46
46
 
47
- private companion object {
47
+ companion object {
48
48
  /**
49
49
  * Constructor called from C++
50
50
  */
@@ -2,7 +2,7 @@
2
2
  /// HybridNitroCookiesSpec.kt
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  package com.margelo.nitro.nitrocookies
@@ -2,7 +2,7 @@
2
2
  /// nitrocookiesOnLoad.kt
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  package com.margelo.nitro.nitrocookies
@@ -2,7 +2,7 @@
2
2
  # nitrocookies+autolinking.cmake
3
3
  # This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  # https://github.com/mrousavy/nitro
5
- # Copyright © 2025 Marc Rousavy @ Margelo
5
+ # Copyright © Marc Rousavy @ Margelo
6
6
  #
7
7
 
8
8
  # This is a CMake file that adds all files generated by Nitrogen
@@ -2,7 +2,7 @@
2
2
  /// nitrocookies+autolinking.gradle
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  /// This is a Gradle file that adds all files generated by Nitrogen
@@ -2,7 +2,7 @@
2
2
  /// nitrocookiesOnLoad.cpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #ifndef BUILDING_NITROCOOKIES_WITH_GENERATED_CMAKE_PROJECT
@@ -2,7 +2,7 @@
2
2
  /// nitrocookiesOnLoad.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #include <jni.h>
@@ -2,7 +2,7 @@
2
2
  # NitroCookies+autolinking.rb
3
3
  # This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  # https://github.com/mrousavy/nitro
5
- # Copyright © 2025 Marc Rousavy @ Margelo
5
+ # Copyright © Marc Rousavy @ Margelo
6
6
  #
7
7
 
8
8
  # This is a Ruby script that adds all files generated by Nitrogen
@@ -52,7 +52,7 @@ def add_nitrogen_files(spec)
52
52
  spec.pod_target_xcconfig = current_pod_target_xcconfig.merge({
53
53
  # Use C++ 20
54
54
  "CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
55
- # Enables C++ <-> Swift interop (by default it's only C)
55
+ # Enables C++ <-> Swift interop (by default it's only ObjC)
56
56
  "SWIFT_OBJC_INTEROP_MODE" => "objcxx",
57
57
  # Enables stricter modular headers
58
58
  "DEFINES_MODULE" => "YES",
@@ -2,7 +2,7 @@
2
2
  /// NitroCookies-Swift-Cxx-Bridge.cpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #include "NitroCookies-Swift-Cxx-Bridge.hpp"
@@ -10,6 +10,7 @@
10
10
  // Include C++ implementation defined types
11
11
  #include "HybridNitroCookiesSpecSwift.hpp"
12
12
  #include "NitroCookies-Swift-Cxx-Umbrella.hpp"
13
+ #include <NitroModules/NitroDefines.hpp>
13
14
 
14
15
  namespace margelo::nitro::nitrocookies::bridge::swift {
15
16
 
@@ -2,7 +2,7 @@
2
2
  /// NitroCookies-Swift-Cxx-Bridge.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -48,7 +48,7 @@ namespace margelo::nitro::nitrocookies::bridge::swift {
48
48
  return optional.has_value();
49
49
  }
50
50
  inline std::string get_std__optional_std__string_(const std::optional<std::string>& optional) noexcept {
51
- return *optional;
51
+ return optional.value();
52
52
  }
53
53
 
54
54
  // pragma MARK: std::optional<bool>
@@ -63,7 +63,7 @@ namespace margelo::nitro::nitrocookies::bridge::swift {
63
63
  return optional.has_value();
64
64
  }
65
65
  inline bool get_std__optional_bool_(const std::optional<bool>& optional) noexcept {
66
- return *optional;
66
+ return optional.value();
67
67
  }
68
68
 
69
69
  // pragma MARK: std::vector<Cookie>