@ocap/indexdb-sqlite 1.29.14 → 1.29.16

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/esm/db/base.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Database } from "../interfaces.mjs";
2
2
  import { Kysely } from "kysely";
3
3
  import { BaseIndexDB } from "@ocap/indexdb";
4
- import { IIndexDB, IIndexTable, IListAccountsResult, IListAssetsResult, IListDelegationsResult, IListFactoriesResult, IListRollupBlocksResult, IListRollupValidatorsResult, IListRollupsResult, IListStakesResult, IListTokenFactoriesResult, IListTokensResult, IListTransactionsResult, IndexTableTypeMap, TRequestListAssets, TRequestListDelegations, TRequestListFactories, TRequestListRollupBlocks, TRequestListRollupValidators, TRequestListRollups, TRequestListStakes, TRequestListTokenFactories, TRequestListTokens, TRequestListTopAccounts, TRequestListTransactions } from "@ocap/types";
4
+ import { IIndexDB, IIndexTable, IListAccountsResult, IListAssetsResult, IListDelegationsResult, IListFactoriesResult, IListRollupBlocksResult, IListRollupValidatorsResult, IListRollupsResult, IListStakesResult, IListTokenFactoriesResult, IListTokensResult, IListTransactionsResult, IndexTableTypeMap, TRequestListAssets, TRequestListDelegations, TRequestListFactories, TRequestListRollupBlocks, TRequestListRollupValidators, TRequestListRollups, TRequestListStakes, TRequestListTokenFactories, TRequestListTokens, TRequestListTopAccounts, TRequestListTransactions, TSearchResult } from "@ocap/types";
5
5
 
6
6
  //#region src/db/base.d.ts
7
7
 
@@ -73,6 +73,10 @@ declare class SqliteBaseIndexDB extends BaseIndexDB implements IIndexDB {
73
73
  * List delegations
74
74
  */
75
75
  listDelegations(params?: Partial<TRequestListDelegations>): Promise<IListDelegationsResult>;
76
+ /**
77
+ * Search entities by semantic fields (moniker, name, symbol, description)
78
+ */
79
+ search(keyword: string): Promise<TSearchResult[]>;
76
80
  }
77
81
  //#endregion
78
82
  export { SqliteBaseIndexDB as default };
package/esm/db/base.mjs CHANGED
@@ -8,6 +8,18 @@ import omit from "lodash/omit.js";
8
8
  //#region src/db/base.ts
9
9
  const debug = debugFactory("@ocap/indexdb-sqlite");
10
10
  const MAX_REQUEST_FACTORY_ADDRESS_SIZE = 100;
