mindoodb-app-sdk 0.0.53 → 0.0.54
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/README.md +29 -55
- package/dist/index.d.ts +61 -3
- package/dist/index.js +273 -7
- package/dist/testing/index.d.ts +1 -1
- package/dist/{types-CsKw_niD.d.ts → types-CX-o1Xyq.d.ts} +7 -0
- package/dist/vite/index.d.ts +18 -5
- package/dist/vite/index.js +156 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,26 +22,17 @@ A **MindooDB App** is any web application that uses this SDK to communicate with
|
|
|
22
22
|
|
|
23
23
|
## Architecture
|
|
24
24
|
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
│ │ │
|
|
37
|
-
│ ┌─────────────────────────┼─────────────────────────┐ │
|
|
38
|
-
│ │ Your App (sandboxed iframe / window) │ │
|
|
39
|
-
│ │ │ │ │
|
|
40
|
-
│ │ ┌──────────▼──────────┐ │ │
|
|
41
|
-
│ │ │ mindoodb-app-sdk │ │ │
|
|
42
|
-
│ │ └─────────────────────┘ │ │
|
|
43
|
-
│ └───────────────────────────────────────────────────┘ │
|
|
44
|
-
└─────────────────────────────────────────────────────────┘
|
|
25
|
+
```mermaid
|
|
26
|
+
flowchart TB
|
|
27
|
+
subgraph haven["Haven (browser tab)"]
|
|
28
|
+
direction TB
|
|
29
|
+
ui["Haven UI<br/>(theme, viewport)"] --> bridge["Bridge Host<br/>(RPC + streams)"]
|
|
30
|
+
bridge --> db["MindooDB<br/>(encrypted databases)"]
|
|
31
|
+
subgraph app["Your App (sandboxed iframe / window)"]
|
|
32
|
+
sdk["mindoodb-app-sdk"]
|
|
33
|
+
end
|
|
34
|
+
bridge -- "postMessage + MessagePort" --> sdk
|
|
35
|
+
end
|
|
45
36
|
```
|
|
46
37
|
|
|
47
38
|
The bridge carries RPC calls (documents, views, database info), binary attachment streams, and push events (theme changes, viewport resizes) over a single `MessagePort`.
|
|
@@ -757,23 +748,11 @@ Two layers are available:
|
|
|
757
748
|
|
|
758
749
|
The end-to-end flow is the same in both cases:
|
|
759
750
|
|
|
760
|
-
```
|
|
761
|
-
|
|
762
|
-
edit
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
│ text: [{ path, baseHeads, edits }]
|
|
766
|
-
│ })
|
|
767
|
-
▼
|
|
768
|
-
┌────────────────────────────────────────────────────┐
|
|
769
|
-
│ Haven applies edits at `baseHeads` and merges with │
|
|
770
|
-
│ concurrent changes via Automerge │
|
|
771
|
-
└─────────────────────────┬──────────────────────────┘
|
|
772
|
-
│ canonical merged document
|
|
773
|
-
▼
|
|
774
|
-
┌────────────────────────────────────────────────────┐
|
|
775
|
-
│ App reconciles its editor with the canonical text │
|
|
776
|
-
└────────────────────────────────────────────────────┘
|
|
751
|
+
```mermaid
|
|
752
|
+
flowchart TB
|
|
753
|
+
edit(["edit"]) --> buffer["App buffer<br/>(local string + pending splices)"]
|
|
754
|
+
buffer -- "flush: documents.update({ text: [{ path, baseHeads, edits }] })" --> merge["Haven applies edits at baseHeads<br/>and merges with concurrent changes via Automerge"]
|
|
755
|
+
merge -- "canonical merged document" --> reconcile["App reconciles its editor<br/>with the canonical text"]
|
|
777
756
|
```
|
|
778
757
|
|
|
779
758
|
#### Text patch shape
|
|
@@ -1003,24 +982,14 @@ If you must use binary sync, Haven decrypts the canonical document, merges incom
|
|
|
1003
982
|
|
|
1004
983
|
Typical flow:
|
|
1005
984
|
|
|
1006
|
-
```
|
|
1007
|
-
|
|
1008
|
-
open
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
▼
|
|
1015
|
-
┌────────────────────────────────────────────────────┐
|
|
1016
|
-
save ──► │ applyAutomergeChanges({ baseHeads, replicaHeads, │
|
|
1017
|
-
│ changes }) │
|
|
1018
|
-
└─────────────────────────┬──────────────────────────┘
|
|
1019
|
-
│ Haven merges + persists
|
|
1020
|
-
▼
|
|
1021
|
-
┌────────────────────────────────────────────────────┐
|
|
1022
|
-
│ Apply result.changesSince locally (or skip if empty) │
|
|
1023
|
-
└────────────────────────────────────────────────────┘
|
|
985
|
+
```mermaid
|
|
986
|
+
flowchart TB
|
|
987
|
+
open(["open"]) --> snapshot["getAutomergeSnapshot<br/>→ load local replica"]
|
|
988
|
+
snapshot --> local["Local Automerge doc<br/>(or span edits applied locally)"]
|
|
989
|
+
editStep(["edit"]) --> local
|
|
990
|
+
local -- "getChangesSince(baseHeads)" --> apply["applyAutomergeChanges({<br/>baseHeads, replicaHeads, changes })"]
|
|
991
|
+
saveStep(["save"]) --> apply
|
|
992
|
+
apply -- "Haven merges + persists" --> result["Apply result.changesSince locally<br/>(or skip if empty)"]
|
|
1024
993
|
```
|
|
1025
994
|
|
|
1026
995
|
Bridge RPCs: `documents.automerge.getSnapshot` and `documents.automerge.applyChanges`.
|
|
@@ -1702,6 +1671,7 @@ What the page shows comes from the optional `listing` in `haven-app.json`. Haven
|
|
|
1702
1671
|
"listing": {
|
|
1703
1672
|
"summary": { "en": "Plan trips together.", "de": "Reisen gemeinsam planen." },
|
|
1704
1673
|
"description": { "en": "First paragraph.\n\nSecond paragraph." },
|
|
1674
|
+
"descriptionMarkdown": { "en": "**Plan** together.\n\n- Shared board\n- [Website](https://trips.example.com)" },
|
|
1705
1675
|
"icon": "icon.svg",
|
|
1706
1676
|
"screenshots": [{ "file": "screenshots/board.webp", "caption": { "en": "The trip board" } }],
|
|
1707
1677
|
"publisher": { "name": "Mindoo GmbH", "url": "https://mindoo.de" }
|
|
@@ -1711,6 +1681,10 @@ What the page shows comes from the optional `listing` in `haven-app.json`. Haven
|
|
|
1711
1681
|
|
|
1712
1682
|
Texts are a string or a per-locale map with an `en` fallback. Image paths are relative to the app origin or absolute `https:` URLs. The listing is display-only and grants nothing.
|
|
1713
1683
|
|
|
1684
|
+
Opening the app URL directly also puts share tags into `index.html` (`twitter:card` = `summary`, plus the Open Graph tags other apps read), with the app icon as the image. A production build takes the absolute URL from `publicUrl` in `haven-app.json`. `vite dev` uses the dev server's own origin instead, so `http://127.0.0.1:<port>/` previews against itself. Crawlers do not run the landing page's JavaScript, which is why the tags are in the HTML file.
|
|
1685
|
+
|
|
1686
|
+
`description` is plain text. `descriptionMarkdown` is the same text with formatting, in a small Markdown subset: paragraphs, headings, bullet and numbered lists, `**bold**`, `_italic_`, `` `code` ``, `[text](https://…)`, `[text](mailto:…)` and bare `https://…` links. Links to any other scheme render as plain text. Readers that know `descriptionMarkdown` show it instead of `description`; older Haven versions ignore it, so set both if they matter. `listingMarkdownToPlainText()` derives the plain version. A publisher `url` (`https:` only) turns the publisher name into a link.
|
|
1687
|
+
|
|
1714
1688
|
For automated and manual tests use a separate test URL that frames the app with a mock host instead — see "Browser test host" in [`TESTING.md`](./TESTING.md). End users never see that page, and they never see mock data.
|
|
1715
1689
|
|
|
1716
1690
|
### Haven-hosted bundles
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { M as MindooDBAppAttachmentPreviewMode, a as MindooDBAppDragBindSourceOptions, b as MindooDBAppDragStartInput, c as MindooDBAppDragStartResult, d as MindooDBAppDragPreview, e as MindooDBAppBridge, f as MindooDBAppHostShortcutBinding, g as MindooDBAppHostShortcutAction, h as MindooDBAppHostingMode, i as MindooDBAppDefinition, j as MindooDBAppDatabase, k as MindooDBAppDocument, l as MindooDBAppRichTextSpan, m as MindooDBAppRichTextSnapshot, n as MindooDBAppCreateDocumentInput } from './types-
|
|
2
|
-
export { o as MINDOODB_APP_DEFINITION_FILE_NAME, p as MINDOODB_APP_DEFINITION_FORMAT, q as MINDOODB_APP_DEFINITION_PERMISSIONS, r as MINDOODB_APP_DEFINITION_REGISTRATION_PERMISSIONS, s as MINDOODB_APP_DEFINITION_VERSION, t as MINDOODB_APP_LISTING_DESCRIPTION_MAX, u as MINDOODB_APP_LISTING_MAX_SCREENSHOTS, v as MINDOODB_APP_LISTING_SUMMARY_MAX, w as MINDOODB_APP_SEAL_SIGNING_DOMAIN, x as MINDOODB_APP_WELL_KNOWN_DRAG_TYPES, y as MindooDBAppAccessDecision, z as MindooDBAppAccessTier, A as MindooDBAppAttachmentApi, B as MindooDBAppAttachmentChunk, C as MindooDBAppAttachmentInfo, D as MindooDBAppAttachmentPreviewOptions, E as MindooDBAppAttachmentPreviewSession, F as MindooDBAppAutomergeChangesPatch, G as MindooDBAppAutomergeChangesSince, H as MindooDBAppAutomergeGetOptions, I as MindooDBAppAutomergePatchResult, J as MindooDBAppAutomergeSnapshot, K as MindooDBAppBridgeBeforeCloseAck, L as MindooDBAppBridgeBeforeCloseMessage, N as MindooDBAppBridgeConnectMessage, O as MindooDBAppBridgeConnectOptions, P as MindooDBAppBridgeConnectedMessage, Q as MindooDBAppBridgeDragDropMessage, R as MindooDBAppBridgeDragLeaveMessage, S as MindooDBAppBridgeDragOverMessage, T as MindooDBAppBridgeErrorPayload, U as MindooDBAppBridgeHandshakeErrorMessage, V as MindooDBAppBridgeHostFocusChangedMessage, W as MindooDBAppBridgeLocaleChangedMessage, X as MindooDBAppBridgePortMessage, Y as MindooDBAppBridgeQueryResultMessage, Z as MindooDBAppBridgeRpcError, _ as MindooDBAppBridgeRpcMessage, $ as MindooDBAppBridgeRpcRequest, a0 as MindooDBAppBridgeRpcSuccess, a1 as MindooDBAppBridgeShortcutInvokedMessage, a2 as MindooDBAppBridgeShortcutsChangedMessage, a3 as MindooDBAppBridgeStreamAbortRequest, a4 as MindooDBAppBridgeStreamAck, a5 as MindooDBAppBridgeStreamCloseRequest, a6 as MindooDBAppBridgeStreamError, a7 as MindooDBAppBridgeStreamMessage, a8 as MindooDBAppBridgeStreamOpenResult, a9 as MindooDBAppBridgeStreamReadRequest, aa as MindooDBAppBridgeStreamWriteRequest, ab as MindooDBAppBridgeThemeChangedMessage, ac as MindooDBAppBridgeUiPreferencesChangedMessage, ad as MindooDBAppBridgeViewChangedMessage, ae as MindooDBAppBridgeViewportChangedMessage, af as MindooDBAppBridgeWorkspaceFocusRequestedMessage, ag as MindooDBAppCapability, ah as MindooDBAppConfiguredViewCategorizationStyle, ai as MindooDBAppConfiguredViewColumn, aj as MindooDBAppConfiguredViewColumnRole, ak as MindooDBAppConfiguredViewExpressionMode, al as MindooDBAppConfiguredViewFieldExpression, am as MindooDBAppConfiguredViewFilterDefinition, an as MindooDBAppConfiguredViewFilterMode, ao as MindooDBAppConfiguredViewFilterRule, ap as MindooDBAppConfiguredViewFormulaExpression, aq as MindooDBAppConfiguredViewFormulaFilterDefinition, ar as MindooDBAppConfiguredViewPreviewMode, as as MindooDBAppConfiguredViewRuleFilterDefinition, at as MindooDBAppConfiguredViewRuleMatchMode, au as MindooDBAppConfiguredViewRuleOperator, av as MindooDBAppConfiguredViewValueExpression, aw as MindooDBAppCreateKeyInfo, ax as MindooDBAppCreateViewInput, ay as MindooDBAppCreateViewNavigatorInput, az as MindooDBAppDatabaseInfo, aA as MindooDBAppDefinitionDatabase, aB as MindooDBAppDefinitionListing, aC as MindooDBAppDefinitionPermission, aD as MindooDBAppDefinitionRegistrationPermission, aE as MindooDBAppDefinitionScreenshot, aF as MindooDBAppDefinitionValidation, aG as MindooDBAppDirectoryApi, aH as MindooDBAppDirectoryEntry, aI as MindooDBAppDocumentApi, aJ as MindooDBAppDocumentHeadCursorResult, aK as MindooDBAppDocumentHistoryEntry, aL as MindooDBAppDocumentListQuery, aM as MindooDBAppDocumentListResult, aN as MindooDBAppDocumentQuery, aO as MindooDBAppDocumentRevisionId, aP as MindooDBAppDocumentScanPreset, aQ as MindooDBAppDocumentSummary, aR as MindooDBAppDragApi, aS as MindooDBAppDragCancelReason, aT as MindooDBAppDragDropEvent, aU as MindooDBAppDragEffect, aV as MindooDBAppDragHoverResult, aW as MindooDBAppDragOffer, aX as MindooDBAppDragOverEvent, aY as MindooDBAppDragPointer, aZ as MindooDBAppDragProfile, a_ as MindooDBAppEntryAttachmentRef, a$ as MindooDBAppEntryProvenance, b0 as MindooDBAppExtractDocumentTextInput, b1 as MindooDBAppExtractDocumentTextResult, b2 as MindooDBAppExtractTextFormat, b3 as MindooDBAppExtractionSetup, b4 as MindooDBAppFulltextSetup, b5 as MindooDBAppHistoricalDocument, b6 as MindooDBAppHistoryQuery, b7 as MindooDBAppHostTheme, b8 as MindooDBAppIdentityApi, b9 as MindooDBAppInaccessibleDocument, ba as MindooDBAppInaccessibleDocumentListQuery, bb as MindooDBAppInaccessibleDocumentListResult, bc as MindooDBAppJsonCounterIncrementPatch, bd as MindooDBAppJsonListDeletePatch, be as MindooDBAppJsonListInsertPatch, bf as MindooDBAppJsonPatch, bg as MindooDBAppJsonSetPatch, bh as MindooDBAppJsonTextMarkPatch, bi as MindooDBAppJsonTextSplicePatch, bj as MindooDBAppJsonTextUnmarkPatch, bk as MindooDBAppJsonUnsetPatch, bl as MindooDBAppLaunchContext, bm as MindooDBAppLiveQuerySubscription, bn as MindooDBAppLocalizedText, bo as MindooDBAppMenuAnchor, bp as MindooDBAppMenuApi, bq as MindooDBAppMenuCommandItem, br as MindooDBAppMenuDismissReason, bs as MindooDBAppMenuDismissedResult, bt as MindooDBAppMenuItem, bu as MindooDBAppMenuKind, bv as MindooDBAppMenuPlacement, bw as MindooDBAppMenuPointAnchor, bx as MindooDBAppMenuRect, by as MindooDBAppMenuRectAnchor, bz as MindooDBAppMenuSelectionResult, bA as MindooDBAppMenuSeparatorItem, bB as MindooDBAppNotificationSeverity, bC as MindooDBAppNotifyInput, bD as MindooDBAppNotifyResult, bE as MindooDBAppProposeAppInput, bF as MindooDBAppProposeAppResult, bG as MindooDBAppQueryCoverage, bH as MindooDBAppQueryInclude, bI as MindooDBAppQueryIncludeCardinality, bJ as MindooDBAppQueryIncludeSlots, bK as MindooDBAppQueryResult, bL as MindooDBAppQueryRow, bM as MindooDBAppQuerySortKey, bN as MindooDBAppQueryTextClause, bO as MindooDBAppReadableAttachmentStream, bP as MindooDBAppRecipientOptions, bQ as MindooDBAppResolvedViewDefinition, bR as MindooDBAppResolvedViewSource, bS as MindooDBAppRevisionPhase, bT as MindooDBAppRevisionVerification, bU as MindooDBAppRichTextBlockSpan, bV as MindooDBAppRichTextGetOptions, bW as MindooDBAppRichTextImmutableString, bX as MindooDBAppRichTextMarkRange, bY as MindooDBAppRichTextMaterializeValue, bZ as MindooDBAppRichTextPatch, b_ as MindooDBAppRichTextScalar, b$ as MindooDBAppRichTextSpliceStep, c0 as MindooDBAppRichTextStep, c1 as MindooDBAppRichTextStepPatch, c2 as MindooDBAppRichTextTextSpan, c3 as MindooDBAppRuntime, c4 as MindooDBAppScanAttachmentOptions, c5 as MindooDBAppScanAttachmentResult, c6 as MindooDBAppScopedDocId, c7 as MindooDBAppScopedDocumentSummary, c8 as MindooDBAppSealIntent, c9 as MindooDBAppSealedChannelOpenInput, ca as MindooDBAppSealedChannelOpenResult, cb as MindooDBAppSealedChannelRequestInput, cc as MindooDBAppSession, cd as MindooDBAppShowMenuInput, ce as MindooDBAppShowMenuResult, cf as MindooDBAppSignPreview, cg as MindooDBAppSignPreviewScope, ch as MindooDBAppSignStatementInput, ci as MindooDBAppSignStatementResult, cj as MindooDBAppStorageApi, ck as MindooDBAppSummarySetup, cl as MindooDBAppTextCursorOptions, cm as MindooDBAppTextCursorPosition, cn as MindooDBAppTextCursorPositionsResult, co as MindooDBAppTextCursorsResult, cp as MindooDBAppTextEdit, cq as MindooDBAppTextPatch, cr as MindooDBAppThemeMode, cs as MindooDBAppTimestampApi, ct as MindooDBAppTimestampInput, cu as MindooDBAppTimestampProvider, cv as MindooDBAppTimestampResult, cw as MindooDBAppUiPreferences, cx as MindooDBAppUpdateDocumentInput, cy as MindooDBAppViewCursorDocumentListResult, cz as MindooDBAppViewCursorResult, cA as MindooDBAppViewEntry, cB as MindooDBAppViewEntryKind, cC as MindooDBAppViewNavigator, cD as MindooDBAppViewNavigatorExpansionState, cE as MindooDBAppViewNavigatorOpenOptions, cF as MindooDBAppViewNavigatorPageOptions, cG as MindooDBAppViewNavigatorPageResult, cH as MindooDBAppViewNavigatorRangeQuery, cI as MindooDBAppViewNavigatorSelectionState, cJ as MindooDBAppViewUpdateStats, cK as MindooDBAppViewport, cL as MindooDBAppWellKnownDragType, cM as MindooDBAppWritableAttachmentStream, cN as resolveMindooDBAppDefinitionUrl, cO as resolveMindooDBAppListingAssetUrl, cP as resolveMindooDBAppLocalizedText, cQ as validateMindooDBAppDefinition } from './types-
|
|
1
|
+
import { M as MindooDBAppAttachmentPreviewMode, a as MindooDBAppDragBindSourceOptions, b as MindooDBAppDragStartInput, c as MindooDBAppDragStartResult, d as MindooDBAppDragPreview, e as MindooDBAppBridge, f as MindooDBAppHostShortcutBinding, g as MindooDBAppHostShortcutAction, h as MindooDBAppHostingMode, i as MindooDBAppDefinition, j as MindooDBAppDatabase, k as MindooDBAppDocument, l as MindooDBAppRichTextSpan, m as MindooDBAppRichTextSnapshot, n as MindooDBAppCreateDocumentInput } from './types-CX-o1Xyq.js';
|
|
2
|
+
export { o as MINDOODB_APP_DEFINITION_FILE_NAME, p as MINDOODB_APP_DEFINITION_FORMAT, q as MINDOODB_APP_DEFINITION_PERMISSIONS, r as MINDOODB_APP_DEFINITION_REGISTRATION_PERMISSIONS, s as MINDOODB_APP_DEFINITION_VERSION, t as MINDOODB_APP_LISTING_DESCRIPTION_MAX, u as MINDOODB_APP_LISTING_MAX_SCREENSHOTS, v as MINDOODB_APP_LISTING_SUMMARY_MAX, w as MINDOODB_APP_SEAL_SIGNING_DOMAIN, x as MINDOODB_APP_WELL_KNOWN_DRAG_TYPES, y as MindooDBAppAccessDecision, z as MindooDBAppAccessTier, A as MindooDBAppAttachmentApi, B as MindooDBAppAttachmentChunk, C as MindooDBAppAttachmentInfo, D as MindooDBAppAttachmentPreviewOptions, E as MindooDBAppAttachmentPreviewSession, F as MindooDBAppAutomergeChangesPatch, G as MindooDBAppAutomergeChangesSince, H as MindooDBAppAutomergeGetOptions, I as MindooDBAppAutomergePatchResult, J as MindooDBAppAutomergeSnapshot, K as MindooDBAppBridgeBeforeCloseAck, L as MindooDBAppBridgeBeforeCloseMessage, N as MindooDBAppBridgeConnectMessage, O as MindooDBAppBridgeConnectOptions, P as MindooDBAppBridgeConnectedMessage, Q as MindooDBAppBridgeDragDropMessage, R as MindooDBAppBridgeDragLeaveMessage, S as MindooDBAppBridgeDragOverMessage, T as MindooDBAppBridgeErrorPayload, U as MindooDBAppBridgeHandshakeErrorMessage, V as MindooDBAppBridgeHostFocusChangedMessage, W as MindooDBAppBridgeLocaleChangedMessage, X as MindooDBAppBridgePortMessage, Y as MindooDBAppBridgeQueryResultMessage, Z as MindooDBAppBridgeRpcError, _ as MindooDBAppBridgeRpcMessage, $ as MindooDBAppBridgeRpcRequest, a0 as MindooDBAppBridgeRpcSuccess, a1 as MindooDBAppBridgeShortcutInvokedMessage, a2 as MindooDBAppBridgeShortcutsChangedMessage, a3 as MindooDBAppBridgeStreamAbortRequest, a4 as MindooDBAppBridgeStreamAck, a5 as MindooDBAppBridgeStreamCloseRequest, a6 as MindooDBAppBridgeStreamError, a7 as MindooDBAppBridgeStreamMessage, a8 as MindooDBAppBridgeStreamOpenResult, a9 as MindooDBAppBridgeStreamReadRequest, aa as MindooDBAppBridgeStreamWriteRequest, ab as MindooDBAppBridgeThemeChangedMessage, ac as MindooDBAppBridgeUiPreferencesChangedMessage, ad as MindooDBAppBridgeViewChangedMessage, ae as MindooDBAppBridgeViewportChangedMessage, af as MindooDBAppBridgeWorkspaceFocusRequestedMessage, ag as MindooDBAppCapability, ah as MindooDBAppConfiguredViewCategorizationStyle, ai as MindooDBAppConfiguredViewColumn, aj as MindooDBAppConfiguredViewColumnRole, ak as MindooDBAppConfiguredViewExpressionMode, al as MindooDBAppConfiguredViewFieldExpression, am as MindooDBAppConfiguredViewFilterDefinition, an as MindooDBAppConfiguredViewFilterMode, ao as MindooDBAppConfiguredViewFilterRule, ap as MindooDBAppConfiguredViewFormulaExpression, aq as MindooDBAppConfiguredViewFormulaFilterDefinition, ar as MindooDBAppConfiguredViewPreviewMode, as as MindooDBAppConfiguredViewRuleFilterDefinition, at as MindooDBAppConfiguredViewRuleMatchMode, au as MindooDBAppConfiguredViewRuleOperator, av as MindooDBAppConfiguredViewValueExpression, aw as MindooDBAppCreateKeyInfo, ax as MindooDBAppCreateViewInput, ay as MindooDBAppCreateViewNavigatorInput, az as MindooDBAppDatabaseInfo, aA as MindooDBAppDefinitionDatabase, aB as MindooDBAppDefinitionListing, aC as MindooDBAppDefinitionPermission, aD as MindooDBAppDefinitionRegistrationPermission, aE as MindooDBAppDefinitionScreenshot, aF as MindooDBAppDefinitionValidation, aG as MindooDBAppDirectoryApi, aH as MindooDBAppDirectoryEntry, aI as MindooDBAppDocumentApi, aJ as MindooDBAppDocumentHeadCursorResult, aK as MindooDBAppDocumentHistoryEntry, aL as MindooDBAppDocumentListQuery, aM as MindooDBAppDocumentListResult, aN as MindooDBAppDocumentQuery, aO as MindooDBAppDocumentRevisionId, aP as MindooDBAppDocumentScanPreset, aQ as MindooDBAppDocumentSummary, aR as MindooDBAppDragApi, aS as MindooDBAppDragCancelReason, aT as MindooDBAppDragDropEvent, aU as MindooDBAppDragEffect, aV as MindooDBAppDragHoverResult, aW as MindooDBAppDragOffer, aX as MindooDBAppDragOverEvent, aY as MindooDBAppDragPointer, aZ as MindooDBAppDragProfile, a_ as MindooDBAppEntryAttachmentRef, a$ as MindooDBAppEntryProvenance, b0 as MindooDBAppExtractDocumentTextInput, b1 as MindooDBAppExtractDocumentTextResult, b2 as MindooDBAppExtractTextFormat, b3 as MindooDBAppExtractionSetup, b4 as MindooDBAppFulltextSetup, b5 as MindooDBAppHistoricalDocument, b6 as MindooDBAppHistoryQuery, b7 as MindooDBAppHostTheme, b8 as MindooDBAppIdentityApi, b9 as MindooDBAppInaccessibleDocument, ba as MindooDBAppInaccessibleDocumentListQuery, bb as MindooDBAppInaccessibleDocumentListResult, bc as MindooDBAppJsonCounterIncrementPatch, bd as MindooDBAppJsonListDeletePatch, be as MindooDBAppJsonListInsertPatch, bf as MindooDBAppJsonPatch, bg as MindooDBAppJsonSetPatch, bh as MindooDBAppJsonTextMarkPatch, bi as MindooDBAppJsonTextSplicePatch, bj as MindooDBAppJsonTextUnmarkPatch, bk as MindooDBAppJsonUnsetPatch, bl as MindooDBAppLaunchContext, bm as MindooDBAppLiveQuerySubscription, bn as MindooDBAppLocalizedText, bo as MindooDBAppMenuAnchor, bp as MindooDBAppMenuApi, bq as MindooDBAppMenuCommandItem, br as MindooDBAppMenuDismissReason, bs as MindooDBAppMenuDismissedResult, bt as MindooDBAppMenuItem, bu as MindooDBAppMenuKind, bv as MindooDBAppMenuPlacement, bw as MindooDBAppMenuPointAnchor, bx as MindooDBAppMenuRect, by as MindooDBAppMenuRectAnchor, bz as MindooDBAppMenuSelectionResult, bA as MindooDBAppMenuSeparatorItem, bB as MindooDBAppNotificationSeverity, bC as MindooDBAppNotifyInput, bD as MindooDBAppNotifyResult, bE as MindooDBAppProposeAppInput, bF as MindooDBAppProposeAppResult, bG as MindooDBAppQueryCoverage, bH as MindooDBAppQueryInclude, bI as MindooDBAppQueryIncludeCardinality, bJ as MindooDBAppQueryIncludeSlots, bK as MindooDBAppQueryResult, bL as MindooDBAppQueryRow, bM as MindooDBAppQuerySortKey, bN as MindooDBAppQueryTextClause, bO as MindooDBAppReadableAttachmentStream, bP as MindooDBAppRecipientOptions, bQ as MindooDBAppResolvedViewDefinition, bR as MindooDBAppResolvedViewSource, bS as MindooDBAppRevisionPhase, bT as MindooDBAppRevisionVerification, bU as MindooDBAppRichTextBlockSpan, bV as MindooDBAppRichTextGetOptions, bW as MindooDBAppRichTextImmutableString, bX as MindooDBAppRichTextMarkRange, bY as MindooDBAppRichTextMaterializeValue, bZ as MindooDBAppRichTextPatch, b_ as MindooDBAppRichTextScalar, b$ as MindooDBAppRichTextSpliceStep, c0 as MindooDBAppRichTextStep, c1 as MindooDBAppRichTextStepPatch, c2 as MindooDBAppRichTextTextSpan, c3 as MindooDBAppRuntime, c4 as MindooDBAppScanAttachmentOptions, c5 as MindooDBAppScanAttachmentResult, c6 as MindooDBAppScopedDocId, c7 as MindooDBAppScopedDocumentSummary, c8 as MindooDBAppSealIntent, c9 as MindooDBAppSealedChannelOpenInput, ca as MindooDBAppSealedChannelOpenResult, cb as MindooDBAppSealedChannelRequestInput, cc as MindooDBAppSession, cd as MindooDBAppShowMenuInput, ce as MindooDBAppShowMenuResult, cf as MindooDBAppSignPreview, cg as MindooDBAppSignPreviewScope, ch as MindooDBAppSignStatementInput, ci as MindooDBAppSignStatementResult, cj as MindooDBAppStorageApi, ck as MindooDBAppSummarySetup, cl as MindooDBAppTextCursorOptions, cm as MindooDBAppTextCursorPosition, cn as MindooDBAppTextCursorPositionsResult, co as MindooDBAppTextCursorsResult, cp as MindooDBAppTextEdit, cq as MindooDBAppTextPatch, cr as MindooDBAppThemeMode, cs as MindooDBAppTimestampApi, ct as MindooDBAppTimestampInput, cu as MindooDBAppTimestampProvider, cv as MindooDBAppTimestampResult, cw as MindooDBAppUiPreferences, cx as MindooDBAppUpdateDocumentInput, cy as MindooDBAppViewCursorDocumentListResult, cz as MindooDBAppViewCursorResult, cA as MindooDBAppViewEntry, cB as MindooDBAppViewEntryKind, cC as MindooDBAppViewNavigator, cD as MindooDBAppViewNavigatorExpansionState, cE as MindooDBAppViewNavigatorOpenOptions, cF as MindooDBAppViewNavigatorPageOptions, cG as MindooDBAppViewNavigatorPageResult, cH as MindooDBAppViewNavigatorRangeQuery, cI as MindooDBAppViewNavigatorSelectionState, cJ as MindooDBAppViewUpdateStats, cK as MindooDBAppViewport, cL as MindooDBAppWellKnownDragType, cM as MindooDBAppWritableAttachmentStream, cN as resolveMindooDBAppDefinitionUrl, cO as resolveMindooDBAppListingAssetUrl, cP as resolveMindooDBAppLocalizedText, cQ as validateMindooDBAppDefinition } from './types-CX-o1Xyq.js';
|
|
3
3
|
export { M as MINDOODB_APP_BUNDLE_ARCHIVE_FILE_NAME, a as MINDOODB_APP_BUNDLE_MANIFEST_FILE_NAME, b as MINDOODB_APP_BUNDLE_MANIFEST_FORMAT, c as MINDOODB_APP_BUNDLE_MANIFEST_VERSION, d as MindooDBAppBundleArchive, e as MindooDBAppBundleFileEntry, f as MindooDBAppBundleHash, g as MindooDBAppBundleManifest, h as MindooDBAppBundleManifestValidation, i as buildMindooDBAppBundleContentHashInput, j as isMindooDBAppBundleHash, n as normalizeMindooDBAppBundlePath, v as validateMindooDBAppBundleManifest } from './appBundleManifest-B0xfpaXG.js';
|
|
4
4
|
import { MindooDBAppBooleanExpression } from 'mindoodb-view-language';
|
|
5
5
|
export { MindooDBAppBooleanExpression, MindooDBAppExpression, MindooDBAppFilterDefinition, MindooDBAppViewCategoryChildrenPageRequest, MindooDBAppViewColumn, MindooDBAppViewColumnRole, MindooDBAppViewDefinition, MindooDBAppViewExpansionState, MindooDBAppViewExpressionBase, MindooDBAppViewExpressionDatePart, MindooDBAppViewExpressionOperation, MindooDBAppViewFieldExpression, MindooDBAppViewIfExpression, MindooDBAppViewLetExpression, MindooDBAppViewLiteralExpression, MindooDBAppViewLookupByPath, MindooDBAppViewOperationExpression, MindooDBAppViewOriginExpression, MindooDBAppViewPageRequest, MindooDBAppViewPageResult, MindooDBAppViewRow, MindooDBAppViewSortDirection, MindooDBAppViewTotalMode, MindooDBAppViewValueExpressionRef, MindooDBAppViewVariableExpression, createViewLanguage } from 'mindoodb-view-language';
|
|
@@ -295,6 +295,64 @@ declare function buildHavenAppInstallUrl(appUrl: string, havenUrl?: string): str
|
|
|
295
295
|
*/
|
|
296
296
|
declare function renderHavenAppLandingPage(options?: RenderHavenAppLandingPageOptions): Promise<HavenAppLandingPage>;
|
|
297
297
|
|
|
298
|
+
/**
|
|
299
|
+
* The Markdown subset a publisher may use in `listing.descriptionMarkdown`.
|
|
300
|
+
*
|
|
301
|
+
* The text comes from a file on the publisher's server and is shown before anyone has
|
|
302
|
+
* agreed to install the app, so it is parsed into a small tree here and rendered with
|
|
303
|
+
* `createElement`/`textContent` (or Vue render functions) — never as HTML. What the
|
|
304
|
+
* subset knows:
|
|
305
|
+
*
|
|
306
|
+
* - paragraphs (blank lines), headings (`#`), bullet (`-`, `*`, `+`) and numbered lists
|
|
307
|
+
* - `**bold**`, `__bold__`, `*italic*`, `_italic_`, `` `code` ``, `\` escapes
|
|
308
|
+
* - `[text](https://…)`, `[text](mailto:…)` and bare `https://…` links
|
|
309
|
+
*
|
|
310
|
+
* Anything else stays literal text. Links are limited to `https:` and `mailto:` by
|
|
311
|
+
* {@link sanitizeListingHref}; a link with any other target renders as its text only.
|
|
312
|
+
*
|
|
313
|
+
* DOM-free on purpose, so Haven, the landing page and build scripts can share it.
|
|
314
|
+
*/
|
|
315
|
+
type ListingInline = {
|
|
316
|
+
type: "text";
|
|
317
|
+
text: string;
|
|
318
|
+
} | {
|
|
319
|
+
type: "code";
|
|
320
|
+
text: string;
|
|
321
|
+
} | {
|
|
322
|
+
type: "strong";
|
|
323
|
+
children: ListingInline[];
|
|
324
|
+
} | {
|
|
325
|
+
type: "em";
|
|
326
|
+
children: ListingInline[];
|
|
327
|
+
} | {
|
|
328
|
+
type: "link";
|
|
329
|
+
href: string;
|
|
330
|
+
children: ListingInline[];
|
|
331
|
+
};
|
|
332
|
+
type ListingBlock = {
|
|
333
|
+
type: "paragraph";
|
|
334
|
+
children: ListingInline[];
|
|
335
|
+
} | {
|
|
336
|
+
type: "heading";
|
|
337
|
+
children: ListingInline[];
|
|
338
|
+
} | {
|
|
339
|
+
type: "list";
|
|
340
|
+
ordered: boolean;
|
|
341
|
+
items: ListingInline[][];
|
|
342
|
+
};
|
|
343
|
+
/**
|
|
344
|
+
* `https:` and `mailto:` only. Embedded tab/LF/CR are stripped first, as browsers do,
|
|
345
|
+
* so `java\nscript:` cannot slip past the scheme check.
|
|
346
|
+
*/
|
|
347
|
+
declare function sanitizeListingHref(raw: string): string | null;
|
|
348
|
+
/** Parses a description into blocks. Unknown syntax stays text; nothing is dropped. */
|
|
349
|
+
declare function parseListingMarkdown(markdown: string): ListingBlock[];
|
|
350
|
+
/**
|
|
351
|
+
* The same text for readers that only show plain paragraphs (`listing.description`):
|
|
352
|
+
* one paragraph per block and per list item, links as "text (url)".
|
|
353
|
+
*/
|
|
354
|
+
declare function listingMarkdownToPlainText(markdown: string): string;
|
|
355
|
+
|
|
298
356
|
interface InstallHavenStorageShimOptions {
|
|
299
357
|
/**
|
|
300
358
|
* Key prefixes whose values are written through to the host and restored on the next
|
|
@@ -501,4 +559,4 @@ declare function inheritDocumentEncryption(parent: Pick<MindooDBAppDocument, "de
|
|
|
501
559
|
*/
|
|
502
560
|
declare function watchWordChunks(database: MindooDBAppDatabase, parentId: string, listener: (docIds: string[]) => void): Promise<() => Promise<void>>;
|
|
503
561
|
|
|
504
|
-
export { type CreateMindooDBRichTextHandleOptions, type CreateMindooDBTextBufferOptions, DEFAULT_DRAG_LONG_PRESS_MS, DEFAULT_DRAG_POINTER_THRESHOLD_PX, DEFAULT_HAVEN_HOST_SHORTCUTS, DEFAULT_HAVEN_URL, type HavenAppLandingPage, type HavenStorageShimHandle, type InstallHavenStorageShimOptions, MINDOODB_APP_HOSTING_QUERY_PARAM, MINDOODB_APP_LAUNCH_ID_QUERY_PARAM, MINDOODB_APP_MAX_DRAG_PAYLOAD_BYTES, MINDOODB_APP_MAX_DRAG_PREVIEW_BYTES, MINDOODB_APP_MAX_DRAG_PREVIEW_EDGE, MINDOODB_APP_MAX_DRAG_TYPES, MINDOODB_APP_VALUE_TAG, MINIMAL_DRAG_PREVIEW_PNG, type MindooDBAppAtomicValue, MindooDBAppAttachmentPreviewMode, MindooDBAppBridge, type MindooDBAppCounterValue, MindooDBAppCreateDocumentInput, MindooDBAppDatabase, MindooDBAppDefinition, MindooDBAppDocument, MindooDBAppDragBindSourceOptions, MindooDBAppDragInputError, MindooDBAppDragPreview, MindooDBAppDragStartInput, MindooDBAppDragStartResult, MindooDBAppHostShortcutAction, MindooDBAppHostShortcutBinding, MindooDBAppHostingMode, MindooDBAppRichTextSnapshot, MindooDBAppRichTextSpan, type MindooDBAppTimestampValue, type MindooDBAppTypedValue, MindooDBAppValue, MindooDBRichTextHandle, type MindooDBRichTextHandleChangeListener, type MindooDBRichTextHandleFlushResult, MindooDBTextBuffer, type MindooDBTextBufferFlushResult, type RenderHavenAppLandingPageOptions, abbreviateCanonicalName, applyHostedDocumentOverscrollContain, bindDragSource, buildHavenAppInstallUrl, canPreviewAttachment, createMindooDBAppBridge, createMindooDBRichTextHandle, createMindooDBTextBuffer, expandAbbreviatedName, inheritDocumentEncryption, installHavenStorageShim, installHostShortcutCapture, isHostShortcutAction, isHostedBundleRuntime, isLaunchedByHaven, isMindooDBAppDragType, matchHostShortcut, normalizeDragAccepts, normalizeDragPointerInput, normalizeDragStartInput, queryDocuments, readMindooDBAppHostingMode, readMindooDBAppLaunchId, releaseMindooDBAppBridgeSessions, renderHavenAppLandingPage, resolveCurrentHavenAppUrl, sanitizeHostShortcutBindings, snapshotElementToPng, watchWordChunks };
|
|
562
|
+
export { type CreateMindooDBRichTextHandleOptions, type CreateMindooDBTextBufferOptions, DEFAULT_DRAG_LONG_PRESS_MS, DEFAULT_DRAG_POINTER_THRESHOLD_PX, DEFAULT_HAVEN_HOST_SHORTCUTS, DEFAULT_HAVEN_URL, type HavenAppLandingPage, type HavenStorageShimHandle, type InstallHavenStorageShimOptions, type ListingBlock, type ListingInline, MINDOODB_APP_HOSTING_QUERY_PARAM, MINDOODB_APP_LAUNCH_ID_QUERY_PARAM, MINDOODB_APP_MAX_DRAG_PAYLOAD_BYTES, MINDOODB_APP_MAX_DRAG_PREVIEW_BYTES, MINDOODB_APP_MAX_DRAG_PREVIEW_EDGE, MINDOODB_APP_MAX_DRAG_TYPES, MINDOODB_APP_VALUE_TAG, MINIMAL_DRAG_PREVIEW_PNG, type MindooDBAppAtomicValue, MindooDBAppAttachmentPreviewMode, MindooDBAppBridge, type MindooDBAppCounterValue, MindooDBAppCreateDocumentInput, MindooDBAppDatabase, MindooDBAppDefinition, MindooDBAppDocument, MindooDBAppDragBindSourceOptions, MindooDBAppDragInputError, MindooDBAppDragPreview, MindooDBAppDragStartInput, MindooDBAppDragStartResult, MindooDBAppHostShortcutAction, MindooDBAppHostShortcutBinding, MindooDBAppHostingMode, MindooDBAppRichTextSnapshot, MindooDBAppRichTextSpan, type MindooDBAppTimestampValue, type MindooDBAppTypedValue, MindooDBAppValue, MindooDBRichTextHandle, type MindooDBRichTextHandleChangeListener, type MindooDBRichTextHandleFlushResult, MindooDBTextBuffer, type MindooDBTextBufferFlushResult, type RenderHavenAppLandingPageOptions, abbreviateCanonicalName, applyHostedDocumentOverscrollContain, bindDragSource, buildHavenAppInstallUrl, canPreviewAttachment, createMindooDBAppBridge, createMindooDBRichTextHandle, createMindooDBTextBuffer, expandAbbreviatedName, inheritDocumentEncryption, installHavenStorageShim, installHostShortcutCapture, isHostShortcutAction, isHostedBundleRuntime, isLaunchedByHaven, isMindooDBAppDragType, listingMarkdownToPlainText, matchHostShortcut, normalizeDragAccepts, normalizeDragPointerInput, normalizeDragStartInput, parseListingMarkdown, queryDocuments, readMindooDBAppHostingMode, readMindooDBAppLaunchId, releaseMindooDBAppBridgeSessions, renderHavenAppLandingPage, resolveCurrentHavenAppUrl, sanitizeHostShortcutBindings, sanitizeListingHref, snapshotElementToPng, watchWordChunks };
|
package/dist/index.js
CHANGED
|
@@ -286,6 +286,13 @@ function readListing(value, errors) {
|
|
|
286
286
|
errors
|
|
287
287
|
);
|
|
288
288
|
if (description) listing.description = description;
|
|
289
|
+
const descriptionMarkdown = readLocalizedText(
|
|
290
|
+
value.descriptionMarkdown,
|
|
291
|
+
"App definition listing.descriptionMarkdown",
|
|
292
|
+
MINDOODB_APP_LISTING_DESCRIPTION_MAX,
|
|
293
|
+
errors
|
|
294
|
+
);
|
|
295
|
+
if (descriptionMarkdown) listing.descriptionMarkdown = descriptionMarkdown;
|
|
289
296
|
const icon = readListingAssetPath(value.icon, "App definition listing.icon", errors);
|
|
290
297
|
if (icon) listing.icon = icon;
|
|
291
298
|
if (value.screenshots !== void 0 && value.screenshots !== null) {
|
|
@@ -575,6 +582,212 @@ function isHostedBundleRuntime(search) {
|
|
|
575
582
|
return readMindooDBAppHostingMode(search) === "hosted";
|
|
576
583
|
}
|
|
577
584
|
|
|
585
|
+
// src/listingMarkdown.ts
|
|
586
|
+
var MAX_INLINE_DEPTH = 4;
|
|
587
|
+
var HEADING = /^#{1,6}\s+(.*?)\s*#*\s*$/;
|
|
588
|
+
var BULLET = /^[-*+]\s+(.*)$/;
|
|
589
|
+
var ORDERED = /^\d{1,9}[.)]\s+(.*)$/;
|
|
590
|
+
var ESCAPABLE = new Set("\\`*_[]()#+-.!<>".split(""));
|
|
591
|
+
var BARE_URL_TRAILING_PUNCTUATION = /[.,;:!?)\]'"]+$/;
|
|
592
|
+
function sanitizeListingHref(raw) {
|
|
593
|
+
const cleaned = raw.replace(/[\t\n\r]/g, "").trim();
|
|
594
|
+
if (!cleaned) {
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
try {
|
|
598
|
+
const url = new URL(cleaned);
|
|
599
|
+
if (url.protocol === "https:") {
|
|
600
|
+
return url.toString();
|
|
601
|
+
}
|
|
602
|
+
if (url.protocol === "mailto:" && url.pathname) {
|
|
603
|
+
return url.toString();
|
|
604
|
+
}
|
|
605
|
+
} catch {
|
|
606
|
+
}
|
|
607
|
+
return null;
|
|
608
|
+
}
|
|
609
|
+
function isWordCharacter(char) {
|
|
610
|
+
return char !== void 0 && /[\p{L}\p{N}]/u.test(char);
|
|
611
|
+
}
|
|
612
|
+
function pushText(nodes, text) {
|
|
613
|
+
if (!text) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
const last = nodes[nodes.length - 1];
|
|
617
|
+
if (last?.type === "text") {
|
|
618
|
+
last.text += text;
|
|
619
|
+
} else {
|
|
620
|
+
nodes.push({ type: "text", text });
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
function findClosingDelimiter(text, from, delimiter) {
|
|
624
|
+
let index = text.indexOf(delimiter, from);
|
|
625
|
+
while (index !== -1) {
|
|
626
|
+
const before = text[index - 1];
|
|
627
|
+
const after = text[index + delimiter.length];
|
|
628
|
+
const closesAfterContent = index > from && before !== " " && before !== "\\";
|
|
629
|
+
const underscoreBoundary = delimiter[0] !== "_" || !isWordCharacter(after);
|
|
630
|
+
if (closesAfterContent && underscoreBoundary) {
|
|
631
|
+
return index;
|
|
632
|
+
}
|
|
633
|
+
index = text.indexOf(delimiter, index + 1);
|
|
634
|
+
}
|
|
635
|
+
return -1;
|
|
636
|
+
}
|
|
637
|
+
function findLinkTargetEnd(text, from) {
|
|
638
|
+
let open = 0;
|
|
639
|
+
for (let index = from; index < text.length; index += 1) {
|
|
640
|
+
const char = text[index];
|
|
641
|
+
if (char === "(") {
|
|
642
|
+
open += 1;
|
|
643
|
+
} else if (char === ")") {
|
|
644
|
+
if (open === 0) return index;
|
|
645
|
+
open -= 1;
|
|
646
|
+
} else if (char === " ") {
|
|
647
|
+
return -1;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
return -1;
|
|
651
|
+
}
|
|
652
|
+
function parseInline(text, depth = 0) {
|
|
653
|
+
const nodes = [];
|
|
654
|
+
let index = 0;
|
|
655
|
+
while (index < text.length) {
|
|
656
|
+
const char = text[index];
|
|
657
|
+
if (char === "\\" && ESCAPABLE.has(text[index + 1] ?? "")) {
|
|
658
|
+
pushText(nodes, text[index + 1]);
|
|
659
|
+
index += 2;
|
|
660
|
+
continue;
|
|
661
|
+
}
|
|
662
|
+
if (char === "`") {
|
|
663
|
+
const end = text.indexOf("`", index + 1);
|
|
664
|
+
if (end > index + 1) {
|
|
665
|
+
nodes.push({ type: "code", text: text.slice(index + 1, end) });
|
|
666
|
+
index = end + 1;
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
if (depth < MAX_INLINE_DEPTH && (char === "*" || char === "_")) {
|
|
671
|
+
const strong = text[index + 1] === char;
|
|
672
|
+
const delimiter = strong ? char + char : char;
|
|
673
|
+
const next = text[index + delimiter.length];
|
|
674
|
+
const opens = next !== void 0 && next !== " " && (char !== "_" || !isWordCharacter(text[index - 1]));
|
|
675
|
+
if (opens) {
|
|
676
|
+
const end = findClosingDelimiter(text, index + delimiter.length, delimiter);
|
|
677
|
+
if (end !== -1) {
|
|
678
|
+
const children = parseInline(text.slice(index + delimiter.length, end), depth + 1);
|
|
679
|
+
nodes.push(strong ? { type: "strong", children } : { type: "em", children });
|
|
680
|
+
index = end + delimiter.length;
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
if (char === "[" && depth < MAX_INLINE_DEPTH) {
|
|
686
|
+
const labelEnd = text.indexOf("](", index + 1);
|
|
687
|
+
const urlEnd = labelEnd === -1 ? -1 : findLinkTargetEnd(text, labelEnd + 2);
|
|
688
|
+
if (labelEnd > index + 1 && urlEnd !== -1) {
|
|
689
|
+
const label = parseInline(text.slice(index + 1, labelEnd), depth + 1);
|
|
690
|
+
const href = sanitizeListingHref(text.slice(labelEnd + 2, urlEnd));
|
|
691
|
+
if (href) {
|
|
692
|
+
nodes.push({ type: "link", href, children: label });
|
|
693
|
+
} else {
|
|
694
|
+
nodes.push(...label);
|
|
695
|
+
}
|
|
696
|
+
index = urlEnd + 1;
|
|
697
|
+
continue;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
if (char === "h" && text.startsWith("https://", index) && !isWordCharacter(text[index - 1])) {
|
|
701
|
+
let end = index;
|
|
702
|
+
while (end < text.length && !/\s/.test(text[end])) end += 1;
|
|
703
|
+
const candidate = text.slice(index, end).replace(BARE_URL_TRAILING_PUNCTUATION, "");
|
|
704
|
+
const href = sanitizeListingHref(candidate);
|
|
705
|
+
if (href) {
|
|
706
|
+
nodes.push({ type: "link", href, children: [{ type: "text", text: candidate }] });
|
|
707
|
+
index += candidate.length;
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
pushText(nodes, char);
|
|
712
|
+
index += 1;
|
|
713
|
+
}
|
|
714
|
+
return nodes;
|
|
715
|
+
}
|
|
716
|
+
function parseListingMarkdown(markdown) {
|
|
717
|
+
const blocks = [];
|
|
718
|
+
let paragraph = [];
|
|
719
|
+
let list = null;
|
|
720
|
+
const flushParagraph = () => {
|
|
721
|
+
if (paragraph.length) {
|
|
722
|
+
blocks.push({ type: "paragraph", children: parseInline(paragraph.join(" ")) });
|
|
723
|
+
paragraph = [];
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
const flushList = () => {
|
|
727
|
+
if (list) {
|
|
728
|
+
blocks.push({ type: "list", ordered: list.ordered, items: list.items.map((item) => parseInline(item)) });
|
|
729
|
+
list = null;
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
for (const rawLine of markdown.split(/\r?\n/)) {
|
|
733
|
+
const line = rawLine.trim();
|
|
734
|
+
if (!line) {
|
|
735
|
+
flushParagraph();
|
|
736
|
+
flushList();
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
const heading = HEADING.exec(line);
|
|
740
|
+
const bullet = BULLET.exec(line);
|
|
741
|
+
const ordered = bullet ? null : ORDERED.exec(line);
|
|
742
|
+
if (heading) {
|
|
743
|
+
flushParagraph();
|
|
744
|
+
flushList();
|
|
745
|
+
blocks.push({ type: "heading", children: parseInline(heading[1]) });
|
|
746
|
+
} else if (bullet || ordered) {
|
|
747
|
+
flushParagraph();
|
|
748
|
+
const isOrdered = Boolean(ordered);
|
|
749
|
+
if (list && list.ordered !== isOrdered) {
|
|
750
|
+
flushList();
|
|
751
|
+
}
|
|
752
|
+
list ??= { ordered: isOrdered, items: [] };
|
|
753
|
+
list.items.push((bullet ?? ordered)[1]);
|
|
754
|
+
} else if (list) {
|
|
755
|
+
list.items[list.items.length - 1] += ` ${line}`;
|
|
756
|
+
} else {
|
|
757
|
+
paragraph.push(line);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
flushParagraph();
|
|
761
|
+
flushList();
|
|
762
|
+
return blocks;
|
|
763
|
+
}
|
|
764
|
+
function inlineToPlainText(nodes) {
|
|
765
|
+
return nodes.map((node) => {
|
|
766
|
+
if (node.type === "text" || node.type === "code") {
|
|
767
|
+
return node.text;
|
|
768
|
+
}
|
|
769
|
+
const label = inlineToPlainText(node.children);
|
|
770
|
+
if (node.type !== "link") {
|
|
771
|
+
return label;
|
|
772
|
+
}
|
|
773
|
+
const target = node.href.replace(/^mailto:/, "").replace(/^https:\/\//, "").replace(/\/$/, "");
|
|
774
|
+
return label.includes(target) ? label : `${label} (${node.href.replace(/^mailto:/, "")})`;
|
|
775
|
+
}).join("");
|
|
776
|
+
}
|
|
777
|
+
function listingMarkdownToPlainText(markdown) {
|
|
778
|
+
const paragraphs = [];
|
|
779
|
+
for (const block of parseListingMarkdown(markdown)) {
|
|
780
|
+
if (block.type === "list") {
|
|
781
|
+
block.items.forEach((item, index) => {
|
|
782
|
+
paragraphs.push(`${block.ordered ? `${index + 1}.` : "\u2022"} ${inlineToPlainText(item)}`);
|
|
783
|
+
});
|
|
784
|
+
} else {
|
|
785
|
+
paragraphs.push(inlineToPlainText(block.children));
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
return paragraphs.filter((paragraph) => paragraph.trim()).join("\n\n");
|
|
789
|
+
}
|
|
790
|
+
|
|
578
791
|
// src/landing.ts
|
|
579
792
|
var DEFAULT_HAVEN_URL = "https://haven.mindoodb.com";
|
|
580
793
|
var APP_ICON_FALLBACKS = ["appicon.png", "appicon.webp", "appicon.svg"];
|
|
@@ -638,6 +851,43 @@ function el(tag, className, text) {
|
|
|
638
851
|
if (text !== void 0) node.textContent = text;
|
|
639
852
|
return node;
|
|
640
853
|
}
|
|
854
|
+
function externalLink(href) {
|
|
855
|
+
const link = el("a");
|
|
856
|
+
link.href = href;
|
|
857
|
+
link.rel = "noopener noreferrer";
|
|
858
|
+
link.target = "_blank";
|
|
859
|
+
return link;
|
|
860
|
+
}
|
|
861
|
+
function appendInline(parent, nodes) {
|
|
862
|
+
for (const node of nodes) {
|
|
863
|
+
if (node.type === "text") {
|
|
864
|
+
parent.append(node.text);
|
|
865
|
+
} else if (node.type === "code") {
|
|
866
|
+
parent.append(el("code", void 0, node.text));
|
|
867
|
+
} else {
|
|
868
|
+
const child = node.type === "link" ? externalLink(node.href) : el(node.type);
|
|
869
|
+
appendInline(child, node.children);
|
|
870
|
+
parent.append(child);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
function renderMarkdownDescription(block, markdown) {
|
|
875
|
+
for (const entry of parseListingMarkdown(markdown)) {
|
|
876
|
+
if (entry.type === "list") {
|
|
877
|
+
const list = el(entry.ordered ? "ol" : "ul");
|
|
878
|
+
for (const item of entry.items) {
|
|
879
|
+
const li = el("li");
|
|
880
|
+
appendInline(li, item);
|
|
881
|
+
list.append(li);
|
|
882
|
+
}
|
|
883
|
+
block.append(list);
|
|
884
|
+
} else {
|
|
885
|
+
const node = el(entry.type === "heading" ? "h2" : "p");
|
|
886
|
+
appendInline(node, entry.children);
|
|
887
|
+
block.append(node);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
641
891
|
var STYLE_ID = "mdb-landing-style";
|
|
642
892
|
var STYLE = `
|
|
643
893
|
.mdb-landing{--bg:#f4f6fb;--card:#fff;--text:#172033;--muted:#5b6478;--line:#e2e6ef;--accent:#1f3a8a;--accent-text:#fff;
|
|
@@ -657,7 +907,12 @@ var STYLE = `
|
|
|
657
907
|
.mdb-landing__button:focus-visible{outline:3px solid var(--accent);outline-offset:3px}
|
|
658
908
|
.mdb-landing__hint{margin:0;max-width:420px;color:var(--muted);font-size:14px}
|
|
659
909
|
.mdb-landing__description{margin:32px 0 0}
|
|
660
|
-
.mdb-landing__description p{margin:0 0 12px}
|
|
910
|
+
.mdb-landing__description p,.mdb-landing__description ul,.mdb-landing__description ol{margin:0 0 12px}
|
|
911
|
+
.mdb-landing__description ul,.mdb-landing__description ol{padding-left:22px}
|
|
912
|
+
.mdb-landing__description li+li{margin-top:4px}
|
|
913
|
+
.mdb-landing__description h2{margin:20px 0 8px;font-size:17px}
|
|
914
|
+
.mdb-landing__description code{font:.92em ui-monospace,SFMono-Regular,Menlo,monospace;padding:1px 5px;border-radius:5px;background:var(--line)}
|
|
915
|
+
.mdb-landing__description a,.mdb-landing__meta a{color:var(--accent)}
|
|
661
916
|
.mdb-landing__shots-title{margin:32px 0 12px;font-size:15px;color:var(--muted);font-weight:600}
|
|
662
917
|
.mdb-landing__shots{display:grid;grid-auto-flow:column;grid-auto-columns:min(78%,420px);gap:16px;overflow-x:auto;padding-bottom:8px;scroll-snap-type:x mandatory}
|
|
663
918
|
.mdb-landing__shot{margin:0;scroll-snap-align:start}
|
|
@@ -706,11 +961,14 @@ async function renderHavenAppLandingPage(options = {}) {
|
|
|
706
961
|
}
|
|
707
962
|
const titles = el("div");
|
|
708
963
|
titles.append(el("p", "mdb-landing__eyebrow", strings.eyebrow), el("h1", "mdb-landing__title", label));
|
|
709
|
-
const meta =
|
|
964
|
+
const meta = el("p", "mdb-landing__meta");
|
|
710
965
|
if (listing?.publisher) {
|
|
711
|
-
|
|
966
|
+
const [before, after = ""] = strings.by.split("{publisher}");
|
|
967
|
+
const name = listing.publisher.url ? Object.assign(externalLink(listing.publisher.url), { textContent: listing.publisher.name }) : listing.publisher.name;
|
|
968
|
+
meta.append(before ?? "", name, after, " \xB7 ");
|
|
712
969
|
}
|
|
713
|
-
|
|
970
|
+
meta.append(format(strings.from, { origin }));
|
|
971
|
+
titles.append(meta);
|
|
714
972
|
head.append(titles);
|
|
715
973
|
card.append(head);
|
|
716
974
|
const summary = resolveMindooDBAppLocalizedText(listing?.summary, locale) || definition?.description || strings.fallbackSummary;
|
|
@@ -722,11 +980,16 @@ async function renderHavenAppLandingPage(options = {}) {
|
|
|
722
980
|
button.dataset.testid = "haven-app-landing-install";
|
|
723
981
|
cta.append(button, el("p", "mdb-landing__hint", format(strings.ctaHint, { label })));
|
|
724
982
|
card.append(cta);
|
|
983
|
+
const descriptionMarkdown = resolveMindooDBAppLocalizedText(listing?.descriptionMarkdown, locale);
|
|
725
984
|
const description = resolveMindooDBAppLocalizedText(listing?.description, locale);
|
|
726
|
-
if (description) {
|
|
985
|
+
if (descriptionMarkdown || description) {
|
|
727
986
|
const block = el("section", "mdb-landing__description");
|
|
728
|
-
|
|
729
|
-
|
|
987
|
+
if (descriptionMarkdown) {
|
|
988
|
+
renderMarkdownDescription(block, descriptionMarkdown);
|
|
989
|
+
} else {
|
|
990
|
+
for (const paragraph of description.split(/\n\s*\n/)) {
|
|
991
|
+
if (paragraph.trim()) block.append(el("p", void 0, paragraph.trim()));
|
|
992
|
+
}
|
|
730
993
|
}
|
|
731
994
|
card.append(block);
|
|
732
995
|
}
|
|
@@ -1461,11 +1724,13 @@ export {
|
|
|
1461
1724
|
isLaunchedByHaven,
|
|
1462
1725
|
isMindooDBAppBundleHash,
|
|
1463
1726
|
isMindooDBAppDragType,
|
|
1727
|
+
listingMarkdownToPlainText,
|
|
1464
1728
|
matchHostShortcut,
|
|
1465
1729
|
normalizeDragAccepts,
|
|
1466
1730
|
normalizeDragPointerInput,
|
|
1467
1731
|
normalizeDragStartInput,
|
|
1468
1732
|
normalizeMindooDBAppBundlePath,
|
|
1733
|
+
parseListingMarkdown,
|
|
1469
1734
|
queryDocuments,
|
|
1470
1735
|
readMindooDBAppHostingMode,
|
|
1471
1736
|
readMindooDBAppLaunchId,
|
|
@@ -1476,6 +1741,7 @@ export {
|
|
|
1476
1741
|
resolveMindooDBAppListingAssetUrl,
|
|
1477
1742
|
resolveMindooDBAppLocalizedText,
|
|
1478
1743
|
sanitizeHostShortcutBindings,
|
|
1744
|
+
sanitizeListingHref,
|
|
1479
1745
|
snapshotElementToPng,
|
|
1480
1746
|
validateMindooDBAppBundleManifest,
|
|
1481
1747
|
validateMindooDBAppDefinition,
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ay as MindooDBAppCreateViewNavigatorInput, cC as MindooDBAppViewNavigator, $ as MindooDBAppBridgeRpcRequest, b7 as MindooDBAppHostTheme, ag as MindooDBAppCapability, i as MindooDBAppDefinition, e as MindooDBAppBridge, cc as MindooDBAppSession, bE as MindooDBAppProposeAppInput, cK as MindooDBAppViewport, cw as MindooDBAppUiPreferences, bK as MindooDBAppQueryResult, cJ as MindooDBAppViewUpdateStats, X as MindooDBAppBridgePortMessage, bl as MindooDBAppLaunchContext, az as MindooDBAppDatabaseInfo, aI as MindooDBAppDocumentApi, cE as MindooDBAppViewNavigatorOpenOptions, A as MindooDBAppAttachmentApi, b8 as MindooDBAppIdentityApi, cs as MindooDBAppTimestampApi, aG as MindooDBAppDirectoryApi, k as MindooDBAppDocument, b4 as MindooDBAppFulltextSetup, b3 as MindooDBAppExtractionSetup, ck as MindooDBAppSummarySetup, bF as MindooDBAppProposeAppResult, c as MindooDBAppDragStartResult, aZ as MindooDBAppDragProfile } from '../types-
|
|
1
|
+
import { ay as MindooDBAppCreateViewNavigatorInput, cC as MindooDBAppViewNavigator, $ as MindooDBAppBridgeRpcRequest, b7 as MindooDBAppHostTheme, ag as MindooDBAppCapability, i as MindooDBAppDefinition, e as MindooDBAppBridge, cc as MindooDBAppSession, bE as MindooDBAppProposeAppInput, cK as MindooDBAppViewport, cw as MindooDBAppUiPreferences, bK as MindooDBAppQueryResult, cJ as MindooDBAppViewUpdateStats, X as MindooDBAppBridgePortMessage, bl as MindooDBAppLaunchContext, az as MindooDBAppDatabaseInfo, aI as MindooDBAppDocumentApi, cE as MindooDBAppViewNavigatorOpenOptions, A as MindooDBAppAttachmentApi, b8 as MindooDBAppIdentityApi, cs as MindooDBAppTimestampApi, aG as MindooDBAppDirectoryApi, k as MindooDBAppDocument, b4 as MindooDBAppFulltextSetup, b3 as MindooDBAppExtractionSetup, ck as MindooDBAppSummarySetup, bF as MindooDBAppProposeAppResult, c as MindooDBAppDragStartResult, aZ as MindooDBAppDragProfile } from '../types-CX-o1Xyq.js';
|
|
2
2
|
import * as mindoodb from 'mindoodb';
|
|
3
3
|
import 'mindoodb-view-language';
|
|
4
4
|
|
|
@@ -118,6 +118,13 @@ interface MindooDBAppDefinitionListing {
|
|
|
118
118
|
summary?: MindooDBAppLocalizedText;
|
|
119
119
|
/** Longer plain text. Blank lines separate paragraphs; no markup is rendered. */
|
|
120
120
|
description?: MindooDBAppLocalizedText;
|
|
121
|
+
/**
|
|
122
|
+
* The same description with formatting: the Markdown subset of `listingMarkdown.ts`
|
|
123
|
+
* (paragraphs, headings, lists, bold/italic, code, `https:`/`mailto:` links).
|
|
124
|
+
* Readers that know this field show it instead of `description`; older ones ignore it
|
|
125
|
+
* and keep showing `description`, so set both when older Haven versions matter.
|
|
126
|
+
*/
|
|
127
|
+
descriptionMarkdown?: MindooDBAppLocalizedText;
|
|
121
128
|
/** Square icon, path relative to the app origin or an absolute `https:` URL. */
|
|
122
129
|
icon?: string;
|
|
123
130
|
screenshots?: MindooDBAppDefinitionScreenshot[];
|
package/dist/vite/index.d.ts
CHANGED
|
@@ -26,22 +26,35 @@ interface HavenBundleOptions {
|
|
|
26
26
|
}
|
|
27
27
|
interface ResolvedViteConfig {
|
|
28
28
|
root: string;
|
|
29
|
+
command?: "build" | "serve";
|
|
29
30
|
build: {
|
|
30
31
|
outDir: string;
|
|
31
32
|
};
|
|
33
|
+
server?: {
|
|
34
|
+
host?: string | boolean;
|
|
35
|
+
port?: number;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
interface ShareHtmlContext {
|
|
39
|
+
filename?: string;
|
|
40
|
+
server?: {
|
|
41
|
+
resolvedUrls?: {
|
|
42
|
+
local?: string[];
|
|
43
|
+
} | null;
|
|
44
|
+
};
|
|
32
45
|
}
|
|
33
46
|
/** Structural subset of Vite's `Plugin`, so the SDK does not need to depend on Vite. */
|
|
34
47
|
interface HavenBundleVitePlugin {
|
|
35
48
|
name: string;
|
|
36
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Runs in dev and in build. The zip is still build-only; dev needs the same plugin so
|
|
51
|
+
* `index.html` carries the share tags while `vite dev` is serving it.
|
|
52
|
+
*/
|
|
37
53
|
configResolved: (config: ResolvedViteConfig) => void;
|
|
54
|
+
transformIndexHtml: (html: string, ctx: ShareHtmlContext) => Promise<string>;
|
|
38
55
|
writeBundle: () => Promise<void>;
|
|
39
56
|
closeBundle: () => Promise<void>;
|
|
40
57
|
}
|
|
41
|
-
/**
|
|
42
|
-
* Emits `haven-bundle.json` and `haven-bundle.zip` next to the build output so a MindooDB
|
|
43
|
-
* host can install and update the app from a URL.
|
|
44
|
-
*/
|
|
45
58
|
declare function havenBundle(options?: HavenBundleOptions): HavenBundleVitePlugin;
|
|
46
59
|
|
|
47
60
|
export { type HavenBundleOptions, type HavenBundleVitePlugin, havenBundle };
|
package/dist/vite/index.js
CHANGED
|
@@ -11,6 +11,127 @@ import { createHash } from "crypto";
|
|
|
11
11
|
import { access, readdir, readFile, writeFile } from "fs/promises";
|
|
12
12
|
import path from "path";
|
|
13
13
|
|
|
14
|
+
// src/shareMeta.ts
|
|
15
|
+
var SUMMARY_CARD = "summary";
|
|
16
|
+
function escapeText(value) {
|
|
17
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
18
|
+
}
|
|
19
|
+
function escapeAttr(value) {
|
|
20
|
+
return escapeText(value).replace(/"/g, """).replace(/[\t\n\r]/g, " ");
|
|
21
|
+
}
|
|
22
|
+
function meta(attr, key, content) {
|
|
23
|
+
return `<meta ${attr}="${key}" content="${escapeAttr(content)}">`;
|
|
24
|
+
}
|
|
25
|
+
function localized(value) {
|
|
26
|
+
if (typeof value === "string") {
|
|
27
|
+
return value.trim();
|
|
28
|
+
}
|
|
29
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
30
|
+
return "";
|
|
31
|
+
}
|
|
32
|
+
const record = value;
|
|
33
|
+
if (typeof record.en === "string" && record.en.trim()) {
|
|
34
|
+
return record.en.trim();
|
|
35
|
+
}
|
|
36
|
+
for (const text of Object.values(record)) {
|
|
37
|
+
if (typeof text === "string" && text.trim()) {
|
|
38
|
+
return text.trim();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return "";
|
|
42
|
+
}
|
|
43
|
+
function isRecord(value) {
|
|
44
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
45
|
+
}
|
|
46
|
+
function havenAppPublicUrl(raw) {
|
|
47
|
+
if (!isRecord(raw)) {
|
|
48
|
+
return void 0;
|
|
49
|
+
}
|
|
50
|
+
return havenAppSharePageUrl(raw.publicUrl);
|
|
51
|
+
}
|
|
52
|
+
function havenAppSharePageUrl(value) {
|
|
53
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const url = new URL(value.trim());
|
|
58
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
59
|
+
return void 0;
|
|
60
|
+
}
|
|
61
|
+
return url.origin + "/";
|
|
62
|
+
} catch {
|
|
63
|
+
return void 0;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function absoluteRasterUrl(asset, pageUrl) {
|
|
67
|
+
if (/\.svg($|\?)/i.test(asset)) {
|
|
68
|
+
return void 0;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const url = new URL(asset, pageUrl);
|
|
72
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
73
|
+
return void 0;
|
|
74
|
+
}
|
|
75
|
+
return url.href;
|
|
76
|
+
} catch {
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function havenAppShareMeta(raw, pageUrl) {
|
|
81
|
+
const page = havenAppSharePageUrl(pageUrl);
|
|
82
|
+
if (!isRecord(raw) || !page) {
|
|
83
|
+
return void 0;
|
|
84
|
+
}
|
|
85
|
+
const title = typeof raw.label === "string" ? raw.label.trim() : "";
|
|
86
|
+
if (!title) {
|
|
87
|
+
return void 0;
|
|
88
|
+
}
|
|
89
|
+
const listing = isRecord(raw.listing) ? raw.listing : void 0;
|
|
90
|
+
const summary = localized(listing?.summary);
|
|
91
|
+
const descriptionText = localized(listing?.description);
|
|
92
|
+
const description = summary || descriptionText.split(/\n\s*\n/)[0]?.trim() || (typeof raw.description === "string" ? raw.description.trim() : "");
|
|
93
|
+
const icon = typeof listing?.icon === "string" ? listing.icon.trim() : "";
|
|
94
|
+
const imageUrl = icon ? absoluteRasterUrl(icon, page) : void 0;
|
|
95
|
+
return { title, description, pageUrl: page, ...imageUrl ? { imageUrl } : {} };
|
|
96
|
+
}
|
|
97
|
+
function renderHavenAppShareMeta(metaData) {
|
|
98
|
+
const lines = [
|
|
99
|
+
"<!-- mindoodb-share -->",
|
|
100
|
+
meta("name", "description", metaData.description),
|
|
101
|
+
meta("property", "og:type", "website"),
|
|
102
|
+
meta("property", "og:title", metaData.title),
|
|
103
|
+
meta("property", "og:description", metaData.description),
|
|
104
|
+
meta("property", "og:url", metaData.pageUrl)
|
|
105
|
+
];
|
|
106
|
+
if (metaData.imageUrl) {
|
|
107
|
+
lines.push(meta("property", "og:image", metaData.imageUrl), meta("property", "og:image:alt", metaData.title));
|
|
108
|
+
}
|
|
109
|
+
lines.push(
|
|
110
|
+
meta("name", "twitter:card", SUMMARY_CARD),
|
|
111
|
+
meta("name", "twitter:title", metaData.title),
|
|
112
|
+
meta("name", "twitter:description", metaData.description)
|
|
113
|
+
);
|
|
114
|
+
if (metaData.imageUrl) {
|
|
115
|
+
lines.push(meta("name", "twitter:image", metaData.imageUrl));
|
|
116
|
+
}
|
|
117
|
+
lines.push("<!-- /mindoodb-share -->");
|
|
118
|
+
return lines.filter((line) => !line.includes('content=""')).join("\n");
|
|
119
|
+
}
|
|
120
|
+
var TITLE_PATTERN = /<title>[^<]*<\/title>/i;
|
|
121
|
+
function injectHavenAppShareMeta(html, metaData) {
|
|
122
|
+
if (html.includes("<!-- mindoodb-share -->")) {
|
|
123
|
+
return html;
|
|
124
|
+
}
|
|
125
|
+
const block = renderHavenAppShareMeta(metaData);
|
|
126
|
+
const titled = TITLE_PATTERN.test(html) ? html.replace(TITLE_PATTERN, `<title>${escapeText(metaData.title)}</title>`) : html;
|
|
127
|
+
const headEnd = titled.search(/<\/head>/i);
|
|
128
|
+
if (headEnd === -1) {
|
|
129
|
+
return titled;
|
|
130
|
+
}
|
|
131
|
+
return `${titled.slice(0, headEnd)}${block}
|
|
132
|
+
${titled.slice(headEnd)}`;
|
|
133
|
+
}
|
|
134
|
+
|
|
14
135
|
// src/vite/zip.ts
|
|
15
136
|
import { deflateRawSync } from "zlib";
|
|
16
137
|
var CRC32_TABLE = (() => {
|
|
@@ -229,11 +350,26 @@ async function readPackageMetadata(root) {
|
|
|
229
350
|
return { name: void 0, version: void 0 };
|
|
230
351
|
}
|
|
231
352
|
}
|
|
353
|
+
function devPageUrl(config, ctx) {
|
|
354
|
+
const local = ctx.server?.resolvedUrls?.local ?? [];
|
|
355
|
+
const fromServer = havenAppSharePageUrl(local.find((url) => url.includes("127.0.0.1")) ?? local[0]);
|
|
356
|
+
if (fromServer) {
|
|
357
|
+
return fromServer;
|
|
358
|
+
}
|
|
359
|
+
const port = config.server?.port;
|
|
360
|
+
if (!port) {
|
|
361
|
+
return void 0;
|
|
362
|
+
}
|
|
363
|
+
const host = config.server?.host;
|
|
364
|
+
const hostname = !host || host === true || host === "0.0.0.0" ? "127.0.0.1" : host;
|
|
365
|
+
return havenAppSharePageUrl(`http://${hostname}:${port}/`);
|
|
366
|
+
}
|
|
232
367
|
function havenBundle(options = {}) {
|
|
233
368
|
let resolvedConfig = null;
|
|
234
369
|
let emitted = false;
|
|
370
|
+
let isBuild = true;
|
|
235
371
|
async function emitBundle() {
|
|
236
|
-
if (emitted) {
|
|
372
|
+
if (!isBuild || emitted) {
|
|
237
373
|
return;
|
|
238
374
|
}
|
|
239
375
|
if (!resolvedConfig) {
|
|
@@ -296,9 +432,27 @@ function havenBundle(options = {}) {
|
|
|
296
432
|
}
|
|
297
433
|
return {
|
|
298
434
|
name: "haven-bundle",
|
|
299
|
-
apply: "build",
|
|
300
435
|
configResolved(config) {
|
|
301
436
|
resolvedConfig = config;
|
|
437
|
+
isBuild = config.command !== "serve";
|
|
438
|
+
},
|
|
439
|
+
async transformIndexHtml(html, ctx) {
|
|
440
|
+
if (!resolvedConfig || ctx.filename?.includes("__haven-test")) {
|
|
441
|
+
return html;
|
|
442
|
+
}
|
|
443
|
+
let raw;
|
|
444
|
+
try {
|
|
445
|
+
raw = JSON.parse(await readFile(path.join(resolvedConfig.root, "public", "haven-app.json"), "utf8"));
|
|
446
|
+
} catch {
|
|
447
|
+
return html;
|
|
448
|
+
}
|
|
449
|
+
const baked = havenAppPublicUrl(raw);
|
|
450
|
+
const pageUrl = resolvedConfig.command === "serve" ? devPageUrl(resolvedConfig, ctx) ?? baked : baked;
|
|
451
|
+
if (!pageUrl) {
|
|
452
|
+
return html;
|
|
453
|
+
}
|
|
454
|
+
const meta2 = havenAppShareMeta(raw, pageUrl);
|
|
455
|
+
return meta2 ? injectHavenAppShareMeta(html, meta2) : html;
|
|
302
456
|
},
|
|
303
457
|
async writeBundle() {
|
|
304
458
|
await emitBundle();
|