@tstdl/base 0.92.151 → 0.92.152

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 (32) hide show
  1. package/api/client/client.js +11 -0
  2. package/api/server/gateway.js +4 -2
  3. package/api/types.d.ts +4 -2
  4. package/data-structures/array-dictionary.d.ts +1 -0
  5. package/data-structures/array-dictionary.js +13 -18
  6. package/data-structures/array-list.js +1 -1
  7. package/data-structures/cache.js +7 -3
  8. package/data-structures/dictionary.js +1 -1
  9. package/data-structures/distinct-collection.d.ts +4 -0
  10. package/data-structures/distinct-collection.js +1 -1
  11. package/data-structures/iterable-weak-map.d.ts +2 -2
  12. package/data-structures/iterable-weak-map.js +3 -3
  13. package/data-structures/set-collection.js +1 -0
  14. package/data-structures/sorted-array-list.js +1 -1
  15. package/data-structures/weak-ref-map.d.ts +2 -2
  16. package/data-structures/weak-ref-map.js +3 -3
  17. package/document-management/api/document-management.api.d.ts +9 -3
  18. package/document-management/api/document-management.api.js +3 -3
  19. package/document-management/server/api/document-management.api.d.ts +2 -2
  20. package/document-management/server/api/document-management.api.js +2 -47
  21. package/document-management/server/services/document-management.service.d.ts +1 -1
  22. package/dom/observation/resize-observer.d.ts +1 -1
  23. package/dom/observation/resize-observer.js +1 -1
  24. package/orm/decorators.d.ts +1 -1
  25. package/package.json +4 -3
  26. package/sse/data-stream-source.d.ts +18 -0
  27. package/sse/data-stream-source.js +66 -0
  28. package/sse/data-stream.d.ts +8 -0
  29. package/sse/data-stream.js +15 -0
  30. package/sse/index.d.ts +2 -0
  31. package/sse/index.js +2 -0
  32. package/utils/math.js +2 -3
@@ -4,6 +4,7 @@ import { inject } from '../../injector/inject.js';
4
4
  import { Injector } from '../../injector/injector.js';
5
5
  import { resolveArgumentType } from '../../injector/interfaces.js';
6
6
  import { Schema } from '../../schema/index.js';
7
+ import { DataStream } from '../../sse/data-stream.js';
7
8
  import { ServerSentEvents } from '../../sse/server-sent-events.js';
8
9
  import { toArray } from '../../utils/array/array.js';
9
10
  import { copyObjectProperties, objectEntries } from '../../utils/object/object.js';
@@ -74,6 +75,12 @@ export function compileClient(definition, options = defaultOptions) {
74
75
  }
75
76
  return getServerSentEvents(this[httpClientSymbol].options.baseUrl, resource, endpoint, parameters);
76
77
  }
78
+ if (endpoint.result == DataStream) {
79
+ if (isDefined(requestBody)) {
80
+ throw new Error('Body not supported for DataStream.');
81
+ }
82
+ return getDataStream(this[httpClientSymbol].options.baseUrl, resource, endpoint, parameters);
83
+ }
77
84
  if (context.endpoint.data?.[bustCacheToken] == true) {
78
85
  context[bustCacheToken] = true;
79
86
  }
@@ -126,6 +133,10 @@ async function getResponseBody(response, schema) {
126
133
  : undefined;
127
134
  return Schema.parse(schema, body, { mask: true });
128
135
  }
136
+ function getDataStream(baseUrl, resource, endpoint, parameters) {
137
+ const sse = getServerSentEvents(baseUrl, resource, endpoint, parameters);
138
+ return DataStream.parse(sse);
139
+ }
129
140
  function getServerSentEvents(baseUrl, resource, endpoint, parameters) {
130
141
  const { parsedUrl, parametersRest } = buildUrl(resource, parameters, { arraySeparator: ',' });
131
142
  const url = new URL(parsedUrl, baseUrl);
@@ -18,6 +18,7 @@ import { HttpServerResponse } from '../../http/server/index.js';
18
18
  import { InjectArg, ResolveArg, Singleton, resolveArgumentType } from '../../injector/index.js';
19
19
  import { Logger } from '../../logger/index.js';
20
20
  import { Schema } from '../../schema/index.js';
21
+ import { DataStreamSource } from '../../sse/data-stream-source.js';
21
22
  import { ServerSentEventsSource } from '../../sse/server-sent-events-source.js';
22
23
  import { toArray } from '../../utils/array/array.js';
23
24
  import { composeAsyncMiddleware } from '../../utils/middleware.js';
@@ -192,8 +193,9 @@ let ApiGateway = class ApiGateway {
192
193
  : isBlob(result) ? { stream: result.stream() }
193
194
  : isReadableStream(result) ? { stream: result }
194
195
  : (result instanceof ServerSentEventsSource) ? { events: result }
195
- : (context.endpoint.definition.result == String) ? { text: result }
196
- : { json: result };
196
+ : (result instanceof DataStreamSource) ? { events: result.eventSource }
197
+ : (context.endpoint.definition.result == String) ? { text: result }
198
+ : { json: result };
197
199
  }
198
200
  await next();
199
201
  }