11
+ const SEARCH_LIMIT_PER_TABLE = 5;
12
+ /** Escape SQL LIKE special characters */
13
+ function escapeLikePattern(s) {
14
+ return s.replace(/[%_\\]/g, (c) => `\\${c}`);
15
+ }
16
+ /** Score a match: 3=exact, 2=prefix, 1=contains */
17
+ function scoreMatch(fieldValue, keyword) {
18
+ const lower = fieldValue.toLowerCase();
19
+ if (lower === keyword) return 3;
20
+ if (lower.startsWith(keyword)) return 2;
21
+ return 1;
22
+ }
11
23
  function buildPagingResult(total, pagination, itemCount) {
12
24
  return {
13
25
  cursor: String(pagination.cursor + itemCount),
@@ -740,6 +752,172 @@ var SqliteBaseIndexDB = class extends BaseIndexDB {
740
752
  paging: buildPagingResult(total, pagination, delegations.length)
741
753
  };
742
754
  }
755
+ /**
756
+ * Search entities by semantic fields (moniker, name, symbol, description)
757
+ */
758
+ async search(keyword) {
759
+ const trimmed = keyword?.trim();
760
+ if (!trimmed) return [];
761
+ const escaped = escapeLikePattern(trimmed);
762
+ const lowerKw = trimmed.toLowerCase();
763
+ const containsPattern = `%${escaped}%`;
764
+ const limit = sql.raw(String(SEARCH_LIMIT_PER_TABLE));
765
+ const typePriority = {
766
+ token: 0,
767
+ account: 1,
768
+ factory: 2,
769
+ asset: 3,
770
+ tokenFactory: 4,
771
+ stake: 5
772
+ };
773
+ const isDidLike = /^(did:abt:)?(z[1-9A-HJ-NP-Za-km-z]|0x[0-9a-fA-F])/.test(trimmed);
774
+ const didPrefix = isDidLike ? trimmed.replace(/^did:abt:/i, "") : "";
775
+ const doDidSearch = isDidLike && didPrefix.length >= 4;
776
+ const queries = [
777
+ sql`
778
+ SELECT address, name, symbol, description FROM token
779
+ WHERE LOWER(name) LIKE LOWER(${containsPattern}) ESCAPE '\\' OR LOWER(symbol) LIKE LOWER(${containsPattern}) ESCAPE '\\' OR LOWER(description) LIKE LOWER(${containsPattern}) ESCAPE '\\'
780
+ LIMIT ${limit}
781
+ `.execute(this.db),
782
+ sql`
783
+ SELECT address, moniker FROM account
784
+ WHERE LOWER(moniker) LIKE LOWER(${containsPattern}) ESCAPE '\\'
785
+ LIMIT ${limit}
786
+ `.execute(this.db),
787
+ sql`
788
+ SELECT address, name, description FROM factory
789
+ WHERE LOWER(name) LIKE LOWER(${containsPattern}) ESCAPE '\\' OR LOWER(description) LIKE LOWER(${containsPattern}) ESCAPE '\\'
790
+ LIMIT ${limit}
791
+ `.execute(this.db),
792
+ sql`
793
+ SELECT address, moniker, tags FROM asset
794
+ WHERE LOWER(moniker) LIKE LOWER(${containsPattern}) ESCAPE '\\' OR LOWER(tags) LIKE LOWER(${containsPattern}) ESCAPE '\\'
795
+ LIMIT ${limit}
796
+ `.execute(this.db),
797
+ sql`
798
+ SELECT address, name, moniker FROM tokenFactory
799
+ WHERE LOWER(name) LIKE LOWER(${containsPattern}) ESCAPE '\\' OR LOWER(moniker) LIKE LOWER(${containsPattern}) ESCAPE '\\'
800
+ LIMIT ${limit}
801
+ `.execute(this.db),
802
+ sql`
803
+ SELECT address, message FROM stake
804
+ WHERE LOWER(message) LIKE LOWER(${containsPattern}) ESCAPE '\\'
805
+ LIMIT ${limit}
806
+ `.execute(this.db)
807
+ ];
808
+ if (doDidSearch) {
809
+ const prefixPattern = `${escapeLikePattern(didPrefix)}%`;
810
+ queries.push(sql`
811
+ SELECT * FROM (SELECT address, 'account' as type, COALESCE(moniker, address) as title FROM account WHERE address LIKE ${prefixPattern} ESCAPE '\\' LIMIT ${limit})
812
+ UNION ALL SELECT * FROM (SELECT address, 'token', COALESCE(name, address) FROM token WHERE address LIKE ${prefixPattern} ESCAPE '\\' LIMIT ${limit})
813
+ UNION ALL SELECT * FROM (SELECT address, 'asset', COALESCE(moniker, address) FROM asset WHERE address LIKE ${prefixPattern} ESCAPE '\\' LIMIT ${limit})
814
+ UNION ALL SELECT * FROM (SELECT address, 'factory', COALESCE(name, address) FROM factory WHERE address LIKE ${prefixPattern} ESCAPE '\\' LIMIT ${limit})
815
+ UNION ALL SELECT * FROM (SELECT address, 'tokenFactory', COALESCE(name, address) FROM tokenFactory WHERE address LIKE ${prefixPattern} ESCAPE '\\' LIMIT ${limit})
816
+ UNION ALL SELECT * FROM (SELECT address, 'stake', COALESCE(message, address) FROM stake WHERE address LIKE ${prefixPattern} ESCAPE '\\' LIMIT ${limit})
817
+ `.execute(this.db));
818
+ }
819
+ const allResults = await Promise.all(queries);
820
+ const [tokenRows, accountRows, factoryRows, assetRows, tokenFactoryRows, stakeRows] = allResults;
821
+ const results = [];
822
+ for (const row of tokenRows.rows) {
823
+ const nameScore = row.name ? scoreMatch(row.name, lowerKw) : 0;
824
+ const symbolScore = row.symbol ? scoreMatch(row.symbol, lowerKw) : 0;
825
+ const descScore = row.description ? scoreMatch(row.description, lowerKw) : 0;
826
+ const score = Math.max(nameScore, symbolScore, descScore);
827
+ const title = nameScore >= symbolScore ? row.name || row.symbol || "" : row.symbol || row.name || "";
828
+ results.push({
829
+ type: "token",
830
+ id: row.address,
831
+ title,
832
+ score,
833
+ priority: typePriority.token
834
+ });
835
+ }
836
+ for (const row of accountRows.rows) {
837
+ const score = scoreMatch(row.moniker, lowerKw);
838
+ results.push({
839
+ type: "account",
840
+ id: row.address,
841
+ title: row.moniker || "",
842
+ score,
843
+ priority: typePriority.account
844
+ });
845
+ }
846
+ for (const row of factoryRows.rows) {
847
+ const nameScore = row.name ? scoreMatch(row.name, lowerKw) : 0;
848
+ const descScore = row.description ? scoreMatch(row.description, lowerKw) : 0;
849
+ const score = Math.max(nameScore, descScore);
850
+ results.push({
851
+ type: "factory",
852
+ id: row.address,
853
+ title: row.name || "",
854
+ score,
855
+ priority: typePriority.factory
856
+ });
857
+ }
858
+ for (const row of assetRows.rows) {
859
+ const monikerScore = row.moniker ? scoreMatch(row.moniker, lowerKw) : 0;
860
+ let tagScore = 0;
861
+ if (row.tags) try {
862
+ const tags = typeof row.tags === "string" ? JSON.parse(row.tags) : row.tags;
863
+ if (Array.isArray(tags)) tagScore = Math.max(0, ...tags.map((t) => scoreMatch(t, lowerKw)));
864
+ } catch {}
865
+ const score = Math.max(monikerScore, tagScore);
866
+ results.push({
867
+ type: "asset",
868
+ id: row.address,
869
+ title: row.moniker || "",
870
+ score,
871
+ priority: typePriority.asset
872
+ });
873
+ }
874
+ for (const row of tokenFactoryRows.rows) {
875
+ const nameScore = row.name ? scoreMatch(row.name, lowerKw) : 0;
876
+ const monikerScore = row.moniker ? scoreMatch(row.moniker, lowerKw) : 0;
877
+ const score = Math.max(nameScore, monikerScore);
878
+ const title = nameScore >= monikerScore ? row.name || row.moniker || "" : row.moniker || row.name || "";
879
+ results.push({
880
+ type: "tokenFactory",
881
+ id: row.address,
882
+ title,
883
+ score,
884
+ priority: typePriority.tokenFactory
885
+ });
886
+ }
887
+ for (const row of stakeRows.rows) {
888
+ const score = scoreMatch(row.message, lowerKw);
889
+ results.push({
890
+ type: "stake",
891
+ id: row.address,
892
+ title: row.message || "",
893
+ score,
894
+ priority: typePriority.stake
895
+ });
896
+ }
897
+ if (doDidSearch) {
898
+ const didRows = allResults[6];
899
+ const seen = new Set(results.map((r) => `${r.type}:${r.id}`));
900
+ for (const row of didRows.rows) {
901
+ const key = `${row.type}:${row.address}`;
902
+ if (!seen.has(key)) {
903
+ seen.add(key);
904
+ results.push({
905
+ type: row.type,
906
+ id: row.address,
907
+ title: row.title || row.address,
908
+ score: 2,
909
+ priority: typePriority[row.type] ?? 99
910
+ });
911
+ }
912
+ }
913
+ }
914
+ results.sort((a, b) => b.score - a.score || a.priority - b.priority);
915
+ return results.map(({ type, id, title }) => ({
916
+ type,
917
+ id,
918
+ title
919
+ }));
920
+ }
743
921
  };
