@fabriktor/fx 0.0.37 → 0.0.38

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.
@@ -1,5 +1,5 @@
1
- import { type Chat, type ChatRoom, type ChatRoomMember } from "@fabriktor/schema";
2
1
  import type { ChatOperator, WSCloseHandler, WSConnection, WSErrorHandler, WSMessageHandler } from "@fabriktor/client";
2
+ import type { Chat, ChatRoom, ChatRoomMember } from "@fabriktor/schema";
3
3
  export type ReactChatOptions = Parameters<ChatOperator["reactChat"]>[0];
4
4
  export type ChatFXOptions = {
5
5
  chat: ChatOperator;
@@ -3,10 +3,8 @@
3
3
  // Licensed under the Apache License, Version 2.0 (the "License"); you may
4
4
  // not use this file except in compliance with the License. You may obtain
5
5
  // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
- import { SearchPageKey, SearchPerPageKey, SearchResultResultsKey, } from "@fabriktor/schema";
7
6
  import { errValidation } from "../core/err.js";
8
- const firstPage = 1;
9
- const defaultPerPage = 30;
7
+ import { normalizeSearchPage, normalizeSearchPerPage, runSearch, } from "../core/search.js";
10
8
  const closeCodeNormal = 1000;
11
9
  const closeCodeLeavingPage = 1001;
12
10
  const msgChatObjectsUploading = "Cannot react to a chat while objects are still uploading.";
@@ -18,25 +16,22 @@ export class ChatFX {
18
16
  newLatestChatsCursor(opts) {
19
17
  return {
20
18
  chat_room_id: opts.chat_room_id,
21
- next_page: normalizePage(opts.page),
22
- per_page: normalizePerPage(opts.per_page),
19
+ next_page: normalizeSearchPage(opts.page),
20
+ per_page: normalizeSearchPerPage(opts.per_page),
23
21
  done: false,
24
22
  };
25
23
  }
26
24
  async latestChats(opts) {
27
- const page = normalizePage(opts.page);
28
- const per_page = normalizePerPage(opts.per_page);
29
- const raw = await this.chat.searchManyChats({
25
+ const raw = await runSearch({
26
+ search: (searchOpts) => this.chat.searchManyChats(searchOpts),
30
27
  query: {
31
28
  chat_room_id: opts.chat_room_id,
32
- [SearchPageKey]: page,
33
- [SearchPerPageKey]: per_page,
34
29
  },
30
+ page: opts.page,
31
+ per_page: opts.per_page,
35
32
  });
36
33
  return latestChatsPage({
37
34
  chat_room_id: opts.chat_room_id,
38
- page,
39
- per_page,
40
35
  raw,
41
36
  });
42
37
  }
@@ -131,29 +126,18 @@ export function newChatFX(opts) {
131
126
  return new ChatFX(opts);
132
127
  }
133
128
  function latestChatsPage(opts) {
134
- const value = opts.raw.value;
135
- const chats = value?.[SearchResultResultsKey] ?? [];
136
- const total_count = value?.total_count;
137
- const last_page = value?.last_page;
138
- const has_more = hasMoreChats({
139
- chats,
140
- page: opts.page,
141
- per_page: opts.per_page,
142
- total_count,
143
- last_page,
144
- });
145
129
  return {
146
- chats,
147
- page: opts.page,
148
- per_page: opts.per_page,
149
- total_count,
150
- last_page,
151
- has_more,
130
+ chats: opts.raw.results,
131
+ page: opts.raw.page,
132
+ per_page: opts.raw.per_page,
133
+ total_count: opts.raw.total_count,
134
+ last_page: opts.raw.last_page,
135
+ has_more: opts.raw.has_more,
152
136
  next_cursor: {
153
137
  chat_room_id: opts.chat_room_id,
154
- next_page: has_more ? opts.page + 1 : opts.page,
155
- per_page: opts.per_page,
156
- done: !has_more,
138
+ next_page: opts.raw.next_page,
139
+ per_page: opts.raw.per_page,
140
+ done: opts.raw.done,
157
141
  },
158
142
  };
159
143
  }
@@ -166,29 +150,8 @@ function emptyLatestChatsPage(cursor) {
166
150
  next_cursor: cursor,
167
151
  };
168
152
  }
169
- function hasMoreChats(opts) {
170
- if (opts.last_page !== undefined) {
171
- return opts.page < opts.last_page;
172
- }
173
- if (opts.total_count !== undefined) {
174
- return opts.page * opts.per_page < opts.total_count;
175
- }
176
- return opts.chats.length >= opts.per_page;
177
- }
178
153
  function closeWS(conns, code, reason) {
179
154
  for (const conn of conns) {
180
155
  conn.close(code, reason);
181
156
  }
182
157
  }
183
- function normalizePage(v) {
184
- if (v === undefined || !Number.isFinite(v)) {
185
- return firstPage;
186
- }
187
- return Math.max(firstPage, Math.trunc(v));
188
- }
189
- function normalizePerPage(v) {
190
- if (v === undefined || !Number.isFinite(v)) {
191
- return defaultPerPage;
192
- }
193
- return Math.max(1, Math.trunc(v));
194
- }
@@ -0,0 +1,24 @@
1
+ import type { OperationResultOf, SearchManyOptionsCRUD, SearchResultOf } from "@fabriktor/client";
2
+ export type SearchQuery = NonNullable<SearchManyOptionsCRUD["query"]>;
3
+ export type SearchCall<T> = (opts: SearchManyOptionsCRUD) => Promise<OperationResultOf<SearchResultOf<T>>>;
4
+ export type RunSearchOptions<T> = {
5
+ search: SearchCall<T>;
6
+ query?: SearchQuery;
7
+ q?: string;
8
+ page?: number;
9
+ per_page?: number;
10
+ };
11
+ export type SearchPage<T> = {
12
+ results: T[];
13
+ page: number;
14
+ per_page: number;
15
+ total_count?: number;
16
+ last_page?: number;
17
+ has_more: boolean;
18
+ next_page: number;
19
+ done: boolean;
20
+ };
21
+ export declare function runSearch<T>(opts: RunSearchOptions<T>): Promise<SearchPage<T>>;
22
+ export declare function normalizeSearchPage(value?: number): number;
23
+ export declare function normalizeSearchPerPage(value?: number): number;
24
+ export declare function normalizeSearchQuery(value?: string): string | undefined;
@@ -0,0 +1,84 @@
1
+ // Copyright (C) Fabriktor, Inc. 2025-present.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+ // not use this file except in compliance with the License. You may obtain
5
+ // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ import { SearchPageKey, SearchPerPageKey, SearchQueryKey, SearchResultResultsKey, } from "@fabriktor/schema";
7
+ const firstSearchPage = 1;
8
+ const defaultSearchPerPage = 30;
9
+ export async function runSearch(opts) {
10
+ const page = normalizeSearchPage(opts.page);
11
+ const per_page = normalizeSearchPerPage(opts.per_page);
12
+ const q = normalizeSearchQuery(opts.q);
13
+ const query = q === undefined
14
+ ? {
15
+ ...opts.query,
16
+ [SearchPageKey]: page,
17
+ [SearchPerPageKey]: per_page,
18
+ }
19
+ : {
20
+ ...opts.query,
21
+ [SearchPageKey]: page,
22
+ [SearchPerPageKey]: per_page,
23
+ [SearchQueryKey]: q,
24
+ };
25
+ const raw = await opts.search({
26
+ query,
27
+ });
28
+ return resolveSearchPage({
29
+ raw,
30
+ page,
31
+ per_page,
32
+ });
33
+ }
34
+ export function normalizeSearchPage(value) {
35
+ if (value === undefined || !Number.isFinite(value)) {
36
+ return firstSearchPage;
37
+ }
38
+ return Math.max(firstSearchPage, Math.trunc(value));
39
+ }
40
+ export function normalizeSearchPerPage(value) {
41
+ if (value === undefined || !Number.isFinite(value)) {
42
+ return defaultSearchPerPage;
43
+ }
44
+ return Math.max(1, Math.trunc(value));
45
+ }
46
+ export function normalizeSearchQuery(value) {
47
+ const query = value?.trim();
48
+ if (!query) {
49
+ return undefined;
50
+ }
51
+ return query;
52
+ }
53
+ function resolveSearchPage(opts) {
54
+ const value = opts.raw.value;
55
+ const results = value?.[SearchResultResultsKey] ?? [];
56
+ const total_count = value?.total_count;
57
+ const last_page = value?.last_page;
58
+ const has_more = hasMoreSearchResults({
59
+ result_count: results.length,
60
+ page: opts.page,
61
+ per_page: opts.per_page,
62
+ total_count,
63
+ last_page,
64
+ });
65
+ return {
66
+ results,
67
+ page: opts.page,
68
+ per_page: opts.per_page,
69
+ total_count,
70
+ last_page,
71
+ has_more,
72
+ next_page: has_more ? opts.page + 1 : opts.page,
73
+ done: !has_more,
74
+ };
75
+ }
76
+ function hasMoreSearchResults(opts) {
77
+ if (opts.last_page !== undefined) {
78
+ return opts.page < opts.last_page;
79
+ }
80
+ if (opts.total_count !== undefined) {
81
+ return opts.page * opts.per_page < opts.total_count;
82
+ }
83
+ return opts.result_count >= opts.per_page;
84
+ }
@@ -5,6 +5,7 @@ export * from "./chat/chat.js";
5
5
  export * from "./contacts/contacts.js";
6
6
  export * from "./core/err.js";
7
7
  export * from "./core/pull.js";
8
+ export * from "./core/search.js";
8
9
  export * from "./feed/feed.js";
9
10
  export * from "./fx.js";
10
11
  export * from "./jobs/jobs.js";
package/dist/src/index.js CHANGED
@@ -5,6 +5,7 @@ export * from "./chat/chat.js";
5
5
  export * from "./contacts/contacts.js";
6
6
  export * from "./core/err.js";
7
7
  export * from "./core/pull.js";
8
+ export * from "./core/search.js";
8
9
  export * from "./feed/feed.js";
9
10
  export * from "./fx.js";
10
11
  export * from "./jobs/jobs.js";
@@ -1,5 +1,6 @@
1
1
  import type { MemosOperator } from "@fabriktor/client";
2
2
  import { type Memo, type MemoFolder } from "@fabriktor/schema";
3
+ import { type SearchPage } from "../core/search.js";
3
4
  type MemoInsertOptions = Parameters<MemosOperator["insertOneMemo"]>[0];
4
5
  type MemoReplaceOptions = Parameters<MemosOperator["replaceOneMemo"]>[0];
5
6
  type MemoFolderInsertOptions = Parameters<MemosOperator["insertOneMemoFolder"]>[0];
@@ -8,11 +9,27 @@ export type CreateMemoOptions = MemoInsertOptions;
8
9
  export type ReplaceMemoOptions = MemoReplaceOptions;
9
10
  export type CreateMemoFolderOptions = MemoFolderInsertOptions;
10
11
  export type ReplaceMemoFolderOptions = MemoFolderReplaceOptions;
12
+ export type SearchMemosOptions = {
13
+ owner_id: string;
14
+ q?: string;
15
+ page?: number;
16
+ per_page?: number;
17
+ };
18
+ export type SearchMemoFoldersOptions = {
19
+ owner_id: string;
20
+ q?: string;
21
+ page?: number;
22
+ per_page?: number;
23
+ };
24
+ export type SearchMemosPage = SearchPage<Memo>;
25
+ export type SearchMemoFoldersPage = SearchPage<MemoFolder>;
11
26
  export interface MemosFXOperator {
12
27
  createMemo(opts: CreateMemoOptions): Promise<Memo>;
13
28
  replaceMemo(opts: ReplaceMemoOptions): Promise<Memo>;
14
29
  createMemoFolder(opts: CreateMemoFolderOptions): Promise<MemoFolder>;
15
30
  replaceMemoFolder(opts: ReplaceMemoFolderOptions): Promise<MemoFolder>;
31
+ searchMemos(opts: SearchMemosOptions): Promise<SearchMemosPage>;
32
+ searchMemoFolders(opts: SearchMemoFoldersOptions): Promise<SearchMemoFoldersPage>;
16
33
  }
17
34
  export type MemosFXOptions = {
18
35
  memos: MemosOperator;
@@ -24,6 +41,8 @@ export declare class MemosFX implements MemosFXOperator {
24
41
  replaceMemo(opts: ReplaceMemoOptions): Promise<Memo>;
25
42
  createMemoFolder(opts: CreateMemoFolderOptions): Promise<MemoFolder>;
26
43
  replaceMemoFolder(opts: ReplaceMemoFolderOptions): Promise<MemoFolder>;
44
+ searchMemos(opts: SearchMemosOptions): Promise<SearchMemosPage>;
45
+ searchMemoFolders(opts: SearchMemoFoldersOptions): Promise<SearchMemoFoldersPage>;
27
46
  private findMemo;
28
47
  private findMemoFolder;
29
48
  }
@@ -3,8 +3,9 @@
3
3
  // Licensed under the Apache License, Version 2.0 (the "License"); you may
4
4
  // not use this file except in compliance with the License. You may obtain
5
5
  // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
- import { ZeroID, } from "@fabriktor/schema";
6
+ import { OwnerIDKey, ZeroID, } from "@fabriktor/schema";
7
7
  import { errResolveFailed } from "../core/err.js";
8
+ import { runSearch } from "../core/search.js";
8
9
  const resourceMemoID = "memo_id";
9
10
  const resourceMemo = "memo";
10
11
  const resourceMemoFolderID = "memo_folder_id";
@@ -42,6 +43,28 @@ export class MemosFX {
42
43
  await this.memos.replaceOneMemoFolder(opts);
43
44
  return await this.findMemoFolder(opts.id);
44
45
  }
46
+ async searchMemos(opts) {
47
+ return await runSearch({
48
+ search: (searchOpts) => this.memos.searchManyMemos(searchOpts),
49
+ query: {
50
+ [OwnerIDKey]: opts.owner_id,
51
+ },
52
+ q: opts.q,
53
+ page: opts.page,
54
+ per_page: opts.per_page,
55
+ });
56
+ }
57
+ async searchMemoFolders(opts) {
58
+ return await runSearch({
59
+ search: (searchOpts) => this.memos.searchManyMemoFolders(searchOpts),
60
+ query: {
61
+ [OwnerIDKey]: opts.owner_id,
62
+ },
63
+ q: opts.q,
64
+ page: opts.page,
65
+ per_page: opts.per_page,
66
+ });
67
+ }
45
68
  async findMemo(id) {
46
69
  const out = await this.memos.findOneMemo({
47
70
  id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabriktor/fx",
3
- "version": "0.0.37",
3
+ "version": "0.0.38",
4
4
  "description": "![Fabriktor Logo](./img/fabriktor-character.gif)",
5
5
  "type": "module",
6
6
  "exports": {
@@ -17,7 +17,7 @@
17
17
  "typescript": "^6.0.3"
18
18
  },
19
19
  "dependencies": {
20
- "@fabriktor/client": "0.0.43",
21
- "@fabriktor/schema": "0.0.31"
20
+ "@fabriktor/client": "0.0.44",
21
+ "@fabriktor/schema": "0.0.32"
22
22
  }
23
23
  }