package/api/types.d.ts CHANGED
@@ -1,6 +1,8 @@
1
+ import type { Observable } from 'rxjs';
1
2
  import type { HttpServerRequest, HttpServerResponse } from '../http/server/index.js';
2
3
  import type { HttpMethod } from '../http/types.js';
3
4
  import type { SchemaOutput, SchemaTestable } from '../schema/index.js';
5
+ import type { DataStream } from '../sse/index.js';
4
6
  import type { ServerSentEventsSource } from '../sse/server-sent-events-source.js';
5
7
  import type { ServerSentEvents } from '../sse/server-sent-events.js';
6
8
  import type { NonUndefinable, OneOrMany, Record, ReturnTypeOrT } from '../types/index.js';
@@ -91,8 +93,8 @@ export type ApiEndpointParametersSchema<T extends ApiDefinition, K extends ApiEn
91
93
  export type ApiEndpointBodySchema<T extends ApiDefinition, K extends ApiEndpointKeys<T>> = NonUndefinable<ApiEndpoint<T, K>['body']>;
92
94
  export type ApiEndpointResultSchema<T extends ApiDefinition, K extends ApiEndpointKeys<T>> = NonUndefinable<ApiEndpoint<T, K>['result']>;
93
95
  export type ApiBinaryType = typeof Uint8Array | typeof Blob | typeof ReadableStream<any>;
94
- export type ApiInputType<T extends SchemaTestable> = T extends ApiBinaryType ? InstanceType<ApiBinaryType> : T extends typeof ServerSentEvents ? ServerSentEventsSource : T extends SchemaTestable ? SchemaOutput<T> : never;
95
- export type ApiOutputType<T extends SchemaTestable> = T extends typeof ReadableStream ? ReadableStream<Uint8Array> : T extends SchemaTestable ? SchemaOutput<T> : never;
96
+ export type ApiInputType<T extends SchemaTestable> = T extends ApiBinaryType ? InstanceType<ApiBinaryType> : T extends typeof ServerSentEvents ? ServerSentEventsSource : T extends typeof DataStream<infer U> ? AsyncIterable<U> : T extends SchemaTestable ? SchemaOutput<T> : never;
97
+ export type ApiOutputType<T extends SchemaTestable> = T extends typeof ReadableStream ? ReadableStream<Uint8Array> : T extends typeof DataStream<infer U> ? Observable<U> : T extends SchemaTestable ? SchemaOutput<T> : never;
96
98
  export type ApiParameters<T extends ApiDefinition, K extends ApiEndpointKeys<T>> = ApiInputType<ApiEndpointParametersSchema<T, K>>;
97
99
  export type ApiClientBody<T extends ApiDefinition, K extends ApiEndpointKeys<T>> = ApiInputType<ApiEndpointBodySchema<T, K>>;
98
100
  export type ApiServerBody<T extends ApiDefinition, K extends ApiEndpointKeys<T>> = ApiOutputType<ApiEndpointBodySchema<T, K>>;
@@ -16,5 +16,6 @@ export declare class ArrayDictionary<K, V> extends Dictionary<K, V, ArrayDiction
16
16
  keys(): MapIterator<K>;
17
17
  values(): MapIterator<V>;
18
18
  protected _clear(): void;
19
+ private _setWithoutUpdate;
19
20
  private updateSize;
20
21
  }
@@ -10,7 +10,6 @@ export class ArrayDictionary extends Dictionary {
10
10
  this.valueArray = [];
11
11
  if (isDefined(items)) {
12
12
  this.addMany(items);
13
- this.updateSize();
14
13
  }
15
14
  }
