@tinacms/search 1.0.0 → 1.0.2

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,4 +1,6 @@
1
1
  export type { SearchClient } from './types';
2
+ export { processDocumentForIndexing } from './indexer/utils';
3
+ export declare const queryToSearchIndexQuery: (query: string) => any;
2
4
  export declare const optionsToSearchIndexOptions: (options?: {
3
5
  limit?: number;
4
6
  cursor?: string;
@@ -1,3 +1,109 @@
1
+ class StringBuilder {
2
+ constructor(limit) {
3
+ this.length = 0;
4
+ this.buffer = [];
5
+ this.limit = limit;
6
+ }
7
+ append(str) {
8
+ if (this.length + str.length > this.limit) {
9
+ return true;
10
+ } else {
11
+ this.buffer.push(str);
12
+ this.length += str.length;
13
+ if (this.length > this.limit) {
14
+ return true;
15
+ }
16
+ return false;
17
+ }
18
+ }
19
+ toString() {
20
+ return this.buffer.join(" ");
21
+ }
22
+ }
23
+ const extractText = (data, acc, indexableNodeTypes) => {
24
+ var _a, _b;
25
+ if (data) {
26
+ if (indexableNodeTypes.indexOf(data.type) !== -1 && (data.text || data.value)) {
27
+ const tokens = tokenizeString(data.text || data.value);
28
+ for (const token of tokens) {
29
+ if (acc.append(token)) {
30
+ return;
31
+ }
32
+ }
33
+ }
34
+ (_b = (_a = data.children) == null ? void 0 : _a.forEach) == null ? void 0 : _b.call(_a, (child) => extractText(child, acc, indexableNodeTypes));
35
+ }
36
+ };
37
+ const relativePath = (path, collection) => {
38
+ return path.replace(/\\/g, "/").replace(collection.path, "").replace(/^\/|\/$/g, "");
39
+ };
40
+ const tokenizeString = (str) => {
41
+ return str.split(/[\s\.,]+/).map((s) => s.toLowerCase()).filter((s) => s);
42
+ };
43
+ const processTextFieldValue = (value, maxLen) => {
44
+ const tokens = tokenizeString(value);
45
+ const builder = new StringBuilder(maxLen);
46
+ for (const part of tokens) {
47
+ if (builder.append(part)) {
48
+ break;
49
+ }
50
+ }
51
+ return builder.toString();
52
+ };
53
+ const processDocumentForIndexing = (data, path, collection, textIndexLength, field) => {
54
+ if (!field) {
55
+ const relPath = relativePath(path, collection);
56
+ data["_id"] = `${collection.name}:${relPath}`;
57
+ data["_relativePath"] = relPath;
58
+ }
59
+ for (const f of collection.fields || (field == null ? void 0 : field.fields) || []) {
60
+ if (!f.searchable) {
61
+ delete data[f.name];
62
+ continue;
63
+ }
64
+ const isList = f.list;
65
+ if (data[f.name]) {
66
+ if (f.type === "object") {
67
+ if (isList) {
68
+ data[f.name] = data[f.name].map((obj) => processDocumentForIndexing(obj, path, collection, textIndexLength, f));
69
+ } else {
70
+ data[f.name] = processDocumentForIndexing(data[f.name], path, collection, textIndexLength, f);
71
+ }
72
+ } else if (f.type === "string") {
73
+ const fieldTextIndexLength = f.maxSearchIndexFieldLength || textIndexLength;
74
+ if (isList) {
75
+ data[f.name] = data[f.name].map((value) => processTextFieldValue(value, fieldTextIndexLength));
76
+ } else {
77
+ data[f.name] = processTextFieldValue(data[f.name], fieldTextIndexLength);
78
+ }
79
+ } else if (f.type === "rich-text") {
80
+ const fieldTextIndexLength = f.maxSearchIndexFieldLength || textIndexLength;
81
+ if (isList) {
82
+ data[f.name] = data[f.name].map((value) => {
83
+ const acc = new StringBuilder(fieldTextIndexLength);
84
+ extractText(value, acc, ["text", "code_block", "html"]);
85
+ return acc.toString();
86
+ });
87
+ } else {
88
+ const acc = new StringBuilder(fieldTextIndexLength);
89
+ extractText(data[f.name], acc, ["text", "code_block", "html"]);
90
+ data[f.name] = acc.toString();
91
+ }
92
+ }
93
+ }
94
+ }
95
+ return data;
96
+ };
97
+ const queryToSearchIndexQuery = (query) => {
98
+ let q;
99
+ const parts = query.split(" ");
100
+ if (parts.length === 1) {
101
+ q = { AND: [parts[0]] };
102
+ } else {
103
+ q = { AND: parts.filter((part) => part.toLowerCase() !== "and") };
104
+ }
105
+ return q;
106
+ };
1
107
  const optionsToSearchIndexOptions = (options) => {
2
108
  const opt = {};
3
109
  if (options == null ? void 0 : options.limit) {
@@ -38,4 +144,4 @@ const parseSearchIndexResponse = (data, options) => {
38
144
  };
39
145
  }
40
146
  };
41
- export { optionsToSearchIndexOptions, parseSearchIndexResponse };
147
+ export { optionsToSearchIndexOptions, parseSearchIndexResponse, processDocumentForIndexing, queryToSearchIndexQuery };
@@ -2,6 +2,112 @@
2
2
  typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["@tinacms/search"] = {}));
