Merge branch 'master' into enhance/i18n

This commit is contained in:
Tienson Qin
2026-04-20 08:28:43 +08:00
13 changed files with 230 additions and 28 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@logseq/libs",
"version": "0.3.1",
"version": "0.3.2",
"description": "Logseq SDK libraries",
"main": "dist/lsplugin.user.js",
"typings": "index.d.ts",

View File

@@ -11,6 +11,8 @@ const log = (...args: any) => (Postmate.debug ? console.log(...args) : null)
const resolveOrigin = (url: string) => {
const a = document.createElement('a')
a.href = url
// file:// URLs always have origin === 'null'; use '*' to allow postMessage
if (a.protocol === 'file:') return '*'
const protocol = a.protocol.length > 4 ? a.protocol : window.location.protocol
const host = a.host.length
? a.port === '80' || a.port === '443'
@@ -30,7 +32,7 @@ const messageTypes = {
}
export const sanitize = (message: any, allowedOrigin: any) => {
if (typeof allowedOrigin === 'string' && message.origin !== allowedOrigin)
if (typeof allowedOrigin === 'string' && allowedOrigin !== '*' && message.origin !== allowedOrigin)
return false
if (!message.data) return false
if (typeof message.data === 'object' && !('postmate' in message.data))
@@ -240,7 +242,8 @@ export class ChildAPI {
}
// reply uses the event source/origin, others use stored parentOrigin.
if (fallbackEvent?.source) {
;(fallbackEvent.source as WindowProxy).postMessage(payload, fallbackEvent.origin)
const replyOrigin = fallbackEvent.origin === 'null' ? '*' : fallbackEvent.origin
;(fallbackEvent.source as WindowProxy).postMessage(payload, replyOrigin)
} else {
this.parent.postMessage(payload, this.parentOrigin)
}
@@ -583,7 +586,7 @@ export class Model {
// Tell parent if child can accept MessageChannel
acceptsMessageChannel: this.enableMessageChannel && runtimeSupportsMessageChannel ? 1 : 0,
},
e.origin
e.origin === 'null' ? '*' : e.origin
)
// Extend model with the one provided by the parent

File diff suppressed because one or more lines are too long

View File

@@ -40,7 +40,7 @@
"keytar": "^7.9.0"
},
"devDependencies": {
"electron": "41.2.1",
"electron": "39.8.8",
"electron-builder": "26.8.2",
"electron-devtools-installer": "4.0.0"
},

View File

@@ -1,11 +1,9 @@
(ns frontend.idb
(ns frontend.common.idb
"This system component provides indexedDB functionality"
(:require ["/frontend/idbkv" :as idb-keyval]))
(:require [frontend.common.idbkv :as idb-keyval]))
;; offline db
;; To maintain backward compatibility
(defonce store (atom nil))
(defn remove-item!
@@ -16,13 +14,13 @@
(defn set-item!
[key value]
(when (and key @store)
(idb-keyval/set key value @store)))
(idb-keyval/set-item key value @store)))
(comment
(defn rename-item!
[old-key new-key]
(when (and old-key new-key @store)
(p/let [value (idb-keyval/get old-key @store)]
(p/let [value (idb-keyval/get-item old-key @store)]
(when value
(idb-keyval/set new-key value @store)
(idb-keyval/del old-key @store))))))
@@ -31,15 +29,15 @@
(defn set-batch!
[items]
(when (and (seq items) @store)
(idb-keyval/setBatch (clj->js items) @store))))
(idb-keyval/set-batch (clj->js items) @store))))
(defn get-item
[key]
(when (and key @store)
(idb-keyval/get key @store)))
(idb-keyval/get-item key @store)))
(defn start
"This component's only responsibility is to create a Store object"
[]
(when (nil? @store)
(reset! store (idb-keyval/newStore "localforage" "keyvaluepairs" 2))))
(reset! store (idb-keyval/new-store "localforage" "keyvaluepairs" 2))))

View File

