@twasik4/pocket-service 1.0.4 → 1.1.0

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/LICENSE +21 -0
  3. package/README.md +637 -297
  4. package/dist/index.d.mts +747 -0
  5. package/dist/index.d.mts.map +1 -0
  6. package/dist/index.mjs +4 -0
  7. package/dist/index.mjs.map +1 -0
  8. package/dist/runtime/worker-thread.d.mts +1 -0
  9. package/dist/runtime/worker-thread.mjs +2 -0
  10. package/dist/runtime/worker-thread.mjs.map +1 -0
  11. package/package.json +53 -10
  12. package/dist/index.d.ts +0 -734
  13. package/dist/index.js +0 -6
  14. package/dist/index.js.map +0 -1
  15. package/dist/worker-thread.d.ts +0 -2
  16. package/dist/worker-thread.js +0 -2
  17. package/dist/worker-thread.js.map +0 -1
  18. package/src/index.ts +0 -1
  19. package/src/worker-thread.ts +0 -159
  20. package/src/workers/auth/strategies.ts +0 -304
  21. package/src/workers/db/clickhouse/index.ts +0 -76
  22. package/src/workers/db/mongo/collection.ts +0 -293
  23. package/src/workers/db/mongo/mongo.ts +0 -401
  24. package/src/workers/express-types.ts +0 -442
  25. package/src/workers/index.ts +0 -7
  26. package/src/workers/logger.ts +0 -19
  27. package/src/workers/service.ts +0 -1015
  28. package/src/workers/stream-handler.ts +0 -25
  29. package/src/workers/types.ts +0 -59
  30. package/src/workers/utils.ts +0 -19
  31. package/tests/auth-strategies.spec.ts +0 -150
  32. package/tests/clickhouse.spec.ts +0 -102
  33. package/tests/express-types.spec.ts +0 -232
  34. package/tests/mongo-advanced.spec.ts +0 -172
  35. package/tests/mongo.spec.ts +0 -141
  36. package/tests/redis.spec.ts +0 -36
  37. package/tests/service.spec.ts +0 -82
  38. package/tests/utils.spec.ts +0 -30
  39. package/tsconfig.json +0 -12
  40. package/tsup.config.ts +0 -11
  41. package/vitest.config.ts +0 -8
