expo-app-intents 0.2.0 → 0.3.0

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 (44) hide show
  1. package/.npmignore +5 -0
  2. package/CHANGELOG.md +10 -0
  3. package/build/AppEntityView.d.ts +13 -0
  4. package/build/AppEntityView.ios.d.ts +2 -0
  5. package/build/AppEntityView.ios.js +20 -0
  6. package/build/AppEntityView.ios.js.map +1 -0
  7. package/build/AppEntityView.js +20 -0
  8. package/build/AppEntityView.js.map +1 -0
  9. package/build/AppEntityView.types.d.ts +11 -0
  10. package/build/AppEntityView.types.js +5 -0
  11. package/build/AppEntityView.types.js.map +1 -0
  12. package/build/ExpoAppIntents.types.d.ts +26 -0
  13. package/build/ExpoAppIntents.types.js +3 -6
  14. package/build/ExpoAppIntents.types.js.map +1 -1
  15. package/build/ExpoAppIntentsModule.d.ts +1 -0
  16. package/build/ExpoAppIntentsModule.js.map +1 -1
  17. package/build/index.d.ts +39 -1
  18. package/build/index.js +46 -0
  19. package/build/index.js.map +1 -1
  20. package/cli/build/index.js +7 -2
  21. package/cli/build/index.js.map +1 -1
  22. package/cli/build/init.d.ts +28 -1
  23. package/cli/build/init.js +120 -19
  24. package/cli/build/init.js.map +1 -1
  25. package/cli/src/index.ts +22 -2
  26. package/cli/src/init.ts +174 -19
  27. package/ios/AppEntityIdentifierModifier.swift +524 -0
  28. package/ios/AppEntityView.swift +43 -0
  29. package/ios/AppIntentEntityStore.swift +93 -9
  30. package/ios/ExpoAppIntents.podspec +10 -1
  31. package/ios/ExpoAppIntentsModule.swift +133 -8
  32. package/package.json +4 -3
  33. package/src/AppEntityView.ios.tsx +20 -0
  34. package/src/AppEntityView.tsx +24 -0
  35. package/src/AppEntityView.types.ts +14 -0
  36. package/src/ExpoAppIntents.types.ts +30 -0
  37. package/src/ExpoAppIntentsModule.ts +1 -0
  38. package/src/index.ts +52 -0
  39. package/templates/examples/mail/Entities/MailDraftEntity.swift +26 -10
  40. package/templates/examples/mail/Queries/MailDraftEntityQuery.swift +8 -1
  41. package/templates/examples/mail-visual-intelligence/Entities/MailDraftEntity+Spotlight.swift +54 -0
  42. package/templates/examples/mail-visual-intelligence/Entities/MailDraftEntity+Transferable.swift +65 -0
  43. package/templates/examples/mail-visual-intelligence/OpenMailDraftIntent.swift +25 -0
  44. package/templates/examples/mail-visual-intelligence/Queries/MailDraftEntityQuery+Indexed.swift +47 -0
package/.npmignore CHANGED
@@ -20,3 +20,8 @@ __rsc_tests__
20
20
 
21
21
  CLAUDE.md
22
22
  CONTRIBUTING.md