16
15
  has(key) {
@@ -24,14 +23,7 @@ export class ArrayDictionary extends Dictionary {
24
23
  return this.valueArray[index];
25
24
  }
26
25
  set(key, value) {
27
- const index = this.keyArray.indexOf(key);
28
- if (index == -1) {
29
- this.keyArray.push(key);
30
- this.valueArray.push(value);
31
- }
32
- else {
33
- this.valueArray[index] = value;
34
- }
26
+ this._setWithoutUpdate(key, value);
35
27
  this.updateSize();
36
28
  }
37
29
  delete(key) {
@@ -58,14 +50,7 @@ export class ArrayDictionary extends Dictionary {
58
50
  }
59
51
  addMany(items) {
60
52
  for (const [key, value] of items) {
61
- const index = this.keyArray.indexOf(key);
62
- if (index == -1) {
63
- this.keyArray.push(key);
64
- this.valueArray.push(value);
65
- }
66
- else {
67
- this.valueArray[index] = value;
68
- }
53
+ this._setWithoutUpdate(key, value);
69
54
  }
70
55
  this.updateSize();
71
56
  }
@@ -91,7 +76,17 @@ export class ArrayDictionary extends Dictionary {
91
76
  this.keyArray = [];
92
77
  this.valueArray = [];
93
78
  }
79
+ _setWithoutUpdate(key, value) {
80
+ const index = this.keyArray.indexOf(key);
81
+ if (index == -1) {
82
+ this.keyArray.push(key);
83
+ this.valueArray.push(value);
84
+ }
85
+ else {
86
+ this.valueArray[index] = value;
87
+ }
88
+ }
94
89
  updateSize() {
95
- this.setSize(this.keyArray.length / 2);
90
+ this.setSize(this.keyArray.length);
96
91
  }
97
92
  }
@@ -100,7 +100,7 @@ export class ArrayList extends List {
100
100
  }
101
101
  }
102
102
  _clear() {
103
- this.backingArray.splice(0, this.backingArray.length);
103
+ this.backingArray.length = 0;
104
104
  }