@@ -0,0 +1,199 @@
(ns frontend.common.idbkv
"IndexedDB")
(defn- get-indexeddb []
(cond
(exists? js/window) (.-indexedDB js/window)
(exists? js/indexedDB) js/indexedDB
:else nil))
(defn- make-store
([]
(make-store "keyval-store" "keyval" 1))
([db-name store-name version]
(let [state (atom {:store-name store-name
:db-name db-name
:store-name* store-name
:version version
:id (str "dbName:" db-name ";;storeName:" store-name)
:dbp nil})]
(letfn [(init! []
(when-not (:dbp @state)
(let [p (js/Promise.
(fn [resolve reject]
(let [idb (get-indexeddb)]
(if-not idb
(reject (js/Error. "indexedDB is not available"))
(let [openreq (.open idb db-name version)]
(set! (.-onerror openreq)
(fn []
(reject (.-error openreq))))
(set! (.-onsuccess openreq)
(fn []
(resolve (.-result openreq))))
(set! (.-onupgradeneeded openreq)
(fn []
(.createObjectStore (.-result openreq) store-name))))))))]
(swap! state assoc :dbp p))))
(with-idb-store
[tx-type callback]
(init!)
(.then (:dbp @state)
(fn [db]
(js/Promise.
(fn [resolve reject]
(let [tx (.transaction db (:store-name @state) tx-type)]
(set! (.-oncomplete tx)
(fn []
(resolve nil)))
(set! (.-onabort tx)
(fn []
(reject (.-error tx))))
(set! (.-onerror tx)
(fn []
(reject (.-error tx))))
(callback (.objectStore tx (:store-name @state)))))))))
(close! []
(init!)
(.then (:dbp @state)
(fn [db]
(.close db)
(swap! state assoc :dbp nil))))]
{:state state
:init! init!
:with-idb-store with-idb-store
:close! close!}))))
(defn new-store
([] (make-store))
([db-name store-name version]
(make-store db-name store-name version)))
(defonce ^:private default-store* (atom nil))
(defn- get-default-store []
(or @default-store*
(let [s (make-store)]
(reset! default-store* s)
s)))
(defn- store-id [store]
(:id @(:state store)))
(defn get-item
([key]
(get-item key (get-default-store)))
([key store]
(let [req* (atom nil)]
(.then ((:with-idb-store store)
"readwrite"
(fn [os]
(reset! req* (.get os key))))
(fn []
(.-result @req*))))))
(defn- make-batcher [executor]
(let [state (atom {:items []
:ongoing nil})]
(letfn [(process! []
(let [to-process (:items @state)]
(swap! state assoc :items [])
(.then
(executor (mapv :item to-process))
(fn []
(doseq [{:keys [on-processed]} to-process]
(on-processed))
(if (seq (:items @state))
(let [p (process!)]
(swap! state assoc :ongoing p)
p)
(do
(swap! state assoc :ongoing nil)
nil))))))
(queue! [item]
(let [p (js/Promise.
(fn [resolve _reject]
(swap! state update :items conj {:item item
:on-processed resolve})))]
(when-not (:ongoing @state)
(let [ongoing (process!)]
(swap! state assoc :ongoing ongoing)))
p))]
{:queue! queue!
:state state})))
(defonce ^:private set-batchers* (atom {}))
(defn set-item
([key value]
(set-item key value (get-default-store)))
([key value store]
(let [sid (store-id store)
batcher (or (get @set-batchers* sid)
(let [b (make-batcher
(fn [items]
(prn :debug :fn (:with-idb-store store))
((:with-idb-store store)
"readwrite"
(fn [os]
(doseq [{:keys [key value]} items]
(.put os value key))))))]
(swap! set-batchers* assoc sid b)
b))]
(prn :debug :batcher batcher)
((:queue! batcher) {:key key :value value}))))
(comment
(defn set-batch
([items]
(set-batch items (get-default-store)))
([items store]
((:with-idb-store store)
"readwrite"
(fn [os]
(doseq [{:keys [key value]} items]
(.put os value key)))))))
(defn del
([key]
(del key (get-default-store)))
([key store]
((:with-idb-store store)
"readwrite"
(fn [os]
(.delete os key)))))
(comment
(defn get-keys
([]
(get-keys (get-default-store)))
([store]
(let [result* (atom [])]
(.then
((:with-idb-store store)
"readwrite"
(fn [os]
(let [cursor-fn (or (.-openKeyCursor os)
(.-openCursor os))
req (.call cursor-fn os)]
(set! (.-onsuccess req)
(fn []
(let [res (.-result req)]
(when res
(swap! result* conj (.-key res))
(.continue res))))))))
(fn []
@result*))))))
(comment
(defn close
([]
(close (get-default-store)))
([store]
((:close! store)))))

