AI Wrapper Core

ProReact Native · Expo

What a store expects of an AI wrapper, in one folder: a versioned consent gate with withdraw, paywall rules without the screen, report, block and filter hooks, share card, delete account, published contact, photo deletion timer, self-photo attestation, an AI-generated label, privacy disclosure text and a client for the server proxy.

View as Markdown

Installation

$ npx shadcn@latest add @goodui-native-pro/ai-core

Then run npx expo install --fix so @react-native-async-storage/async-storage, expo-image-picker, expo-notifications, expo-sharing, react-native-view-shot match your Expo SDK. Files land in components/goodui-native/ai-core.

Pro screens install from the license-gated @goodui-native-pro registry. Setup: Pro access.

Usage

import { useAiConsent } from "@/components/goodui-native/ai-core/consent";
import { ConsentRow } from "@/components/goodui-native/ai-core/consent-row";
import { deviceStorage } from "@/components/goodui-native/ai-core/device";

const consent = useAiConsent({ version: 2, provider: "OpenAI", storage: deviceStorage });
if (!consent.granted) router.push("/consent");

<ConsentRow consent={consent} provider="OpenAI" onReview={() => router.push("/consent")} />

When to use

Use it for
  • Any app that sends a person's data to a third-party model.
  • Any app that generates images or text a person can save or share.
Reach for something else
  • AI that runs fully on the device: there is no third party to disclose, though the label and report rules can still apply.

API reference

AiLabel

PropTypeDefault
kind"generated" | "written""generated"
tone
`scrim` sits on a picture; `plain` sits on the page.
"scrim" | "plain""plain"
labelsPartial<AiLabelLabels>—
style
Style for the outer container.
StyleProp<ViewStyle>—
testID
Identifier for end-to-end tests.
string—

PaywallLegal

PropTypeDefault
model*PaywallModel—
onRestore*() => unknown—
onTerms*() => void—
onPrivacy*() => void—
onNotNow
Quiet way out. Leave the paywall from here; do not open a second offer.
() => void—
style
Style for the outer container.
StyleProp<ViewStyle>—
testID
Identifier for end-to-end tests.
string—

ConsentRow

PropTypeDefault
consent*AiConsent—
provider*string—
onReview*
Opens the consent screen again.
() => void—
labelsPartial<ConsentRowLabels>—
style
Style for the outer container.
StyleProp<ViewStyle>—
testID
Identifier for end-to-end tests.
string—

ContactRow

PropTypeDefault
email*
Published on the row, where a reviewer can see it (App Store 1.2).
string—
subjectstring—
labelsPartial<ContactRowLabels>—
style
Style for the outer container.
StyleProp<ViewStyle>—
testID
Identifier for end-to-end tests.
string—

DeleteAccount

PropTypeDefault
onDelete*
Calls the server, clears local data, then send the person back to the start. Reject to show the error line.
() => Promise<unknown>—
labelsPartial<DeleteAccountLabels>—
style
Style for the outer container.
StyleProp<ViewStyle>—
testID
Identifier for end-to-end tests.
string—

PhotoRetention

PropTypeDefault
deleteAt*
When the server deletes the uploads, in ms. Null once they are gone.
number | null—
onDeleteNow*
Deletes the uploads right away.
() => void—
labelsPartial<PhotoRetentionLabels>—
style
Style for the outer container.
StyleProp<ViewStyle>—
testID
Identifier for end-to-end tests.
string—

SelfAttestation

PropTypeDefault
minimumAgenumber18
onChange*
True once every box is ticked. Hold the upload until then.
(attested: boolean) => void—
labelsPartial<SelfAttestationLabels>—
style
Style for the outer container.
StyleProp<ViewStyle>—
testID
Identifier for end-to-end tests.
string—

ShareCard

PropTypeDefault
cardRef
Pass the same ref to `shareView`.
RefObject<ComponentRef<typeof View> | null>—
children*
The art. Pass the template's own card: this frame owns size and the mark, not the look.
ReactNode—
brand*
Your app's name, drawn into the picture, so a shared card carries the source.
ReactNode—
aspectRatio
Width over height. 4:5 suits feeds and Stories crops.
number0.8
widthnumber360
background*string—
showAiLabel
Leave the label on. Article 50 expects output to be marked.
booleantrue
style
Style for the outer container.
StyleProp<ViewStyle>—
testID
Identifier for end-to-end tests.
string—

Motion and haptics

  • None of its own. Sheets and holds inherit the kit's motion.
  • Haptic: tap on rows, the hold-to-confirm haptics on delete.
  • PhotoRetention ticks once a second and only while mounted.

Accessibility

  • Every row is a named button or link. Status changes on ConsentRow and PhotoRetention use a live region where the state is read out.

Notes for AI

  • Import device.ts directly. It is not in the kit index because it needs five native packages. Those packages are in each AI template.
  • Check consent.granted before every send, not only at launch.
  • The client filter is a convenience. Real moderation runs on the server.
  • Bump the consent version when the provider or the data sent changes.
  • A custom paywall must use usePaywallModel and PaywallLegal; check-kit reads template paywalls.
  • Copy in PhotoRetention and ContactRow makes promises. Keep them true for your server and your support.