@@ -1,401 +0,0 @@
1
- import { Collection, Db, Document, MongoClient } from "mongodb";
2
- import { CollectionWrapper, SchemaParser } from "./collection";
3
-
4
- type AnyMongoMethod = (...args: any[]) => any;
5
-
6
- export type MongoCollectionMethods = Record<string, AnyMongoMethod>;
7
-
8
- export type MongoIndexSpec = {
9
- /**
10
- * Index key specification. Example: { userId: 1 } for ascending, { userId: -1 } for descending
11
- */
12
- key: Record<string, 1 | -1>;
13
- /**
14
- * Optional name for the index. If not provided, MongoDB will auto-generate.
15
- */
16
- name?: string;
17
- /**
18
- * Whether the index should enforce uniqueness.
19
- */
20
- unique?: boolean;
21
- /**
22
- * Whether the index should be sparse (only index documents with the indexed field).
23
- */
24
- sparse?: boolean;
25
- /**
26
- * Whether to build the index in the background without blocking other operations.
27
- */
28
- background?: boolean;
29
- /**
30
- * The time-to-live (TTL) for documents in the collection, in seconds. Only applicable for TTL indexes.
31
- */
32
- expireAfterSeconds?: number;
33
- };
34
-
35
- export type MongoTimeSeriesSpec = {
36
- /**
37
- * Name of the date field that MongoDB uses as the event time.
38
- */
39
- timeField: string;
40
- /**
41
- * Optional metadata field used to group measurements.
42
- */
43
- metaField?: string;
44
- /**
45
- * Optional bucket granularity hint used by MongoDB.
46
- */
47
- granularity?: "seconds" | "minutes" | "hours";
48
- /**
49
- * Optional retention in seconds for automatic expiry.
50
- */
51
- expireAfterSeconds?: number;
52
- };
53
-
54
- export type MongoCollectionMethodContext<TDocument extends Document> = {
55
- /**
56
- * The MongoDB client instance
57
- */
58
- client: MongoClient;
59
- /**
60
- * The MongoDB database instance
61
- */
62
- db: Db;
63
- /**
64
- * The MongoDB collection instance
65
- */
66
- collection: Collection<TDocument>;
67
- /**
68
- * The base collection wrapper instance
69
- */
70
- base: CollectionWrapper<TDocument>;
71
- };
72
-
73
- export type MongoCollectionDefinition<
74
- TDocument extends Document = Document,
75
- TMethods extends MongoCollectionMethods = {},
76
- > = {
77
- name?: string;
78
- /**
79
- * Whether to automatically track revisions of documents in this collection. If enabled, every update will insert a copy of the updated document into a separate revision collection, allowing you to keep a history of changes. The revision collection will have the same name as the main collection with `_revisions` appended to it (e.g. `users` -> `users_revisions`).
80
- */
81
- trackRevisions: boolean;
82
- schema: SchemaParser<TDocument>;
83
- /**
84
- * Custom methods to add to the collection wrapper. These methods receive a context object with the MongoDB client, database, collection, and base wrapper instance, allowing you to build complex queries and operations while still benefiting from the schema validation and soft delete functionality provided by the base wrapper.
85
- * @param ctx
86
- * @returns
87
- */
88
- methods?: (ctx: MongoCollectionMethodContext<TDocument>) => TMethods;
89
- /**
90
- * Optional array of index specifications to create on this collection. Indexes are created idempotently on service startup, so duplicate indexes are safely ignored.
91
- */
92
- indexes?: MongoIndexSpec[];
93
- /**
94
- * Optional MongoDB time-series settings. When provided, the collection is created as a time-series collection if it does not already exist.
95
- */
96
- timeSeries?: MongoTimeSeriesSpec;
97
- };
98
-
99
- export type MongoCollectionsConfig = Record<
100
- string,
101
- MongoCollectionDefinition<any, MongoCollectionMethods>
102
- >;
103
-
104
- type InferDocument<TDefinition> = TDefinition extends {
105
- schema: SchemaParser<infer TDocument>;
106
- }
107
- ? TDocument
108
- : Document;
109
-
110
- type NormalizeDocument<TDocument> = TDocument extends Document
111
- ? TDocument
112
- : Document;
113
-
114
- type InferMethods<TDefinition> = TDefinition extends {
115
- methods: (...args: any[]) => infer TMethods;
116
- }
117
- ? TMethods
118
- : TDefinition extends {
119
- methods?: (...args: any[]) => infer TMethods;
120
- }
121
- ? TMethods extends undefined
122
- ? {}
123
- : TMethods
124
- : {};
125
-
126
- export type MongoBoundCollection<
127
- TDocument extends Document,
128
- TMethods extends MongoCollectionMethods = {},
129
- > = CollectionWrapper<TDocument> & TMethods;
130
-
131
- export type InferMongoCollections<TCollections extends MongoCollectionsConfig> =
132
- {
133
- [K in keyof TCollections]: MongoBoundCollection<
134
- NormalizeDocument<InferDocument<TCollections[K]>>,
135
- InferMethods<TCollections[K]>
136
- >;
137
- };
138
-
139
- export type MongoDatabase<TCollections extends MongoCollectionsConfig> = {
140
- client: MongoClient;
141
- db: Db;
142
- collections: InferMongoCollections<TCollections>;
143
- disconnect: () => Promise<void>;
144
- connect: () => Promise<MongoClient>;
145
- } & InferMongoCollections<TCollections>;
146
-
147
- type SchemaOutput<TSchema> = TSchema extends {
148
- parse: (input: unknown) => infer TOutput;
149
- }
150
- ? NormalizeDocument<TOutput>
151
- : Document;
152
-
153
- /**
154
- * Define a MongoDB collection with an associated Zod schema for validation and optional custom methods. The returned collection definition can then be used to create a MongoDatabase instance, which will automatically wrap the collection with the provided schema validation and methods.
155
- * @param config The configuration object for the MongoDB collection, including the schema and optional custom methods.
156
- */
157
- export function defineMongoCollection<
158
- TSchema extends SchemaParser<any>,
159
- >(config: {
160
- /**
161
- * Optional name for the collection. If not provided, the key used in the collections config will be used as the collection name. This allows you to have more control over the actual collection names in the database, while still using descriptive keys in your code.
162
- */
163
- name?: string;
164
- /**
165
- * Zod schema for validating documents in the collection. The schema will be used to parse and validate documents returned from the database, ensuring that they conform to the expected structure and types. If a document does not match the schema, an error will be thrown.
166
- */
167
- schema: TSchema;
168
- methods?: undefined;
169
- /**
170
- * Optional array of index specifications to create on this collection.
171
- */
172
- indexes?: MongoIndexSpec[];
173
- /**
174
- * Optional MongoDB time-series settings.
175
- */
176
- timeSeries?: MongoTimeSeriesSpec;
177
- }): MongoCollectionDefinition<SchemaOutput<TSchema>, {}>;
178
-
179
- /**
180
- * Define a MongoDB collection with an associated Zod schema for validation and optional custom methods. The returned collection definition can then be used to create a MongoDatabase instance, which will automatically wrap the collection with the provided schema validation and methods.
181
- * @param config The configuration object for the MongoDB collection, including the schema and optional custom methods.
182
- */
183
- export function defineMongoCollection<
184
- TSchema extends SchemaParser<any>,
185
- TMethods extends MongoCollectionMethods,
186
- >(config: {
187
- /**
188
- * Optional name for the collection. If not provided, the key used in the collections config will be used as the collection name. This allows you to have more control over the actual collection names in the database, while still using descriptive keys in your code.
189
- */
190
- name?: string;
191
- /**
192
- * Zod schema for validating documents in the collection. The schema will be used to parse and validate documents returned from the database, ensuring that they conform to the expected structure and types. If a document does not match the schema, an error will be thrown.
193
- */
194
- schema: TSchema;
195
- /**
196
- * Optional custom methods for the collection. These methods will be added to the collection instance and can be used to implement custom queries or operations.
197
- * @param ctx The context object containing the MongoDB client, database, collection, and base collection wrapper.
198
- * @returns An object containing the custom methods to be added to the collection instance.
199
- */
200
- methods: (
201
- ctx: MongoCollectionMethodContext<SchemaOutput<TSchema>>,
202
- ) => TMethods;
203
- /**
204
- * Optional array of index specifications to create on this collection.
205
- */
206
- indexes?: MongoIndexSpec[];
207
- /**
208
- * Optional MongoDB time-series settings.
209
- */
210
- timeSeries?: MongoTimeSeriesSpec;
211
- }): MongoCollectionDefinition<SchemaOutput<TSchema>, TMethods>;
212
-
213
- /**
214
- * Define a MongoDB collection with an associated Zod schema for validation and optional custom methods. The returned collection definition can then be used to create a MongoDatabase instance, which will automatically wrap the collection with the provided schema validation and methods.
215
- * @param config The configuration object for the MongoDB collection, including the schema and optional custom methods.
216
- */
217
- export function defineMongoCollection<
218
- TSchema extends SchemaParser<any>,
219
- TMethods extends MongoCollectionMethods = {},
220
- >(config: {
221
- /**
222
- * Optional name for the collection. If not provided, the key used in the collections config will be used as the collection name. This allows you to have more control over the actual collection names in the database, while still using descriptive keys in your code.
223
- */
224
- name?: string;
225
- /**
226
- * Zod schema for validating documents in the collection. The schema will be used to parse and validate documents returned from the database, ensuring that they conform to the expected structure and types. If a document does not match the schema, an error will be thrown.
227
- */
228
- schema: TSchema;
229
- /**
230
- * Optional custom methods for the collection. These methods will be added to the collection instance and can be used to implement custom queries or operations.
231
- * @param ctx The context object containing the MongoDB client, database, collection, and base collection wrapper.
232
- * @returns An object containing the custom methods to be added to the collection instance.
233
- */
234
- methods?: (
235
- ctx: MongoCollectionMethodContext<SchemaOutput<TSchema>>,
236
- ) => TMethods;
237
- /**
238
- * Optional array of index specifications to create on this collection.
239
- */
240
- indexes?: MongoIndexSpec[];
241
- /**
242
- * Optional MongoDB time-series settings.
243
- */
244
- timeSeries?: MongoTimeSeriesSpec;
245
- }): MongoCollectionDefinition<SchemaOutput<TSchema>, TMethods> {
246
- return {
247
- name: config.name,
248
- schema: config.schema,
249
- /**
250
- * Optional custom methods for the collection. These methods will be added to the collection instance and can be used to implement custom queries or operations.
251
- * @param ctx The context object containing the MongoDB client, database, collection, and base collection wrapper.
252
- * @returns An object containing the custom methods to be added to the collection instance.
253
- */
254
- methods: config.methods,
255
- indexes: config.indexes,
256
- timeSeries: config.timeSeries,
257
- /**
258
- * Whether to automatically track revisions of documents in this collection. If enabled, every update will insert a copy of the updated document into a separate revision collection, allowing you to keep a history of changes. The revision collection will have the same name as the main collection with `_revisions` appended to it (e.g. `users` -> `users_revisions`).
259
- */
260
- trackRevisions: false,
261
- } as MongoCollectionDefinition<SchemaOutput<TSchema>, TMethods>;
262
- }
263
-
264
- export function createMongo<TCollections extends MongoCollectionsConfig>(
265
- dbName: string,
266
- config: TCollections,
267
- options: { uri?: string } = {},
268
- ): MongoDatabase<TCollections> {
269
- const client = new MongoClient(
270
- options.uri || process.env.MONGO_URI || "mongodb://mongo:27017",
271
- );
272
- const db = client.db(dbName);
273
-
274
- const wrapped = {} as InferMongoCollections<TCollections>;
275
- const setupFns: Array<() => Promise<void>> = [];
276
-
277
- for (const key in config) {
278
- const def = config[key];
279
- const collectionName = def.name || key;
280
- const collection = db.collection(collectionName);
281
- const revisionCollection = def.trackRevisions
282
- ? db.collection(`${collectionName}_revisions`)
283
- : undefined;
284
- const base = new CollectionWrapper(
285
- collection as Collection<any>,
286
- def.schema,
287
- revisionCollection,
288
- );
289
- const methods =
290
- def.methods?.({
291
- client,
292
- db,
293
- collection: collection as Collection<any>,
294
- base,
295
- }) || {};
296
-
297
- setupFns.push(async () => {
298
- if (def.timeSeries) {
299
- const existingCollection = await db
300
- .listCollections({ name: collectionName }, { nameOnly: false })
301
- .next();
302
-
303
- if (!existingCollection) {
304
- await db.createCollection(collectionName, {
305
- timeseries: {
306
- timeField: def.timeSeries.timeField,
307
- ...(def.timeSeries.metaField
308
- ? { metaField: def.timeSeries.metaField }
309
- : {}),
310
- ...(def.timeSeries.granularity
311
- ? { granularity: def.timeSeries.granularity }
312
- : {}),
313
- },
314
- ...(typeof def.timeSeries.expireAfterSeconds === "number"
315
- ? { expireAfterSeconds: def.timeSeries.expireAfterSeconds }
316
- : {}),
317
- });
318
- } else {
319
- const hasTimeSeriesOptions =
320
- existingCollection.type === "timeseries" ||
321
- Boolean((existingCollection.options as any)?.timeseries);
322
-
323
- if (!hasTimeSeriesOptions) {
324
- throw new Error(
325
- `Collection ${collectionName} already exists and is not a time-series collection. Migration is required before enabling timeSeries.`,
326
- );
327
- }
328
-
329
- const existingTimeSeries = (existingCollection.options as any)
330
- ?.timeseries as
331
- | {
332
- timeField?: string;
333
- metaField?: string;
334
- }
335
- | undefined;
336
-
337
- if (
338
- existingTimeSeries?.timeField &&
339
- existingTimeSeries.timeField !== def.timeSeries.timeField
340
- ) {
341
- throw new Error(
342
- `Collection ${collectionName} has timeField '${existingTimeSeries.timeField}' but config expects '${def.timeSeries.timeField}'.`,
343
- );
344
- }
345
-
346
- if (
347
- def.timeSeries.metaField &&
348
- existingTimeSeries?.metaField &&
349
- existingTimeSeries.metaField !== def.timeSeries.metaField
350
- ) {
351
- throw new Error(
352
- `Collection ${collectionName} has metaField '${existingTimeSeries.metaField}' but config expects '${def.timeSeries.metaField}'.`,
353
- );
354
- }
355
- }
356
- }
357
-
358
- if (def.indexes && def.indexes.length > 0) {
359
- for (const indexSpec of def.indexes) {
360
- const { key, ...indexOptions } = indexSpec;
361
- await collection.createIndex(key, indexOptions).catch((err) => {
362
- console.error(
363
- `Failed to create index on ${collectionName}: ${err.message}`,
364
- );
365
- });
366
- }
367
- }
368
- });
369
-
370
- wrapped[key] = Object.assign(
371
- base,
372
- methods,
373
- ) as InferMongoCollections<TCollections>[typeof key];
374
- }
375
-
376
- let setupPromise: Promise<void> | null = null;
377
-
378
- const ensureSetup = async () => {
379
- if (!setupPromise) {
380
- setupPromise = (async () => {
381
- for (const setup of setupFns) {
382
- await setup();
383
- }
384
- })();
385
- }
386
- return setupPromise;
387
- };
388
-
389
- return {
390
- client,
391
- db,
392
- collections: wrapped,
393
- ...wrapped,
394
- disconnect: async () => client.close(),
395
- connect: async () => {
396
- await client.connect();
397
- await ensureSetup();
398
- return client;
399
- },
400
- } as MongoDatabase<TCollections>;
401
- }