@stacksjs/defaults 0.75.54 → 0.75.56

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.
@@ -392,14 +392,17 @@ store in its group container, so Full Disk Access again), never written. Its
392
392
  `controller` is `{ archive(names), unarchive(names) }`, given the chat's name
393
393
  and formatted number. Message types map onto the inbox shape: captions come
394
394
  from the media item's title, contact cards and locations become text, deleted
395
- messages are `unsent`, group events and calls are `kind: 'event'`. Reactions and
396
- quoted replies sit in protobuf blobs the driver does not decode, so they are
397
- absent rather than guessed. Status updates and broadcast lists are not listed.
395
+ messages are `unsent`, group events and calls are `kind: 'event'`. Reactions
396
+ come out of the receipts protobuf (field 7) as `kind: 'reaction'` messages, and
397
+ a reply's `replyToId` is field 5 of the media item's metadata - both read with
398
+ the schema-less `formats/protobuf` reader. Status updates and broadcast lists
399
+ are not listed.
398
400
 
399
401
  Profile pictures: a person (and a group or server conversation) may carry an
400
402
  `avatar` reference; pass it to the optional `driver.avatar(ref)` for the image
401
403
  as a `Response`. iMessage reads the contact's photo from Contacts (inline, or
402
- the store's `_EXTERNAL_DATA` file for larger iCloud photos), WhatsApp the
404
+ the store's `_EXTERNAL_DATA` file for larger iCloud photos) and a group's own
405
+ photo from `chat.properties` (a binary plist, read by `formats/bplist`), WhatsApp the
403
406
  pictures it has cached on this Mac (only some - it keeps the ones it showed
404
407
  recently), Slack `profile.image_72`, Discord user avatars and server icons.
405
408
  The remote ones are fetched only from the provider's own image hosts.
@@ -96,6 +96,61 @@ Choose exactly one primary content source:
96
96
  Only enable capabilities the product uses. Craft turns enabled capabilities
97
97
  into native bridge availability and required iOS privacy descriptions.
98
98
 
99
+ ## Device search index
100
+
101
+ `spotlight` says what of the application's own content a device may index, so
102
+ somebody searching their home screen finds a record rather than only finding
103
+ the app:
104
+
105
+ ```ts
106
+ export default {
107
+ ios: { /* ... */ },
108
+ spotlight: {
109
+ kinds: {
110
+ trail: { slots: 24, route: '/trail/:id', noun: 'Trail' },
111
+ club: { slots: 8, route: '/club/:id', noun: 'Club' },
112
+ },
113
+ // Anything the app donates outside the registry: a Siri phrase, an App Intent.
114
+ activityTypes: ['favorites', 'trails-near-me'],
115
+ },
116
+ } satisfies MobileConfig
117
+ ```
118
+
119
+ `slots` is a budget, not a guess. iOS indexes donated `NSUserActivity` objects
120
+ and hands a tapped one back only for an activity type the build declares in
121
+ `Info.plist`, a list fixed at build time — so a type per record id cannot be
122
+ declared at all. Each kind gets that many slots, each slot holds whichever
123
+ record is currently in it, and the oldest donation makes room for the next.
124
+ `buddy build:ios` writes the declarations; an entry the build did not declare
125
+ still appears in Spotlight and merely opens the app wherever it was last, which
126
+ looks like the feature working until somebody taps a result.
127
+
128
+ Drive it with one index per application:
129
+
130
+ ```ts
131
+ import mobileConfig from '../config/mobile'
132
+ import { createSpotlightIndex, onSpotlightTap } from '@stacksjs/mobile'
133
+
134
+ export const spotlight = createSpotlightIndex({ kinds: mobileConfig.spotlight.kinds })
135
+
136
+ await spotlight.index('trail', { id: trail.id, name: trail.name }) // one record
137
+ await spotlight.sync('club', myClubs) // a list that is theirs, most important first
138
+ await spotlight.remove('club', club.id) // left, unsaved, withdrawn from, deleted
139
+ await spotlight.clear() // sign-out: none of it is this person's
140
+ onSpotlightTap(spotlight, route => location.assign(route))
141
+ ```
142
+
143
+ Every call is a no-op that reports as much off a native host, on a build whose
144
+ host predates the bridge, and where the index is turned off (`enabled: false`),
145
+ so a page can donate unconditionally. `spotlight.routeFor(action)` answers a tap
146
+ synchronously for an app that already routes Craft's shortcut events itself.
147
+
148
+ Index what is the person's — saved, joined, entered — rather than what they
149
+ looked at, wherever the page re-renders on that change: a page that donates on
150
+ every render would put a record straight back the moment they left it. Donating
151
+ the same record twice is free, so an effect over the record is the natural call
152
+ site.
153
+
99
154
  ## Runtime API
100
155
 
101
156
  ```ts
@@ -201,3 +256,9 @@ physical-device archive. Compile the Android project with Gradle when Android is
201
256
  configured. Verify permission prompts, safe-area
202
257
  layout, deep links, offline/error states, background transitions, and native
203
258
  feedback on device.
259
+
260
+ A device search index needs its own device check, because nothing about it is
261
+ observable from the generated project: search a record's name from the home
262
+ screen, confirm the entry appears and opens that record rather than the last
263
+ screen, then make it stop being the person's (leave, unsave, withdraw, sign
264
+ out) and confirm it stops being findable.
@@ -2,7 +2,7 @@
2
2
  "publisher": "Stacks",
3
3
  "name": "vscode-stacks",
4
4
  "displayName": "Stacks",
5
- "version": "0.75.54",
5
+ "version": "0.75.56",
6
6
  "description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
7
7
  "license": "MIT",
8
8
  "funding": "https://github.com/sponsors/chrisbbreuer",
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/defaults",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.54",
5
+ "version": "0.75.56",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/stacksjs/stacks.git",
@@ -55,7 +55,7 @@
55
55
  "dependencies": {
56
56
  "@iconify-json/f7": "^1.2.2",
57
57
  "@iconify-json/hugeicons": "^1.2.35",
58
- "@stacksjs/mobile": "^0.75.54",
58
+ "@stacksjs/mobile": "^0.75.56",
59
59
  "@stacksjs/sanitizer": "^0.2.348",
60
60
  "ts-qr-codes": "^0.1.8"
61
61
  }