23
+
24
+ # Exclude native build output (pnpm pack ignores nested .gitignore files)
25
+ .cxx/
26
+ .gradle/
27
+ /android/build/
package/CHANGELOG.md CHANGED
@@ -10,6 +10,16 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 0.3.0 — 2026-09-14
14
+
15
+ ### 🎉 New features
16
+
17
+ - [iOS] Add `AppEntityView`, a UIKit wrapper for associating React Native content with an App Entity. ([#49663](https://github.com/expo/expo/pull/49663) by [@behenate](https://github.com/behenate))
18
+
19
+ ### 🐛 Bug fixes
20
+
21
+ - [iOS] Drop macOS from the podspec platforms to fix `pod install` failing with "Unable to find a specification for `ExpoUI`". ([#50065](https://github.com/expo/expo/pull/50065) by [@gabrieldonadel](https://github.com/gabrieldonadel))
22
+
13
23
  ## 0.2.0 — 2026-09-10
14
24
 
15
25
  ### 🎉 New features
@@ -0,0 +1,13 @@
1
+ import type { AppEntityViewProps } from './AppEntityView.types';
2
+ /**
3
+ * A wrapper that associates its contents with an App Entity so Apple Intelligence and Siri
4
+ * can understand which entity is visible onscreen. Use it around React Native views; for `@expo/ui`
5
+ * views, use the [`appEntityIdentifier()`](#appintentsappentityidentifierentity-id) modifier instead.
6
+ *
7
+ * > **Note:** The entity association requires iOS 18.4 or later and a project compiled with Xcode 27
8
+ * > or later. The children still render normally when those requirements are not met, on other
9
+ * > platforms, or when the native module is unavailable.
10
+ *
11
+ * @platform ios
12
+ */
13
+ export default function AppEntityView({ entity: _entity, entityId: _entityId, ...props }: AppEntityViewProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import type { AppEntityViewProps } from './AppEntityView.types';
2
+ export default function AppEntityView(props: AppEntityViewProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { requireNativeView } from 'expo';
4
+ import { View } from 'react-native';
5
+ import ExpoAppIntents from './ExpoAppIntentsModule';
6
+ const NativeAppEntityView = ExpoAppIntents ? requireNativeView('ExpoAppIntents', 'AppEntityView') : null;
7
+ export default function AppEntityView(props) {
8
+ if (!NativeAppEntityView) {
9
+ const { entity: _entity, entityId: _entityId, ...viewProps } = props;
10
+ return /*#__PURE__*/ _jsx(View, {
11
+ ...viewProps
12
+ });
13
+ }
14
+ return /*#__PURE__*/ _jsx(NativeAppEntityView, {
15
+ ...props,
16
+ collapsable: false
17
+ });
18
+ }
19
+
20
+ //# sourceMappingURL=AppEntityView.ios.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["AppEntityView.ios.tsx"],"sourcesContent":[null],"names":["requireNativeView","View","ExpoAppIntents","NativeAppEntityView","AppEntityView","props","entity","_entity","entityId","_entityId","viewProps","collapsable"],"mappings":"AAAA;;AAEA,SAASA,iBAAiB,QAAQ,OAAO;AAEzC,SAASC,IAAI,QAAQ,eAAe;AAGpC,OAAOC,oBAAoB,yBAAyB;AAEpD,MAAMC,sBAAgED,iBAClEF,kBAAsC,kBAAkB,mBACxD;AAEJ,eAAe,SAASI,cAAcC,KAAyB;IAC7D,IAAI,CAACF,qBAAqB;QACxB,MAAM,EAAEG,QAAQC,OAAO,EAAEC,UAAUC,SAAS,EAAE,GAAGC,WAAW,GAAGL;QAC/D,qBAAO,KAACJ;YAAM,GAAGS,SAAS;;IAC5B;IACA,qBAAO,KAACP;QAAqB,GAAGE,KAAK;QAAEM,aAAa;;AACtD"}
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { View } from 'react-native';
4
+ /**
5
+ * A wrapper that associates its contents with an App Entity so Apple Intelligence and Siri
6
+ * can understand which entity is visible onscreen. Use it around React Native views; for `@expo/ui`
7
+ * views, use the [`appEntityIdentifier()`](#appintentsappentityidentifierentity-id) modifier instead.
8
+ *
9
+ * > **Note:** The entity association requires iOS 18.4 or later and a project compiled with Xcode 27
10
+ * > or later. The children still render normally when those requirements are not met, on other
11
+ * > platforms, or when the native module is unavailable.
12
+ *
13
+ * @platform ios
14
+ */ export default function AppEntityView({ entity: _entity, entityId: _entityId, ...props }) {
15
+ return /*#__PURE__*/ _jsx(View, {
16
+ ...props
17
+ });
18
+ }
19
+
20
+ //# sourceMappingURL=AppEntityView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["AppEntityView.tsx"],"sourcesContent":[null],"names":["View","AppEntityView","entity","_entity","entityId","_entityId","props"],"mappings":"AAAA;;AAEA,SAASA,IAAI,QAAQ,eAAe;AAIpC;;;;;;;;;;CAUC,GACD,eAAe,SAASC,cAAc,EACpCC,QAAQC,OAAO,EACfC,UAAUC,SAAS,EACnB,GAAGC,OACgB;IACnB,qBAAO,KAACN;QAAM,GAAGM,KAAK;;AACxB"}
@@ -0,0 +1,11 @@
1
+ import type { PropsWithChildren } from 'react';
2
+ import type { ViewProps } from 'react-native';
3
+ /**
4
+ * Props for a UIKit wrapper that associates its onscreen content with one App Entity.
5
+ */
6
+ export type AppEntityViewProps = PropsWithChildren<ViewProps & {
7
+ /** App-specific entity kind registered natively, for example `person` or `dish`. */
8
+ entity: string;
9
+ /** Stable entity id from the matching App Intents entity catalog. */
10
+ entityId: string;
11
+ }>;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Props for a UIKit wrapper that associates its onscreen content with one App Entity.
3
+ */ export { };
4
+
5
+ //# sourceMappingURL=AppEntityView.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["AppEntityView.types.ts"],"sourcesContent":[null],"names":[],"mappings":"AAGA;;CAEC,GACD,WAOE"}
@@ -1,3 +1,4 @@
1
+ import type { ModifierConfig } from '@expo/ui/swift-ui/modifiers';
1
2
  /**
2
3
  * A single recorded App Intent invocation.
3
4
  *
@@ -50,6 +51,31 @@ export type AppIntentEntity = {
50
51
  * Provides alternative spoken names that resolve to this entity.
51
52
  */
52
53
  synonyms?: string[];
54
+ /** App-specific string metadata consumed by native AppEntity implementations. */
55
+ metadata?: Record<string, string>;
56
+ /**
57
+ * Whether to keep this entity out of the Spotlight index. It stays resolvable, so Siri can still
58
+ * offer it as a parameter and open it by identifier — it just is not searchable.
59
+ *
60
+ * Only applies to entities registered natively with `registerIndexed`. Defaults to `false`.
61
+ *
62
+ * @platform ios
63
+ */
64
+ hideInSpotlight?: boolean;
65
+ };
66
+ /**
67
+ * ExpoUI modifier config that associates a SwiftUI view with an AppEntity identifier.
68
+ *
69
+ * Built on `@expo/ui`'s own `ModifierConfig` rather than restating its shape, so that a change to
70
+ * what the `modifiers` prop accepts is a type error here instead of a value ExpoUI rejects at
71
+ * runtime.
72
+ */
73
+ export type AppEntityIdentifierModifier = ModifierConfig & {
74
+ $type: 'appEntityIdentifier';
75
+ /** App-specific entity kind registered natively, for example `person` or `dish`. */
76
+ entity: string;
77
+ /** Stable entity id from the matching App Intents entity catalog. */
78
+ id: string;
53
79
  };
54
80
  export type ExpoAppIntentsModuleEvents = {
55
81
  onIntent: (invocation: AppIntentInvocation) => void;
@@ -1,8 +1,5 @@
1
- /**
2
- * A single recorded App Intent invocation.
3
- *
4
- * The native layer persists each invocation until `removePendingInvocationAsync` removes it.
5
- * Delivery is at-least-once, so handlers must be idempotent for each `id`.
6
- */ export { };
1
+ // A type-only import, so nothing from ExpoUI is pulled in at runtime on the platforms where App
2
+ // Intents do not exist.
3
+ export { };
7
4
 
8
5
  //# sourceMappingURL=ExpoAppIntents.types.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["ExpoAppIntents.types.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;;;;;CAKC,GAsDD,WAEE"}
1
+ {"version":3,"sources":["ExpoAppIntents.types.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA,gGAAgG;AAChG,wBAAwB;AAwFxB,WAEE"}
@@ -5,6 +5,7 @@ declare class ExpoAppIntentsNativeModule extends NativeModule<ExpoAppIntentsModu
5
5
  removePendingInvocationAsync(id: string): Promise<void>;
6
6
  clearPendingInvocationsAsync(): Promise<void>;
7
7
  setEntityCatalogAsync(kind: string, entities: AppIntentEntity[]): Promise<void>;
8
+ reindexEntitiesAsync(kind: string | null): Promise<void>;
8
9
  getEntityCatalogAsync(kind: string): Promise<AppIntentEntity[]>;
9
10
  refreshShortcutsAsync(): Promise<void>;
10
11
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["ExpoAppIntentsModule.ts"],"sourcesContent":[null],"names":["NativeModule","requireOptionalNativeModule"],"mappings":"AAAA,SAASA,YAAY,EAAEC,2BAA2B,QAAQ,oBAAoB;AAiB9E,eAAeA,4BAAwD,kBAAkB"}
1
+ {"version":3,"sources":["ExpoAppIntentsModule.ts"],"sourcesContent":[null],"names":["NativeModule","requireOptionalNativeModule"],"mappings":"AAAA,SAASA,YAAY,EAAEC,2BAA2B,QAAQ,oBAAoB;AAkB9E,eAAeA,4BAAwD,kBAAkB"}
package/build/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { type EventSubscription } from 'expo-modules-core';
2
- import type { AppIntentEntity, AppIntentInvocation, AppIntentsHandler } from './ExpoAppIntents.types';
2
+ import type { AppEntityIdentifierModifier, AppIntentEntity, AppIntentInvocation, AppIntentsHandler } from './ExpoAppIntents.types';
3
3
  export type * from './ExpoAppIntents.types';
4
+ export { default as AppEntityView } from './AppEntityView';
5
+ export type { AppEntityViewProps } from './AppEntityView.types';
4
6
  /**
5
7
  * Returns whether App Intents are available on this device.
6
8
  * Returns `false` on Android and web.
@@ -59,6 +61,11 @@ export declare function clearPendingInvocationsAsync(): Promise<void>;
59
61
  /**
60
62
  * Replaces the entity catalog of the given kind and asks the system to retrain
61
63
  * parameterized shortcut phrases against the new values.
64
+ * Entities registered natively with
65
+ * `registerIndexed` also have their Spotlight index rebuilt from the new catalog.
66
+ *
67
+ * Publishing a catalog that matches the stored catalog does nothing, so apps can safely call this
68
+ * function on every start.
62
69
  *
63
70
  * The native store uses `UserDefaults`, which is best suited to compact catalogs. For large
64
71
  * datasets, such as thousands of contacts or songs, apps should store the full data locally and
@@ -70,6 +77,24 @@ export declare function clearPendingInvocationsAsync(): Promise<void>;
70
77
  * invalid when another entity in the catalog has the same `id`.
71
78
  */
72
79
  export declare function setEntityCatalogAsync(kind: string, entities: AppIntentEntity[]): Promise<void>;
80
+ /**
81
+ * Rebuilds the Spotlight index from the stored entity catalog, whether or not the catalog
82
+ * changed. `setEntityCatalogAsync` already keeps the index in step, so this is only needed to
83
+ * recover from an index that no longer matches the catalog: one the system evicted, or one left
84
+ * stale by an app update that changed how entities describe themselves.
85
+ *
86
+ * Pass a `kind` to rebuild one catalog, or omit it to rebuild every kind registered natively with
87
+ * `registerIndexed`. Kinds with no indexed registration are ignored.
88
+ *
89
+ * Rejects when a catalog cannot be read or the index cannot be written, because this is the retry
90
+ * path and a caller that asked for a rebuild has no other way to learn it did not happen. Every
91
+ * kind is attempted before the first failure is reported, so one unreadable catalog does not skip
92
+ * the rest. A kind whose rebuild failed is retried by the next `setEntityCatalogAsync`, even when
93
+ * the catalog it publishes is unchanged.
94
+ *
95
+ * @platform ios
96
+ */
97
+ export declare function reindexEntitiesAsync(kind?: string): Promise<void>;
73
98
  /**
74
99
  * Returns the current entity catalog of the given kind.
75
100
  * The returned promise is fulfilled with an empty array when the kind was never published or App
@@ -87,3 +112,16 @@ export declare function getEntityCatalogAsync(kind: string): Promise<AppIntentEn
87
112
  * shortcuts.
88
113
  */
89
114
  export declare function refreshShortcutsAsync(): Promise<void>;
115
+ /**
116
+ * Returns an ExpoUI SwiftUI modifier config that ties a view to an AppEntity identifier.
117
+ *
118
+ * The `entity` value must be registered from app-target Swift with
119
+ * `AppEntityIdentifierRegistry.shared.register(_:as:)` or
120
+ * `AppEntityIdentifierRegistry.shared.registerIndexed(_:as:)`.
121
+ *
122
+ * > **Note:** The entity association requires iOS 18.4 or later and a project compiled with Xcode 27
123
+ * > or later. Otherwise the view renders normally without it.
124
+ *
125
+ * @platform ios
126
+ */
127
+ export declare function appEntityIdentifier(entity: string, id: string): AppEntityIdentifierModifier;
package/build/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { UnavailabilityError } from 'expo-modules-core';
2
2
  import { useEffect, useRef } from 'react';
3
3
  import ExpoAppIntents from './ExpoAppIntentsModule';
4
+ export { default as AppEntityView } from './AppEntityView';
4
5
  const MAX_SEEN_INVOCATION_IDS = 100;
5
6
  /**
6
7
  * Returns whether App Intents are available on this device.
@@ -149,6 +150,11 @@ function callAppIntentsHandler(handler, pendingIntents, newIntent) {
149
150
  /**
150
151
  * Replaces the entity catalog of the given kind and asks the system to retrain
151
152
  * parameterized shortcut phrases against the new values.
153
+ * Entities registered natively with
154
+ * `registerIndexed` also have their Spotlight index rebuilt from the new catalog.
155
+ *
156
+ * Publishing a catalog that matches the stored catalog does nothing, so apps can safely call this
157
+ * function on every start.
152
158
  *
153
159
  * The native store uses `UserDefaults`, which is best suited to compact catalogs. For large
154
160
  * datasets, such as thousands of contacts or songs, apps should store the full data locally and
@@ -164,6 +170,28 @@ function callAppIntentsHandler(handler, pendingIntents, newIntent) {
164
170
  }
165
171
  return ExpoAppIntents.setEntityCatalogAsync(kind, entities);
166
172
  }
173
+ /**
174
+ * Rebuilds the Spotlight index from the stored entity catalog, whether or not the catalog
175
+ * changed. `setEntityCatalogAsync` already keeps the index in step, so this is only needed to
176
+ * recover from an index that no longer matches the catalog: one the system evicted, or one left
177
+ * stale by an app update that changed how entities describe themselves.
178
+ *
179
+ * Pass a `kind` to rebuild one catalog, or omit it to rebuild every kind registered natively with
180
+ * `registerIndexed`. Kinds with no indexed registration are ignored.
181
+ *
182
+ * Rejects when a catalog cannot be read or the index cannot be written, because this is the retry
183
+ * path and a caller that asked for a rebuild has no other way to learn it did not happen. Every
184
+ * kind is attempted before the first failure is reported, so one unreadable catalog does not skip
185
+ * the rest. A kind whose rebuild failed is retried by the next `setEntityCatalogAsync`, even when
186
+ * the catalog it publishes is unchanged.
187
+ *
188
+ * @platform ios
189
+ */ export async function reindexEntitiesAsync(kind) {
190
+ if (!ExpoAppIntents) {
191
+ return;
192
+ }
193
+ return ExpoAppIntents.reindexEntitiesAsync(kind ?? null);
194
+ }
167
195
  /**
168
196
  * Returns the current entity catalog of the given kind.
169
197
  * The returned promise is fulfilled with an empty array when the kind was never published or App
@@ -189,5 +217,23 @@ function callAppIntentsHandler(handler, pendingIntents, newIntent) {
189
217
  }
190
218
  return ExpoAppIntents.refreshShortcutsAsync();
191
219
  }
220
+ /**
221
+ * Returns an ExpoUI SwiftUI modifier config that ties a view to an AppEntity identifier.
222
+ *
223
+ * The `entity` value must be registered from app-target Swift with
224
+ * `AppEntityIdentifierRegistry.shared.register(_:as:)` or
225
+ * `AppEntityIdentifierRegistry.shared.registerIndexed(_:as:)`.
226
+ *
227
+ * > **Note:** The entity association requires iOS 18.4 or later and a project compiled with Xcode 27
228
+ * > or later. Otherwise the view renders normally without it.
229
+ *
230
+ * @platform ios
231
+ */ export function appEntityIdentifier(entity, id) {
232
+ return {
233
+ $type: 'appEntityIdentifier',
234
+ entity,
235
+ id
236
+ };
237
+ }
192
238
 
193
239
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["index.ts"],"sourcesContent":[null],"names":["UnavailabilityError","useEffect","useRef","ExpoAppIntents","MAX_SEEN_INVOCATION_IDS","isAvailable","addAppIntentListener","listener","remove","addListener","callAppIntentsHandler","handler","pendingIntents","newIntent","Promise","resolve","then","catch","error","console","warn","useAppIntents","handlerRef","current","isMounted","seenLiveInvocationIds","Set","deliveryQueue","enqueue","deliver","notify","deliverNewIntent","getPendingInvocationsAsync","length","deliverInitialPendingIntents","initialPendingIntents","filter","invocation","has","id","forEach","add","subscription","size","delete","values","next","value","removePendingInvocationAsync","clearPendingInvocationsAsync","setEntityCatalogAsync","kind","entities","getEntityCatalogAsync","refreshShortcutsAsync"],"mappings":"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"}
1
+ {"version":3,"sources":["index.ts"],"sourcesContent":[null],"names":["UnavailabilityError","useEffect","useRef","ExpoAppIntents","default","AppEntityView","MAX_SEEN_INVOCATION_IDS","isAvailable","addAppIntentListener","listener","remove","addListener","callAppIntentsHandler","handler","pendingIntents","newIntent","Promise","resolve","then","catch","error","console","warn","useAppIntents","handlerRef","current","isMounted","seenLiveInvocationIds","Set","deliveryQueue","enqueue","deliver","notify","deliverNewIntent","getPendingInvocationsAsync","length","deliverInitialPendingIntents","initialPendingIntents","filter","invocation","has","id","forEach","add","subscription","size","delete","values","next","value","removePendingInvocationAsync","clearPendingInvocationsAsync","setEntityCatalogAsync","kind","entities","reindexEntitiesAsync","getEntityCatalogAsync","refreshShortcutsAsync","appEntityIdentifier","entity","$type"],"mappings":"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"}
@@ -42,20 +42,25 @@ function isInteractive() {
42
42
  }
43
43
  return true;
44
44
  }
45
+ /** Printed before the examples are picked, since it says what picking one gets you. */ function printScaffoldIntro(directory) {
46
+ console.log(`App Intents are declared in Swift, compiled into your app target. expo-app-intents\n` + `scaffolds example Swift into ${directory}/ and hands invocations to JavaScript.\n`);
47
+ }
45
48
  async function runInitCommand(options) {
46
49
  const interactive = isInteractive();
47
50
  const directory = (0, _init.normalizeDirectory)(options.directory ?? options.dir);
48
- const examples = await (0, _init.resolveExamplesAsync)(interactive, options.examples);
51
+ printScaffoldIntro(directory);
52
+ const { examples, visualIntelligence } = await (0, _init.resolveExamplesAsync)(interactive, options.examples, options.visualIntelligence ?? false);
49
53
  await (0, _init.runInit)({
50
54
  projectRoot: process.cwd(),
51
55
  directory,
52
56
  examples,
57
+ visualIntelligence,
53
58
  templatesDir: process.env.EXPO_APP_INTENTS_TEMPLATES_DIR ?? _path().default.join(__dirname, '..', '..', TEMPLATES_DIRECTORY_NAME)
54
59
  });
55
60
  }
56
61
  const program = new (_commander()).Command();
57
62
  program.name('expo-app-intents').description('Add Apple App Intents support to Expo apps.');
58
- program.command('init').description('Add Expo App Intents inline-module Swift files to the current Expo app.').option('-d, --dir <directory>', 'Directory for the generated App Intents inline module.').option('--directory <directory>', 'Alias for --dir.').option('--examples <examples...>', 'Examples to include. Use "all", or choose any of: minimal, counter, restaurant, mail.').action(runInitCommand);
63
+ program.command('init').description('Add Expo App Intents inline-module Swift files to the current Expo app.').option('-d, --dir <directory>', 'Directory for the generated App Intents inline module.').option('--directory <directory>', 'Alias for --dir.').option('--examples <examples...>', 'Example native code to scaffold. Use "all", or choose any of: minimal, counter, ' + 'restaurant, mail.').option('--visual-intelligence', 'Extend the mail example with Spotlight indexing, a Transferable export, and an open intent.').action(runInitCommand);
59
64
  program.parseAsync(process.argv).catch((error)=>{
60
65
  console.error(error.message);
61
66
  process.exitCode = 1;
@@ -1 +1 @@
1
- {"version":3,"sources":["index.ts"],"sourcesContent":[null],"names":["isInteractive","TEMPLATES_DIRECTORY_NAME","ci","process","env","CI","toLowerCase","EXPO_NONINTERACTIVE","stdin","isTTY","runInitCommand","options","interactive","directory","normalizeDirectory","dir","examples","resolveExamplesAsync","runInit","projectRoot","cwd","templatesDir","EXPO_APP_INTENTS_TEMPLATES_DIR","path","join","__dirname","program","Command","name","description","command","option","action","parseAsync","argv","catch","error","console","message","exitCode"],"mappings":";;;;+BAiBgBA;;;eAAAA;;;;yBAjBQ;;;;;;;gEACP;;;;;;sBAEiD;;;;;;AAQlE,MAAMC,2BAA2B;AAM1B,SAASD;IACd,MAAME,KAAKC,QAAQC,GAAG,CAACC,EAAE;IACzB,IAAIH,OAAO,OAAOA,IAAII,kBAAkB,QAAQ;QAC9C,OAAO;IACT;IACA,IAAIH,QAAQC,GAAG,CAACG,mBAAmB,EAAE;QACnC,OAAO;IACT;IACA,IAAI,CAACJ,QAAQK,KAAK,CAACC,KAAK,EAAE;QACxB,OAAO;IACT;IACA,OAAO;AACT;AAEA,eAAeC,eAAeC,OAA2B;IACvD,MAAMC,cAAcZ;IACpB,MAAMa,YAAYC,IAAAA,wBAAkB,EAACH,QAAQE,SAAS,IAAIF,QAAQI,GAAG;IACrE,MAAMC,WAAW,MAAMC,IAAAA,0BAAoB,EAACL,aAAaD,QAAQK,QAAQ;IAEzE,MAAME,IAAAA,aAAO,EAAC;QACZC,aAAahB,QAAQiB,GAAG;QACxBP;QACAG;QACAK,cACElB,QAAQC,GAAG,CAACkB,8BAA8B,IAC1CC,eAAI,CAACC,IAAI,CAACC,WAAW,MAAM,MAAMxB;IACrC;AACF;AAEA,MAAMyB,UAAU,IAAIC,CAAAA,YAAM,SAAC;AAE3BD,QAAQE,IAAI,CAAC,oBAAoBC,WAAW,CAAC;AAE7CH,QACGI,OAAO,CAAC,QACRD,WAAW,CAAC,2EACZE,MAAM,CAAC,yBAAyB,0DAChCA,MAAM,CAAC,2BAA2B,oBAClCA,MAAM,CACL,4BACA,yFAEDC,MAAM,CAACtB;AAEVgB,QAAQO,UAAU,CAAC9B,QAAQ+B,IAAI,EAAEC,KAAK,CAAC,CAACC;IACtCC,QAAQD,KAAK,CAACA,MAAME,OAAO;IAC3BnC,QAAQoC,QAAQ,GAAG;AACrB"}
1
+ {"version":3,"sources":["index.ts"],"sourcesContent":[null],"names":["isInteractive","TEMPLATES_DIRECTORY_NAME","ci","process","env","CI","toLowerCase","EXPO_NONINTERACTIVE","stdin","isTTY","printScaffoldIntro","directory","console","log","runInitCommand","options","interactive","normalizeDirectory","dir","examples","visualIntelligence","resolveExamplesAsync","runInit","projectRoot","cwd","templatesDir","EXPO_APP_INTENTS_TEMPLATES_DIR","path","join","__dirname","program","Command","name","description","command","option","action","parseAsync","argv","catch","error","message","exitCode"],"mappings":";;;;+BAkBgBA;;;eAAAA;;;;yBAlBQ;;;;;;;gEACP;;;;;;sBAEiD;;;;;;AASlE,MAAMC,2BAA2B;AAM1B,SAASD;IACd,MAAME,KAAKC,QAAQC,GAAG,CAACC,EAAE;IACzB,IAAIH,OAAO,OAAOA,IAAII,kBAAkB,QAAQ;QAC9C,OAAO;IACT;IACA,IAAIH,QAAQC,GAAG,CAACG,mBAAmB,EAAE;QACnC,OAAO;IACT;IACA,IAAI,CAACJ,QAAQK,KAAK,CAACC,KAAK,EAAE;QACxB,OAAO;IACT;IACA,OAAO;AACT;AAEA,qFAAqF,GACrF,SAASC,mBAAmBC,SAAiB;IAC3CC,QAAQC,GAAG,CACT,CAAC,oFAAoF,CAAC,GACpF,CAAC,6BAA6B,EAAEF,UAAU,wCAAwC,CAAC;AAEzF;AAEA,eAAeG,eAAeC,OAA2B;IACvD,MAAMC,cAAchB;IACpB,MAAMW,YAAYM,IAAAA,wBAAkB,EAACF,QAAQJ,SAAS,IAAII,QAAQG,GAAG;IACrER,mBAAmBC;IACnB,MAAM,EAAEQ,QAAQ,EAAEC,kBAAkB,EAAE,GAAG,MAAMC,IAAAA,0BAAoB,EACjEL,aACAD,QAAQI,QAAQ,EAChBJ,QAAQK,kBAAkB,IAAI;IAGhC,MAAME,IAAAA,aAAO,EAAC;QACZC,aAAapB,QAAQqB,GAAG;QACxBb;QACAQ;QACAC;QACAK,cACEtB,QAAQC,GAAG,CAACsB,8BAA8B,IAC1CC,eAAI,CAACC,IAAI,CAACC,WAAW,MAAM,MAAM5B;IACrC;AACF;AAEA,MAAM6B,UAAU,IAAIC,CAAAA,YAAM,SAAC;AAE3BD,QAAQE,IAAI,CAAC,oBAAoBC,WAAW,CAAC;AAE7CH,QACGI,OAAO,CAAC,QACRD,WAAW,CAAC,2EACZE,MAAM,CAAC,yBAAyB,0DAChCA,MAAM,CAAC,2BAA2B,oBAClCA,MAAM,CACL,4BACA,qFACE,qBAEHA,MAAM,CACL,yBACA,+FAEDC,MAAM,CAACtB;AAEVgB,QAAQO,UAAU,CAAClC,QAAQmC,IAAI,EAAEC,KAAK,CAAC,CAACC;IACtC5B,QAAQ4B,KAAK,CAACA,MAAMC,OAAO;IAC3BtC,QAAQuC,QAAQ,GAAG;AACrB"}
@@ -6,12 +6,39 @@ export type InitOptions = {
6
6
  directory: string;
7
7
  examples: InitExample[];
8
8
  templatesDir: string;
9
+ /**
10
+ * Adds Spotlight indexing, a `Transferable` export, and an open intent on top of the mail
11
+ * example, and has the setup module register the entity kind so `appEntityIdentifier()` works
12
+ * from JavaScript.
13
+ */
14
+ visualIntelligence?: boolean;
9
15
  };
10
16
  export declare const DEFAULT_DIRECTORY = "app-intents";
17
+ /** The example that `--visual-intelligence` extends. */
18
+ export declare const VISUAL_INTELLIGENCE_EXAMPLE: InitExample;
11
19
  export declare function resolveExamples(values: readonly string[] | undefined): InitExample[];
12
20
  export declare function getExamplesPrompt(): PromptObject;
13
- export declare function resolveExamplesAsync(interactive: boolean, values: readonly string[] | undefined): Promise<InitExample[]>;
21
+ /**
22
+ * Asked only after the example it extends has been selected, which is why it is a follow-up prompt
23
+ * rather than an entry in the picker: a `prompts` multiselect cannot enable a choice in response to
24
+ * another choice being selected.
25
+ */
26
+ export declare function getVisualIntelligencePrompt(): PromptObject;
27
+ export type ResolvedExamples = {
28
+ examples: InitExample[];
29
+ visualIntelligence: boolean;
30
+ };
31
+ export declare function resolveExamplesAsync(interactive: boolean, values: readonly string[] | undefined, visualIntelligence?: boolean): Promise<ResolvedExamples>;
14
32
  export declare function normalizeDirectory(directory: string | undefined): string;
33
+ /**
34
+ * Throws when `--visual-intelligence` was requested without the example it extends, rather than
35
+ * scaffolding the flag away silently.
36
+ *
37
+ * The flag reaches this check from the interactive picker too — it is passed on the command line
38
+ * while the examples are chosen in the prompt — so the message cannot assume that passing
39
+ * `--examples` is the only way out.
40
+ */
41
+ export declare function assertVisualIntelligenceSelection(examples: readonly InitExample[], visualIntelligence: boolean): void;
15
42
  /**
16
43
  * Scaffolds App Intents support into an Expo app:
17
44
  * 1. copies starter Swift files without overwriting user-owned files,