105
105
  updateSize() {
106
106
  this.setSize(this.backingArray.length);
@@ -5,12 +5,16 @@ export class Cache {
5
5
  return this._capacity;
6
6
  }
7
7
  set capacity(capacity) {
8
- this.removeEntries(this._capacity - capacity);
8
+ if (capacity < 0) {
9
+ throw new Error('Capacity must be positive.');
10
+ }
11
+ const itemsToRemove = Math.max(0, this.cache.size - capacity);
12
+ this.removeEntries(itemsToRemove);
9
13
  this._capacity = capacity;
10
14
  }
11
15
  constructor(capacity) {
12
- this._capacity = capacity;
13
16
  this.cache = new Map();
17
+ this.capacity = capacity;
14
18
  }
15
19
  get(key) {
16
20
  if (!this.cache.has(key)) {
@@ -29,7 +33,7 @@ export class Cache {
29
33
  this.cache.set(key, value);
30
34
  }
31
35
  delete(key) {
32
- this.delete(key);
36
+ this.cache.delete(key);
33
37
  }
34
38
  removeEntries(count) {
35
39
  if (count <= 0) {
@@ -6,7 +6,7 @@ export class Dictionary extends Collection {
6
6
  }
7
7
  /** Returns an adapter that has the same interface as {@link Map}. No copying of data involved. */
8
8
  asMap() {
9
- return new DictionaryAdapter(this); // eslint-disable-line @typescript-eslint/no-use-before-define
9
+ return new DictionaryAdapter(this);
10
10
  }
11
11
  }
12
12
  export class DictionaryAdapter {
@@ -6,6 +6,10 @@ export declare abstract class DistinctCollection<T, TThis extends DistinctCollec
6
6
  asSet(): Set<T>;
7
7
  abstract has(value: T): boolean;
8
8
  abstract delete(value: T): boolean;
9
+ /**
10
+ * @internal
11
+ * Do not use directly. For internal adapter optimization.
12
+ */
9
13
  protected abstract _getBackingSet(): ReadonlySet<T> | undefined;
10
14
  }
11
15
  export declare class SetAdapter<T> implements Set<T> {
@@ -14,7 +14,7 @@ export class SetAdapter {
14
14
  collection;
15
15
  [Symbol.toStringTag] = 'SetAdapter';
16
16
  get fastestBackingSet() {
17
- return this.collection._backingSet ?? this.collection.toSet();
17
+ return this.collection._getBackingSet() ?? this.collection.toSet();
18
18
  }
19
19
  get size() {
20
20
  return this.collection.size;
@@ -1,5 +1,5 @@
1
- import { Collection } from './collection.js';
2
- export declare class IterableWeakMap<K extends object, V> extends Collection<[K, V], MapIterator<[K, V]>, IterableWeakMap<K, V>> implements Map<K, V> {
1
+ import { Dictionary } from './dictionary.js';
2
+ export declare class IterableWeakMap<K extends object, V> extends Dictionary<K, V, IterableWeakMap<K, V>> implements Map<K, V> {
3
3
  private weakMap;
4
4
  private refMap;
5
5
  private finalizationRegistry;
@@ -1,9 +1,9 @@
1
+ import { takeUntil } from 'rxjs';
1
2
  import { ObservableFinalizationRegistry } from '../memory/observable-finalization-registry.js';
2
3
  import { drain } from '../utils/iterable-helpers/drain.js';
3
4
  import { isDefined, isUndefined } from '../utils/type-guards.js';
4
- import { takeUntil } from 'rxjs';
5
- import { Collection } from './collection.js';
6
- export class IterableWeakMap extends Collection {
5
+ import { Dictionary } from './dictionary.js';
6
+ export class IterableWeakMap extends Dictionary {
7
7
  weakMap;
8
8
  refMap;
9
9
  finalizationRegistry;
@@ -10,6 +10,7 @@ export class SetCollection extends DistinctCollection {
10
10
  static withBackingSet(set) {
11
11
  const collection = new SetCollection();
12
12
  collection.backingSet = set;
13
+ collection.updateSize();
13
14
  return collection;
14
15
  }
15
16
  includes(item) {
@@ -133,7 +133,7 @@ let SortedArrayList = SortedArrayList_1 = class SortedArrayList extends List {
133
133
  }
134
134
  }
135
135
  _clear() {
136
- this.backingArray.splice(0, this.backingArray.length);
136
+ this.backingArray.length = 0;
137
137
  }
138
138
  updateSize() {
139
139
  this.setSize(this.backingArray.length);
@@ -1,5 +1,5 @@
1
- import { Collection } from './collection.js';
2
- export declare class WeakRefMap<K, V extends object> extends Collection<[K, V], MapIterator<[K, V]>, WeakRefMap<K, V>> implements Map<K, V> {
1
+ import { Dictionary } from './dictionary.js';
2
+ export declare class WeakRefMap<K, V extends object> extends Dictionary<K, V, WeakRefMap<K, V>> implements Map<K, V> {
3
3
  private readonly backingMapProvider;
4
4
  private backingMap;
5
5
  private finalizationRegistry;
@@ -1,8 +1,8 @@
1
+ import { takeUntil } from 'rxjs';
1
2
  import { ObservableFinalizationRegistry } from '../memory/observable-finalization-registry.js';
2
3
  import { isDefined, isUndefined } from '../utils/type-guards.js';
3
- import { takeUntil } from 'rxjs';
4
- import { Collection } from './collection.js';
5
- export class WeakRefMap extends Collection {
4
+ import { Dictionary } from './dictionary.js';
5
+ export class WeakRefMap extends Dictionary {
6
6
  backingMapProvider;
7
7
  backingMap;
8
8
  finalizationRegistry;
@@ -1,5 +1,5 @@
1
1
  import { bustCacheToken } from '../../http/tokens.js';
2
- import { ServerSentEvents } from '../../sse/server-sent-events.js';
2
+ import { DataStream } from '../../sse/index.js';
3
3
  import { Document, DocumentCategory, DocumentRequest, DocumentRequestsTemplate, DocumentRequestTemplate, DocumentType } from '../models/index.js';
4
4
  import { DocumentCategoryView, DocumentManagementData, DocumentRequestsTemplateData } from '../service-models/index.js';
5
5
  export type DocumentManagementApiDefinition = typeof documentManagementApiDefinition;
@@ -21,7 +21,10 @@ export declare const documentManagementApiDefinition: {
21
21
  parameters: import("../../schema/index.js").ObjectSchema<{
22
22
  collectionIds: string | string[];
23
23
  }>;
24
- result: typeof ServerSentEvents;
24
+ result: {
25
+ new (): DataStream<DocumentManagementData>;
26
+ parse<T>(eventSource: import("../../sse/index.js").ServerSentEvents): import("rxjs").Observable<T>;
27
+ };
25
28
  credentials: true;
26
29
  data: {
27
30
  [bustCacheToken]: boolean;
@@ -418,7 +421,10 @@ declare const _DocumentManagementApi: import("../../api/client/index.js").ApiCli
418
421
  parameters: import("../../schema/index.js").ObjectSchema<{
419
422
  collectionIds: string | string[];
420
423
  }>;
421
- result: typeof ServerSentEvents;
424
+ result: {
425
+ new (): DataStream<DocumentManagementData>;
426
+ parse<T>(eventSource: import("../../sse/index.js").ServerSentEvents): import("rxjs").Observable<T>;
427
+ };
422
428
  credentials: true;
423
429
  data: {
424
430
  [bustCacheToken]: boolean;
@@ -8,9 +8,9 @@ import { compileClient } from '../../api/client/index.js';
8
8
  import { defineApi } from '../../api/index.js';
9
9
  import { defaultAccessControlAllowHeaders } from '../../api/utils.js';
10
10
  import { bustCacheToken } from '../../http/tokens.js';
11
- import { ReplaceClass } from '../../injector/decorators.js';
11
+ import { ReplaceClass } from '../../injector/index.js';
12
12
  import { array, boolean, literal, number, object, optional, string } from '../../schema/index.js';
13
- import { ServerSentEvents } from '../../sse/server-sent-events.js';
13
+ import { DataStream } from '../../sse/index.js';
14
14
  import { policy } from '../authorization/index.js';
15
15
  import { Document, DocumentCategory, DocumentRequest, DocumentRequestsTemplate, DocumentRequestTemplate, DocumentType } from '../models/index.js';
16
16
  import { addOrArchiveDocumentToOrFromCollectionParametersSchema, applyDocumentRequestsTemplateParametersSchema, createDocumentCategoryParametersSchema, createDocumentParametersSchema, createDocumentRequestParametersSchema, createDocumentRequestsTemplateParametersSchema, createDocumentRequestTemplateParametersSchema, createDocumentTypeParametersSchema, deleteDocumentRequestParametersSchema, deleteDocumentRequestsTemplateParametersSchema, deleteDocumentRequestTemplateParametersSchema, DocumentCategoryView, DocumentManagementData, DocumentRequestsTemplateData, loadDataParametersSchema, updateDocumentParametersSchema, updateDocumentRequestParametersSchema, updateDocumentRequestsTemplateParametersSchema, updateDocumentRequestTemplateParametersSchema } from '../service-models/index.js';
@@ -28,7 +28,7 @@ export const documentManagementApiDefinition = defineApi({
28
28
  resource: 'data/stream',
29
29
  method: 'GET',
30
30
  parameters: loadDataParametersSchema,
31
- result: ServerSentEvents,
31
+ result: (DataStream),
32
32
  credentials: true,
33
33
  data: {
34
34
  [bustCacheToken]: true,
@@ -1,9 +1,9 @@
1
- import { type ApiController, type ApiRequestContext, type ApiServerResult } from '../../../api/index.js';
1
+ import type { ApiController, ApiRequestContext, ApiServerResult } from '../../../api/index.js';
2
2
  import { type DocumentManagementApiDefinition } from '../../api/index.js';
3
3
  export declare class DocumentManagementApiController implements ApiController<DocumentManagementApiDefinition> {
4
4
  #private;
5
5
  loadData(context: ApiRequestContext<DocumentManagementApiDefinition, 'loadData'>): Promise<ApiServerResult<DocumentManagementApiDefinition, 'loadData'>>;
6
- loadDataStream(context: ApiRequestContext<DocumentManagementApiDefinition, 'loadDataStream'>): Promise<ApiServerResult<DocumentManagementApiDefinition, 'loadDataStream'>>;
6
+ loadDataStream(context: ApiRequestContext<DocumentManagementApiDefinition, 'loadDataStream'>): ApiServerResult<DocumentManagementApiDefinition, 'loadDataStream'>;
7
7
  loadDocumentRequestsTemplateData(context: ApiRequestContext<DocumentManagementApiDefinition, 'loadDocumentRequestsTemplateData'>): Promise<ApiServerResult<DocumentManagementApiDefinition, 'loadDocumentRequestsTemplateData'>>;
8
8
  loadAvailableCategories(context: ApiRequestContext<DocumentManagementApiDefinition, 'loadAvailableCategories'>): Promise<ApiServerResult<DocumentManagementApiDefinition, 'loadAvailableCategories'>>;
9
9
  loadContent(context: ApiRequestContext<DocumentManagementApiDefinition, 'loadContent'>): Promise<ApiServerResult<DocumentManagementApiDefinition, 'loadContent'>>;
@@ -6,9 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  var _a;
8
8
  var DocumentManagementApiController_1;
9
- import { create as createDiffPatch } from 'jsondiffpatch';
10
9
  import { match, P } from 'ts-pattern';
11
- import { createErrorResponse } from '../../../api/index.js';
12
10
  import { apiController } from '../../../api/server/index.js';
13
11
  import { CancellationSignal } from '../../../cancellation/token.js';
14
12
  import { ForbiddenError, NotImplementedError } from '../../../errors/index.js';
@@ -16,24 +14,11 @@ import { HttpServerResponse } from '../../../http/index.js';
16
14
  import { inject } from '../../../injector/index.js';
17
15
  import { Logger } from '../../../logger/logger.js';
18
16
  import { injectRepository } from '../../../orm/server/repository.js';
19
- import { ServerSentEventsSource } from '../../../sse/server-sent-events-source.js';
20
17
  import { toArray } from '../../../utils/array/index.js';
21
- import { tryIgnoreAsync } from '../../../utils/try-ignore.js';
22
- import { isDefined, isUndefined } from '../../../utils/type-guards.js';
23
18
  import { documentManagementApiDefinition } from '../../api/index.js';
24
19
  import { DocumentManagementAuthorizationService } from '../../authorization/index.js';
25
20
  import { DocumentRequestCollectionAssignment } from '../../models/document-request-collection-assignment.model.js';
26
21
  import { DocumentCategoryTypeService, DocumentFileService, DocumentManagementService, DocumentRequestService, DocumentService, DocumentWorkflowService } from '../services/index.js';
27
- const jsonDiffPatch = createDiffPatch({
28
- omitRemovedValues: true,
29
- arrays: {
30
- detectMove: true,
31
- includeValueOnMove: false,
32
- },
33
- objectHash(item, index) {
34
- return item['id'] ?? String(index);
35
- },
36
- });
37
22
  let DocumentManagementApiController = DocumentManagementApiController_1 = class DocumentManagementApiController {
38
23
  #documentManagementService = inject(DocumentManagementService);
39
24
  #authorizationService = inject(DocumentManagementAuthorizationService);
@@ -56,7 +41,7 @@ let DocumentManagementApiController = DocumentManagementApiController_1 = class
56
41
  }
57
42
  return await this.#documentManagementService.loadData(tenantId, toArray(context.parameters.collectionIds));
58
43
  }
59
- async loadDataStream(context) {
44
+ async *loadDataStream(context) {
60
45
  const token = await context.getToken();
61
46
  const tenantId = await this.#authorizationService.getTenantId(token);
62
47
  for (const collectionId of context.parameters.collectionIds) {
@@ -65,37 +50,7 @@ let DocumentManagementApiController = DocumentManagementApiController_1 = class
65
50
  throw new ForbiddenError(`You are not allowed to read collection ${collectionId}`);
66
51
  }
67
52
  }
68
- const stream = this.#documentManagementService.loadDataStream(tenantId, toArray(context.parameters.collectionIds), this.#cancellationSignal);
69
- const eventSource = new ServerSentEventsSource();
70
- void (async () => {
71
- let lastData;
72
- try {
73
- for await (const data of stream) {
74
- if (eventSource.closed()) {
75
- break;
76
- }
77
- if (isUndefined(lastData)) {
78
- await eventSource.sendJson({ name: 'data', data });
79
- }
80
- else {
81
- const delta = jsonDiffPatch.diff(lastData, data);
82
- if (isDefined(delta)) {
83
- await eventSource.sendJson({ name: 'delta', data: delta });
84
- }
85
- }
86
- lastData = data;
87
- }
88
- }
89
- catch (error) {
90
- this.#logger.error(error);
91
- await tryIgnoreAsync(async () => await eventSource.sendJson({ name: 'error', data: createErrorResponse(error).error }));
92
- await tryIgnoreAsync(async () => await eventSource.close());
93
- }
94
- finally {
95
- await tryIgnoreAsync(async () => await eventSource.close());
96
- }
97
- })();
98
- return eventSource;
53
+ yield* this.#documentManagementService.loadDataStream(tenantId, toArray(context.parameters.collectionIds), this.#cancellationSignal);
99
54
  }
100
55
  async loadDocumentRequestsTemplateData(context) {
101
56
  const token = await context.getToken();
@@ -94,7 +94,7 @@ export declare class DocumentManagementService extends Transactional {
94
94
  * @param documentId The ID of the document to retrieve collection IDs for.
95
95
  */
96
96
  getRelevantDocumentCollectionIds(tenantId: string, documentId: string): Promise<string[]>;
97
- loadDataStream(tenantId: string, collectionIds: string[], cancellationSignal: CancellationSignal): AsyncIterableIterator<DocumentManagementData>;
97
+ loadDataStream(tenantId: string, collectionIds: string[], cancellationSignal: CancellationSignal): AsyncGenerator<DocumentManagementData>;
98
98
  loadData(tenantId: string, collectionIds: string[]): Promise<DocumentManagementData>;
99
99
  loadDocumentRequestsTemplateData(tenantId: string | null): Promise<DocumentRequestsTemplateData>;
100
100
  initializeCategoriesAndTypes<CategoryKey extends string, TypeKey extends string, DocumentPropertyKey extends string>(tenantId: string | null, data: CategoriesAndTypesInitializationData<CategoryKey, TypeKey, DocumentPropertyKey>): Promise<{
@@ -1,4 +1,4 @@
1
- import { type Signal } from '../../signals/api.js';
2
1
  import { type Observable } from 'rxjs';
2
+ import { type Signal } from '../../signals/api.js';
3
3
  export declare function observeResize$(element: Element, options?: ResizeObserverOptions): Observable<ResizeObserverEntry>;
4
4
  export declare function observeResize(elements: Element, options?: ResizeObserverOptions): Signal<ResizeObserverEntry | undefined>;
@@ -1,8 +1,8 @@
1
+ import { Subject, filter, fromEventPattern, map, shareReplay } from 'rxjs';
1
2
  import { IterableWeakMap } from '../../data-structures/iterable-weak-map.js';
2
3
  import { toSignal } from '../../signals/api.js';
3
4
  import { FactoryMap } from '../../utils/factory-map.js';
4
5
  import { isDefined } from '../../utils/type-guards.js';
5
- import { Subject, filter, fromEventPattern, map, shareReplay } from 'rxjs';
6
6
  let observer;
7
7
  let subject;
8
8
  const elementObservablesMap = new FactoryMap(() => ({}), new IterableWeakMap());
@@ -121,7 +121,7 @@ export declare function createColumnDecorator(data?: OrmColumnReflectionData): P
121
121
  * @param data - The ORM reflection data to add.
122
122
  * @returns A class or property decorator.
123
123
  */
124
- export declare function createTableAndColumnDecorator(data?: OrmColumnReflectionData): PropertyDecorator & ClassDecorator;
124
+ export declare function createTableAndColumnDecorator(data?: OrmColumnReflectionData): ClassDecorator & PropertyDecorator;
125
125
  /**
126
126
  * Decorator to specify ORM column options.
127
127
  * @param options - Column configuration options.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tstdl/base",
3
- "version": "0.92.151",
3
+ "version": "0.92.152",
4
4
  "author": "Patrick Hein",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -11,6 +11,7 @@
11
11
  "build:watch": "concurrently --raw --kill-others npm:tsc:watch npm:tsc-alias:watch",
12
12
  "build:production": "rm -rf dist && npm run build && npm run build:production:copy-files",
13
13
  "build:production:copy-files": "cp package.json eslint.config.js tsconfig.server.json dist/ && cp tsconfig.base.json dist/tsconfig.json && npm run copy:orm",
14
+ "build:dts": "tsc -p tsconfig.dts.json",
14
15
  "build:docs": "typedoc",
15
16
  "build:docs:watch": "typedoc --watch",
16
17
  "lint": "eslint --cache source/",
@@ -167,7 +168,7 @@
167
168
  "preact": "^10.27",
168
169
  "preact-render-to-string": "^6.5",
169
170
  "sharp": "^0.34",
170
- "undici": "^7.13",
171
+ "undici": "^7.14",
171
172
  "urlpattern-polyfill": "^10.1"
172
173
  },
173
174
  "peerDependenciesMeta": {
@@ -183,7 +184,7 @@
183
184
  "@types/minio": "7.1",
184
185
  "@types/mjml": "4.7",
185
186
  "@types/node": "24",
186
- "@types/nodemailer": "6.4",
187
+ "@types/nodemailer": "7.0",
187
188
  "@types/pg": "8.15",
188
189
  "concurrently": "9.2",
189
190
  "drizzle-kit": "0.31",
@@ -0,0 +1,18 @@
1
+ import type { AnyIterable } from '../utils/any-iterable-iterator.js';
2
+ import { ServerSentEventsSource } from './server-sent-events-source.js';
3
+ export type DataStreamSourceOptions = {
4
+ /**
5
+ * Whether to send deltas (the changes) between the last and current data or always the full data.
6
+ */
7
+ delta?: boolean;
8
+ };
9
+ export declare class DataStreamSource<T> {
10
+ #private;
11
+ readonly eventSource: ServerSentEventsSource;
12
+ readonly closed: import("../signals/api.js").Signal<boolean>;
13
+ constructor(options?: DataStreamSourceOptions);
14
+ static fromIterable<T>(iterable: AnyIterable<T>, options?: DataStreamSourceOptions): DataStreamSource<T>;
15
+ send(data: T): Promise<void>;
16
+ close(): Promise<void>;
17
+ error(error: unknown): Promise<void>;
18
+ }
@@ -0,0 +1,66 @@
1
+ import { create as createDiffPatch } from 'jsondiffpatch';
2
+ import { createErrorResponse } from '../api/index.js';
3
+ import { tryIgnoreAsync } from '../utils/try-ignore.js';
4
+ import { isDefined } from '../utils/type-guards.js';
5
+ import { ServerSentEventsSource } from './server-sent-events-source.js';
6
+ const jsonDiffPatch = createDiffPatch({
7
+ omitRemovedValues: true,
8
+ arrays: {
9
+ detectMove: true,
10
+ includeValueOnMove: false,
11
+ },
12
+ objectHash(item, index) {
13
+ return item['id'] ?? String(index);
14
+ },
15
+ });
16
+ export class DataStreamSource {
17
+ #options;
18
+ eventSource = new ServerSentEventsSource();
19
+ closed = this.eventSource.closed;
20
+ #lastData;
21
+ constructor(options = { delta: true }) {
22
+ this.#options = options;
23
+ }
24
+ static fromIterable(iterable, options) {
25
+ const source = new DataStreamSource(options);
26
+ void (async () => {
27
+ try {
28
+ for await (const data of iterable) {
29
+ if (source.closed()) {
30
+ break;
31
+ }
32
+ await source.send(data);
33
+ }
34
+ }
35
+ catch (error) {
36
+ await tryIgnoreAsync(async () => await source.error(error));
37
+ }
38
+ finally {
39
+ await tryIgnoreAsync(async () => await source.close());
40
+ }
41
+ })();
42
+ return source;
43
+ }
44
+ async send(data) {
45
+ if (this.eventSource.closed()) {
46
+ throw new Error('Cannot send data to a closed DataStreamSource connection.');
47
+ }
48
+ if (this.#options.delta && isDefined(this.#lastData)) {
49
+ const delta = jsonDiffPatch.diff(this.#lastData, data);
50
+ await this.eventSource.sendJson({ name: 'delta', data: delta });
51
+ }
52
+ else {
53
+ await this.eventSource.sendJson({ name: 'data', data });
54
+ }
55
+ if (this.#options.delta) {
56
+ this.#lastData = data;
57
+ }
58
+ }
59
+ async close() {
60
+ await this.eventSource.close();
61
+ }
62
+ async error(error) {
63
+ await tryIgnoreAsync(async () => await this.eventSource.sendJson({ name: 'error', data: createErrorResponse(error).error }));
64
+ await tryIgnoreAsync(async () => await this.eventSource.close());
65
+ }
66
+ }
@@ -0,0 +1,8 @@
1
+ import { type Observable } from 'rxjs';
2
+ import type { ServerSentEvents } from './server-sent-events.js';
3
+ declare const dataStreamType: unique symbol;
4
+ export declare class DataStream<T> {
5
+ readonly [dataStreamType]?: T;
6
+ static parse<T>(eventSource: ServerSentEvents): Observable<T>;
7
+ }
8
+ export {};
@@ -0,0 +1,15 @@
1
+ import { patch } from 'jsondiffpatch';
2
+ import { hasOwnProperty } from '../utils/object/object.js';
3
+ import { finalize, map, merge, scan } from 'rxjs';
4
+ export class DataStream {
5
+ static parse(eventSource) {
6
+ const data$ = eventSource.message$('data').pipe(map((message) => ({ data: JSON.parse(message.data) })));
7
+ const delta$ = eventSource.message$('delta').pipe(map((message) => ({ delta: JSON.parse(message.data) })));
8
+ return merge(data$, delta$).pipe(scan((data, message) => {
9
+ if (hasOwnProperty(message, 'data')) {
10
+ return message.data;
11
+ }
12
+ return patch(structuredClone(data), message.delta);
13
+ }, undefined), finalize(() => eventSource.close()));
14
+ }
15
+ }
package/sse/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export * from './data-stream-source.js';
2
+ export * from './data-stream.js';
1
3
  export * from './model.js';
2
4
  export * from './server-sent-events-source.js';
3
5
  export * from './server-sent-events.js';
package/sse/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ export * from './data-stream-source.js';
2
+ export * from './data-stream.js';
1
3
  export * from './model.js';
2
4
  export * from './server-sent-events-source.js';
3
5
  export * from './server-sent-events.js';
package/utils/math.js CHANGED
@@ -1,4 +1,3 @@
1
- import { NotSupportedError } from '../errors/not-supported.error.js';
2
1
  import { defaultRandomNumberGeneratorFn } from '../random/number-generator/random-number-generator-function.js';
3
2
  import { isNull } from './type-guards.js';
4
3
  /**
@@ -44,7 +43,7 @@ export function average(values) {
44
43
  */
45
44
  export function minimum(values) {
46
45
  if (values.length == 0) {
47
- throw new NotSupportedError('No values provided.');
46
+ throw new Error('No values provided.');
48
47
  }
49
48
  return values.reduce((previous, current) => Math.min(previous, current), Number.POSITIVE_INFINITY);
50
49
  }
@@ -55,7 +54,7 @@ export function minimum(values) {
55
54
  */
56
55
  export function maximum(values) {
57
56
  if (values.length == 0) {
58
- throw new NotSupportedError('No values provided.');
57
+ throw new Error('No values provided.');
59
58
  }
60
59
  return values.reduce((previous, current) => Math.max(previous, current), Number.NEGATIVE_INFINITY);
61
60
  }