@ankhorage/expo-runtime 0.0.0 → 0.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 (47) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +3 -0
  3. package/dist/ExpoBarcodeScannerAdapter.d.ts +4 -0
  4. package/dist/ExpoBarcodeScannerAdapter.d.ts.map +1 -0
  5. package/dist/ExpoBarcodeScannerAdapter.js +49 -0
  6. package/dist/ExpoBarcodeScannerAdapter.js.map +1 -0
  7. package/dist/ExpoRuntimeProviders.d.ts +8 -0
  8. package/dist/ExpoRuntimeProviders.d.ts.map +1 -0
  9. package/dist/ExpoRuntimeProviders.js +11 -0
  10. package/dist/ExpoRuntimeProviders.js.map +1 -0
  11. package/dist/barcodeScanRuntime.d.ts +15 -0
  12. package/dist/barcodeScanRuntime.d.ts.map +1 -0
  13. package/dist/barcodeScanRuntime.js +48 -0
  14. package/dist/barcodeScanRuntime.js.map +1 -0
  15. package/dist/componentRegistry.d.ts +4 -0
  16. package/dist/componentRegistry.d.ts.map +1 -0
  17. package/dist/componentRegistry.js +6 -0
  18. package/dist/componentRegistry.js.map +1 -0
  19. package/dist/createExpoRuntimeRegistry.d.ts +3 -0
  20. package/dist/createExpoRuntimeRegistry.d.ts.map +1 -0
  21. package/dist/createExpoRuntimeRegistry.js +14 -0
  22. package/dist/createExpoRuntimeRegistry.js.map +1 -0
  23. package/dist/index.d.ts +8 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +6 -2
  26. package/dist/index.js.map +1 -1
  27. package/dist/permissionRuntime.d.ts +3 -0
  28. package/dist/permissionRuntime.d.ts.map +1 -0
  29. package/dist/permissionRuntime.js +3 -0
  30. package/dist/permissionRuntime.js.map +1 -0
  31. package/dist/resolveExpoRuntimePlan.d.ts +53 -0
  32. package/dist/resolveExpoRuntimePlan.d.ts.map +1 -0
  33. package/dist/resolveExpoRuntimePlan.js +215 -0
  34. package/dist/resolveExpoRuntimePlan.js.map +1 -0
  35. package/package.json +19 -4
  36. package/src/ExpoBarcodeScannerAdapter.test.tsx +75 -0
  37. package/src/ExpoBarcodeScannerAdapter.tsx +84 -0
  38. package/src/ExpoRuntimeProviders.test.tsx +61 -0
  39. package/src/ExpoRuntimeProviders.tsx +21 -0
  40. package/src/barcodeScanRuntime.ts +78 -0
  41. package/src/componentRegistry.ts +11 -0
  42. package/src/createExpoRuntimeRegistry.test.tsx +31 -0
  43. package/src/createExpoRuntimeRegistry.tsx +17 -0
  44. package/src/index.ts +20 -1
  45. package/src/permissionRuntime.ts +2 -0
  46. package/src/resolveExpoRuntimePlan.test.ts +212 -0
  47. package/src/resolveExpoRuntimePlan.ts +337 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveExpoRuntimePlan.js","sourceRoot":"","sources":["../src/resolveExpoRuntimePlan.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AnkhorageCapabilityName,\n AppManifest,\n ScreenCapabilityRequirement,\n ScreenPermissionRequirement,\n} from '@ankhorage/contracts';\nimport type { Permission } from '@ankhorage/permissions';\nimport { isPermission } from '@ankhorage/permissions';\nimport {\n EXPO_PERMISSION_SUPPORT,\n type ExpoPermissionMetadata,\n type PermissionSupport,\n} from '@ankhorage/permissions/expo/manifest';\n\ninterface ExpoRuntimeDependency {\n readonly name: string;\n readonly version: string;\n readonly reasons: readonly string[];\n}\n\ninterface ExpoRuntimeConfigPlugin {\n readonly name: string;\n readonly options?: Readonly<Record<string, boolean | string>>;\n}\n\nexport type ExpoRuntimeProviderId = 'permissions';\nexport type ExpoRuntimeAdapterId = 'ExpoBarcodeScannerAdapter';\n\ninterface ExpoRuntimeDiagnostic {\n readonly severity: 'error' | 'warning';\n readonly requirementType: 'capability' | 'configHint' | 'package' | 'permission';\n readonly requirement: string;\n readonly message: string;\n readonly support?: PermissionSupport;\n}\n\nexport interface ExpoRuntimePlan {\n readonly permissions: readonly ScreenPermissionRequirement[];\n readonly capabilities: readonly ScreenCapabilityRequirement[];\n readonly impliedPermissions: readonly ScreenPermissionRequirement[];\n readonly dependencies: readonly ExpoRuntimeDependency[];\n readonly nativeConfig: {\n readonly androidPermissions: readonly string[];\n readonly configHints: readonly string[];\n readonly plugins: readonly ExpoRuntimeConfigPlugin[];\n };\n readonly providers: readonly ExpoRuntimeProviderId[];\n readonly runtimeAdapters: readonly ExpoRuntimeAdapterId[];\n readonly usesExpoRuntimeRegistry: boolean;\n readonly needsPermissionsProvider: boolean;\n readonly diagnostics: readonly ExpoRuntimeDiagnostic[];\n}\n\ninterface ExpoRuntimeCapabilityMetadata {\n readonly impliedPermissions?: readonly ScreenPermissionRequirement[];\n readonly requiredPackages?: readonly string[];\n readonly providers?: readonly ExpoRuntimeProviderId[];\n readonly runtimeAdapters?: readonly ExpoRuntimeAdapterId[];\n readonly androidPermissions?: readonly string[];\n readonly plugins?: readonly ExpoRuntimeConfigPlugin[];\n}\n\ninterface ExpoRuntimeHintMetadata {\n readonly androidPermissions?: readonly string[];\n readonly plugin?: ExpoRuntimeConfigPlugin;\n}\n\ninterface ResolveExpoRuntimePlanOptions {\n readonly capabilityRegistry?: Readonly<\n Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>\n >;\n readonly dependencyVersions?: Readonly<Record<string, string>>;\n readonly permissionSupport?: Readonly<Record<Permission, ExpoPermissionMetadata>>;\n}\n\nconst CAMERA_ANDROID_PERMISSION = 'android.permission.CAMERA';\nconst EXPO_RUNTIME_PACKAGE_NAME = '@ankhorage/expo-runtime';\n\nconst GENERATED_EXPO_DEPENDENCY_VERSIONS = {\n '@ankhorage/permissions': '^0.2.0',\n '@ankhorage/expo-runtime': 'latest',\n 'expo-camera': '~17.0.10',\n} as const satisfies Record<string, string>;\n\nconst EXPO_RUNTIME_PROVIDER_PACKAGES = {\n permissions: '@ankhorage/permissions',\n} as const satisfies Record<ExpoRuntimeProviderId, string>;\n\nconst EXPO_RUNTIME_CONFIG_HINTS = {\n cameraPermission: {\n androidPermissions: [CAMERA_ANDROID_PERMISSION],\n plugin: {\n name: 'expo-camera',\n options: {\n cameraPermission: 'Allow camera access.',\n },\n },\n },\n} as const satisfies Readonly<Record<string, ExpoRuntimeHintMetadata>>;\n\nconst EXPO_CAPABILITY_RUNTIME_REGISTRY = {\n barcodeScanner: {\n impliedPermissions: [{ permission: 'camera' }],\n requiredPackages: ['expo-camera'],\n providers: ['permissions'],\n runtimeAdapters: ['ExpoBarcodeScannerAdapter'],\n androidPermissions: [CAMERA_ANDROID_PERMISSION],\n plugins: [\n {\n name: 'expo-camera',\n options: {\n cameraPermission: 'Allow camera access to scan barcodes.',\n },\n },\n ],\n },\n} as const satisfies Readonly<\n Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>\n>;\n\nexport function resolveExpoRuntimePlan(\n manifest: AppManifest,\n options: ResolveExpoRuntimePlanOptions = {},\n): ExpoRuntimePlan {\n const permissionsByName = new Map<string, ScreenPermissionRequirement>();\n const impliedPermissionsByName = new Map<string, ScreenPermissionRequirement>();\n const capabilitiesByName = new Map<string, ScreenCapabilityRequirement>();\n\n for (const screen of Object.values(manifest.screens)) {\n screen.requires?.permissions?.forEach((requirement) => {\n permissionsByName.set(requirement.permission, requirement);\n });\n screen.requires?.capabilities?.forEach((requirement) => {\n capabilitiesByName.set(requirement.capability, requirement);\n });\n }\n\n const capabilityRegistry: Readonly<\n Partial<Record<AnkhorageCapabilityName, ExpoRuntimeCapabilityMetadata>>\n > = options.capabilityRegistry ?? EXPO_CAPABILITY_RUNTIME_REGISTRY;\n\n for (const capabilityRequirement of capabilitiesByName.values()) {\n capabilityRegistry[capabilityRequirement.capability]?.impliedPermissions?.forEach(\n (permissionRequirement: ScreenPermissionRequirement) => {\n if (!permissionsByName.has(permissionRequirement.permission)) {\n permissionsByName.set(permissionRequirement.permission, permissionRequirement);\n impliedPermissionsByName.set(permissionRequirement.permission, permissionRequirement);\n }\n },\n );\n }\n\n const diagnostics: ExpoRuntimeDiagnostic[] = [];\n const dependencies = new Map<string, ExpoRuntimeDependency>();\n const pluginOptions = new Map<string, Record<string, boolean | string>>();\n const configHints = new Set<string>();\n const androidPermissions = new Set<string>();\n const providers = new Set<ExpoRuntimeProviderId>();\n const runtimeAdapters = new Set<ExpoRuntimeAdapterId>();\n const dependencyVersions: Readonly<Record<string, string>> =\n options.dependencyVersions ?? GENERATED_EXPO_DEPENDENCY_VERSIONS;\n const permissionSupport = options.permissionSupport ?? EXPO_PERMISSION_SUPPORT;\n const configHintRegistry: Readonly<Record<string, ExpoRuntimeHintMetadata>> =\n EXPO_RUNTIME_CONFIG_HINTS;\n\n const addDependency = (name: string, reason: string) => {\n const version = dependencyVersions[name];\n if (version === undefined) {\n diagnostics.push({\n severity: 'warning',\n requirementType: 'package',\n requirement: name,\n message: `No generated-app dependency version is registered for '${name}'.`,\n });\n return;\n }\n\n const existing = dependencies.get(name);\n if (existing) {\n dependencies.set(name, {\n ...existing,\n reasons: Array.from(new Set([...existing.reasons, reason])),\n });\n return;\n }\n\n dependencies.set(name, {\n name,\n version,\n reasons: [reason],\n });\n };\n\n const addProvider = (provider: ExpoRuntimeProviderId, reason: string) => {\n providers.add(provider);\n addDependency(EXPO_RUNTIME_PROVIDER_PACKAGES[provider], reason);\n };\n\n const addPlugin = (plugin: ExpoRuntimeConfigPlugin) => {\n const existingOptions = pluginOptions.get(plugin.name) ?? {};\n pluginOptions.set(plugin.name, {\n ...existingOptions,\n ...(plugin.options ?? {}),\n });\n };\n\n for (const permissionRequirement of permissionsByName.values()) {\n if (!isPermission(permissionRequirement.permission)) {\n diagnostics.push({\n severity: 'error',\n requirementType: 'permission',\n requirement: permissionRequirement.permission,\n message: `Unknown permission '${permissionRequirement.permission}' cannot be resolved for Expo runtime generation.`,\n });\n continue;\n }\n\n const supportMetadata = permissionSupport[permissionRequirement.permission];\n if (\n supportMetadata.support === 'unsupported' ||\n supportMetadata.support === 'notImplemented' ||\n supportMetadata.support === 'limited'\n ) {\n diagnostics.push({\n severity: supportMetadata.support === 'limited' ? 'warning' : 'error',\n requirementType: 'permission',\n requirement: permissionRequirement.permission,\n message: `Expo runtime support for '${permissionRequirement.permission}' is '${supportMetadata.support}'.`,\n support: supportMetadata.support,\n });\n continue;\n }\n\n if (supportMetadata.support === 'notRequired') {\n continue;\n }\n\n addProvider('permissions', `permission:${permissionRequirement.permission}`);\n supportMetadata.requiredPackages.forEach((packageName) => {\n addDependency(packageName, `permission:${permissionRequirement.permission}`);\n });\n\n supportMetadata.configHints.forEach((configHint) => {\n configHints.add(configHint);\n const configHintMetadata = configHintRegistry[configHint];\n if (!configHintMetadata) {\n diagnostics.push({\n severity: 'warning',\n requirementType: 'configHint',\n requirement: configHint,\n message: `Config hint '${configHint}' is not translated into generated Expo config yet.`,\n });\n return;\n }\n\n configHintMetadata.androidPermissions?.forEach((permissionName) => {\n androidPermissions.add(permissionName);\n });\n if (configHintMetadata.plugin) {\n addPlugin(configHintMetadata.plugin);\n }\n });\n }\n\n for (const capabilityRequirement of capabilitiesByName.values()) {\n const capabilityMetadata = capabilityRegistry[capabilityRequirement.capability];\n if (!capabilityMetadata) {\n diagnostics.push({\n severity: 'warning',\n requirementType: 'capability',\n requirement: capabilityRequirement.capability,\n message: `No Expo runtime metadata is registered for capability '${capabilityRequirement.capability}'.`,\n });\n continue;\n }\n\n capabilityMetadata.requiredPackages?.forEach((packageName) => {\n addDependency(packageName, `capability:${capabilityRequirement.capability}`);\n });\n capabilityMetadata.providers?.forEach((provider) => {\n addProvider(provider, `capability:${capabilityRequirement.capability}`);\n });\n capabilityMetadata.runtimeAdapters?.forEach((runtimeAdapter) => {\n runtimeAdapters.add(runtimeAdapter);\n });\n capabilityMetadata.androidPermissions?.forEach((permissionName) => {\n androidPermissions.add(permissionName);\n });\n capabilityMetadata.plugins?.forEach(addPlugin);\n }\n\n if (providers.size > 0 || runtimeAdapters.size > 0) {\n addDependency(EXPO_RUNTIME_PACKAGE_NAME, 'runtime:expo');\n }\n\n const plugins = Array.from(pluginOptions.entries())\n .map(([name, options]) => ({\n name,\n options: Object.keys(options).length > 0 ? options : undefined,\n }))\n .sort((left, right) => left.name.localeCompare(right.name));\n\n return {\n permissions: Array.from(permissionsByName.values()).sort(comparePermissionRequirements),\n capabilities: Array.from(capabilitiesByName.values()).sort(compareCapabilityRequirements),\n impliedPermissions: Array.from(impliedPermissionsByName.values()).sort(\n comparePermissionRequirements,\n ),\n dependencies: Array.from(dependencies.values()).sort((left, right) =>\n left.name.localeCompare(right.name),\n ),\n nativeConfig: {\n androidPermissions: Array.from(androidPermissions).sort(),\n configHints: Array.from(configHints).sort(),\n plugins,\n },\n providers: Array.from(providers).sort(),\n runtimeAdapters: Array.from(runtimeAdapters).sort(),\n usesExpoRuntimeRegistry: runtimeAdapters.size > 0,\n needsPermissionsProvider: providers.has('permissions'),\n diagnostics,\n };\n}\n\nfunction compareCapabilityRequirements(\n left: ScreenCapabilityRequirement,\n right: ScreenCapabilityRequirement,\n): number {\n return left.capability.localeCompare(right.capability);\n}\n\nfunction comparePermissionRequirements(\n left: ScreenPermissionRequirement,\n right: ScreenPermissionRequirement,\n): number {\n return left.permission.localeCompare(right.permission);\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ankhorage/expo-runtime",
3
3
  "type": "module",
4
- "version": "0.0.0",
4
+ "version": "0.0.2",
5
5
  "description": "Declarative runtime integration for Expo apps: maps app capabilities to permissions, packages, config plugins, providers, and adapters",
6
6
  "homepage": "https://github.com/ankhorage/expo-runtime#readme",
7
7
  "bugs": {
@@ -10,7 +10,7 @@
10
10
  "license": "MIT",
11
11
  "main": "./dist/index.js",
12
12
  "sideEffects": false,
13
- "types": "./dist/index.d.ts",
13
+ "types": "./src/index.ts",
14
14
  "repository": {
15
15
  "type": "git",
16
16
  "url": "git+https://github.com/ankhorage/expo-runtime.git"
@@ -21,7 +21,11 @@
21
21
  "expo",
22
22
  "runtime"
23
23
  ],
24
- "dependencies": {},
24
+ "dependencies": {
25
+ "@ankhorage/contracts": "^1.18.0",
26
+ "@ankhorage/permissions": "^0.2.0",
27
+ "@ankhorage/zora": "^2.8.0"
28
+ },
25
29
  "files": [
26
30
  "dist",
27
31
  "src",
@@ -34,7 +38,7 @@
34
38
  ".": {
35
39
  "react-native": "./src/index.ts",
36
40
  "browser": "./src/index.ts",
37
- "types": "./dist/index.d.ts",
41
+ "types": "./src/index.ts",
38
42
  "import": "./dist/index.js",
39
43
  "default": "./dist/index.js"
40
44
  }
@@ -57,12 +61,23 @@
57
61
  "typecheck": "bun x tsc --noEmit -p tsconfig.json",
58
62
  "version-packages": "changeset version"
59
63
  },
64
+ "peerDependencies": {
65
+ "expo": "~54.0.34",
66
+ "expo-camera": "~17.0.10",
67
+ "react": "19.1.0",
68
+ "react-native": "0.81.5"
69
+ },
60
70
  "devDependencies": {
61
71
  "@ankhorage/devtools": "^1.0.6",
62
72
  "@ankhorage/paradox": "^0.1.10",
63
73
  "@changesets/cli": "^2.31.0",
64
74
  "@types/bun": "^1.3.13",
65
75
  "@types/node": "^25.6.0",
76
+ "@types/react": "^19.2.14",
77
+ "expo": "~54.0.34",
78
+ "expo-camera": "~17.0.10",
79
+ "react": "19.1.0",
80
+ "react-native": "0.81.5",
66
81
  "typescript": "^5.9.3"
67
82
  },
68
83
  "packageManager": "bun@1.3.13"
@@ -0,0 +1,75 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+
3
+ import {
4
+ BARCODE_SCAN_DEDUPE_WINDOW_MS,
5
+ BARCODE_SCANNER_TYPES,
6
+ mapPermissionStatusToCameraPermissionStatus,
7
+ normalizeExpoBarcodeScanResult,
8
+ shouldIgnoreBarcodeScan,
9
+ } from './barcodeScanRuntime';
10
+
11
+ describe('ExpoBarcodeScannerAdapter helpers', () => {
12
+ it('normalizes Expo barcode scan payloads for the runtime event pipeline', () => {
13
+ expect(
14
+ normalizeExpoBarcodeScanResult({
15
+ data: ' 0123456789 ',
16
+ type: 'ean13',
17
+ }),
18
+ ).toEqual({
19
+ value: '0123456789',
20
+ type: 'ean13',
21
+ });
22
+ });
23
+
24
+ it('drops empty scan payloads', () => {
25
+ expect(
26
+ normalizeExpoBarcodeScanResult({
27
+ data: ' ',
28
+ type: 'qr',
29
+ }),
30
+ ).toBeNull();
31
+ });
32
+
33
+ it('suppresses repeated scans inside the dedupe window', () => {
34
+ expect(
35
+ shouldIgnoreBarcodeScan(
36
+ {
37
+ value: '0123456789',
38
+ type: 'ean13',
39
+ timestamp: 1_000,
40
+ },
41
+ {
42
+ value: '0123456789',
43
+ type: 'ean13',
44
+ },
45
+ 1_000 + BARCODE_SCAN_DEDUPE_WINDOW_MS - 1,
46
+ ),
47
+ ).toBe(true);
48
+ expect(
49
+ shouldIgnoreBarcodeScan(
50
+ {
51
+ value: '0123456789',
52
+ type: 'ean13',
53
+ timestamp: 1_000,
54
+ },
55
+ {
56
+ value: '0123456789',
57
+ type: 'ean13',
58
+ },
59
+ 1_000 + BARCODE_SCAN_DEDUPE_WINDOW_MS,
60
+ ),
61
+ ).toBe(false);
62
+ });
63
+
64
+ it('maps permission states into the ZORA camera permission surface', () => {
65
+ expect(mapPermissionStatusToCameraPermissionStatus('unknown', false)).toBe('unknown');
66
+ expect(mapPermissionStatusToCameraPermissionStatus('granted', false)).toBe('granted');
67
+ expect(mapPermissionStatusToCameraPermissionStatus('denied', false)).toBe('denied');
68
+ expect(mapPermissionStatusToCameraPermissionStatus('blocked', true)).toBe('requesting');
69
+ });
70
+
71
+ it('keeps the exported scanner barcode type allowlist intact', () => {
72
+ expect(BARCODE_SCANNER_TYPES).toContain('qr');
73
+ expect(BARCODE_SCANNER_TYPES).toContain('ean13');
74
+ });
75
+ });
@@ -0,0 +1,84 @@
1
+ import { Permission, usePermission } from '@ankhorage/permissions';
2
+ import { BarcodeScannerView, type BarcodeScannerViewProps } from '@ankhorage/zora';
3
+ import { type BarcodeScanningResult, type BarcodeType, CameraView } from 'expo-camera';
4
+ import React from 'react';
5
+ import { StyleSheet } from 'react-native';
6
+
7
+ import {
8
+ BARCODE_SCANNER_TYPES,
9
+ type BarcodeScanRecord,
10
+ mapPermissionStatusToCameraPermissionStatus,
11
+ normalizeExpoBarcodeScanResult,
12
+ shouldIgnoreBarcodeScan,
13
+ } from './barcodeScanRuntime';
14
+
15
+ const CAMERA_BARCODE_TYPES: BarcodeType[] = [...BARCODE_SCANNER_TYPES];
16
+
17
+ export function ExpoBarcodeScannerAdapter(props: BarcodeScannerViewProps) {
18
+ const { onBarcodeScanned, onRequestPermission, ...viewProps } = props;
19
+ const cameraPermission = usePermission(Permission.Camera);
20
+ const [isRequestingPermission, setIsRequestingPermission] = React.useState(false);
21
+ const lastScanRef = React.useRef<BarcodeScanRecord | null>(null);
22
+
23
+ const permissionStatus = mapPermissionStatusToCameraPermissionStatus(
24
+ cameraPermission.status,
25
+ isRequestingPermission,
26
+ );
27
+
28
+ const handleRequestPermission = React.useCallback(async () => {
29
+ setIsRequestingPermission(true);
30
+ try {
31
+ await cameraPermission.request();
32
+ await onRequestPermission?.();
33
+ } finally {
34
+ setIsRequestingPermission(false);
35
+ }
36
+ }, [cameraPermission, onRequestPermission]);
37
+
38
+ const handleBarcodeScanned = React.useCallback(
39
+ (result: BarcodeScanningResult) => {
40
+ void (async () => {
41
+ const normalizedResult = normalizeExpoBarcodeScanResult(result);
42
+ if (normalizedResult === null) {
43
+ return;
44
+ }
45
+
46
+ const now = Date.now();
47
+ if (shouldIgnoreBarcodeScan(lastScanRef.current, normalizedResult, now)) {
48
+ return;
49
+ }
50
+
51
+ lastScanRef.current = {
52
+ ...normalizedResult,
53
+ timestamp: now,
54
+ };
55
+ await onBarcodeScanned?.(normalizedResult);
56
+ })();
57
+ },
58
+ [onBarcodeScanned],
59
+ );
60
+
61
+ const camera =
62
+ permissionStatus === 'granted' ? (
63
+ <CameraView
64
+ barcodeScannerSettings={{ barcodeTypes: CAMERA_BARCODE_TYPES }}
65
+ onBarcodeScanned={handleBarcodeScanned}
66
+ style={styles.camera}
67
+ />
68
+ ) : undefined;
69
+
70
+ return (
71
+ <BarcodeScannerView
72
+ {...viewProps}
73
+ camera={camera}
74
+ onRequestPermission={handleRequestPermission}
75
+ permissionStatus={permissionStatus}
76
+ />
77
+ );
78
+ }
79
+
80
+ const styles = StyleSheet.create({
81
+ camera: {
82
+ flex: 1,
83
+ },
84
+ });
@@ -0,0 +1,61 @@
1
+ import { afterEach, describe, expect, it, mock } from 'bun:test';
2
+ import React from 'react';
3
+
4
+ describe('ExpoRuntimeProviders', () => {
5
+ afterEach(() => {
6
+ mock.restore();
7
+ });
8
+
9
+ it('wraps children in PermissionsProvider when the permissions runtime is enabled', async () => {
10
+ const permissionClient = { name: 'permission-client' };
11
+ const PermissionsProvider = ({
12
+ children,
13
+ client,
14
+ }: {
15
+ children: React.ReactNode;
16
+ client: unknown;
17
+ }) => React.createElement('permissions-provider', { client }, children);
18
+
19
+ void mock.module('./permissionRuntime', () => ({
20
+ PermissionsProvider,
21
+ createPermissionClient: () => permissionClient,
22
+ }));
23
+
24
+ const { ExpoRuntimeProviders } = await import('./ExpoRuntimeProviders');
25
+ const child = React.createElement('child');
26
+ const element = ExpoRuntimeProviders({
27
+ children: child,
28
+ providers: ['permissions'],
29
+ });
30
+
31
+ expect(React.isValidElement(element)).toBe(true);
32
+ if (!React.isValidElement(element)) {
33
+ throw new Error('expected a React element');
34
+ }
35
+
36
+ expect(element.type).toBe(PermissionsProvider);
37
+ expect(element.props.client).toBe(permissionClient);
38
+ expect(element.props.children).toBe(child);
39
+ });
40
+
41
+ it('returns children unchanged when no runtime providers are enabled', async () => {
42
+ void mock.module('./permissionRuntime', () => ({
43
+ PermissionsProvider: ({ children }: { children: React.ReactNode }) => children,
44
+ createPermissionClient: () => ({ name: 'permission-client' }),
45
+ }));
46
+
47
+ const { ExpoRuntimeProviders } = await import('./ExpoRuntimeProviders');
48
+ const child = React.createElement('child');
49
+ const element = ExpoRuntimeProviders({
50
+ children: child,
51
+ providers: [],
52
+ });
53
+
54
+ expect(React.isValidElement(element)).toBe(true);
55
+ if (!React.isValidElement(element)) {
56
+ throw new Error('expected a React element');
57
+ }
58
+
59
+ expect(element.props.children).toBe(child);
60
+ });
61
+ });
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+
3
+ import { createPermissionClient, PermissionsProvider } from './permissionRuntime';
4
+ import type { ExpoRuntimeProviderId } from './resolveExpoRuntimePlan';
5
+
6
+ const permissionClient = createPermissionClient();
7
+
8
+ export interface ExpoRuntimeProvidersProps {
9
+ readonly children: React.ReactNode;
10
+ readonly providers?: readonly ExpoRuntimeProviderId[];
11
+ }
12
+
13
+ export function ExpoRuntimeProviders(props: ExpoRuntimeProvidersProps) {
14
+ const { children, providers = [] } = props;
15
+
16
+ if (providers.includes('permissions')) {
17
+ return <PermissionsProvider client={permissionClient}>{children}</PermissionsProvider>;
18
+ }
19
+
20
+ return <>{children}</>;
21
+ }
@@ -0,0 +1,78 @@
1
+ import type { PermissionStatus } from '@ankhorage/permissions';
2
+ import type { BarcodeScanResult, CameraPermissionStatus } from '@ankhorage/zora';
3
+
4
+ export const BARCODE_SCAN_DEDUPE_WINDOW_MS = 1500;
5
+
6
+ export const BARCODE_SCANNER_TYPES = [
7
+ 'aztec',
8
+ 'code128',
9
+ 'code39',
10
+ 'code93',
11
+ 'datamatrix',
12
+ 'ean13',
13
+ 'ean8',
14
+ 'itf14',
15
+ 'pdf417',
16
+ 'qr',
17
+ 'upc_a',
18
+ 'upc_e',
19
+ ] as const;
20
+
21
+ export interface BarcodeScanRecord extends BarcodeScanResult {
22
+ readonly timestamp: number;
23
+ }
24
+
25
+ export interface ExpoBarcodeScanResultLike {
26
+ readonly data: string;
27
+ readonly type?: string;
28
+ }
29
+
30
+ export function mapPermissionStatusToCameraPermissionStatus(
31
+ status: PermissionStatus,
32
+ isRequestingPermission: boolean,
33
+ ): CameraPermissionStatus {
34
+ if (isRequestingPermission) {
35
+ return 'requesting';
36
+ }
37
+
38
+ switch (status) {
39
+ case 'granted':
40
+ return 'granted';
41
+ case 'unknown':
42
+ return 'unknown';
43
+ default:
44
+ return 'denied';
45
+ }
46
+ }
47
+
48
+ export function normalizeExpoBarcodeScanResult(
49
+ result: ExpoBarcodeScanResultLike,
50
+ ): BarcodeScanResult | null {
51
+ const value = result.data.trim();
52
+ if (value.length === 0) {
53
+ return null;
54
+ }
55
+
56
+ const type = typeof result.type === 'string' && result.type.length > 0 ? result.type : undefined;
57
+
58
+ return {
59
+ value,
60
+ type,
61
+ };
62
+ }
63
+
64
+ export function shouldIgnoreBarcodeScan(
65
+ previous: BarcodeScanRecord | null,
66
+ next: BarcodeScanResult,
67
+ now: number,
68
+ ): boolean {
69
+ if (previous === null) {
70
+ return false;
71
+ }
72
+
73
+ return (
74
+ previous.value === next.value &&
75
+ previous.type === next.type &&
76
+ now - previous.timestamp < BARCODE_SCAN_DEDUPE_WINDOW_MS
77
+ );
78
+ }
@@ -0,0 +1,11 @@
1
+ import type React from 'react';
2
+
3
+ export type ComponentRegistry = Record<string, React.ElementType>;
4
+
5
+ export function createComponentRegistry(
6
+ ...registries: readonly ComponentRegistry[]
7
+ ): ComponentRegistry {
8
+ return registries.reduce<ComponentRegistry>((mergedRegistry, registry) => {
9
+ return { ...mergedRegistry, ...registry };
10
+ }, {});
11
+ }
@@ -0,0 +1,31 @@
1
+ import { afterEach, describe, expect, it, mock } from 'bun:test';
2
+ import React from 'react';
3
+
4
+ const BaseBarcodeScannerView = (): React.ReactElement => React.createElement(React.Fragment);
5
+ const BaseText = (): React.ReactElement => React.createElement(React.Fragment);
6
+ const MockExpoBarcodeScannerAdapter = (): React.ReactElement => React.createElement(React.Fragment);
7
+
8
+ describe('createExpoRuntimeRegistry', () => {
9
+ afterEach(() => {
10
+ mock.restore();
11
+ });
12
+
13
+ it('overrides BarcodeScannerView while preserving unrelated registry entries', async () => {
14
+ void mock.module('./ExpoBarcodeScannerAdapter', () => ({
15
+ ExpoBarcodeScannerAdapter: MockExpoBarcodeScannerAdapter,
16
+ }));
17
+
18
+ const { createExpoRuntimeRegistry } = await import('./createExpoRuntimeRegistry');
19
+ const baseRegistry = {
20
+ BarcodeScannerView: BaseBarcodeScannerView,
21
+ Text: BaseText,
22
+ };
23
+
24
+ const registry = createExpoRuntimeRegistry(baseRegistry);
25
+
26
+ expect(registry).not.toBe(baseRegistry);
27
+ expect(registry.Text).toBe(BaseText);
28
+ expect(registry.BarcodeScannerView).not.toBe(BaseBarcodeScannerView);
29
+ expect(typeof registry.BarcodeScannerView).toBe('function');
30
+ });
31
+ });
@@ -0,0 +1,17 @@
1
+ import { type BarcodeScannerViewProps } from '@ankhorage/zora';
2
+ import React from 'react';
3
+
4
+ import { type ComponentRegistry, createComponentRegistry } from './componentRegistry';
5
+ import { ExpoBarcodeScannerAdapter } from './ExpoBarcodeScannerAdapter';
6
+
7
+ const EXPO_RUNTIME_OVERRIDES: ComponentRegistry = {
8
+ BarcodeScannerView: ExpoBarcodeScannerView,
9
+ };
10
+
11
+ export function createExpoRuntimeRegistry(baseRegistry: ComponentRegistry): ComponentRegistry {
12
+ return createComponentRegistry(baseRegistry, EXPO_RUNTIME_OVERRIDES);
13
+ }
14
+
15
+ function ExpoBarcodeScannerView(props: BarcodeScannerViewProps) {
16
+ return <ExpoBarcodeScannerAdapter {...props} />;
17
+ }
package/src/index.ts CHANGED
@@ -1 +1,20 @@
1
- /* todo */
1
+ export {
2
+ BARCODE_SCAN_DEDUPE_WINDOW_MS,
3
+ BARCODE_SCANNER_TYPES,
4
+ type BarcodeScanRecord,
5
+ type ExpoBarcodeScanResultLike,
6
+ mapPermissionStatusToCameraPermissionStatus,
7
+ normalizeExpoBarcodeScanResult,
8
+ shouldIgnoreBarcodeScan,
9
+ } from './barcodeScanRuntime';
10
+ export type { ComponentRegistry } from './componentRegistry';
11
+ export { createComponentRegistry } from './componentRegistry';
12
+ export { createExpoRuntimeRegistry } from './createExpoRuntimeRegistry';
13
+ export { ExpoBarcodeScannerAdapter } from './ExpoBarcodeScannerAdapter';
14
+ export { ExpoRuntimeProviders, type ExpoRuntimeProvidersProps } from './ExpoRuntimeProviders';
15
+ export type {
16
+ ExpoRuntimeAdapterId,
17
+ ExpoRuntimePlan,
18
+ ExpoRuntimeProviderId,
19
+ } from './resolveExpoRuntimePlan';
20
+ export { resolveExpoRuntimePlan } from './resolveExpoRuntimePlan';
@@ -0,0 +1,2 @@
1
+ export { PermissionsProvider } from '@ankhorage/permissions';
2
+ export { createPermissionClient } from '@ankhorage/permissions/expo';