3
3
  })(this, function(exports2) {
4
4
  "use strict";
5
+ class StringBuilder {
6
+ constructor(limit) {
7
+ this.length = 0;
8
+ this.buffer = [];
9
+ this.limit = limit;
10
+ }
11
+ append(str) {
12
+ if (this.length + str.length > this.limit) {
13
+ return true;
14
+ } else {
15
+ this.buffer.push(str);
16
+ this.length += str.length;
17
+ if (this.length > this.limit) {
18
+ return true;
19
+ }
20
+ return false;
21
+ }
22
+ }
23
+ toString() {
24
+ return this.buffer.join(" ");
25
+ }
26
+ }
27
+ const extractText = (data, acc, indexableNodeTypes) => {
28
+ var _a, _b;
29
+ if (data) {
30
+ if (indexableNodeTypes.indexOf(data.type) !== -1 && (data.text || data.value)) {
31
+ const tokens = tokenizeString(data.text || data.value);
32
+ for (const token of tokens) {
33
+ if (acc.append(token)) {
34
+ return;
35
+ }
36
+ }
37
+ }
38
+ (_b = (_a = data.children) == null ? void 0 : _a.forEach) == null ? void 0 : _b.call(_a, (child) => extractText(child, acc, indexableNodeTypes));
39
+ }
40
+ };
41
+ const relativePath = (path, collection) => {
42
+ return path.replace(/\\/g, "/").replace(collection.path, "").replace(/^\/|\/$/g, "");
43
+ };
44
+ const tokenizeString = (str) => {
45
+ return str.split(/[\s\.,]+/).map((s) => s.toLowerCase()).filter((s) => s);
46
+ };
47
+ const processTextFieldValue = (value, maxLen) => {
48
+ const tokens = tokenizeString(value);
49
+ const builder = new StringBuilder(maxLen);
50
+ for (const part of tokens) {
51
+ if (builder.append(part)) {
52
+ break;
53
+ }
54
+ }
55
+ return builder.toString();
56
+ };
57
+ const processDocumentForIndexing = (data, path, collection, textIndexLength, field) => {
58
+ if (!field) {
59
+ const relPath = relativePath(path, collection);
60
+ data["_id"] = `${collection.name}:${relPath}`;
61
+ data["_relativePath"] = relPath;
62
+ }
63
+ for (const f of collection.fields || (field == null ? void 0 : field.fields) || []) {
64
+ if (!f.searchable) {
65
+ delete data[f.name];
66
+ continue;
67
+ }
68
+ const isList = f.list;
69
+ if (data[f.name]) {
70
+ if (f.type === "object") {
71
+ if (isList) {
72
+ data[f.name] = data[f.name].map((obj) => processDocumentForIndexing(obj, path, collection, textIndexLength, f));
73
+ } else {
74
+ data[f.name] = processDocumentForIndexing(data[f.name], path, collection, textIndexLength, f);
75
+ }
76
+ } else if (f.type === "string") {
77
+ const fieldTextIndexLength = f.maxSearchIndexFieldLength || textIndexLength;
78
+ if (isList) {
79
+ data[f.name] = data[f.name].map((value) => processTextFieldValue(value, fieldTextIndexLength));
80
+ } else {
81
+ data[f.name] = processTextFieldValue(data[f.name], fieldTextIndexLength);
82
+ }
83
+ } else if (f.type === "rich-text") {
84
+ const fieldTextIndexLength = f.maxSearchIndexFieldLength || textIndexLength;
85
+ if (isList) {
86
+ data[f.name] = data[f.name].map((value) => {
87
+ const acc = new StringBuilder(fieldTextIndexLength);
88
+ extractText(value, acc, ["text", "code_block", "html"]);
89
+ return acc.toString();
90
+ });
91
+ } else {
92
+ const acc = new StringBuilder(fieldTextIndexLength);
93
+ extractText(data[f.name], acc, ["text", "code_block", "html"]);
94
+ data[f.name] = acc.toString();
95
+ }
96
+ }
97
+ }
98
+ }
99
+ return data;
100
+ };
101
+ const queryToSearchIndexQuery = (query) => {
102
+ let q;
103
+ const parts = query.split(" ");
104
+ if (parts.length === 1) {
105
+ q = { AND: [parts[0]] };
106
+ } else {
107
+ q = { AND: parts.filter((part) => part.toLowerCase() !== "and") };
108
+ }
109
+ return q;
110
+ };
5
111
  const optionsToSearchIndexOptions = (options) => {
6
112
  const opt = {};
7
113
  if (options == null ? void 0 : options.limit) {
@@ -44,5 +150,7 @@
44
150
  };
45
151
  exports2.optionsToSearchIndexOptions = optionsToSearchIndexOptions;
46
152
  exports2.parseSearchIndexResponse = parseSearchIndexResponse;
153
+ exports2.processDocumentForIndexing = processDocumentForIndexing;
154
+ exports2.queryToSearchIndexQuery = queryToSearchIndexQuery;
47
155
  Object.defineProperties(exports2, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
48
156
  });
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import si from '@tinacms/search-index';
1
2
  export { SearchIndexer } from './indexer';
2
3
  export { LocalSearchIndexClient, TinaCMSSearchIndexClient } from './client';
3
4
  export type { SearchClient } from './types';
4
5
  export { default as sw } from 'stopword';
6
+ export { si };
5
7
  export declare const lookupStopwords: (keys?: string[], defaultStopWords?: string[]) => string[];
package/dist/index.js CHANGED
@@ -29,13 +29,137 @@ __export(src_exports, {
29
29
  SearchIndexer: () => SearchIndexer,
30
30
  TinaCMSSearchIndexClient: () => TinaCMSSearchIndexClient,
31
31
  lookupStopwords: () => lookupStopwords,
32
+ si: () => import_search_index2.default,
32
33
  sw: () => import_stopword.default
33
34
  });
34
35
  module.exports = __toCommonJS(src_exports);
35
36
  var sw = __toESM(require("stopword"));
37
+ var import_search_index2 = __toESM(require("@tinacms/search-index"));
36
38
 
37
39
  // src/indexer/index.ts
38
40
  var import_graphql = require("@tinacms/graphql");
41
+
42
+ // src/indexer/utils.ts
43
+ var StringBuilder = class {
44
+ constructor(limit) {
45
+ this.length = 0;
46
+ this.buffer = [];
47
+ this.limit = limit;
48
+ }
49
+ append(str) {
50
+ if (this.length + str.length > this.limit) {
51
+ return true;
52
+ } else {
53
+ this.buffer.push(str);
54
+ this.length += str.length;
55
+ if (this.length > this.limit) {
56
+ return true;
57
+ }
58
+ return false;
59
+ }
60
+ }
61
+ toString() {
62
+ return this.buffer.join(" ");
63
+ }
64
+ };
65
+ var extractText = (data, acc, indexableNodeTypes) => {
66
+ var _a, _b;
67
+ if (data) {
68
+ if (indexableNodeTypes.indexOf(data.type) !== -1 && (data.text || data.value)) {
69
+ const tokens = tokenizeString(data.text || data.value);
70
+ for (const token of tokens) {
71
+ if (acc.append(token)) {
72
+ return;
73
+ }
74
+ }
75
+ }
76
+ (_b = (_a = data.children) == null ? void 0 : _a.forEach) == null ? void 0 : _b.call(
77
+ _a,
78
+ (child) => extractText(child, acc, indexableNodeTypes)
79
+ );
80
+ }
81
+ };
82
+ var relativePath = (path, collection) => {
83
+ return path.replace(/\\/g, "/").replace(collection.path, "").replace(/^\/|\/$/g, "");
84
+ };
85
+ var tokenizeString = (str) => {
86
+ return str.split(/[\s\.,]+/).map((s) => s.toLowerCase()).filter((s) => s);
87
+ };
88
+ var processTextFieldValue = (value, maxLen) => {
89
+ const tokens = tokenizeString(value);
90
+ const builder = new StringBuilder(maxLen);
91
+ for (const part of tokens) {
92
+ if (builder.append(part)) {
93
+ break;
94
+ }
95
+ }
96
+ return builder.toString();
97
+ };
98
+ var processDocumentForIndexing = (data, path, collection, textIndexLength, field) => {
99
+ if (!field) {
100
+ const relPath = relativePath(path, collection);
101
+ data["_id"] = `${collection.name}:${relPath}`;
102
+ data["_relativePath"] = relPath;
103
+ }
104
+ for (const f of collection.fields || (field == null ? void 0 : field.fields) || []) {
105
+ if (!f.searchable) {
106
+ delete data[f.name];
107
+ continue;
108
+ }
109
+ const isList = f.list;
110
+ if (data[f.name]) {
111
+ if (f.type === "object") {
112
+ if (isList) {
113
+ data[f.name] = data[f.name].map(
114
+ (obj) => processDocumentForIndexing(
115
+ obj,
116
+ path,
117
+ collection,
118
+ textIndexLength,
119
+ f
120
+ )
121
+ );
122
+ } else {
123
+ data[f.name] = processDocumentForIndexing(
124
+ data[f.name],
125
+ path,
126
+ collection,
127
+ textIndexLength,
128
+ f
129
+ );
130
+ }
131
+ } else if (f.type === "string") {
132
+ const fieldTextIndexLength = f.maxSearchIndexFieldLength || textIndexLength;
133
+ if (isList) {
134
+ data[f.name] = data[f.name].map(
135
+ (value) => processTextFieldValue(value, fieldTextIndexLength)
136
+ );
137
+ } else {
138
+ data[f.name] = processTextFieldValue(
139
+ data[f.name],
140
+ fieldTextIndexLength
141
+ );
142
+ }
143
+ } else if (f.type === "rich-text") {
144
+ const fieldTextIndexLength = f.maxSearchIndexFieldLength || textIndexLength;
145
+ if (isList) {
146
+ data[f.name] = data[f.name].map((value) => {
147
+ const acc = new StringBuilder(fieldTextIndexLength);
148
+ extractText(value, acc, ["text", "code_block", "html"]);
149
+ return acc.toString();
150
+ });
151
+ } else {
152
+ const acc = new StringBuilder(fieldTextIndexLength);
153
+ extractText(data[f.name], acc, ["text", "code_block", "html"]);
154
+ data[f.name] = acc.toString();
155
+ }
156
+ }
157
+ }
158
+ }
159
+ return data;
160
+ };
161
+
162
+ // src/indexer/index.ts
39
163
  var SearchIndexer = class {
40
164
  constructor(options) {
41
165
  this.client = options.client;
@@ -44,65 +168,52 @@ var SearchIndexer = class {
44
168
  this.batchSize = options.batchSize || 100;
45
169
  this.textIndexLength = options.textIndexLength || 500;
46
170
  }
47
- relativePath(path, collection) {
48
- return path.replace(/\\/g, "/").replace(collection.path, "").replace(/^\/|\/$/g, "");
49
- }
50
- processDocumentForIndexing(data, path, collection, field) {
51
- if (!field) {
52
- data["_id"] = `${collection.name}:${this.relativePath(path, collection)}`;
53
- }
54
- for (const f of collection.fields || (field == null ? void 0 : field.fields) || []) {
55
- const isList = f.list;
56
- if (data[f.name]) {
57
- if (f.type === "object") {
58
- if (isList) {
59
- data[f.name] = data[f.name].map(
60
- (obj) => this.processDocumentForIndexing(obj, path, collection, f)
61
- );
62
- } else {
63
- data[f.name] = this.processDocumentForIndexing(
64
- data[f.name],
171
+ makeIndexerCallback(itemCallback) {
172
+ return async (collection, contentPaths) => {
173
+ const templateInfo = await this.schema.getTemplatesForCollectable(
174
+ collection
175
+ );
176
+ await (0, import_graphql.sequential)(contentPaths, async (path) => {
177
+ const data = await (0, import_graphql.transformDocumentIntoPayload)(
178
+ `${collection.path}/${path}`,
179
+ (0, import_graphql.transformDocument)(
180
+ path,
181
+ await (0, import_graphql.loadAndParseWithAliases)(
182
+ this.bridge,
65
183
  path,
66
184
  collection,
67
- f
68
- );
69
- }
70
- } else if (f.type === "image") {
71
- delete data[f.name];
72
- } else if (f.type === "string" || f.type === "rich-text") {
73
- if (isList) {
74
- data[f.name] = data[f.name].map(
75
- (value) => value.substring(0, this.textIndexLength)
76
- );
77
- } else {
78
- data[f.name] = data[f.name].substring(0, this.textIndexLength);
79
- }
80
- }
81
- }
82
- }
83
- return data;
185
+ templateInfo
186
+ ),
187
+ this.schema
188
+ ),
189
+ this.schema
190
+ );
191
+ await itemCallback(
192
+ processDocumentForIndexing(
193
+ data["_values"],
194
+ path,
195
+ collection,
196
+ this.textIndexLength
197
+ )
198
+ );
199
+ });
200
+ };
84
201
  }
85
202
  async indexContentByPaths(documentPaths) {
86
203
  var _a, _b, _c, _d;
87
204
  let batch = [];
205
+ const itemCallback = async (item) => {
206
+ batch.push(item);
207
+ if (batch.length > this.batchSize) {
208
+ await this.client.put(batch);
209
+ batch = [];
210
+ }
211
+ };
88
212
  await ((_b = (_a = this.client).onStartIndexing) == null ? void 0 : _b.call(_a));
89
213
  await (0, import_graphql.scanContentByPaths)(
90
214
  this.schema,
91
215
  documentPaths,
92
- async (collection, contentPaths) => {
93
- await (0, import_graphql.sequential)(contentPaths, async (path) => {
94
- const data = (0, import_graphql.transformDocument)(
95
- path,
96
- JSON.parse(await this.bridge.get(path)),
97
- this.schema
98
- );
99
- batch.push(this.processDocumentForIndexing(data, path, collection));
100
- if (batch.length > this.batchSize) {
101
- await this.client.put(batch);
102
- batch = [];
103
- }
104
- });
105
- }
216
+ this.makeIndexerCallback(itemCallback)
106
217
  );
107
218
  if (batch.length > 0) {
108
219
  await this.client.put(batch);
@@ -113,31 +224,17 @@ var SearchIndexer = class {
113
224
  var _a, _b, _c, _d;
114
225
  await ((_b = (_a = this.client).onStartIndexing) == null ? void 0 : _b.call(_a));
115
226
  let batch = [];
227
+ const itemCallback = async (item) => {
228
+ batch.push(item);
229
+ if (batch.length > this.batchSize) {
230
+ await this.client.put(batch);
231
+ batch = [];
232
+ }
233
+ };
116
234
  const warnings = await (0, import_graphql.scanAllContent)(
117
235
  this.schema,
118
236
  this.bridge,
119
- async (collection, contentPaths) => {
120
- const templateInfo = await this.schema.getTemplatesForCollectable(
121
- collection
122
- );
123
- await (0, import_graphql.sequential)(contentPaths, async (path) => {
124
- const data = (0, import_graphql.transformDocument)(
125
- path,
126
- await (0, import_graphql.loadAndParseWithAliases)(
127
- this.bridge,
128
- path,
129
- collection,
130
- templateInfo
131
- ),
132
- this.schema
133
- );
134
- batch.push(this.processDocumentForIndexing(data, path, collection));
135
- if (batch.length > this.batchSize) {
136
- await this.client.put(batch);
137
- batch = [];
138
- }
139
- });
140
- }
237
+ this.makeIndexerCallback(itemCallback)
141
238
  );
142
239
  if (batch.length > 0) {
143
240
  await this.client.put(batch);
@@ -153,216 +250,10 @@ var SearchIndexer = class {
153
250
  }
154
251
  };
155
252
 
156
- // src/sqlite-level.ts
157
- var import_abstract_level = require("abstract-level");
158
- var import_module_error = __toESM(require("module-error"));
159
- var import_better_sqlite3 = __toESM(require("better-sqlite3"));
160
- var queryFromOptions = (options) => {
161
- let query = "SELECT key, value FROM kv";
162
- const params = [];
163
- if (options.gt) {
164
- query += ` WHERE key > ?`;
165
- params.push(options.gt);
166
- } else if (options.gte) {
167
- query += ` WHERE key >= ?`;
168
- params.push(options.gte);
169
- }
170
- if (options.lt) {
171
- query += ` ${options.gt || options.gte ? "AND" : "WHERE"} key < ?`;
172
- params.push(options.lt);
173
- } else if (options.lte) {
174
- query += ` ${options.gt || options.gte ? "AND" : "WHERE"} key <= ?`;
175
- params.push(options.lte);
176
- }
177
- if (options.reverse) {
178
- query += " ORDER BY key DESC";
179
- } else {
180
- query += " ORDER BY key ASC";
181
- }
182
- if (options.limit) {
183
- query += ` LIMIT ${options.limit}`;
184
- }
185
- return { query, params };
186
- };
187
- var SqliteIterator = class extends import_abstract_level.AbstractIterator {
188
- constructor(db, options, client) {
189
- super(db, options);
190
- this.client = client;
191
- const { query, params } = queryFromOptions(options);
192
- const stmt = this.client.prepare(query);
193
- this.iterator = stmt.iterate(params);
194
- }
195
- async _next(callback) {
196
- const result = this.iterator.next();
197
- if (!result.done) {
198
- return this.db.nextTick(
199
- callback,
200
- null,
201
- result.value.key,
202
- result.value.value
203
- );
204
- } else {
205
- return this.db.nextTick(callback, null, void 0, void 0);
206
- }
207
- }
208
- };
209
- var SqliteKeyIterator = class extends import_abstract_level.AbstractKeyIterator {
210
- constructor(db, options, client) {
211
- super(db, options);
212
- this.client = client;
213
- const { query, params } = queryFromOptions(options);
214
- const stmt = this.client.prepare(query);
215
- this.iterator = stmt.iterate(params);
216
- }
217
- async _next(callback) {
218
- const result = this.iterator.next();
219
- if (!result.done) {
220
- return this.db.nextTick(callback, null, result.value.key);
221
- } else {
222
- return this.db.nextTick(callback, null, void 0);
223
- }
224
- }
225
- };
226
- var SqliteValueIterator = class extends import_abstract_level.AbstractValueIterator {
227
- constructor(db, options, client) {
228
- super(db, options);
229
- this.client = client;
230
- const { query, params } = queryFromOptions(options);
231
- const stmt = this.client.prepare(query);
232
- this.iterator = stmt.iterate(params);
233
- }
234
- async _next(callback) {
235
- const result = this.iterator.next();
236
- if (!result.done) {
237
- return this.db.nextTick(callback, null, result.value.value);
238
- } else {
239
- return this.db.nextTick(callback, null, void 0);
240
- }
241
- }
242
- };
243
- var SqliteLevel = class extends import_abstract_level.AbstractLevel {
244
- constructor(options) {
245
- super({ encodings: { utf8: true } }, options);
246
- this.readOnly = false;
247
- this.db = new import_better_sqlite3.default(options.filename);
248
- this.db.pragma("journal_mode = WAL");
249
- if (options.readOnly !== void 0) {
250
- this.readOnly = options.readOnly;
251
- }
252
- }
253
- get type() {
254
- return "sqlite3";
255
- }
256
- async _open(options, callback) {
257
- this.db.exec("CREATE TABLE IF NOT EXISTS kv (key TEXT, value TEXT)");
258
- this.nextTick(callback);
259
- }
260
- async _close(callback) {
261
- this.db.close();
262
- this.nextTick(callback);
263
- }
264
- async _get(key, options, callback) {
265
- const stmt = this.db.prepare("SELECT value FROM kv WHERE key = ?");
266
- const row = stmt.get(key.toString());
267
- if (row) {
268
- return this.nextTick(callback, null, row.value);
269
- } else {
270
- return this.nextTick(
271
- callback,
272
- new import_module_error.default(`Key ${key} was not found`, {
273
- code: "LEVEL_NOT_FOUND"
274
- })
275
- );
276
- }
277
- }
278
- async _put(key, value, options, callback) {
279
- if (this.readOnly) {
280
- return this.nextTick(
281
- callback,
282
- new import_module_error.default("not authorized to write to branch", {
283
- code: "LEVEL_READ_ONLY"
284
- })
285
- );
286
- }
287
- const stmt = this.db.prepare("INSERT INTO kv (key, value) VALUES (?, ?)");
288
- stmt.run(key.toString(), value.toString());
289
- this.nextTick(callback);
290
- }
291
- async _del(key, options, callback) {
292
- if (this.readOnly) {
293
- return this.nextTick(
294
- callback,
295
- new import_module_error.default("not authorized to write to branch", {
296
- code: "LEVEL_READ_ONLY"
297
- })
298
- );
299
- }
300
- const stmt = this.db.prepare("DELETE FROM kv WHERE key = ?");
301
- stmt.run(key.toString());
302
- this.nextTick(callback);
303
- }
304
- async _batch(batch, options, callback) {
305
- if (this.readOnly) {
306
- return this.nextTick(
307
- callback,
308
- new import_module_error.default("not authorized to write to branch", {
309
- code: "LEVEL_READ_ONLY"
310
- })
311
- );
312
- }
313
- let batches = [];
314
- let curBatch = [];
315
- let curType = void 0;
316
- for (const op of batch) {
317
- if (curType === void 0) {
318
- curType = op.type;
319
- } else if (curType !== op.type) {
320
- if (curType === "put") {
321
- batches.push(
322
- `INSERT INTO kv (key, value) VALUES ${curBatch.join(",")}`
323
- );
324
- } else if (curType === "del") {
325
- batches.push(`DELETE FROM kv WHERE key IN (${curBatch.join(",")})`);
326
- }
327
- curBatch = [];
328
- curType = op.type;
329
- }
330
- if (op.type === "put") {
331
- curBatch.push(`('${op.key.toString()}', '${op.value.toString()}')`);
332
- } else if (op.type === "del") {
333
- curBatch.push(`'${op.key.toString()}'`);
334
- }
335
- }
336
- if (curBatch.length > 0) {
337
- if (curType === "put") {
338
- batches.push(`INSERT INTO kv (key, value) VALUES ${curBatch.join(",")}`);
339
- } else if (curType === "del") {
340
- batches.push(`DELETE FROM kv WHERE key IN (${curBatch.join(",")})`);
341
- }
342
- }
343
- for (const batch2 of batches) {
344
- this.db.exec(batch2);
345
- }
346
- this.nextTick(callback);
347
- }
348
- async _clear(options, callback) {
349
- this.db.exec(`DELETE FROM kv WHERE key like '${options.gte}%'`);
350
- this.nextTick(callback);
351
- }
352
- _iterator(options) {
353
- return new SqliteIterator(this, options, this.db);
354
- }
355
- _keys(options) {
356
- return new SqliteKeyIterator(this, options, this.db);
357
- }
358
- _values(options) {
359
- return new SqliteValueIterator(this, options, this.db);
360
- }
361
- };
362
-
363
253
  // src/client/index.ts
254
+ var import_sqlite_level = require("sqlite-level");
364
255
  var zlib = __toESM(require("zlib"));
365
- var import_search_index = __toESM(require("@kldavis4/search-index"));
256
+ var import_search_index = __toESM(require("@tinacms/search-index"));
366
257
  var import_memory_level = require("memory-level");
367
258
  var import_node_fetch = __toESM(require("node-fetch"));
368
259
  var LocalSearchIndexClient = class {
@@ -412,26 +303,39 @@ var TinaCMSSearchIndexClient = class {
412
303
  const headers = new import_node_fetch.Headers();
413
304
  headers.append("x-api-key", this.indexerToken || "bogus");
414
305
  headers.append("Content-Type", "application/json");
415
- const res = await (0, import_node_fetch.default)(`${this.apiUrl}/upload/${this.branch}`, {
306
+ let res = await (0, import_node_fetch.default)(`${this.apiUrl}/upload/${this.branch}`, {
416
307
  method: "GET",
417
308
  headers
418
309
  });
310
+ if (res.status !== 200) {
311
+ let json;
312
+ try {
313
+ json = await res.json();
314
+ } catch (e) {
315
+ console.error("Failed to parse error response", e);
316
+ }
317
+ throw new Error(
318
+ `Failed to get upload url. Status: ${res.status}${(json == null ? void 0 : json.message) ? ` - ${json.message}` : ``}`
319
+ );
320
+ }
419
321
  const { signedUrl } = await res.json();
420
- console.log("onFinishIndexing");
421
- const sqliteLevel = new SqliteLevel({ filename: ":memory:" });
422
- console.log("dumping to sqlite");
322
+ const sqliteLevel = new import_sqlite_level.SqliteLevel({ filename: ":memory:" });
423
323
  const iterator = this.memoryLevel.iterator();
424
324
  for await (const [key, value] of iterator) {
425
325
  await sqliteLevel.put(key, value);
426
326
  }
427
327
  const buffer = sqliteLevel.db.serialize();
428
- console.log(buffer.byteLength);
429
328
  await sqliteLevel.close();
430
- await (0, import_node_fetch.default)(signedUrl, {
329
+ res = await (0, import_node_fetch.default)(signedUrl, {
431
330
  method: "PUT",
432
331
  body: zlib.gzipSync(buffer)
433
332
  });
434
- console.log("done onFinishIndexing");
333
+ if (res.status !== 200) {
334
+ throw new Error(
335
+ `Failed to upload search index. Status: ${res.status}
336
+ ${await res.text()}`
337
+ );
338
+ }
435
339
  }
436
340
  getSearchIndex() {
437
341
  return this.searchIndex;
@@ -464,5 +368,6 @@ var lookupStopwords = (keys, defaultStopWords = sw.eng) => {
464
368
  SearchIndexer,
465
369
  TinaCMSSearchIndexClient,
466
370
  lookupStopwords,
371
+ si,
467
372
  sw
468
373
  });
@@ -15,8 +15,7 @@ export declare class SearchIndexer {
15
15
  private readonly schema;
16
16
  private readonly textIndexLength;
17
17
  constructor(options: SearchIndexOptions);
18
- private relativePath;
19
- private processDocumentForIndexing;
18
+ private makeIndexerCallback;
20
19
  indexContentByPaths(documentPaths: string[]): Promise<void>;
21
20
  indexAllContent(): Promise<{
22
21
  warnings: string[];
@@ -0,0 +1,2 @@
1
+ import { Collection, ObjectField } from '@tinacms/schema-tools';
2
+ export declare const processDocumentForIndexing: (data: any, path: string, collection: Collection, textIndexLength: number, field?: ObjectField) => any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinacms/search",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index-client.es.js",
6
6
  "typings": "dist/index.d.ts",
@@ -9,8 +9,14 @@
9
9
  "dist"
10
10
  ],
11
11
  "exports": {
12
- "import": "./dist/index-client.es.js",
13
- "require": "./dist/index.js"
12
+ ".": {
13
+ "import": "./dist/index.es.js",
14
+ "require": "./dist/index.js"
15
+ },
16
+ "./dist/index-client": {
17
+ "import": "./dist/index-client.es.js",
18
+ "require": "./dist/index-client.js"
19
+ }
14
20
  },
15
21
  "license": "SEE LICENSE IN LICENSE",
16
22
  "buildConfig": {
@@ -23,16 +29,15 @@
23
29
  ]
24
30
  },
25
31
  "dependencies": {
26
- "@tinacms/graphql": "1.4.14",
27
- "@tinacms/schema-tools": "1.4.4",
32
+ "@tinacms/graphql": "1.4.17",
33
+ "@tinacms/schema-tools": "1.4.6",
28
34
  "abstract-level": "^1.0.3",
29
- "better-sqlite3": "^7.4.2",
30
- "classic-level": "^1.3.0",
31
35
  "memory-level": "^1.0.0",
32
36
  "module-error": "^1.0.2",
33
37
  "node-fetch": "2",
34
- "@kldavis4/search-index": "4.4.1",
35
- "stopword": "^2.0.8"
38
+ "@tinacms/search-index": "^3.5.2",
39
+ "stopword": "^2.0.8",
40
+ "sqlite-level": "^1.0.1"
36
41
  },
37
42
  "publishConfig": {
38
43
  "registry": "https://registry.npmjs.org"
@@ -1,97 +0,0 @@
1
- /// <reference types="node" />
2
- /**
3
- Copyright 2023 Forestry.io Holdings, Inc.
4
- Licensed under the Apache License, Version 2.0 (the "License");
5
- you may not use this file except in compliance with the License.
6
- You may obtain a copy of the License at
7
- http://www.apache.org/licenses/LICENSE-2.0
8
- Unless required by applicable law or agreed to in writing, software
9
- distributed under the License is distributed on an "AS IS" BASIS,
10
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
- See the License for the specific language governing permissions and
12
- limitations under the License.
13
- */
14
- import { AbstractDatabaseOptions, AbstractIterator, AbstractKeyIterator, AbstractLevel, AbstractOpenOptions, AbstractValueIterator } from 'abstract-level';
15
- import { NextCallback } from 'abstract-level/types/abstract-iterator';
16
- export declare type SqliteLevelOptions<K, V> = {
17
- filename: string;
18
- readOnly?: boolean;
19
- } & AbstractDatabaseOptions<K, V>;
20
- declare type BatchOperation = BatchPutOperation | BatchDelOperation;
21
- /**
22
- * A _put_ operation to be committed by a {@link SqliteLevel}.
23
- */
24
- declare interface BatchPutOperation {
25
- /**
26
- * Type of operation.
27
- */
28
- type: 'put';
29
- /**
30
- * Key of the entry to be added to the database.
31
- */
32
- key: Buffer;
33
- /**
34
- * Value of the entry to be added to the database.
35
- */
36
- value: Buffer;
37
- }
38
- /**
39
- * A _del_ operation to be committed by a {@link SqliteLevel}.
40
- */
41
- declare interface BatchDelOperation {
42
- /**
43
- * Type of operation.
44
- */
45
- type: 'del';
46
- /**
47
- * Key of the entry to be deleted from the database.
48
- */
49
- key: Buffer;
50
- }
51
- declare interface IteratorOptions<KDefault> {
52
- limit?: number;
53
- keyEncoding: string;
54
- valueEncoding: string;
55
- reverse: boolean;
56
- keys: boolean;
57
- values: boolean;
58
- gt?: KDefault;
59
- gte?: KDefault;
60
- lt?: KDefault;
61
- lte?: KDefault;
62
- }
63
- declare class SqliteIterator<KDefault, VDefault> extends AbstractIterator<SqliteLevel<KDefault, VDefault>, KDefault, VDefault> {
64
- private client;
65
- private iterator;
66
- constructor(db: SqliteLevel<KDefault, VDefault>, options: IteratorOptions<KDefault>, client: any);
67
- _next(callback: NextCallback<KDefault, VDefault>): Promise<void>;
68
- }
69
- declare class SqliteKeyIterator<KDefault, VDefault> extends AbstractKeyIterator<SqliteLevel<KDefault, VDefault>, KDefault> {
70
- private client;
71
- private iterator;
72
- constructor(db: SqliteLevel<KDefault, VDefault>, options: IteratorOptions<KDefault>, client: any);
73
- _next(callback: NextCallback<KDefault, VDefault>): Promise<void>;
74
- }
75
- declare class SqliteValueIterator<KDefault, VDefault> extends AbstractValueIterator<SqliteLevel<KDefault, VDefault>, KDefault, VDefault> {
76
- private client;
77
- private iterator;
78
- constructor(db: SqliteLevel<KDefault, VDefault>, options: IteratorOptions<KDefault>, client: any);
79
- _next(callback: NextCallback<KDefault, VDefault>): Promise<void>;
80
- }
81
- export declare class SqliteLevel<KDefault = string, VDefault = string> extends AbstractLevel<Buffer | Uint8Array | string, KDefault, VDefault> {
82
- db: any;
83
- private readOnly;
84
- constructor(options: SqliteLevelOptions<KDefault, VDefault>);
85
- get type(): string;
86
- _open(options: AbstractOpenOptions, callback: (error?: Error) => void): Promise<void>;
87
- _close(callback: (error?: Error) => void): Promise<void>;
88
- _get(key: Buffer, options: any, callback: (error?: Error, value?: Buffer) => void): Promise<void>;
89
- _put(key: Buffer, value: Buffer, options: any, callback: (error?: Error) => void): Promise<void>;
90
- _del(key: Buffer, options: any, callback: (error?: Error) => void): Promise<void>;
91
- _batch(batch: BatchOperation[], options: any, callback: (error?: Error) => void): Promise<void>;
92
- _clear(options: any, callback: (error?: Error) => void): Promise<void>;
93
- _iterator(options: IteratorOptions<KDefault>): SqliteIterator<KDefault, VDefault>;
94
- _keys(options: IteratorOptions<KDefault>): SqliteKeyIterator<KDefault, VDefault>;
95
- _values(options: IteratorOptions<KDefault>): SqliteValueIterator<KDefault, VDefault>;
96
- }
97
- export {};