{"_id":"@airstrings/react-native","_rev":"6-fce104523a1f2726217d714ec3fc5fef","name":"@airstrings/react-native","dist-tags":{"latest":"0.4.0"},"versions":{"0.1.0":{"name":"@airstrings/react-native","version":"0.1.0","keywords":["airstrings","i18n","l10n","localization","internationalization","icu","messageformat","ed25519","cdn","sdk","react-native"],"author":{"name":"Symbionix","email":"info@symbionix.io"},"license":"MIT","_id":"@airstrings/react-native@0.1.0","maintainers":[{"name":"symbionixsl","email":"symbionix.sl@gmail.com"}],"homepage":"https://github.com/symbionix-sl/airstrings-sdk-react-native#readme","bugs":{"url":"https://github.com/symbionix-sl/airstrings-sdk-react-native/issues"},"dist":{"shasum":"970f73d4b278ce7bb3af159dfec7d0e6033e0dac","tarball":"https://registry.npmjs.org/@airstrings/react-native/-/react-native-0.1.0.tgz","fileCount":9,"integrity":"sha512-Vi5rTZMpdxzPtQfe3NKyDXuxR38bxb3fCTPARaYsJGuCUcpAaopDi96OMmRBscci6feJZROnAJbPzgMsSOorqg==","signatures":[{"sig":"MEQCIGRgV6LqEq5onGU9e6Mp3Sqiw9xRSMC1HNSLjBL1TYLQAiAzHw2tBuSFCjL/1T5clWH76hJvEwKTOW6st+dmrP78cw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":585207},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"bd0398b016ccf466030ed7316dcdc28c5650b049","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"symbionixsl","email":"symbionix.sl@gmail.com"},"repository":{"url":"git+https://github.com/symbionix-sl/airstrings-sdk-react-native.git","type":"git"},"_npmVersion":"10.9.4","description":"AirStrings React Native SDK — fetch, verify, cache, and serve Ed25519-signed localized string bundles","directories":{},"sideEffects":false,"_nodeVersion":"22.22.0","dependencies":{"@noble/hashes":"^1.8.0","@noble/ed25519":"^2.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","eslint":"^9.0.0","vitest":"^3.0.0","@eslint/js":"^9.0.0","typescript":"^5.7.0","@types/node":"^22.19.21","typescript-eslint":"^8.0.0","intl-messageformat":"^11.1.3","@vitest/coverage-v8":"^3.0.0"},"peerDependencies":{"react-native":">=0.72.0","@react-native-async-storage/async-storage":">=1.19.0"},"_npmOperationalInternal":{"tmp":"tmp/react-native_0.1.0_1783436071036_0.7882353367096857","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@airstrings/react-native","version":"0.1.1","keywords":["airstrings","i18n","l10n","localization","internationalization","icu","messageformat","ed25519","cdn","sdk","react-native"],"author":{"name":"Symbionix","email":"info@symbionix.io"},"license":"MIT","_id":"@airstrings/react-native@0.1.1","maintainers":[{"name":"symbionixsl","email":"symbionix.sl@gmail.com"}],"homepage":"https://github.com/symbionix-sl/airstrings-sdk-react-native#readme","bugs":{"url":"https://github.com/symbionix-sl/airstrings-sdk-react-native/issues"},"dist":{"shasum":"09cc1c856589f14bd557eb2a0428c9e2e10202d6","tarball":"https://registry.npmjs.org/@airstrings/react-native/-/react-native-0.1.1.tgz","fileCount":9,"integrity":"sha512-7E3ErzcW8bx4aLtwpr2QhpTtwfjVDmEnw+TRl1/YjPONG7XVuVnIr/juFULeJE3tpYcsjPMLrqrh7NVCg9ISvw==","signatures":[{"sig":"MEUCIC6r/wOW+du8uUo5cQjAi9ycblJiM9I7i9RHNKgP6wIvAiEA8sv6Xl2Soa2FGDCPn/5tCm2ihhbdZBrB6oJX1ZUtOAc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@airstrings%2freact-native@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1381690},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"23372656476944511a4a3f1e27c0562c9741b2e2","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b1d2b314-f362-4bf9-9451-48118cb05c42"}},"repository":{"url":"git+https://github.com/symbionix-sl/airstrings-sdk-react-native.git","type":"git"},"_npmVersion":"11.16.0","description":"AirStrings React Native SDK — fetch, verify, cache, and serve Ed25519-signed localized string bundles","directories":{},"sideEffects":["./src/intl-polyfill.ts","./dist/index.cjs","./dist/index.mjs"],"_nodeVersion":"24.18.0","dependencies":{"@noble/hashes":"^1.8.0","@noble/ed25519":"^2.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","eslint":"^9.0.0","vitest":"^3.0.0","@eslint/js":"^9.0.0","typescript":"^5.7.0","@types/node":"^22.19.21","typescript-eslint":"^8.0.0","intl-messageformat":"^11.1.3","@vitest/coverage-v8":"^3.0.0","@formatjs/intl-pluralrules":"^6.3.10"},"peerDependencies":{"react-native":">=0.72.0","@react-native-async-storage/async-storage":">=1.19.0"},"_npmOperationalInternal":{"tmp":"tmp/react-native_0.1.1_1783439052559_0.9477150566399548","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@airstrings/react-native","version":"0.2.0","keywords":["airstrings","i18n","l10n","localization","internationalization","icu","messageformat","ed25519","cdn","sdk","react-native"],"author":{"name":"Symbionix","email":"info@symbionix.io"},"license":"MIT","_id":"@airstrings/react-native@0.2.0","maintainers":[{"name":"symbionixsl","email":"symbionix.sl@gmail.com"}],"homepage":"https://github.com/symbionix-sl/airstrings-sdk-react-native#readme","bugs":{"url":"https://github.com/symbionix-sl/airstrings-sdk-react-native/issues"},"dist":{"shasum":"6fdb6955beaf00621394e6c454821792e5023647","tarball":"https://registry.npmjs.org/@airstrings/react-native/-/react-native-0.2.0.tgz","fileCount":9,"integrity":"sha512-0SECjhMo4OSWlvn30MbPHwh8EL2ncnctz/R6eSWlrd7wOsxK6DjvkhliGJBrBeqlrEu9wpdTlDsfY5sDDx1Rgg==","signatures":[{"sig":"MEQCIHc2FBnbq2GWDaR2pNj4MSV5sjkS9u0k3VNQideBdQ2DAiAM/oQLMjqR+bMP6mHDR64ofilBy9rgRFTTc6PeQjunjw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@airstrings%2freact-native@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1425532},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"7b41e0ebc11f9cf9dac486c9f1ef3821b83a970a","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b1d2b314-f362-4bf9-9451-48118cb05c42"}},"repository":{"url":"git+https://github.com/symbionix-sl/airstrings-sdk-react-native.git","type":"git"},"_npmVersion":"11.16.0","description":"AirStrings React Native SDK — fetch, verify, cache, and serve Ed25519-signed localized string bundles","directories":{},"sideEffects":["./src/intl-polyfill.ts","./dist/index.cjs","./dist/index.mjs"],"_nodeVersion":"24.18.0","dependencies":{"@noble/hashes":"^1.8.0","@noble/ed25519":"^2.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","eslint":"^9.0.0","vitest":"^3.0.0","@eslint/js":"^9.0.0","typescript":"^5.7.0","@types/node":"^22.19.21","typescript-eslint":"^8.0.0","intl-messageformat":"^11.1.3","@vitest/coverage-v8":"^3.0.0","@formatjs/intl-pluralrules":"^6.3.10"},"peerDependencies":{"react-native":">=0.72.0","@react-native-async-storage/async-storage":">=1.19.0"},"_npmOperationalInternal":{"tmp":"tmp/react-native_0.2.0_1784052245787_0.707287765063745","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@airstrings/react-native","version":"0.3.0","keywords":["airstrings","i18n","l10n","localization","internationalization","icu","messageformat","ed25519","cdn","sdk","react-native"],"author":{"name":"Symbionix","email":"info@symbionix.io"},"license":"MIT","_id":"@airstrings/react-native@0.3.0","maintainers":[{"name":"symbionixsl","email":"symbionix.sl@gmail.com"}],"homepage":"https://github.com/symbionix-sl/airstrings-sdk-react-native#readme","bugs":{"url":"https://github.com/symbionix-sl/airstrings-sdk-react-native/issues"},"dist":{"shasum":"3be7954b903064ff58a22633c5bcccd47be42e8b","tarball":"https://registry.npmjs.org/@airstrings/react-native/-/react-native-0.3.0.tgz","fileCount":9,"integrity":"sha512-nLQtOJj47Kah8rtlOoDNo4FW70enGfpc+nzwO9jc1zHfMZILk78ZHs7j/hf1P+u02Klq9YUlNkZSoVmYztEKJg==","signatures":[{"sig":"MEQCIBWjK+S2aCbVWALNhm3IsoKUqShl/XgJydxDec0qI/K/AiA1Cph2qCAMH7SD1cUhnIsIpYBQA7zqDcwi6qYZ2nF9AA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@airstrings%2freact-native@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1426201},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"27c427e3218304b409812b7326ad780273e1992d","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b1d2b314-f362-4bf9-9451-48118cb05c42"}},"repository":{"url":"git+https://github.com/symbionix-sl/airstrings-sdk-react-native.git","type":"git"},"_npmVersion":"11.16.0","description":"AirStrings React Native SDK — fetch, verify, cache, and serve Ed25519-signed localized string bundles","directories":{},"sideEffects":["./src/intl-polyfill.ts","./dist/index.cjs","./dist/index.mjs"],"_nodeVersion":"24.18.0","dependencies":{"@noble/hashes":"^1.8.0","@noble/ed25519":"^2.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","eslint":"^9.0.0","vitest":"^3.0.0","@eslint/js":"^9.0.0","typescript":"^5.7.0","@types/node":"^22.19.21","typescript-eslint":"^8.0.0","intl-messageformat":"^11.1.3","@vitest/coverage-v8":"^3.0.0","@formatjs/intl-pluralrules":"^6.3.10"},"peerDependencies":{"react-native":">=0.72.0","@react-native-async-storage/async-storage":">=1.19.0"},"_npmOperationalInternal":{"tmp":"tmp/react-native_0.3.0_1784068567624_0.5881223749991975","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@airstrings/react-native","version":"0.3.1","keywords":["airstrings","i18n","l10n","localization","internationalization","icu","messageformat","ed25519","cdn","sdk","react-native"],"author":{"name":"Symbionix","email":"info@symbionix.io"},"license":"MIT","_id":"@airstrings/react-native@0.3.1","maintainers":[{"name":"symbionixsl","email":"symbionix.sl@gmail.com"}],"homepage":"https://github.com/symbionix-sl/airstrings-sdk-react-native#readme","bugs":{"url":"https://github.com/symbionix-sl/airstrings-sdk-react-native/issues"},"dist":{"shasum":"27068fe6774aca105ba83931cb38542c0fbda902","tarball":"https://registry.npmjs.org/@airstrings/react-native/-/react-native-0.3.1.tgz","fileCount":9,"integrity":"sha512-bTuqOeIJ45HUfRjNrW8JALhUXGg4JppvPg7VYRYCHJOS9Ph1+kiDqxj+XlcgGT8H5ouTCzOFlFEuUHhLVqtDEw==","signatures":[{"sig":"MEUCIGKp3PS3jk50uzUDO4BWUxwBrhg7nzKTsXRhsZT8QVXJAiEAj7f+tHJk6RARFR9HIwNLATKJ7H3hJYgyCpvbWgQOynA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@airstrings%2freact-native@0.3.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1430372},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"35c65e69dfa257fcf08b789e787011544d198ce8","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b1d2b314-f362-4bf9-9451-48118cb05c42"}},"repository":{"url":"git+https://github.com/symbionix-sl/airstrings-sdk-react-native.git","type":"git"},"_npmVersion":"11.16.0","description":"AirStrings React Native SDK — fetch, verify, cache, and serve Ed25519-signed localized string bundles","directories":{},"sideEffects":["./src/intl-polyfill.ts","./dist/index.cjs","./dist/index.mjs"],"_nodeVersion":"24.18.0","dependencies":{"@noble/hashes":"^1.8.0","@noble/ed25519":"^2.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","eslint":"^9.0.0","vitest":"^3.0.0","@eslint/js":"^9.0.0","typescript":"^5.7.0","@types/node":"^22.19.21","typescript-eslint":"^8.0.0","intl-messageformat":"^11.1.3","@vitest/coverage-v8":"^3.0.0","@formatjs/intl-pluralrules":"^6.3.10"},"peerDependencies":{"react-native":">=0.72.0","@react-native-async-storage/async-storage":">=1.19.0"},"_npmOperationalInternal":{"tmp":"tmp/react-native_0.3.1_1784095651834_0.47387415873570227","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"_id":"@airstrings/react-native@0.4.0","bugs":{"url":"https://github.com/symbionix-sl/airstrings-sdk-react-native/issues"},"dist":{"shasum":"cbc7b2fccc54db8f22a95bb2a2667f33246cf120","tarball":"https://registry.npmjs.org/@airstrings/react-native/-/react-native-0.4.0.tgz","fileCount":9,"integrity":"sha512-0PzinvbQQdESREJMajR3UJQLcpNvSQZAlZndRhQSu4tXOxTt8/2R/cQyjBdtPSanJU/JpNzh872ZJ7SE29xmsA==","signatures":[{"sig":"MEQCIB/B5gFpTtW5pT3ErRM5rIjTrkIwrM2P2zl8szkX4VcNAiA8fTXrTXuD/0UajD4ieuLIP7GUl/c5MewYD8kcU2PalQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICTS32WY39F9wIIUcbgfxYcTnsQvYTZPRUn6yMefDCb2AiAZFgCfbJ5orgoJ0IMtsFEgH7Wj8/qRYytTc4HCjanxgA=="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@airstrings%2freact-native@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1438626},"main":"./dist/index.cjs","name":"@airstrings/react-native","type":"module","types":"./dist/index.d.ts","author":{"name":"Symbionix","email":"info@symbionix.io"},"module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"5bfdce208841ae596c8f57fd15621c57a084ae94","license":"MIT","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"version":"0.4.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b1d2b314-f362-4bf9-9451-48118cb05c42"}},"homepage":"https://github.com/symbionix-sl/airstrings-sdk-react-native#readme","keywords":["airstrings","i18n","l10n","localization","internationalization","icu","messageformat","ed25519","cdn","sdk","react-native"],"repository":{"url":"git+https://github.com/symbionix-sl/airstrings-sdk-react-native.git","type":"git"},"_npmVersion":"11.19.0","description":"AirStrings React Native SDK — fetch, verify, cache, and serve Ed25519-signed localized string bundles","directories":{},"maintainers":[{"name":"symbionixsl","email":"symbionix.sl@gmail.com"}],"sideEffects":["./src/intl-polyfill.ts","./dist/index.cjs","./dist/index.mjs"],"_nodeVersion":"24.20.0","dependencies":{"@noble/hashes":"^1.8.0","@noble/ed25519":"^2.1.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","eslint":"^9.0.0","vitest":"^3.0.0","@eslint/js":"^9.0.0","typescript":"^5.7.0","@types/node":"^22.19.21","typescript-eslint":"^8.0.0","intl-messageformat":"^11.1.3","@vitest/coverage-v8":"^3.0.0","@formatjs/intl-pluralrules":"^6.3.10"},"peerDependencies":{"react-native":">=0.72.0","@react-native-async-storage/async-storage":">=1.19.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/react-native_0.4.0_1789629128951_0.40156442721358054"}}},"time":{"created":"2026-07-07T14:54:30.325Z","modified":"2026-09-17T07:12:09.429Z","0.1.0":"2026-07-07T14:54:31.183Z","0.1.1":"2026-07-07T15:44:12.693Z","0.2.0":"2026-07-14T18:04:06.015Z","0.3.0":"2026-07-14T22:36:07.817Z","0.3.1":"2026-07-15T06:07:32.041Z","0.4.0":"2026-09-17T07:12:09.061Z"},"bugs":{"url":"https://github.com/symbionix-sl/airstrings-sdk-react-native/issues"},"author":{"name":"Symbionix","email":"info@symbionix.io"},"license":"MIT","homepage":"https://github.com/symbionix-sl/airstrings-sdk-react-native#readme","keywords":["airstrings","i18n","l10n","localization","internationalization","icu","messageformat","ed25519","cdn","sdk","react-native"],"repository":{"url":"git+https://github.com/symbionix-sl/airstrings-sdk-react-native.git","type":"git"},"description":"AirStrings React Native SDK — fetch, verify, cache, and serve Ed25519-signed localized string bundles","maintainers":[{"name":"symbionixsl","email":"symbionix.sl@gmail.com"}],"readme":"# @airstrings/react-native\n\nThe official **AirStrings React Native SDK** — fetches, verifies, caches, and serves Ed25519-signed localized string bundles from the [AirStrings](https://airstrings.com) CDN.\n\n- **Signed bundles.** Every bundle is verified with Ed25519 before strings are exposed. Tampered or unsigned content is rejected, never served.\n- **Cache-first.** Bundles are cached in AsyncStorage and re-verified on every load. Anti-downgrade: a higher-revision bundle is never replaced by a lower one.\n- **Offline-safe.** Bundled fallback seeds committed bundles at startup, so a cold offline start serves real strings instead of key names.\n- **ICU MessageFormat.** Plurals, selects, number/date formatting via [`intl-messageformat`](https://www.npmjs.com/package/intl-messageformat).\n\n## Install\n\n```bash\nnpm install @airstrings/react-native @react-native-async-storage/async-storage\n```\n\n`@react-native-async-storage/async-storage` is a peer dependency used as the default cache backend. Requires React Native 0.72+.\n\n## Quick start\n\n```ts\nimport { AirStrings } from '@airstrings/react-native'\n\nconst airstrings = new AirStrings({\n  organizationId: 'org_xxx',\n  projectId: 'proj_xxx',\n  environmentId: 'env_xxx',\n  publicKeys: ['BASE64_ED25519_PUBLIC_KEY'],\n  locale: 'en-US',\n  seed: [\n    require('./airstrings/bundles/en-US.json'),\n    require('./airstrings/bundles/ja.json'),\n  ],\n})\n\nairstrings.on('strings:updated', ({ locale, revision }) => {\n  console.log(`Loaded ${locale} (revision ${revision})`)\n})\n\nairstrings.t('greeting')\nairstrings.format('items.count', { count: 3 })\n```\n\nReact integration is a few lines:\n\n```ts\nconst useStrings = (a: AirStrings) =>\n  useSyncExternalStore(\n    (cb) => a.on('strings:updated', cb),\n    () => a.strings,\n  )\n```\n\n## Bundled fallback (offline cold start)\n\n1. Pull published bundles: `airstrings bundles pull`\n2. Commit the resulting `airstrings/bundles/` directory to your repo.\n3. Pass the files via the `seed` option using Metro's `require`, as shown above.\n\nSeed bundles are untrusted input: every candidate runs the full Ed25519 verification pipeline plus `project_id` and locale checks. The highest verified revision wins across cache / seed / network (ties go to the cache), and a winning seed is persisted to the cache. A tampered or wrong-project seed emits `strings:error` and is never served or cached; entries for other locales are skipped silently; a missing seed is a silent no-op. Keep the committed seed fresh by running `airstrings bundles pull` in CI or as a pre-release step.\n\n## String Variants (experiments)\n\nExperiment-backed strings resolve to a variant deterministically from a stable assignment id you supply — no server round-trip, no local state to persist. The same id always maps to the same variant. Experiment definitions are covered by the bundle's Ed25519 signature; if that verification fails, the SDK soft-fails to the base string values (experiment content is never served unverified).\n\n```ts\nairstrings.setAssignmentId(userId) // or null to clear\n\nairstrings.onExposure(({ key, experimentId, variant, locale, assignmentId }) => {\n  analytics.track('experiment_exposure', { key, experimentId, variant, locale, assignmentId })\n})\n\nairstrings.t('cta') // returns the assigned variant's value\n```\n\n`t(key)` / `format(key)` return the assigned variant's value; an `experiment:exposure` event fires once per unique `(key, experimentId, variant, assignmentId)` the first time that string is read, so you can forward exposures to your own analytics.\n\n**Exposure fires once per session.** `onExposure` is deduped per SDK instance — a user re-entering the same screen won't fire it again; it resets on app relaunch (new instance) or when the assignment id changes. This is deliberate: exposure attributes a user to a variant (join to conversions by `assignmentId`). For per-render impression counts, track your own event on view appear.\n\n## Caching & offline\n\n- Bundles are cached per `{projectId}:{environmentId}:{locale}` and re-verified on every load.\n- Offline: cached (or seeded) strings are served; with no cache and no seed, `t(key)` returns the key name. The SDK never throws and never blocks app startup.\n- Conditional requests use ETag / `If-None-Match`, and the SDK auto-refreshes when the app returns to the foreground.\n- Without AsyncStorage the SDK falls back to an in-memory cache (process lifetime only). Any custom backend can be injected via the `store` config option (`BundleStore` interface).\n- ponytail: AsyncStorage is the default cache today; an MMKV adapter can slot in later through the same `BundleStore` interface.\n\n## Demo\n\nA runnable demo lives in [`Demo/`](Demo/) — a single-screen app wired to a fully local stack (Postgres + MinIO + the Go backend). From `Demo/`, run `make setup`, then `make ios` or `make android`. See [Demo/README.md](Demo/README.md).\n\n## ICU formatting on Hermes\n\nICU plural formatting needs `Intl.PluralRules`, which the default Hermes engine (iOS and Android) does not ship. The SDK bundles a guarded `Intl.PluralRules` polyfill with plural-rules data for `en`, `fr`, and `es`, so plurals format out of the box for those locales — the polyfill is applied only when the native API is missing, so it's a no-op on engines that already provide it. `Intl.NumberFormat` (used to format `#`) is present natively on Hermes. For locales beyond the bundled set, `format()` falls back to the raw ICU pattern.\n\nTo add locales, install `@formatjs/intl-pluralrules` in your app and import their plural-rules data after the SDK (it registers on the same polyfilled `Intl.PluralRules`):\n\n```ts\nimport '@airstrings/react-native'\nimport '@formatjs/intl-pluralrules/locale-data/de'\n```\n\n## License\n\nMIT © [Symbionix](https://symbionix.io)\n","readmeFilename":"README.md"}