@wix/himalaya-cli 0.1598.0 → 0.1600.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.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/legacy-import/src/index.d.ts +30 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/sdk-types/src/capabilities.generated.d.ts +2 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/webview-page/src/capabilities.generated.d.ts +2 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +12 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/legacy-import.d.ts +134 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/audio-record.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calendar.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calls.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/contacts.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +184 -16
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/legacy-import.mjs +40 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/location.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/motion.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/photos.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdk-types.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/tasks.mjs +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/package.json +4 -0
- package/dist/cli.mjs +1421 -1015
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/app-config.md +1 -1
- package/guides/capabilities.md +1 -0
- package/guides/himi-json-output.md +25 -1
- package/guides/importable-sdks.md +1 -0
- package/guides/one-app-to-himi-app.md +33 -11
- package/guides/sdk-reference.json +43 -0
- package/guides/web-page-native-sdk.md +1 -1
- package/guides/web-page-sdk-reference.md +1 -0
- package/package.json +2 -2
- package/templates/beauty-salon/dev/index.ts +182 -0
- package/templates/beauty-salon/tier5-src/_shared/himi-blog-hidden.ts +66 -0
- package/templates/beauty-salon/tier5-src/himi-blog-feed/index.ts +3 -1
- package/templates/beauty-salon/tier5-src/himi-blog-post/index.ts +42 -0
- package/templates/beauty-salon/tier5-src/himi-blog-saved/index.ts +4 -1
- package/templates/beauty-salon/tier5-src/himi-branded-lite-home/index.ts +5 -2
- package/templates/branded-lite/dev/index.ts +182 -0
- package/templates/branded-lite/l10n/en.json +10 -7
- package/templates/branded-lite/tier5-src/_shared/header-badges.ts +113 -0
- package/templates/branded-lite/tier5-src/_shared/himi-blog-hidden.ts +66 -0
- package/templates/branded-lite/tier5-src/_shared/source-badges.ts +70 -0
- package/templates/branded-lite/tier5-src/himi-blog-feed/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-blog-post/index.ts +42 -0
- package/templates/branded-lite/tier5-src/himi-blog-saved/index.ts +4 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-header-badges/index.ts +38 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-home/index.ts +5 -2
- package/templates/community-club/dev/index.ts +182 -0
- package/templates/community-club/tier5-src/_shared/himi-blog-hidden.ts +66 -0
- package/templates/community-club/tier5-src/himi-blog-feed/index.ts +3 -1
- package/templates/community-club/tier5-src/himi-blog-post/index.ts +42 -0
- package/templates/community-club/tier5-src/himi-blog-saved/index.ts +4 -1
- package/templates/community-club/tier5-src/himi-branded-lite-home/index.ts +5 -2
- package/templates/events-meetups/dev/index.ts +182 -0
- package/templates/events-meetups/tier5-src/_shared/himi-blog-hidden.ts +66 -0
- package/templates/events-meetups/tier5-src/himi-blog-feed/index.ts +3 -1
- package/templates/events-meetups/tier5-src/himi-blog-post/index.ts +42 -0
- package/templates/events-meetups/tier5-src/himi-blog-saved/index.ts +4 -1
- package/templates/events-meetups/tier5-src/himi-branded-lite-home/index.ts +5 -2
- package/templates/gym-fitness/dev/index.ts +182 -0
- package/templates/gym-fitness/tier5-src/_shared/himi-blog-hidden.ts +66 -0
- package/templates/gym-fitness/tier5-src/himi-blog-feed/index.ts +3 -1
- package/templates/gym-fitness/tier5-src/himi-blog-post/index.ts +42 -0
- package/templates/gym-fitness/tier5-src/himi-blog-saved/index.ts +4 -1
- package/templates/gym-fitness/tier5-src/himi-branded-lite-home/index.ts +5 -2
- package/templates/nonprofit-cause/dev/index.ts +182 -0
- package/templates/nonprofit-cause/tier5-src/_shared/himi-blog-hidden.ts +66 -0
- package/templates/nonprofit-cause/tier5-src/himi-blog-feed/index.ts +3 -1
- package/templates/nonprofit-cause/tier5-src/himi-blog-post/index.ts +42 -0
- package/templates/nonprofit-cause/tier5-src/himi-blog-saved/index.ts +4 -1
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-home/index.ts +5 -2
- package/templates/podcast-creator/dev/index.ts +182 -0
- package/templates/podcast-creator/tier5-src/_shared/himi-blog-hidden.ts +66 -0
- package/templates/podcast-creator/tier5-src/himi-blog-feed/index.ts +3 -1
- package/templates/podcast-creator/tier5-src/himi-blog-post/index.ts +42 -0
- package/templates/podcast-creator/tier5-src/himi-blog-saved/index.ts +4 -1
- package/templates/podcast-creator/tier5-src/himi-branded-lite-home/index.ts +5 -2
- package/templates/portfolio-creative/dev/index.ts +182 -0
- package/templates/portfolio-creative/tier5-src/_shared/himi-blog-hidden.ts +66 -0
- package/templates/portfolio-creative/tier5-src/himi-blog-feed/index.ts +3 -1
- package/templates/portfolio-creative/tier5-src/himi-blog-post/index.ts +42 -0
- package/templates/portfolio-creative/tier5-src/himi-blog-saved/index.ts +4 -1
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-home/index.ts +5 -2
- package/templates/restaurant/dev/index.ts +182 -0
- package/templates/restaurant/tier5-src/_shared/himi-blog-hidden.ts +66 -0
- package/templates/restaurant/tier5-src/himi-blog-feed/index.ts +3 -1
- package/templates/restaurant/tier5-src/himi-blog-post/index.ts +42 -0
- package/templates/restaurant/tier5-src/himi-blog-saved/index.ts +4 -1
- package/templates/restaurant/tier5-src/himi-branded-lite-home/index.ts +5 -2
- package/templates/retail-store/dev/index.ts +182 -0
- package/templates/retail-store/tier5-src/_shared/himi-blog-hidden.ts +66 -0
- package/templates/retail-store/tier5-src/himi-blog-feed/index.ts +3 -1
- package/templates/retail-store/tier5-src/himi-blog-post/index.ts +42 -0
- package/templates/retail-store/tier5-src/himi-blog-saved/index.ts +4 -1
- package/templates/retail-store/tier5-src/himi-branded-lite-home/index.ts +5 -2
- package/templates/yoga-studio/dev/index.ts +182 -0
- package/templates/yoga-studio/tier5-src/_shared/himi-blog-hidden.ts +66 -0
- package/templates/yoga-studio/tier5-src/himi-blog-feed/index.ts +3 -1
- package/templates/yoga-studio/tier5-src/himi-blog-post/index.ts +42 -0
- package/templates/yoga-studio/tier5-src/himi-blog-saved/index.ts +4 -1
- package/templates/yoga-studio/tier5-src/himi-branded-lite-home/index.ts +5 -2
|
Binary file
|
package/guides/app-config.md
CHANGED
|
@@ -137,7 +137,7 @@ does not include answers `module_not_linked` on device. Some components need one
|
|
|
137
137
|
and `himi validate` errors on a screen that uses one the app does not declare.
|
|
138
138
|
`presigned_upload.putFile` also requires `files` on the calling screen.
|
|
139
139
|
|
|
140
|
-
App-level capability vocabulary: `camera`, `barcode_scanner`, `biometrics`, `secure_storage`, `share`, `push`, `file_picker`, `files`, `open_url`, `pdf`, `clipboard`, `theme`, `l10n`, `photos`, `presigned_upload`, `ui`, `calendar`, `contacts`, `tasks`, `audio_record`, `audio_record_background`, `calls`, `location`, `location_background`, `motion`, `health`, `media_playback`, `webview`, `browser_auth`, `haptic`, `himi_apps`, `iap`, `keyboard`, `torch`, `network`, `wix_cashier`, `wix_chat`, `live_activity`, `local_database`, `speech`, `speaker_diarization`, `system_intents`, `on_device_ai`, `app_info`, `release_control`, `godot`, `base44`, `animation`.
|
|
140
|
+
App-level capability vocabulary: `camera`, `barcode_scanner`, `biometrics`, `secure_storage`, `share`, `push`, `file_picker`, `files`, `open_url`, `pdf`, `clipboard`, `theme`, `l10n`, `photos`, `presigned_upload`, `ui`, `calendar`, `contacts`, `tasks`, `audio_record`, `audio_record_background`, `calls`, `location`, `location_background`, `motion`, `health`, `media_playback`, `webview`, `browser_auth`, `haptic`, `himi_apps`, `iap`, `keyboard`, `torch`, `network`, `wix_cashier`, `wix_chat`, `live_activity`, `local_database`, `speech`, `speaker_diarization`, `system_intents`, `on_device_ai`, `app_info`, `release_control`, `legacy_import`, `godot`, `base44`, `animation`.
|
|
141
141
|
|
|
142
142
|
## What `himi validate` checks (7 passes)
|
|
143
143
|
|
package/guides/capabilities.md
CHANGED
|
@@ -278,6 +278,7 @@ prompt.
|
|
|
278
278
|
| `app_info` | the shell's boot has to configure it with the app id it reports |
|
|
279
279
|
| `system_intents` | the shell has to wire the system-intents host (app identity, deep-link routing, refresh) |
|
|
280
280
|
| `release_control` | the shell's boot has to configure it with the app id whose releases it switches |
|
|
281
|
+
| `legacy_import` | the shell's boot has to run the legacy importer before auth and feed it the signed-in principal |
|
|
281
282
|
| `base44` | the shell's boot has to bind the Base44 app it talks to; the module links, the binding is the shell's |
|
|
282
283
|
| `godot` | needs the shell's game surface view and, on Android, the shell's pick of the engine's C++ runtime |
|
|
283
284
|
|
|
@@ -406,7 +406,31 @@ unresolved migration finding.
|
|
|
406
406
|
- `config_uninspectable`: the target `config.ts` cannot be read or the relevant
|
|
407
407
|
`navigation.topBarDefault.actions` cannot be inspected (exit 1).
|
|
408
408
|
- `topbar_coverage_failed`: a source top-bar control has no matching action
|
|
409
|
-
with a non-empty `onTap.actionId
|
|
409
|
+
with a non-empty `onTap.actionId`, or a source badge's action is not a complete
|
|
410
|
+
live count. When the app's `navLogicBundle` is a Branded Lite badge worker, the
|
|
411
|
+
badge's `valuePath` must also be a count that worker holds
|
|
412
|
+
(`$service:brandedLiteNav.chatBadge`, `.notificationsBadge`, `.cartBadge`) and sit on
|
|
413
|
+
the matching button (exit 1).
|
|
414
|
+
|
|
415
|
+
## `himi one-app header-badges` codes
|
|
416
|
+
|
|
417
|
+
Binds the source header's bell, chat and cart counts in `config.ts`. Success prints
|
|
418
|
+
`ok: true` and a `status`: `written`, `unchanged`, `would_write` (`--dry-run`),
|
|
419
|
+
`no_badges` or `nothing_to_bind`; `unmapped` lists badge buttons that are not clearly
|
|
420
|
+
a bell, chat or cart button and are never guessed. Failures print `ok: false` and a
|
|
421
|
+
top-level `code` on stderr.
|
|
422
|
+
|
|
423
|
+
- `invalid_usage`: required options are missing, duplicated, or unknown (exit 2).
|
|
424
|
+
- `evidence_invalid`: the evidence manifest or a collected file is missing, invalid,
|
|
425
|
+
fails its recorded hash, or a platform's runtime context was unavailable (exit 1).
|
|
426
|
+
- `config_uninspectable`: `config.ts` or `himalaya.content.json` cannot be read, so
|
|
427
|
+
the app's screens and navigation cannot be inspected, or `config.ts` cannot be
|
|
428
|
+
written; in that case the coverage ledger is put back as it was (exit 1).
|
|
429
|
+
- `worker_missing`: the app has no `tier5-src/himi-branded-lite-header-badges`, so a
|
|
430
|
+
config naming that worker would 404; re-scaffold from the current template (exit 1).
|
|
431
|
+
- `config_needs_manual_merge`: `config.ts` already has a `topBarDefault` or
|
|
432
|
+
`navLogicBundle` that differs, or its `navigation` cannot be edited safely; the
|
|
433
|
+
literal to merge is returned in `snippet` and nothing is written (exit 1).
|
|
410
434
|
|
|
411
435
|
## `himi one-app validate-design` codes
|
|
412
436
|
|
|
@@ -40,6 +40,7 @@ package in one greppable file) or `GET /v1/sdk/<name>` over HTTP; in the CLI,
|
|
|
40
40
|
- `@himalaya/keyboard` — Tier-5 typed binding for the platform's keyboard capability.
|
|
41
41
|
- `@himalaya/kyber-api` — narrow Tier-5 binding for Kyber BO HTTP calls.
|
|
42
42
|
- `@himalaya/l10n` — synchronous app-catalog copy (SDK foundation; requires host integration).
|
|
43
|
+
- `@himalaya/legacy-import` — Tier-5 typed binding for the one-time legacy import report.
|
|
43
44
|
- `@himalaya/live-activity` — Tier-5 typed binding to the platform's Live Activity capability.
|
|
44
45
|
- `@himalaya/local-db` — Tier-5 typed binding to the platform's local-database capability: a per-entity on-device store (EntityStore) + an offline WriteQueue, so a worker bundle can persist and query real data on device.
|
|
45
46
|
- `@himalaya/location` — Tier-5 typed binding for device location.
|
|
@@ -533,17 +533,39 @@ Apply these interpretation rules:
|
|
|
533
533
|
without observer/listener fields. Do not infer a count badge for every custom
|
|
534
534
|
component. Inspect its implementation and retain unknown behavior as unresolved.
|
|
535
535
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
536
|
+
**Bell, chat and cart badges are bound by a command, not by hand.** `himi one-app migrate` writes
|
|
537
|
+
`header-badge-plan.json`: the counters the source header carries, found by each button's id, icon and
|
|
538
|
+
accessibility label (the observer or listener id only marks a button as carrying a badge; it does not
|
|
539
|
+
say which counter). A badge button that is not clearly a bell, chat or cart button is listed under
|
|
540
|
+
`unmapped`; its counter stays an open obligation, never guessed. After scaffolding from the Branded Lite
|
|
541
|
+
template and mapping each source screen to its Himi screen (the `route` rows of `ONE-APP-COVERAGE.json`), run
|
|
542
|
+
|
|
543
|
+
```bash
|
|
544
|
+
himi one-app header-badges --evidence-dir .himi/one-app --content .
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
It adds `navigation.topBarDefault` with one literal action per counter (ids `chat`, `notifications` and
|
|
548
|
+
`cart`, opening `himi_business_chat`, `himi_notifications` and `himi_cart`, each with
|
|
549
|
+
`badge: { kind: "count", valuePath: "$service:brandedLiteNav.<chatBadge|notificationsBadge|cartBadge>" }`)
|
|
550
|
+
and `navigation.navLogicBundle` for the badges-only worker the template already ships under
|
|
551
|
+
`tier5-src/himi-branded-lite-header-badges`, and it records each bound button's `target` in the coverage
|
|
552
|
+
ledger. A source with no badges changes nothing. It never overwrites: a config that already has a
|
|
553
|
+
`topBarDefault` or `navLogicBundle` (and a ledger target you set) is left alone and reported, with the
|
|
554
|
+
literal to merge (`config_needs_manual_merge`). Run it again after mapping routes if you ran it first:
|
|
555
|
+
the rows it wrote move to the mapped screen. Then run `validate-topbar`, which checks that each badge's
|
|
556
|
+
`valuePath` is a count the worker holds and sits on the right button. A screen with its own `topBar`
|
|
557
|
+
replaces `topBarDefault`, so `validate-topbar` still asks that screen to carry the action.
|
|
558
|
+
|
|
559
|
+
The counts: the bell is the member's unseen notifications (read for the site the native bridge is bound
|
|
560
|
+
to), chat is the member's unread business chatrooms (as the server counts them, capped at 100) and cart is
|
|
561
|
+
the shopper's item count (every line's quantity). Each is `null` while unavailable (a Visitor's bell and
|
|
562
|
+
chat, offline, a failed or stale read, an old binary or the web for the bell) and the shell shows no badge
|
|
563
|
+
for `null` or 0, so none is ever a fake zero. If the source shows the bell or chat badge to Visitors, the plan
|
|
564
|
+
warns: a Himi header shows them to signed-in members only. They refresh at launch, whenever the signed-in
|
|
565
|
+
identity changes (the previous identity's numbers go first), on every foreground and on every notification
|
|
566
|
+
receipt, and a read that finishes after the identity changed is dropped. They do not poll: a screen that
|
|
567
|
+
changes the cart (an add-to-cart, a checkout) must call `tier5.brandedLiteNav.refreshBadges` itself, or the
|
|
568
|
+
cart badge waits for the next trigger.
|
|
547
569
|
|
|
548
570
|
Use a live `badge: { kind: "count", valuePath: "$service:sourceBadges.count" }`
|
|
549
571
|
only after implementing the actual source counter. Preserve the source button
|
|
@@ -3198,6 +3198,49 @@
|
|
|
3198
3198
|
}
|
|
3199
3199
|
]
|
|
3200
3200
|
},
|
|
3201
|
+
{
|
|
3202
|
+
"name": "@himalaya/legacy-import",
|
|
3203
|
+
"source": "core/sdk/legacy-import/src/index.ts",
|
|
3204
|
+
"description": "Tier-5 typed binding for the one-time legacy import report.",
|
|
3205
|
+
"api": [
|
|
3206
|
+
{
|
|
3207
|
+
"name": "LegacyImportSourceReport",
|
|
3208
|
+
"kind": "interface",
|
|
3209
|
+
"jsdoc": "",
|
|
3210
|
+
"decl": "export interface LegacyImportSourceReport {\n id: string;\n /** `done` | `empty` | `incomplete` | `failed` | `unregistered_kind` | `invalid_options` */\n status: string;\n /** Item counts — `items`, plus one per sink the source's items went to. */\n counts: Record<string, number>;\n error?: string;\n}"
|
|
3211
|
+
},
|
|
3212
|
+
{
|
|
3213
|
+
"name": "LegacyImportReportItem",
|
|
3214
|
+
"kind": "interface",
|
|
3215
|
+
"jsdoc": "",
|
|
3216
|
+
"decl": "export interface LegacyImportReportItem {\n key: string;\n /** The item's value — UTF-8 text, or base64 when `meta.encoding === \"base64\"`. */\n value: string;\n meta?: Record<string, string>;\n}"
|
|
3217
|
+
},
|
|
3218
|
+
{
|
|
3219
|
+
"name": "LegacyImportReport",
|
|
3220
|
+
"kind": "interface",
|
|
3221
|
+
"jsdoc": "",
|
|
3222
|
+
"decl": "export interface LegacyImportReport {\n /** The `legacyImport.id` that produced it. */\n id: string;\n /** Epoch ms the import ran. */\n extractedAt: number;\n sources: LegacyImportSourceReport[];\n /** Only the `report` sink's items. */\n items: LegacyImportReportItem[];\n}"
|
|
3223
|
+
},
|
|
3224
|
+
{
|
|
3225
|
+
"name": "read",
|
|
3226
|
+
"kind": "function",
|
|
3227
|
+
"jsdoc": "/** The import report for the signed-in principal, or null — none ran, it was acknowledged, it\n * belongs to another account, or this host has nothing to import (web). */",
|
|
3228
|
+
"decl": "export async function read(): Promise<LegacyImportReport | null>;"
|
|
3229
|
+
},
|
|
3230
|
+
{
|
|
3231
|
+
"name": "ack",
|
|
3232
|
+
"kind": "function",
|
|
3233
|
+
"jsdoc": "/** Delete the report. Idempotent: acknowledging twice (or with nothing to acknowledge) is fine. */",
|
|
3234
|
+
"decl": "export async function ack(): Promise<void>;"
|
|
3235
|
+
},
|
|
3236
|
+
{
|
|
3237
|
+
"name": "version",
|
|
3238
|
+
"kind": "const",
|
|
3239
|
+
"jsdoc": "/** Capability version, for bundles that gate on min binary version. */",
|
|
3240
|
+
"decl": "export const version = 1;"
|
|
3241
|
+
}
|
|
3242
|
+
]
|
|
3243
|
+
},
|
|
3201
3244
|
{
|
|
3202
3245
|
"name": "@himalaya/live-activity",
|
|
3203
3246
|
"source": "core/sdk/live-activity/src/index.ts",
|
|
@@ -39,7 +39,7 @@ Your page can only use capabilities the **app owner** turned on for your site. I
|
|
|
39
39
|
`capabilities`, allowing **every** method the capability's page lists — except
|
|
40
40
|
`presigned_upload.putFile`, which reads a device file and is allowed only when `files` is enabled
|
|
41
41
|
too. So enabling a capability is enough; the owner does not list methods.
|
|
42
|
-
- **What a Brandy app cannot enable:** `app_info`, `godot`, `himi_apps`, `live_activity`,
|
|
42
|
+
- **What a Brandy app cannot enable:** `app_info`, `godot`, `himi_apps`, `legacy_import`, `live_activity`,
|
|
43
43
|
`local_database`, `release_control`, `system_intents`, `ui` and `wix_platform` — most need wiring
|
|
44
44
|
a website app's shell does not have, so plan your page without them. `base44` works only when the
|
|
45
45
|
app also has a Base44 binding. Every other capability in the reference can be enabled; other Himi
|
|
@@ -32,6 +32,7 @@ the SDK sources, so it matches the shipped SDKs.
|
|
|
32
32
|
- [`himi_apps`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fhimi_apps?format=md) — Cross-app open / host queries. 4 methods · not in Brandy.
|
|
33
33
|
- [`iap`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fiap?format=md) — In-app-purchase capability. 9 methods.
|
|
34
34
|
- [`keyboard`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Fkeyboard?format=md) — Keyboard capability. 1 method.
|
|
35
|
+
- [`legacy_import`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Flegacy_import?format=md) — One-time legacy import report. 2 methods · not in Brandy.
|
|
35
36
|
- [`live_activity`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Flive_activity?format=md) — Live Activity capability. 3 methods · not in Brandy.
|
|
36
37
|
- [`local_database`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Flocal_database?format=md) — Local-database capability: a per-entity on-device store (EntityStore) + an offline WriteQueue, so a worker bundle can persist and query real data on device. 11 methods · not in Brandy.
|
|
37
38
|
- [`location`](https://apps.wix.com/_api/himi-serve/authoring/resource/web-sdk%2Flocation?format=md) — Device location. 10 methods.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/himalaya-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1600.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
|
|
6
6
|
"keywords": [
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"artifactId": "himalaya-cli"
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
|
-
"falconPackageHash": "
|
|
75
|
+
"falconPackageHash": "345b024a67019de4aeafb2b81fa91e65d43675b03bb58533eefb85a7"
|
|
76
76
|
}
|
|
@@ -42270,6 +42270,72 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
42270
42270
|
}
|
|
42271
42271
|
}
|
|
42272
42272
|
}
|
|
42273
|
+
},
|
|
42274
|
+
{
|
|
42275
|
+
"id": "",
|
|
42276
|
+
"body": {
|
|
42277
|
+
"package": "himalaya",
|
|
42278
|
+
"type": "HStack",
|
|
42279
|
+
"props": {
|
|
42280
|
+
"spacing": 8,
|
|
42281
|
+
"children": [
|
|
42282
|
+
{
|
|
42283
|
+
"id": "himi_blog_post.report",
|
|
42284
|
+
"body": {
|
|
42285
|
+
"package": "himalaya",
|
|
42286
|
+
"type": "Button",
|
|
42287
|
+
"props": {
|
|
42288
|
+
"title": "Report",
|
|
42289
|
+
"style": "secondary",
|
|
42290
|
+
"fullWidth": true,
|
|
42291
|
+
"action": {
|
|
42292
|
+
"actionId": "tier5.himiBlogPost.report"
|
|
42293
|
+
}
|
|
42294
|
+
}
|
|
42295
|
+
},
|
|
42296
|
+
"modifiers": {
|
|
42297
|
+
"hiddenPath": "$service:himiBlogPost.reported"
|
|
42298
|
+
}
|
|
42299
|
+
},
|
|
42300
|
+
{
|
|
42301
|
+
"id": "himi_blog_post.hide",
|
|
42302
|
+
"body": {
|
|
42303
|
+
"package": "himalaya",
|
|
42304
|
+
"type": "Button",
|
|
42305
|
+
"props": {
|
|
42306
|
+
"title": "Hide post",
|
|
42307
|
+
"style": "secondary",
|
|
42308
|
+
"fullWidth": true,
|
|
42309
|
+
"action": {
|
|
42310
|
+
"actionId": "tier5.himiBlogPost.openHide"
|
|
42311
|
+
}
|
|
42312
|
+
}
|
|
42313
|
+
},
|
|
42314
|
+
"modifiers": {
|
|
42315
|
+
"hiddenPath": "$service:himiBlogPost.hidden"
|
|
42316
|
+
}
|
|
42317
|
+
},
|
|
42318
|
+
{
|
|
42319
|
+
"id": "himi_blog_post.unhide",
|
|
42320
|
+
"body": {
|
|
42321
|
+
"package": "himalaya",
|
|
42322
|
+
"type": "Button",
|
|
42323
|
+
"props": {
|
|
42324
|
+
"title": "Undo hide",
|
|
42325
|
+
"style": "secondary",
|
|
42326
|
+
"fullWidth": true,
|
|
42327
|
+
"action": {
|
|
42328
|
+
"actionId": "tier5.himiBlogPost.unhide"
|
|
42329
|
+
}
|
|
42330
|
+
}
|
|
42331
|
+
},
|
|
42332
|
+
"modifiers": {
|
|
42333
|
+
"hiddenPath": "$service:himiBlogPost.notHidden"
|
|
42334
|
+
}
|
|
42335
|
+
}
|
|
42336
|
+
]
|
|
42337
|
+
}
|
|
42338
|
+
}
|
|
42273
42339
|
}
|
|
42274
42340
|
]
|
|
42275
42341
|
}
|
|
@@ -42528,6 +42594,122 @@ const TEMPLATED: { pattern: string; display: string; liveSeed?: LiveSeed; static
|
|
|
42528
42594
|
"hiddenPath": "$service:himiBlogPost.noPost"
|
|
42529
42595
|
}
|
|
42530
42596
|
},
|
|
42597
|
+
{
|
|
42598
|
+
"id": "himi_blog_post.hide_sheet",
|
|
42599
|
+
"body": {
|
|
42600
|
+
"package": "himalaya",
|
|
42601
|
+
"type": "BottomSheet",
|
|
42602
|
+
"props": {
|
|
42603
|
+
"presentedPath": "$service:himiBlogPost.hideSheetOpen",
|
|
42604
|
+
"dismissible": true,
|
|
42605
|
+
"showGrabber": true,
|
|
42606
|
+
"onDismiss": {
|
|
42607
|
+
"actionId": "tier5.himiBlogPost.closeHide"
|
|
42608
|
+
},
|
|
42609
|
+
"content": {
|
|
42610
|
+
"id": "",
|
|
42611
|
+
"body": {
|
|
42612
|
+
"package": "himalaya",
|
|
42613
|
+
"type": "VStack",
|
|
42614
|
+
"props": {
|
|
42615
|
+
"spacing": 12,
|
|
42616
|
+
"alignment": "leading",
|
|
42617
|
+
"children": [
|
|
42618
|
+
{
|
|
42619
|
+
"id": "",
|
|
42620
|
+
"body": {
|
|
42621
|
+
"package": "himalaya",
|
|
42622
|
+
"type": "Text",
|
|
42623
|
+
"props": {
|
|
42624
|
+
"text": "Why are you hiding this post?",
|
|
42625
|
+
"style": "title3"
|
|
42626
|
+
}
|
|
42627
|
+
}
|
|
42628
|
+
},
|
|
42629
|
+
{
|
|
42630
|
+
"id": "himi_blog_post.hide_offensive",
|
|
42631
|
+
"body": {
|
|
42632
|
+
"package": "himalaya",
|
|
42633
|
+
"type": "Button",
|
|
42634
|
+
"props": {
|
|
42635
|
+
"title": "It is offensive",
|
|
42636
|
+
"style": "secondary",
|
|
42637
|
+
"fullWidth": true,
|
|
42638
|
+
"action": {
|
|
42639
|
+
"actionId": "tier5.himiBlogPost.hide",
|
|
42640
|
+
"params": {
|
|
42641
|
+
"reason": "offensive"
|
|
42642
|
+
}
|
|
42643
|
+
}
|
|
42644
|
+
}
|
|
42645
|
+
}
|
|
42646
|
+
},
|
|
42647
|
+
{
|
|
42648
|
+
"id": "himi_blog_post.hide_misleading",
|
|
42649
|
+
"body": {
|
|
42650
|
+
"package": "himalaya",
|
|
42651
|
+
"type": "Button",
|
|
42652
|
+
"props": {
|
|
42653
|
+
"title": "It is misleading",
|
|
42654
|
+
"style": "secondary",
|
|
42655
|
+
"fullWidth": true,
|
|
42656
|
+
"action": {
|
|
42657
|
+
"actionId": "tier5.himiBlogPost.hide",
|
|
42658
|
+
"params": {
|
|
42659
|
+
"reason": "misleading"
|
|
42660
|
+
}
|
|
42661
|
+
}
|
|
42662
|
+
}
|
|
42663
|
+
}
|
|
42664
|
+
},
|
|
42665
|
+
{
|
|
42666
|
+
"id": "himi_blog_post.hide_other",
|
|
42667
|
+
"body": {
|
|
42668
|
+
"package": "himalaya",
|
|
42669
|
+
"type": "Button",
|
|
42670
|
+
"props": {
|
|
42671
|
+
"title": "Something else",
|
|
42672
|
+
"style": "secondary",
|
|
42673
|
+
"fullWidth": true,
|
|
42674
|
+
"action": {
|
|
42675
|
+
"actionId": "tier5.himiBlogPost.hide",
|
|
42676
|
+
"params": {
|
|
42677
|
+
"reason": "other"
|
|
42678
|
+
}
|
|
42679
|
+
}
|
|
42680
|
+
}
|
|
42681
|
+
}
|
|
42682
|
+
},
|
|
42683
|
+
{
|
|
42684
|
+
"id": "himi_blog_post.hide_cancel",
|
|
42685
|
+
"body": {
|
|
42686
|
+
"package": "himalaya",
|
|
42687
|
+
"type": "Button",
|
|
42688
|
+
"props": {
|
|
42689
|
+
"title": "Cancel",
|
|
42690
|
+
"style": "secondary",
|
|
42691
|
+
"fullWidth": true,
|
|
42692
|
+
"action": {
|
|
42693
|
+
"actionId": "tier5.himiBlogPost.closeHide"
|
|
42694
|
+
}
|
|
42695
|
+
}
|
|
42696
|
+
}
|
|
42697
|
+
}
|
|
42698
|
+
]
|
|
42699
|
+
}
|
|
42700
|
+
},
|
|
42701
|
+
"modifiers": {
|
|
42702
|
+
"padding": {
|
|
42703
|
+
"leading": 20,
|
|
42704
|
+
"trailing": 20,
|
|
42705
|
+
"top": 16,
|
|
42706
|
+
"bottom": 24
|
|
42707
|
+
}
|
|
42708
|
+
}
|
|
42709
|
+
}
|
|
42710
|
+
}
|
|
42711
|
+
}
|
|
42712
|
+
},
|
|
42531
42713
|
{
|
|
42532
42714
|
"id": "",
|
|
42533
42715
|
"body": {
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// The posts this device's reader chose to hide, as the One App blog does: a client-side list of post ids that the
|
|
2
|
+
// blog feed, the Home cards and Saved leave out. Nothing is sent to the site, and another device or account does not
|
|
3
|
+
// share it. It is the saved-posts store's twin (see himi-blog-saved.ts) and reads storage the same way: native workers
|
|
4
|
+
// have only the sync `himalaya.storage` KV, a browser has `localStorage`, and each screen runs its own worker, so
|
|
5
|
+
// the durable arm is what lets a Hide on the post screen reach the feed's worker.
|
|
6
|
+
const KEY = "himi-blog:hidden-posts:v1";
|
|
7
|
+
|
|
8
|
+
type StorageLike = {
|
|
9
|
+
getItem: (key: string) => string | null;
|
|
10
|
+
setItem: (key: string, value: string) => void;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type HiddenHost = typeof globalThis & {
|
|
14
|
+
himalaya?: { storage?: StorageLike };
|
|
15
|
+
localStorage?: StorageLike;
|
|
16
|
+
__himiBlogHiddenIds?: string[];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const host = globalThis as HiddenHost;
|
|
20
|
+
|
|
21
|
+
function storage(): StorageLike | undefined {
|
|
22
|
+
return host.himalaya?.storage ?? host.localStorage;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const unique = (ids: string[]): string[] => Array.from(new Set(ids.map((id) => id.trim()).filter(Boolean)));
|
|
26
|
+
|
|
27
|
+
export function readHiddenIds(): string[] {
|
|
28
|
+
try {
|
|
29
|
+
const raw = storage()?.getItem(KEY);
|
|
30
|
+
if (raw) {
|
|
31
|
+
const parsed = JSON.parse(raw);
|
|
32
|
+
if (Array.isArray(parsed)) return unique(parsed.filter((id): id is string => typeof id === "string"));
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
// Unreadable storage: fall back to what this worker context holds in memory.
|
|
36
|
+
}
|
|
37
|
+
return unique(host.__himiBlogHiddenIds ?? []);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function writeHiddenIds(ids: string[]): void {
|
|
41
|
+
const next = unique(ids);
|
|
42
|
+
host.__himiBlogHiddenIds = next;
|
|
43
|
+
try {
|
|
44
|
+
storage()?.setItem(KEY, JSON.stringify(next));
|
|
45
|
+
} catch {
|
|
46
|
+
// Storage-less hosts keep the in-memory arm only.
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function isHiddenId(id: string): boolean {
|
|
51
|
+
return readHiddenIds().includes(id);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function hideId(id: string): void {
|
|
55
|
+
writeHiddenIds([id, ...readHiddenIds()]);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function unhideId(id: string): void {
|
|
59
|
+
writeHiddenIds(readHiddenIds().filter((hiddenId) => hiddenId !== id));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** The items a list may show: every one whose `id` this device has not hidden. */
|
|
63
|
+
export function withoutHidden<T extends { id?: string | null }>(items: T[]): T[] {
|
|
64
|
+
const hidden = new Set(readHiddenIds());
|
|
65
|
+
return hidden.size ? items.filter((item) => !item.id || !hidden.has(item.id)) : items;
|
|
66
|
+
}
|
|
@@ -4,6 +4,7 @@ import { queryCategories, queryPosts, type WixPost } from "@himalaya/wix-blog";
|
|
|
4
4
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
5
5
|
import { getAll, upsert, type DbEntity } from "@himalaya/local-db";
|
|
6
6
|
import { formatDateMedium } from "../_shared/engine-intl.js";
|
|
7
|
+
import { withoutHidden } from "../_shared/himi-blog-hidden.js";
|
|
7
8
|
|
|
8
9
|
const PAGE_SIZE = 20;
|
|
9
10
|
|
|
@@ -137,7 +138,8 @@ function normalize(post: WixPost, categoryMap: Map<string, string>): PostRow {
|
|
|
137
138
|
|
|
138
139
|
function applyFilters(s: S): S {
|
|
139
140
|
const needle = s.query.trim().toLowerCase();
|
|
140
|
-
|
|
141
|
+
// Posts this device's reader hid (on the post screen) never show, whatever the cache or the live page holds.
|
|
142
|
+
const posts = withoutHidden(s.allPosts).filter((post) => {
|
|
141
143
|
const categoryOk = !s.selectedCategoryId || post.categoryId === s.selectedCategoryId;
|
|
142
144
|
const queryOk =
|
|
143
145
|
!needle ||
|
|
@@ -5,6 +5,7 @@ import { getPost, likePost, unlikePost, type WixPost, type WixPostWithContent }
|
|
|
5
5
|
import { comments, BLOG_COMMENTS_APP_ID, blogCommentRow, listBlogComments, type WixBlogCommentRow } from "@himalaya/wix-comments";
|
|
6
6
|
import { get, type DbEntity } from "@himalaya/local-db";
|
|
7
7
|
import { isSavedId, toggleSavedId } from "../_shared/himi-blog-saved";
|
|
8
|
+
import { hideId, isHiddenId, unhideId } from "../_shared/himi-blog-hidden";
|
|
8
9
|
import { stashCopy, copyParam, copyTemplate } from "../_shared/himi-copy.js";
|
|
9
10
|
import { formatDateMedium, formatMonthDay } from "../_shared/engine-intl.js";
|
|
10
11
|
import { openRichLink } from "../_shared/rich-content-link.js";
|
|
@@ -64,6 +65,14 @@ interface S {
|
|
|
64
65
|
notLiked: boolean;
|
|
65
66
|
saved: boolean;
|
|
66
67
|
notSaved: boolean;
|
|
68
|
+
/** This device's reader hid the post: the feed, Home and Saved leave it out, and this screen offers Undo. */
|
|
69
|
+
hidden: boolean;
|
|
70
|
+
notHidden: boolean;
|
|
71
|
+
/** The reason sheet (offensive / misleading / other) is open. */
|
|
72
|
+
hideSheetOpen: boolean;
|
|
73
|
+
/** The reader reported the post this visit; the report button then says so and stops sending. */
|
|
74
|
+
reported: boolean;
|
|
75
|
+
notReported: boolean;
|
|
67
76
|
commentDraft: string;
|
|
68
77
|
comments: CommentRow[];
|
|
69
78
|
commentsUnavailable: boolean;
|
|
@@ -212,6 +221,8 @@ function derive(s: S): S {
|
|
|
212
221
|
hasBodyJson: s.bodyJson !== "",
|
|
213
222
|
notLiked: !s.liked,
|
|
214
223
|
notSaved: !s.saved,
|
|
224
|
+
notHidden: !s.hidden,
|
|
225
|
+
notReported: !s.reported,
|
|
215
226
|
commentsAvailable: !s.commentsUnavailable,
|
|
216
227
|
};
|
|
217
228
|
}
|
|
@@ -238,6 +249,11 @@ const baseState: S = derive({
|
|
|
238
249
|
notLiked: true,
|
|
239
250
|
saved: false,
|
|
240
251
|
notSaved: true,
|
|
252
|
+
hidden: false,
|
|
253
|
+
notHidden: true,
|
|
254
|
+
hideSheetOpen: false,
|
|
255
|
+
reported: false,
|
|
256
|
+
notReported: true,
|
|
241
257
|
commentDraft: "",
|
|
242
258
|
comments: [],
|
|
243
259
|
commentsUnavailable: false,
|
|
@@ -278,6 +294,7 @@ async function cachedPostState(s: S, id: string): Promise<S> {
|
|
|
278
294
|
initial: String(cached.initial ?? "") || (title[0] || "#").toUpperCase(),
|
|
279
295
|
liked: false,
|
|
280
296
|
saved: isSavedId(id),
|
|
297
|
+
hidden: isHiddenId(id),
|
|
281
298
|
comments: [],
|
|
282
299
|
commentsUnavailable: true,
|
|
283
300
|
commentStatusText: copyParam("blogPost.commentsUnavailable", "Comments are unavailable right now."),
|
|
@@ -331,6 +348,7 @@ async function loadPostState(s: S): Promise<S | undefined> {
|
|
|
331
348
|
initial: (title[0] || "#").toUpperCase(),
|
|
332
349
|
liked: Boolean(post.memberInteraction?.liked),
|
|
333
350
|
saved: isSavedId(id),
|
|
351
|
+
hidden: isHiddenId(id),
|
|
334
352
|
comments,
|
|
335
353
|
commentsUnavailable,
|
|
336
354
|
commentStatusText: commentsUnavailable
|
|
@@ -359,6 +377,14 @@ const svc = defineService<S, {
|
|
|
359
377
|
like: (s: S) => Promise<S>;
|
|
360
378
|
unlike: (s: S) => Promise<S>;
|
|
361
379
|
toggleSave: (s: S) => S;
|
|
380
|
+
/** Report the post: no site API takes a member's report, so the reader is thanked and the tap is the signal. */
|
|
381
|
+
report: (s: S) => S;
|
|
382
|
+
openHide: (s: S) => S;
|
|
383
|
+
closeHide: (s: S) => S;
|
|
384
|
+
/** Hide the post on this device. The sheet's three reasons (offensive, misleading, other) are asked for as the One
|
|
385
|
+
* App asks them, but the list keeps only the id and the site is told nothing, so the worker does not read the reason. */
|
|
386
|
+
hide: (s: S) => S;
|
|
387
|
+
unhide: (s: S) => S;
|
|
362
388
|
share: (s: S) => Promise<S>;
|
|
363
389
|
setComment: (s: S, arg?: unknown) => S;
|
|
364
390
|
submitComment: (s: S) => Promise<S>;
|
|
@@ -397,6 +423,22 @@ const svc = defineService<S, {
|
|
|
397
423
|
const saved = toggleSavedId(s.id);
|
|
398
424
|
return derive({ ...s, saved, actionMessage: saved ? copyParam("blogPost.savedMessage", "Saved for later") : copyParam("blogPost.unsavedMessage", "Removed from saved") });
|
|
399
425
|
},
|
|
426
|
+
report: (s) => {
|
|
427
|
+
if (!s.id || s.reported) return s;
|
|
428
|
+
return derive({ ...s, reported: true, actionMessage: copyParam("blogPost.reportedMessage", "Post reported") });
|
|
429
|
+
},
|
|
430
|
+
openHide: (s) => s.id ? derive({ ...s, hideSheetOpen: true }) : s,
|
|
431
|
+
closeHide: (s) => derive({ ...s, hideSheetOpen: false }),
|
|
432
|
+
hide: (s) => {
|
|
433
|
+
if (!s.id) return s;
|
|
434
|
+
hideId(s.id);
|
|
435
|
+
return derive({ ...s, hidden: true, hideSheetOpen: false, actionMessage: copyParam("blogPost.hiddenMessage", "Post hidden. It will not show in your feeds.") });
|
|
436
|
+
},
|
|
437
|
+
unhide: (s) => {
|
|
438
|
+
if (!s.id) return s;
|
|
439
|
+
unhideId(s.id);
|
|
440
|
+
return derive({ ...s, hidden: false, actionMessage: copyParam("blogPost.unhiddenMessage", "Post is visible again") });
|
|
441
|
+
},
|
|
400
442
|
share: async (s) => {
|
|
401
443
|
if (!s.title) return s;
|
|
402
444
|
try {
|
|
@@ -3,6 +3,7 @@ import { defineService } from "@himalaya/state";
|
|
|
3
3
|
import { getPost, type WixPost } from "@himalaya/wix-blog";
|
|
4
4
|
import { get, type DbEntity } from "@himalaya/local-db";
|
|
5
5
|
import { readSavedIds, writeSavedIds } from "../_shared/himi-blog-saved";
|
|
6
|
+
import { readHiddenIds } from "../_shared/himi-blog-hidden";
|
|
6
7
|
import { stashCopy, copyParam } from "../_shared/himi-copy.js";
|
|
7
8
|
import { formatDateMedium } from "../_shared/engine-intl.js";
|
|
8
9
|
|
|
@@ -144,7 +145,9 @@ const baseState: S = derive({
|
|
|
144
145
|
});
|
|
145
146
|
|
|
146
147
|
async function loadSavedState(s: S): Promise<S> {
|
|
147
|
-
|
|
148
|
+
// A saved post this device's reader also hid stays in the saved list (Undo brings it back) but is not shown.
|
|
149
|
+
const hidden = new Set(readHiddenIds());
|
|
150
|
+
const ids = readSavedIds().filter((id) => !hidden.has(id));
|
|
148
151
|
if (!ids.length) {
|
|
149
152
|
return derive({ ...s, status: "ready", posts: [], emptyText: copyParam("saved.emptyText", "No saved posts yet.") });
|
|
150
153
|
}
|
|
@@ -26,6 +26,7 @@ import { formatDateMedium } from "../_shared/engine-intl.js";
|
|
|
26
26
|
import { readSavedProducts, type SavedProduct } from "../_shared/himi-store-saved.js";
|
|
27
27
|
import { loadStoreCategories, type StoreCategoryCard } from "../_shared/himi-store-categories.js";
|
|
28
28
|
import { readSavedIds } from "../_shared/himi-blog-saved.js";
|
|
29
|
+
import { withoutHidden } from "../_shared/himi-blog-hidden.js";
|
|
29
30
|
import { wixMediaUrl } from "@himalaya/wix-media";
|
|
30
31
|
import { groupImage, programImage } from "../_shared/himi-media.js";
|
|
31
32
|
import { isWixVideoWebRefusal, listLatestVideos, videoCard, type WixVideoCard } from "@himalaya/wix-video";
|
|
@@ -770,8 +771,10 @@ async function fetchExtrasSignal(arg: unknown): Promise<ExtrasSignal> {
|
|
|
770
771
|
// read used to make; a failure collapses both blocks silently.
|
|
771
772
|
jobs.push(queryPosts({ query: { paging: { limit: 8 }, sort: [{ fieldName: "firstPublishedDate", order: "DESC" }] } })
|
|
772
773
|
.then((response) => {
|
|
773
|
-
|
|
774
|
-
|
|
774
|
+
// Posts this device's reader hid on the post screen are left out of both blocks.
|
|
775
|
+
const posts = withoutHidden(response.posts ?? []);
|
|
776
|
+
extras.announcementTitle = cleanTitle(posts[0]?.title);
|
|
777
|
+
extras.postCards = posts.filter((post) => post.id).slice(0, 6).map(postCard);
|
|
775
778
|
})
|
|
776
779
|
.catch(() => { /* collapse silently */ }));
|
|
777
780
|
}
|