744
922
  var base_default = SqliteBaseIndexDB;
745
923
 
package/esm/db/index.mjs CHANGED
@@ -314,6 +314,7 @@ var SqliteIndexDB = class extends base_default$1 {
314
314
  schema: {
315
315
  jsonFields: [
316
316
  "ops",
317
+ "deny",
317
318
  "context",
318
319
  "data"
319
320
  ],
@@ -326,6 +327,8 @@ var SqliteIndexDB = class extends base_default$1 {
326
327
  "from",
327
328
  "to",
328
329
  "ops",
330
+ "deny",
331
+ "validUntil",
329
332
  "context",
330
333
  "data",
331
334
  "genesisTime",
@@ -198,6 +198,8 @@ interface DelegationTable {
198
198
  from_: string | null;
199
199
  to_: string | null;
200
200
  ops: string | null;
201
+ deny: string | null;
202
+ validUntil: number | null;
201
203
  context: string | null;
202
204
  data: string | null;
203
205
  genesisTime: string | null;
@@ -0,0 +1,7 @@
1
+ import { Kysely } from "kysely";
2
+
3
+ //#region src/migrations/003-delegation-extensions.d.ts
4
+ declare function up(db: Kysely<unknown>): Promise<void>;
5
+ declare function down(_db: Kysely<unknown>): Promise<void>;
6
+ //#endregion
7
+ export { down, up };
@@ -0,0 +1,16 @@
1
+ import { __exportAll } from "../_virtual/rolldown_runtime.mjs";
2
+ import { sql } from "kysely";
3
+
4
+ //#region src/migrations/003-delegation-extensions.ts
5
+ var _003_delegation_extensions_exports = /* @__PURE__ */ __exportAll({
6
+ down: () => down,
7
+ up: () => up
8
+ });
9
+ async function up(db) {
10
+ await sql`ALTER TABLE delegation ADD COLUMN deny TEXT`.execute(db);
11
+ await sql`ALTER TABLE delegation ADD COLUMN validUntil INTEGER DEFAULT 0`.execute(db);
12
+ }
13
+ async function down(_db) {}
14
+
15
+ //#endregion
16
+ export { _003_delegation_extensions_exports, down, up };
@@ -0,0 +1,7 @@
1
+ import { Kysely } from "kysely";
2
+
3
+ //#region src/migrations/004-search-indexes.d.ts
4
+ declare function up(db: Kysely<unknown>): Promise<void>;
5
+ declare function down(db: Kysely<unknown>): Promise<void>;
6
+ //#endregion
7
+ export { down, up };
@@ -0,0 +1,21 @@
1
+ import { __exportAll } from "../_virtual/rolldown_runtime.mjs";
2
+ import { sql } from "kysely";
3
+
4
+ //#region src/migrations/004-search-indexes.ts
5
+ var _004_search_indexes_exports = /* @__PURE__ */ __exportAll({
6
+ down: () => down,
7
+ up: () => up
8
+ });
9
+ async function up(db) {
10
+ await sql`CREATE INDEX IF NOT EXISTS idx_asset_moniker ON asset(moniker) WHERE moniker IS NOT NULL`.execute(db);
11
+ await sql`CREATE INDEX IF NOT EXISTS idx_token_name ON token(name) WHERE name IS NOT NULL`.execute(db);
12
+ await sql`CREATE INDEX IF NOT EXISTS idx_tokenfactory_name ON tokenFactory(name) WHERE name IS NOT NULL`.execute(db);
13
+ }
14
+ async function down(db) {
15
+ await sql`DROP INDEX IF EXISTS idx_asset_moniker`.execute(db);
16
+ await sql`DROP INDEX IF EXISTS idx_token_name`.execute(db);
17
+ await sql`DROP INDEX IF EXISTS idx_tokenfactory_name`.execute(db);
18
+ }
19
+
20
+ //#endregion
21
+ export { _004_search_indexes_exports, down, up };
@@ -1,5 +1,7 @@
1
1
  import { _001_genesis_exports } from "./001-genesis.mjs";
2
2
  import { _002_composite_indexes_exports } from "./002-composite-indexes.mjs";
3
+ import { _003_delegation_extensions_exports } from "./003-delegation-extensions.mjs";
4
+ import { _004_search_indexes_exports } from "./004-search-indexes.mjs";
3
5
  import { Migrator } from "kysely";
4
6
 
5
7
  //#region src/migrations/index.ts
@@ -11,7 +13,9 @@ var InMemoryMigrationProvider = class {
11
13
  async getMigrations() {
12
14
  return {
13
15
  "001-genesis": _001_genesis_exports,
14
- "002-composite-indexes": _002_composite_indexes_exports
16
+ "002-composite-indexes": _002_composite_indexes_exports,
17
+ "003-delegation-extensions": _003_delegation_extensions_exports,
18
+ "004-search-indexes": _004_search_indexes_exports
15
19
  };
16
20
  }
17
21
  };
package/lib/db/base.cjs CHANGED
@@ -12,6 +12,18 @@ lodash_omit = require_rolldown_runtime.__toESM(lodash_omit);
12
12
  //#region src/db/base.ts
13
13
  const debug$1 = (0, debug.default)("@ocap/indexdb-sqlite");
14
14
  const MAX_REQUEST_FACTORY_ADDRESS_SIZE = 100;
15
+ const SEARCH_LIMIT_PER_TABLE = 5;
16
+ /** Escape SQL LIKE special characters */
17
+ function escapeLikePattern(s) {
18
+ return s.replace(/[%_\\]/g, (c) => `\\${c}`);
19
+ }
20
+ /** Score a match: 3=exact, 2=prefix, 1=contains */
21
+ function scoreMatch(fieldValue, keyword) {
22
+ const lower = fieldValue.toLowerCase();
23
+ if (lower === keyword) return 3;
24
+ if (lower.startsWith(keyword)) return 2;
25
+ return 1;
26
+ }
15
27
  function buildPagingResult(total, pagination, itemCount) {
16
28
  return {
17
29
  cursor: String(pagination.cursor + itemCount),
@@ -744,6 +756,172 @@ var SqliteBaseIndexDB = class extends _ocap_indexdb.BaseIndexDB {
744
756
  paging: buildPagingResult(total, pagination, delegations.length)
745
757
  };
746
758
  }
759
+ /**
760
+ * Search entities by semantic fields (moniker, name, symbol, description)
761
+ */
762
+ async search(keyword) {
763
+ const trimmed = keyword?.trim();
764
+ if (!trimmed) return [];
765
+ const escaped = escapeLikePattern(trimmed);
766
+ const lowerKw = trimmed.toLowerCase();
767
+ const containsPattern = `%${escaped}%`;
768
+ const limit = kysely.sql.raw(String(SEARCH_LIMIT_PER_TABLE));
769
+ const typePriority = {
770
+ token: 0,
771
+ account: 1,
772
+ factory: 2,
773
+ asset: 3,
774
+ tokenFactory: 4,
775
+ stake: 5
776
+ };
777
+ const isDidLike = /^(did:abt:)?(z[1-9A-HJ-NP-Za-km-z]|0x[0-9a-fA-F])/.test(trimmed);
778
+ const didPrefix = isDidLike ? trimmed.replace(/^did:abt:/i, "") : "";
779
+ const doDidSearch = isDidLike && didPrefix.length >= 4;
780
+ const queries = [
781
+ kysely.sql`
782
+ SELECT address, name, symbol, description FROM token
783
+ WHERE LOWER(name) LIKE LOWER(${containsPattern}) ESCAPE '\\' OR LOWER(symbol) LIKE LOWER(${containsPattern}) ESCAPE '\\' OR LOWER(description) LIKE LOWER(${containsPattern}) ESCAPE '\\'
784
+ LIMIT ${limit}
785
+ `.execute(this.db),
786
+ kysely.sql`
787
+ SELECT address, moniker FROM account
788
+ WHERE LOWER(moniker) LIKE LOWER(${containsPattern}) ESCAPE '\\'
789
+ LIMIT ${limit}
790
+ `.execute(this.db),
791
+ kysely.sql`
792
+ SELECT address, name, description FROM factory
793
+ WHERE LOWER(name) LIKE LOWER(${containsPattern}) ESCAPE '\\' OR LOWER(description) LIKE LOWER(${containsPattern}) ESCAPE '\\'
794
+ LIMIT ${limit}
795
+ `.execute(this.db),
796
+ kysely.sql`
797
+ SELECT address, moniker, tags FROM asset
798
+ WHERE LOWER(moniker) LIKE LOWER(${containsPattern}) ESCAPE '\\' OR LOWER(tags) LIKE LOWER(${containsPattern}) ESCAPE '\\'
799
+ LIMIT ${limit}
800
+ `.execute(this.db),
801
+ kysely.sql`
802
+ SELECT address, name, moniker FROM tokenFactory
803
+ WHERE LOWER(name) LIKE LOWER(${containsPattern}) ESCAPE '\\' OR LOWER(moniker) LIKE LOWER(${containsPattern}) ESCAPE '\\'
804
+ LIMIT ${limit}
805
+ `.execute(this.db),
806
+ kysely.sql`
807
+ SELECT address, message FROM stake
808
+ WHERE LOWER(message) LIKE LOWER(${containsPattern}) ESCAPE '\\'
809
+ LIMIT ${limit}
810
+ `.execute(this.db)
811
+ ];
812
+ if (doDidSearch) {
813
+ const prefixPattern = `${escapeLikePattern(didPrefix)}%`;
814
+ queries.push(kysely.sql`
815
+ SELECT * FROM (SELECT address, 'account' as type, COALESCE(moniker, address) as title FROM account WHERE address LIKE ${prefixPattern} ESCAPE '\\' LIMIT ${limit})
816
+ UNION ALL SELECT * FROM (SELECT address, 'token', COALESCE(name, address) FROM token WHERE address LIKE ${prefixPattern} ESCAPE '\\' LIMIT ${limit})
817
+ UNION ALL SELECT * FROM (SELECT address, 'asset', COALESCE(moniker, address) FROM asset WHERE address LIKE ${prefixPattern} ESCAPE '\\' LIMIT ${limit})
818
+ UNION ALL SELECT * FROM (SELECT address, 'factory', COALESCE(name, address) FROM factory WHERE address LIKE ${prefixPattern} ESCAPE '\\' LIMIT ${limit})
819
+ UNION ALL SELECT * FROM (SELECT address, 'tokenFactory', COALESCE(name, address) FROM tokenFactory WHERE address LIKE ${prefixPattern} ESCAPE '\\' LIMIT ${limit})
820
+ UNION ALL SELECT * FROM (SELECT address, 'stake', COALESCE(message, address) FROM stake WHERE address LIKE ${prefixPattern} ESCAPE '\\' LIMIT ${limit})
821
+ `.execute(this.db));
822
+ }
823
+ const allResults = await Promise.all(queries);
824
+ const [tokenRows, accountRows, factoryRows, assetRows, tokenFactoryRows, stakeRows] = allResults;
825
+ const results = [];
826
+ for (const row of tokenRows.rows) {
827
+ const nameScore = row.name ? scoreMatch(row.name, lowerKw) : 0;
828
+ const symbolScore = row.symbol ? scoreMatch(row.symbol, lowerKw) : 0;
829
+ const descScore = row.description ? scoreMatch(row.description, lowerKw) : 0;
830
+ const score = Math.max(nameScore, symbolScore, descScore);
831
+ const title = nameScore >= symbolScore ? row.name || row.symbol || "" : row.symbol || row.name || "";
832
+ results.push({
833
+ type: "token",
834
+ id: row.address,
835
+ title,
836
+ score,
837
+ priority: typePriority.token
838
+ });
839
+ }
840
+ for (const row of accountRows.rows) {
841
+ const score = scoreMatch(row.moniker, lowerKw);
842
+ results.push({
843
+ type: "account",
844
+ id: row.address,
845
+ title: row.moniker || "",
846
+ score,
847
+ priority: typePriority.account
848
+ });
849
+ }
850
+ for (const row of factoryRows.rows) {
851
+ const nameScore = row.name ? scoreMatch(row.name, lowerKw) : 0;
852
+ const descScore = row.description ? scoreMatch(row.description, lowerKw) : 0;
853
+ const score = Math.max(nameScore, descScore);
854
+ results.push({
855
+ type: "factory",
856
+ id: row.address,
857
+ title: row.name || "",
858
+ score,
859
+ priority: typePriority.factory
860
+ });
861
+ }
862
+ for (const row of assetRows.rows) {
863
+ const monikerScore = row.moniker ? scoreMatch(row.moniker, lowerKw) : 0;
864
+ let tagScore = 0;
865
+ if (row.tags) try {
866
+ const tags = typeof row.tags === "string" ? JSON.parse(row.tags) : row.tags;
867
+ if (Array.isArray(tags)) tagScore = Math.max(0, ...tags.map((t) => scoreMatch(t, lowerKw)));
868
+ } catch {}
869
+ const score = Math.max(monikerScore, tagScore);
870
+ results.push({
871
+ type: "asset",
872
+ id: row.address,
873
+ title: row.moniker || "",
874
+ score,
875
+ priority: typePriority.asset
876
+ });
877
+ }
878
+ for (const row of tokenFactoryRows.rows) {
879
+ const nameScore = row.name ? scoreMatch(row.name, lowerKw) : 0;
880
+ const monikerScore = row.moniker ? scoreMatch(row.moniker, lowerKw) : 0;
881
+ const score = Math.max(nameScore, monikerScore);
882
+ const title = nameScore >= monikerScore ? row.name || row.moniker || "" : row.moniker || row.name || "";
883
+ results.push({
884
+ type: "tokenFactory",
885
+ id: row.address,
886
+ title,
887
+ score,
888
+ priority: typePriority.tokenFactory
889
+ });
890
+ }
891
+ for (const row of stakeRows.rows) {
892
+ const score = scoreMatch(row.message, lowerKw);
893
+ results.push({
894
+ type: "stake",
895
+ id: row.address,
896
+ title: row.message || "",
897
+ score,
898
+ priority: typePriority.stake
899
+ });
900
+ }
901
+ if (doDidSearch) {
902
+ const didRows = allResults[6];
903
+ const seen = new Set(results.map((r) => `${r.type}:${r.id}`));
904
+ for (const row of didRows.rows) {
905
+ const key = `${row.type}:${row.address}`;
906
+ if (!seen.has(key)) {
907
+ seen.add(key);
908
+ results.push({
909
+ type: row.type,
910
+ id: row.address,
911
+ title: row.title || row.address,
912
+ score: 2,
913
+ priority: typePriority[row.type] ?? 99
914
+ });
915
+ }
916
+ }
917
+ }
918
+ results.sort((a, b) => b.score - a.score || a.priority - b.priority);
919
+ return results.map(({ type, id, title }) => ({
920
+ type,
921
+ id,
922
+ title
923
+ }));
924
+ }
747
925
  };
748
926
  var base_default = SqliteBaseIndexDB;
749
927
 
package/lib/db/base.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Database } from "../interfaces.cjs";
2
2
  import { BaseIndexDB } from "@ocap/indexdb";
3
- import { IIndexDB, IIndexTable, IListAccountsResult, IListAssetsResult, IListDelegationsResult, IListFactoriesResult, IListRollupBlocksResult, IListRollupValidatorsResult, IListRollupsResult, IListStakesResult, IListTokenFactoriesResult, IListTokensResult, IListTransactionsResult, IndexTableTypeMap, TRequestListAssets, TRequestListDelegations, TRequestListFactories, TRequestListRollupBlocks, TRequestListRollupValidators, TRequestListRollups, TRequestListStakes, TRequestListTokenFactories, TRequestListTokens, TRequestListTopAccounts, TRequestListTransactions } from "@ocap/types";
3
+ import { IIndexDB, IIndexTable, IListAccountsResult, IListAssetsResult, IListDelegationsResult, IListFactoriesResult, IListRollupBlocksResult, IListRollupValidatorsResult, IListRollupsResult, IListStakesResult, IListTokenFactoriesResult, IListTokensResult, IListTransactionsResult, IndexTableTypeMap, TRequestListAssets, TRequestListDelegations, TRequestListFactories, TRequestListRollupBlocks, TRequestListRollupValidators, TRequestListRollups, TRequestListStakes, TRequestListTokenFactories, TRequestListTokens, TRequestListTopAccounts, TRequestListTransactions, TSearchResult } from "@ocap/types";
4
4
  import { Kysely } from "kysely";
5
5
 
6
6
  //#region src/db/base.d.ts
@@ -73,6 +73,10 @@ declare class SqliteBaseIndexDB extends BaseIndexDB implements IIndexDB {
73
73
  * List delegations
74
74
  */
75
75
  listDelegations(params?: Partial<TRequestListDelegations>): Promise<IListDelegationsResult>;
76
+ /**
77
+ * Search entities by semantic fields (moniker, name, symbol, description)
78
+ */
79
+ search(keyword: string): Promise<TSearchResult[]>;
76
80
  }
77
81
  //#endregion
78
82
  export { SqliteBaseIndexDB as default };
package/lib/db/index.cjs CHANGED
@@ -315,6 +315,7 @@ var SqliteIndexDB = class extends require_db_base.default {
315
315
  schema: {
316
316
  jsonFields: [
317
317
  "ops",
318
+ "deny",
318
319
  "context",
319
320
  "data"
320
321
  ],
@@ -327,6 +328,8 @@ var SqliteIndexDB = class extends require_db_base.default {
327
328
  "from",
328
329
  "to",
329
330
  "ops",
331
+ "deny",
332
+ "validUntil",
330
333
  "context",
331
334
  "data",
332
335
  "genesisTime",
@@ -198,6 +198,8 @@ interface DelegationTable {
198
198
  from_: string | null;
199
199
  to_: string | null;
200
200
  ops: string | null;
201
+ deny: string | null;
202
+ validUntil: number | null;
201
203
  context: string | null;
202
204
  data: string | null;
203
205
  genesisTime: string | null;
@@ -0,0 +1,23 @@
1
+ const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
+ let kysely = require("kysely");
3
+
4
+ //#region src/migrations/003-delegation-extensions.ts
5
+ var _003_delegation_extensions_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
6
+ down: () => down,
7
+ up: () => up
8
+ });
9
+ async function up(db) {
10
+ await kysely.sql`ALTER TABLE delegation ADD COLUMN deny TEXT`.execute(db);
11
+ await kysely.sql`ALTER TABLE delegation ADD COLUMN validUntil INTEGER DEFAULT 0`.execute(db);
12
+ }
13
+ async function down(_db) {}
14
+
15
+ //#endregion
16
+ Object.defineProperty(exports, '_003_delegation_extensions_exports', {
17
+ enumerable: true,
18
+ get: function () {
19
+ return _003_delegation_extensions_exports;
20
+ }
21
+ });
22
+ exports.down = down;
23
+ exports.up = up;
@@ -0,0 +1,7 @@
1
+ import { Kysely } from "kysely";
2
+
3
+ //#region src/migrations/003-delegation-extensions.d.ts
4
+ declare function up(db: Kysely<unknown>): Promise<void>;
5
+ declare function down(_db: Kysely<unknown>): Promise<void>;
6
+ //#endregion
7
+ export { down, up };
@@ -0,0 +1,28 @@
1
+ const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
+ let kysely = require("kysely");
3
+
4
+ //#region src/migrations/004-search-indexes.ts
5
+ var _004_search_indexes_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
6
+ down: () => down,
7
+ up: () => up
8
+ });
9
+ async function up(db) {
10
+ await kysely.sql`CREATE INDEX IF NOT EXISTS idx_asset_moniker ON asset(moniker) WHERE moniker IS NOT NULL`.execute(db);
11
+ await kysely.sql`CREATE INDEX IF NOT EXISTS idx_token_name ON token(name) WHERE name IS NOT NULL`.execute(db);
12
+ await kysely.sql`CREATE INDEX IF NOT EXISTS idx_tokenfactory_name ON tokenFactory(name) WHERE name IS NOT NULL`.execute(db);
13
+ }
14
+ async function down(db) {
15
+ await kysely.sql`DROP INDEX IF EXISTS idx_asset_moniker`.execute(db);
16
+ await kysely.sql`DROP INDEX IF EXISTS idx_token_name`.execute(db);
17
+ await kysely.sql`DROP INDEX IF EXISTS idx_tokenfactory_name`.execute(db);
18
+ }
19
+
20
+ //#endregion
21
+ Object.defineProperty(exports, '_004_search_indexes_exports', {
22
+ enumerable: true,
23
+ get: function () {
24
+ return _004_search_indexes_exports;
25
+ }
26
+ });
27
+ exports.down = down;
28
+ exports.up = up;
@@ -0,0 +1,7 @@
1
+ import { Kysely } from "kysely";
2
+
3
+ //#region src/migrations/004-search-indexes.d.ts
4
+ declare function up(db: Kysely<unknown>): Promise<void>;
5
+ declare function down(db: Kysely<unknown>): Promise<void>;
6
+ //#endregion
7
+ export { down, up };
@@ -1,6 +1,8 @@
1
1
  const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
2
  const require_migrations_001_genesis = require('./001-genesis.cjs');
3
3
  const require_migrations_002_composite_indexes = require('./002-composite-indexes.cjs');
4
+ const require_migrations_003_delegation_extensions = require('./003-delegation-extensions.cjs');
5
+ const require_migrations_004_search_indexes = require('./004-search-indexes.cjs');
4
6
  let kysely = require("kysely");
5
7
 
6
8
  //#region src/migrations/index.ts
@@ -12,7 +14,9 @@ var InMemoryMigrationProvider = class {
12
14
  async getMigrations() {
13
15
  return {
14
16
  "001-genesis": require_migrations_001_genesis._001_genesis_exports,
15
- "002-composite-indexes": require_migrations_002_composite_indexes._002_composite_indexes_exports
17
+ "002-composite-indexes": require_migrations_002_composite_indexes._002_composite_indexes_exports,
18
+ "003-delegation-extensions": require_migrations_003_delegation_extensions._003_delegation_extensions_exports,
19
+ "004-search-indexes": require_migrations_004_search_indexes._004_search_indexes_exports
16
20
  };
17
21
  }
18
22
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ocap/indexdb-sqlite",
3
3
  "description": "OCAP indexdb adapter that uses SQLite as backend",
4
- "version": "1.29.14",
4
+ "version": "1.29.16",
5
5
  "author": "wangshijun <shijun@arcblock.io> (https://www.arcblock.io)",
6
6
  "bugs": {
7
7
  "url": "https://github.com/ArcBlock/blockchain/issues",
@@ -14,7 +14,7 @@
14
14
  "wangshijun <shijun@arcblock.io> (https://www.arcblock.io)"
15
15
  ],
16
16
  "devDependencies": {
17
- "@ocap/indexdb-test": "1.29.14"
17
+ "@ocap/indexdb-test": "1.29.16"
18
18
  },
19
19
  "homepage": "https://github.com/ArcBlock/blockchain/tree/master/indexdb/sqlite",
20
20
  "keywords": [
@@ -63,10 +63,10 @@
63
63
  "clean": "rm -rf lib esm"
64
64
  },
65
65
  "dependencies": {
66
- "@arcblock/did": "1.29.14",
67
- "@ocap/indexdb": "1.29.14",
68
- "@ocap/types": "1.29.14",
69
- "@ocap/util": "1.29.14",
66
+ "@arcblock/did": "1.29.16",
67
+ "@ocap/indexdb": "1.29.16",
68
+ "@ocap/types": "1.29.16",
69
+ "@ocap/util": "1.29.16",
70
70
  "debug": "^4.4.3",
71
71
  "better-sqlite3": "^11.8.1",
72
72
  "kysely": "^0.27.0",