View File

@@ -29,7 +29,7 @@
[frontend.handler.repo-config :as repo-config-handler]
[frontend.handler.ui :as ui-handler]
[frontend.handler.user :as user-handler]
[frontend.idb :as idb]
[frontend.common.idb :as idb]
[frontend.mobile.util :as mobile-util]
[frontend.modules.instrumentation.core :as instrument]
[frontend.modules.shortcut.core :as shortcut]

View File

@@ -8,7 +8,7 @@
[frontend.handler.assets :as assets-handler]
[frontend.handler.export.common :as export-common-handler]
[frontend.handler.notification :as notification]
[frontend.idb :as idb]
[frontend.common.idb :as idb]
[frontend.persist-db :as persist-db]
[frontend.state :as state]
[frontend.util :as util]

View File

@@ -13,7 +13,7 @@
[frontend.handler.common.plugin :as plugin-common-handler]
[frontend.handler.notification :as notification]
[frontend.handler.plugin-config :as plugin-config-handler]
[frontend.idb :as idb]
[frontend.common.idb :as idb]
[frontend.modules.shortcut.utils :as shortcut-utils]
[frontend.state :as state]
[frontend.storage :as storage]

View File

@@ -54,7 +54,8 @@
[me.tonsky.persistent-sorted-set :as set :refer [BTSet]]
[missionary.core :as m]
[promesa.core :as p]
[goog.functions :as gfun]))
[goog.functions :as gfun]
[frontend.common.idb :as idb]))
(def ^:private worker-bootstrap-loaded-key "__logseq_db_worker_bootstrap_loaded__")
@@ -1193,6 +1194,8 @@
(defn init
"web worker entry"
[]
(idb/start)
(ldb/register-transact-invalid-callback-fn! notify-invalid-data)
(let [proxy-object (->>

View File

@@ -1,6 +1,6 @@
(ns frontend.worker.sync.crypt
"E2EE helpers for db-sync."
(:require ["/frontend/idbkv" :as idb-keyval]
(:require [frontend.common.idb :as idb]
[clojure.string :as string]
[frontend.common.crypt :as crypt]
[frontend.common.file.opfs :as opfs]
@@ -15,7 +15,6 @@
(defonce ^:private *graph->aes-key (atom {}))
(defonce ^:private *user-rsa-key-pair-inflight (atom {}))
(defonce ^:private e2ee-store (delay (idb-keyval/newStore "localforage" "keyvaluepairs" 2)))
(defonce ^:private e2ee-password-file "e2ee-password")
(defonce ^:private native-env?
(let [href (try (.. js/self -location -href)
@@ -173,19 +172,19 @@
(defn- <get-item
[k]
(assert (and k @e2ee-store))
(p/let [r (idb-keyval/get k @e2ee-store)]
(assert (and k @idb/store))
(p/let [r (idb/get-item k)]
(some-> r (js->clj :keywordize-keys true))))
(defn- <set-item!
[k value]
(assert (and k @e2ee-store))
(idb-keyval/set k value @e2ee-store))
(assert (and k @idb/store))
(idb/set-item! k value))
(defn- <clear-item!
[k]
(assert (and k @e2ee-store))
(idb-keyval/del k @e2ee-store))
(assert (and k @idb/store))
(idb/remove-item! k))
(defn- graph-encrypted-aes-key-idb-key
[graph-id]

View File

@@ -9,7 +9,7 @@
[frontend.handler.command-palette :as palette-handler]
[frontend.handler.common.plugin :as plugin-common-handler]
[frontend.handler.plugin :as plugin-handler]
[frontend.idb :as idb]
[frontend.common.idb :as idb]
[frontend.modules.layout.core]
[frontend.modules.shortcut.config :as shortcut-config]
[frontend.modules.shortcut.core :as st]