@carlonicora/nestjs-neo4jsonapi 8.15.1 → 8.16.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.
- package/dist/bootstrap/app.module.factory.d.ts.map +1 -1
- package/dist/bootstrap/app.module.factory.js +9 -0
- package/dist/bootstrap/app.module.factory.js.map +1 -1
- package/dist/bootstrap/bootstrap.options.d.ts +10 -0
- package/dist/bootstrap/bootstrap.options.d.ts.map +1 -1
- package/dist/common/helpers/define-entity.d.ts.map +1 -1
- package/dist/common/helpers/define-entity.js +3 -0
- package/dist/common/helpers/define-entity.js.map +1 -1
- package/dist/common/registries/entity-descriptor.registry.d.ts +22 -0
- package/dist/common/registries/entity-descriptor.registry.d.ts.map +1 -0
- package/dist/common/registries/entity-descriptor.registry.js +51 -0
- package/dist/common/registries/entity-descriptor.registry.js.map +1 -0
- package/dist/common/registries/index.d.ts +1 -0
- package/dist/common/registries/index.d.ts.map +1 -1
- package/dist/common/registries/index.js +1 -0
- package/dist/common/registries/index.js.map +1 -1
- package/dist/core/cors/services/cors.service.d.ts +4 -1
- package/dist/core/cors/services/cors.service.d.ts.map +1 -1
- package/dist/core/cors/services/cors.service.js +19 -3
- package/dist/core/cors/services/cors.service.js.map +1 -1
- package/dist/core/neo4j/abstracts/abstract.repository.d.ts +2 -0
- package/dist/core/neo4j/abstracts/abstract.repository.d.ts.map +1 -1
- package/dist/core/neo4j/abstracts/abstract.repository.js +4 -1
- package/dist/core/neo4j/abstracts/abstract.repository.js.map +1 -1
- package/dist/core/neo4j/abstracts/abstract.service.d.ts +6 -0
- package/dist/core/neo4j/abstracts/abstract.service.d.ts.map +1 -1
- package/dist/core/neo4j/abstracts/abstract.service.js +16 -0
- package/dist/core/neo4j/abstracts/abstract.service.js.map +1 -1
- package/dist/core/neo4j/helpers/build-filter-clauses.d.ts.map +1 -1
- package/dist/core/neo4j/helpers/build-filter-clauses.js +8 -1
- package/dist/core/neo4j/helpers/build-filter-clauses.js.map +1 -1
- package/dist/core/offline/index.d.ts +5 -0
- package/dist/core/offline/index.d.ts.map +1 -0
- package/dist/core/offline/index.js +21 -0
- package/dist/core/offline/index.js.map +1 -0
- package/dist/core/offline/offline-request.context.d.ts +12 -0
- package/dist/core/offline/offline-request.context.d.ts.map +1 -0
- package/dist/core/offline/offline-request.context.js +34 -0
- package/dist/core/offline/offline-request.context.js.map +1 -0
- package/dist/core/offline/offline-request.interceptor.d.ts +15 -0
- package/dist/core/offline/offline-request.interceptor.d.ts.map +1 -0
- package/dist/core/offline/offline-request.interceptor.js +43 -0
- package/dist/core/offline/offline-request.interceptor.js.map +1 -0
- package/dist/core/offline/offline.constants.d.ts +12 -0
- package/dist/core/offline/offline.constants.d.ts.map +1 -0
- package/dist/core/offline/offline.constants.js +12 -0
- package/dist/core/offline/offline.constants.js.map +1 -0
- package/dist/core/offline/offline.module.d.ts +12 -0
- package/dist/core/offline/offline.module.d.ts.map +1 -0
- package/dist/core/offline/offline.module.js +42 -0
- package/dist/core/offline/offline.module.js.map +1 -0
- package/dist/foundations/offline-change-set/decorators/offline-replayable.decorator.d.ts +7 -0
- package/dist/foundations/offline-change-set/decorators/offline-replayable.decorator.d.ts.map +1 -0
- package/dist/foundations/offline-change-set/decorators/offline-replayable.decorator.js +12 -0
- package/dist/foundations/offline-change-set/decorators/offline-replayable.decorator.js.map +1 -0
- package/dist/foundations/offline-change-set/dtos/offline-change-set.post.dto.d.ts +33 -0
- package/dist/foundations/offline-change-set/dtos/offline-change-set.post.dto.d.ts.map +1 -0
- package/dist/foundations/offline-change-set/dtos/offline-change-set.post.dto.js +133 -0
- package/dist/foundations/offline-change-set/dtos/offline-change-set.post.dto.js.map +1 -0
- package/dist/foundations/offline-change-set/entities/offline-change-set.d.ts +66 -0
- package/dist/foundations/offline-change-set/entities/offline-change-set.d.ts.map +1 -0
- package/dist/foundations/offline-change-set/entities/offline-change-set.js +31 -0
- package/dist/foundations/offline-change-set/entities/offline-change-set.js.map +1 -0
- package/dist/foundations/offline-change-set/entities/offline-change-set.meta.d.ts +3 -0
- package/dist/foundations/offline-change-set/entities/offline-change-set.meta.d.ts.map +1 -0
- package/dist/foundations/offline-change-set/entities/offline-change-set.meta.js +10 -0
- package/dist/foundations/offline-change-set/entities/offline-change-set.meta.js.map +1 -0
- package/dist/foundations/offline-change-set/index.d.ts +11 -0
- package/dist/foundations/offline-change-set/index.d.ts.map +1 -0
- package/dist/foundations/offline-change-set/index.js +27 -0
- package/dist/foundations/offline-change-set/index.js.map +1 -0
- package/dist/foundations/offline-change-set/merge/deep-equal.d.ts +6 -0
- package/dist/foundations/offline-change-set/merge/deep-equal.d.ts.map +1 -0
- package/dist/foundations/offline-change-set/merge/deep-equal.js +31 -0
- package/dist/foundations/offline-change-set/merge/deep-equal.js.map +1 -0
- package/dist/foundations/offline-change-set/merge/merge-blocks.d.ts +37 -0
- package/dist/foundations/offline-change-set/merge/merge-blocks.d.ts.map +1 -0
- package/dist/foundations/offline-change-set/merge/merge-blocks.js +108 -0
- package/dist/foundations/offline-change-set/merge/merge-blocks.js.map +1 -0
- package/dist/foundations/offline-change-set/merge/three-way-merge.d.ts +57 -0
- package/dist/foundations/offline-change-set/merge/three-way-merge.d.ts.map +1 -0
- package/dist/foundations/offline-change-set/merge/three-way-merge.js +201 -0
- package/dist/foundations/offline-change-set/merge/three-way-merge.js.map +1 -0
- package/dist/foundations/offline-change-set/offline-change-set.module.d.ts +11 -0
- package/dist/foundations/offline-change-set/offline-change-set.module.d.ts.map +1 -0
- package/dist/foundations/offline-change-set/offline-change-set.module.js +41 -0
- package/dist/foundations/offline-change-set/offline-change-set.module.js.map +1 -0
- package/dist/foundations/offline-change-set/repositories/offline-change-set.repository.d.ts +26 -0
- package/dist/foundations/offline-change-set/repositories/offline-change-set.repository.d.ts.map +1 -0
- package/dist/foundations/offline-change-set/repositories/offline-change-set.repository.js +56 -0
- package/dist/foundations/offline-change-set/repositories/offline-change-set.repository.js.map +1 -0
- package/dist/foundations/offline-change-set/services/offline-change-set.service.d.ts +72 -0
- package/dist/foundations/offline-change-set/services/offline-change-set.service.d.ts.map +1 -0
- package/dist/foundations/offline-change-set/services/offline-change-set.service.js +333 -0
- package/dist/foundations/offline-change-set/services/offline-change-set.service.js.map +1 -0
- package/dist/foundations/offline-change-set/services/offline-route-runner.service.d.ts +61 -0
- package/dist/foundations/offline-change-set/services/offline-route-runner.service.d.ts.map +1 -0
- package/dist/foundations/offline-change-set/services/offline-route-runner.service.js +192 -0
- package/dist/foundations/offline-change-set/services/offline-route-runner.service.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var OfflineChangeSetService_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.OfflineChangeSetService = void 0;
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
const nestjs_cls_1 = require("nestjs-cls");
|
|
16
|
+
const entity_descriptor_registry_1 = require("../../../common/registries/entity-descriptor.registry");
|
|
17
|
+
const jsonapi_service_1 = require("../../../core/jsonapi/services/jsonapi.service");
|
|
18
|
+
const abstract_service_1 = require("../../../core/neo4j/abstracts/abstract.service");
|
|
19
|
+
const offline_change_set_1 = require("../entities/offline-change-set");
|
|
20
|
+
const deep_equal_1 = require("../merge/deep-equal");
|
|
21
|
+
const three_way_merge_1 = require("../merge/three-way-merge");
|
|
22
|
+
const offline_change_set_repository_1 = require("../repositories/offline-change-set.repository");
|
|
23
|
+
const offline_route_runner_service_1 = require("./offline-route-runner.service");
|
|
24
|
+
const isOk = (status) => status >= 200 && status < 300;
|
|
25
|
+
/** The reason an app route gave for refusing a step (JSON:API errors, Nest's error body, or the status). */
|
|
26
|
+
function errorDetail(status, body) {
|
|
27
|
+
const error = Array.isArray(body?.errors) ? body.errors[0] : undefined;
|
|
28
|
+
if (error?.detail)
|
|
29
|
+
return String(error.detail);
|
|
30
|
+
if (error?.title)
|
|
31
|
+
return String(error.title);
|
|
32
|
+
if (Array.isArray(body?.message))
|
|
33
|
+
return body.message.join("; ");
|
|
34
|
+
if (typeof body?.message === "string" && body.message)
|
|
35
|
+
return body.message;
|
|
36
|
+
if (typeof body === "string" && body)
|
|
37
|
+
return body;
|
|
38
|
+
return `HTTP ${status}`;
|
|
39
|
+
}
|
|
40
|
+
/** Values the server sets on every write or recomputes on every read: never a change by anyone. */
|
|
41
|
+
const VOLATILE_ATTRIBUTES = new Set(["createdAt", "updatedAt"]);
|
|
42
|
+
/**
|
|
43
|
+
* Attributes only the server (the AI workers) writes. Descriptors carry no marker for them (the
|
|
44
|
+
* app declares them as plain fields), so they are named here; a field marked `immutable` (never
|
|
45
|
+
* written by a client save) counts too. A change to them is never "changed on the server".
|
|
46
|
+
*/
|
|
47
|
+
const SERVER_WRITTEN_ATTRIBUTES = new Set(["aiStatus", "summary", "tldr"]);
|
|
48
|
+
/** How long a stored change set (a package's results, kept for a resend) is kept. */
|
|
49
|
+
const STORED_CHANGE_SET_DAYS = 7;
|
|
50
|
+
/** `npcs/n1?x`, `/npcs/n1` or an absolute URL → `["npcs", "n1"]`. */
|
|
51
|
+
function pathSegments(path) {
|
|
52
|
+
let pathname = path.split("?")[0];
|
|
53
|
+
if (/^https?:\/\//i.test(pathname))
|
|
54
|
+
pathname = new URL(pathname).pathname;
|
|
55
|
+
return pathname.split("/").filter((s) => s.length > 0);
|
|
56
|
+
}
|
|
57
|
+
const linkageIds = (rel) => {
|
|
58
|
+
if (!rel || typeof rel !== "object" || !("data" in rel))
|
|
59
|
+
return undefined;
|
|
60
|
+
const data = rel.data;
|
|
61
|
+
if (data == null)
|
|
62
|
+
return [];
|
|
63
|
+
return (Array.isArray(data) ? data : [data]).map((d) => d.id).sort();
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Opens one offline change set (every change the device queued, in one request) and handles
|
|
67
|
+
* each change in `seq` order through the app's own routes, as the caller (`OfflineRouteRunner`).
|
|
68
|
+
*
|
|
69
|
+
* - POST, and any write that names no record, runs as sent.
|
|
70
|
+
* - PUT/PATCH of a record: the current record is read (GET on the record's own path,
|
|
71
|
+
* `<endpoint>/<id>`) and merged with `base` and the device's document (`threeWayMerge`);
|
|
72
|
+
* only the changed fields are written, as a PATCH of the device's document trimmed to them
|
|
73
|
+
* (merged rich text in place). A change carrying `resolution` merges the same way, and each
|
|
74
|
+
* conflicting field takes the GM's choice.
|
|
75
|
+
* - DELETE of a record: refused as "changed on the server" when a descriptor field or a
|
|
76
|
+
* linked id changed since `base`; with `resolution` (delete anyway) it runs without that check.
|
|
77
|
+
* - After a conflict or a could-not-apply, later changes to the same record wait (a custom
|
|
78
|
+
* write `<endpoint>/<id>/...` counts as a change of that record).
|
|
79
|
+
* - A package is opened once: its results are stored under its id (company-scoped) and a
|
|
80
|
+
* package sent again with the same id is answered with them, without running anything.
|
|
81
|
+
*
|
|
82
|
+
* The package is never paged, batched or capped.
|
|
83
|
+
*/
|
|
84
|
+
let OfflineChangeSetService = OfflineChangeSetService_1 = class OfflineChangeSetService extends abstract_service_1.AbstractService {
|
|
85
|
+
constructor(jsonApiService, offlineChangeSetRepository, clsService, runner) {
|
|
86
|
+
super(jsonApiService, offlineChangeSetRepository, clsService, offline_change_set_1.OfflineChangeSetDescriptor.model);
|
|
87
|
+
this.offlineChangeSetRepository = offlineChangeSetRepository;
|
|
88
|
+
this.runner = runner;
|
|
89
|
+
this.descriptor = offline_change_set_1.OfflineChangeSetDescriptor;
|
|
90
|
+
this.logger = new common_1.Logger(OfflineChangeSetService_1.name);
|
|
91
|
+
}
|
|
92
|
+
async apply(params) {
|
|
93
|
+
const id = params.data.id;
|
|
94
|
+
await this.removeExpired();
|
|
95
|
+
const stored = await this.repository.findById({ id });
|
|
96
|
+
if (stored)
|
|
97
|
+
return this.jsonApiService.buildSingle(offline_change_set_1.OfflineChangeSetDescriptor.model, stored);
|
|
98
|
+
const changes = [...(params.data.attributes?.changes ?? [])].sort((a, b) => a.seq - b.seq);
|
|
99
|
+
const blocked = new Set();
|
|
100
|
+
const results = [];
|
|
101
|
+
for (const change of changes) {
|
|
102
|
+
const key = this.recordKey(change);
|
|
103
|
+
if (key && blocked.has(key)) {
|
|
104
|
+
results.push({ seq: change.seq, status: "waiting" });
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
let result;
|
|
108
|
+
try {
|
|
109
|
+
result = await this.applyChange(change, params.request);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
result = { seq: change.seq, status: "could-not-apply", detail: error?.message ?? String(error) };
|
|
113
|
+
}
|
|
114
|
+
if (key && (result.status === "conflict" || result.status === "could-not-apply"))
|
|
115
|
+
blocked.add(key);
|
|
116
|
+
results.push(result);
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
await this.repository.create({ id, resultsJson: JSON.stringify(results) });
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
// The changes ran: answer them. A package sent again would run once more, as before this store existed.
|
|
123
|
+
this.logger.error(`offline change set ${id}: results not stored: ${error?.message ?? error}`);
|
|
124
|
+
}
|
|
125
|
+
return this.jsonApiService.buildSingle(offline_change_set_1.OfflineChangeSetDescriptor.model, { id, results });
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Removes the company's stored change sets older than `STORED_CHANGE_SET_DAYS`: a device sends a
|
|
129
|
+
* package again only right after a failed answer, never days later. A failed clean-up is
|
|
130
|
+
* logged and never stops the package.
|
|
131
|
+
*/
|
|
132
|
+
async removeExpired() {
|
|
133
|
+
const before = new Date(Date.now() - STORED_CHANGE_SET_DAYS * 24 * 60 * 60 * 1000);
|
|
134
|
+
try {
|
|
135
|
+
await this.offlineChangeSetRepository.deleteOlderThan({ before });
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
this.logger.error(`offline change sets: clean-up failed: ${error?.message ?? error}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/** The JSON:API type answering on an endpoint (the type is the endpoint unless a descriptor says otherwise). */
|
|
142
|
+
typeOfEndpoint(endpoint) {
|
|
143
|
+
return entity_descriptor_registry_1.entityDescriptorRegistry.getByEndpoint(endpoint)?.model?.type ?? endpoint;
|
|
144
|
+
}
|
|
145
|
+
/** The record's own path: `<its type's endpoint>/<id>`. */
|
|
146
|
+
recordPath(change) {
|
|
147
|
+
const type = change.recordType;
|
|
148
|
+
const endpoint = entity_descriptor_registry_1.entityDescriptorRegistry.get(type)?.model?.endpoint ?? type;
|
|
149
|
+
return `${endpoint}/${change.recordId}`;
|
|
150
|
+
}
|
|
151
|
+
/** The record a change touches: its record fields, the resource a create posts, or the `<endpoint>/<id>` its path targets. */
|
|
152
|
+
recordKey(change) {
|
|
153
|
+
if (change.recordType && change.recordId)
|
|
154
|
+
return `${change.recordType}:${change.recordId}`;
|
|
155
|
+
const data = change.body?.data;
|
|
156
|
+
if (change.method === "POST" && typeof data?.type === "string" && typeof data?.id === "string")
|
|
157
|
+
return `${data.type}:${data.id}`;
|
|
158
|
+
const [endpoint, recordId] = pathSegments(change.path);
|
|
159
|
+
if (endpoint && recordId)
|
|
160
|
+
return `${this.typeOfEndpoint(endpoint)}:${recordId}`;
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
async applyChange(change, request) {
|
|
164
|
+
const namesRecord = !!change.recordType && !!change.recordId;
|
|
165
|
+
if (!namesRecord || change.method === "POST")
|
|
166
|
+
return this.runAsSent(change, request);
|
|
167
|
+
if (change.method === "DELETE")
|
|
168
|
+
return this.applyDelete(change, request);
|
|
169
|
+
return this.applyEdit(change, request);
|
|
170
|
+
}
|
|
171
|
+
async runAsSent(change, request) {
|
|
172
|
+
const answer = await this.runner.run({ method: change.method, path: change.path, body: change.body, request });
|
|
173
|
+
return this.toResult(change.seq, answer);
|
|
174
|
+
}
|
|
175
|
+
toResult(seq, answer) {
|
|
176
|
+
if (answer.ran === false)
|
|
177
|
+
return { seq, status: "could-not-apply", detail: answer.detail };
|
|
178
|
+
if (!isOk(answer.status))
|
|
179
|
+
return { seq, status: "could-not-apply", detail: errorDetail(answer.status, answer.body) };
|
|
180
|
+
return answer.body && typeof answer.body === "object"
|
|
181
|
+
? { seq, status: "applied", response: answer.body }
|
|
182
|
+
: { seq, status: "applied" };
|
|
183
|
+
}
|
|
184
|
+
async readCurrent(change, request) {
|
|
185
|
+
const answer = await this.runner.run({ method: "GET", path: this.recordPath(change), request });
|
|
186
|
+
if (answer.ran === false)
|
|
187
|
+
return { kind: "failed", detail: answer.detail };
|
|
188
|
+
if (answer.status === 404)
|
|
189
|
+
return { kind: "deleted" };
|
|
190
|
+
if (!isOk(answer.status))
|
|
191
|
+
return { kind: "failed", detail: errorDetail(answer.status, answer.body) };
|
|
192
|
+
const resource = answer.body?.data;
|
|
193
|
+
if (!resource || typeof resource !== "object" || Array.isArray(resource))
|
|
194
|
+
return { kind: "deleted" };
|
|
195
|
+
return { kind: "found", resource, document: answer.body };
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Relationship names the record's GET always answers when it has a link (the serialiser
|
|
199
|
+
* emits every descriptor relationship and omits only an empty one), so an omitted one is empty.
|
|
200
|
+
*/
|
|
201
|
+
knownRelationships(type) {
|
|
202
|
+
const descriptor = type ? entity_descriptor_registry_1.entityDescriptorRegistry.get(type) : undefined;
|
|
203
|
+
return Object.entries(descriptor?.relationships ?? {}).map(([name, rel]) => rel?.dtoKey ?? name);
|
|
204
|
+
}
|
|
205
|
+
mergeResolution(change) {
|
|
206
|
+
const resolution = change.resolution;
|
|
207
|
+
if (!resolution)
|
|
208
|
+
return undefined;
|
|
209
|
+
const merged = resolution.mergedBody?.data;
|
|
210
|
+
return {
|
|
211
|
+
choices: resolution.choices,
|
|
212
|
+
all: resolution.kind === "mine" ? "mine" : undefined,
|
|
213
|
+
merged: merged && typeof merged === "object" ? merged : undefined,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
async applyEdit(change, request) {
|
|
217
|
+
const current = await this.readCurrent(change, request);
|
|
218
|
+
if (current.kind === "deleted")
|
|
219
|
+
return { seq: change.seq, status: "conflict", conflict: "deleted-on-server", current: null };
|
|
220
|
+
if (current.kind === "failed")
|
|
221
|
+
return { seq: change.seq, status: "could-not-apply", detail: current.detail };
|
|
222
|
+
const body = (change.body ?? {});
|
|
223
|
+
const mine = body.data ?? {};
|
|
224
|
+
const theirs = current.resource;
|
|
225
|
+
const base = change.base ?? theirs;
|
|
226
|
+
const merge = (0, three_way_merge_1.threeWayMerge)({
|
|
227
|
+
base,
|
|
228
|
+
mine,
|
|
229
|
+
theirs,
|
|
230
|
+
richTextFields: entity_descriptor_registry_1.entityDescriptorRegistry.richTextFields(change.recordType),
|
|
231
|
+
knownRelationships: this.knownRelationships(change.recordType),
|
|
232
|
+
resolution: this.mergeResolution(change),
|
|
233
|
+
});
|
|
234
|
+
if (merge.conflictFields.length > 0)
|
|
235
|
+
return {
|
|
236
|
+
seq: change.seq,
|
|
237
|
+
status: "conflict",
|
|
238
|
+
conflict: "fields",
|
|
239
|
+
current: theirs,
|
|
240
|
+
merged: merge.attributes,
|
|
241
|
+
conflictFields: merge.conflictFields,
|
|
242
|
+
conflictBlocks: merge.conflictBlocks,
|
|
243
|
+
};
|
|
244
|
+
if (merge.changed.length === 0)
|
|
245
|
+
return { seq: change.seq, status: "applied", response: current.document };
|
|
246
|
+
// The device's model-built document (decision "1a"), trimmed in place: fields the merge says
|
|
247
|
+
// nobody needs to write are removed, merged values (rich text included) replace the device's.
|
|
248
|
+
// Nothing is rebuilt: type, id and every other member stay as the device's model wrote them.
|
|
249
|
+
const trimmed = structuredClone(body);
|
|
250
|
+
const data = trimmed.data;
|
|
251
|
+
for (const name of Object.keys(data.attributes ?? {})) {
|
|
252
|
+
if (merge.changed.includes(name))
|
|
253
|
+
data.attributes[name] = merge.attributes[name];
|
|
254
|
+
else
|
|
255
|
+
delete data.attributes[name];
|
|
256
|
+
}
|
|
257
|
+
for (const name of Object.keys(data.relationships ?? {})) {
|
|
258
|
+
if (merge.changed.includes(name) && name in merge.relationships)
|
|
259
|
+
data.relationships[name] = merge.relationships[name];
|
|
260
|
+
else
|
|
261
|
+
delete data.relationships[name];
|
|
262
|
+
}
|
|
263
|
+
if (data.relationships && Object.keys(data.relationships).length === 0)
|
|
264
|
+
delete data.relationships;
|
|
265
|
+
const answer = await this.runner.run({ method: "PATCH", path: change.path, body: trimmed, request });
|
|
266
|
+
return this.toResult(change.seq, answer);
|
|
267
|
+
}
|
|
268
|
+
async applyDelete(change, request) {
|
|
269
|
+
if (!change.resolution) {
|
|
270
|
+
const current = await this.readCurrent(change, request);
|
|
271
|
+
if (current.kind === "deleted")
|
|
272
|
+
return { seq: change.seq, status: "applied" };
|
|
273
|
+
if (current.kind === "failed")
|
|
274
|
+
return { seq: change.seq, status: "could-not-apply", detail: current.detail };
|
|
275
|
+
if (change.base && this.changedSince(change.recordType, change.base, current.resource))
|
|
276
|
+
return { seq: change.seq, status: "conflict", conflict: "changed-on-server", current: current.resource };
|
|
277
|
+
}
|
|
278
|
+
const answer = await this.runner.run({ method: "DELETE", path: change.path, body: change.body, request });
|
|
279
|
+
// Already gone: what the GM asked for holds.
|
|
280
|
+
if (answer.ran === true && answer.status === 404)
|
|
281
|
+
return { seq: change.seq, status: "applied" };
|
|
282
|
+
return this.toResult(change.seq, answer);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* The attributes a change could have touched: the descriptor's fields that go on the wire as
|
|
286
|
+
* stored (no transform, such as a signed URL; not meta; not excluded), minus createdAt/updatedAt
|
|
287
|
+
* and the fields only the server writes (`SERVER_WRITTEN_ATTRIBUTES`, `immutable` fields).
|
|
288
|
+
* `undefined` for an unknown type (every attribute base holds is compared, minus those names).
|
|
289
|
+
*/
|
|
290
|
+
comparableAttributes(type) {
|
|
291
|
+
const descriptor = entity_descriptor_registry_1.entityDescriptorRegistry.get(type);
|
|
292
|
+
if (!descriptor)
|
|
293
|
+
return undefined;
|
|
294
|
+
const names = Object.entries(descriptor.fields ?? {})
|
|
295
|
+
.filter(([name, def]) => !VOLATILE_ATTRIBUTES.has(name) &&
|
|
296
|
+
!SERVER_WRITTEN_ATTRIBUTES.has(name) &&
|
|
297
|
+
!def?.immutable &&
|
|
298
|
+
!def?.transform &&
|
|
299
|
+
!def?.meta &&
|
|
300
|
+
!def?.excludeFromJsonApi &&
|
|
301
|
+
def?.serialise !== false)
|
|
302
|
+
.map(([name]) => name);
|
|
303
|
+
return new Set(names);
|
|
304
|
+
}
|
|
305
|
+
/** A descriptor field or a linked id of the record differs from `base`. */
|
|
306
|
+
changedSince(type, base, theirs) {
|
|
307
|
+
const comparable = this.comparableAttributes(type);
|
|
308
|
+
for (const [name, value] of Object.entries(base.attributes ?? {})) {
|
|
309
|
+
if (comparable ? !comparable.has(name) : VOLATILE_ATTRIBUTES.has(name) || SERVER_WRITTEN_ATTRIBUTES.has(name))
|
|
310
|
+
continue;
|
|
311
|
+
if (!(0, deep_equal_1.jsonEqual)(value, theirs.attributes?.[name]))
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
const known = new Set(this.knownRelationships(type));
|
|
315
|
+
for (const [name, rel] of Object.entries(base.relationships ?? {})) {
|
|
316
|
+
const baseIds = linkageIds(rel);
|
|
317
|
+
const theirsRel = theirs.relationships?.[name] ?? (known.has(name) ? { data: null } : undefined);
|
|
318
|
+
const theirsIds = linkageIds(theirsRel);
|
|
319
|
+
if (baseIds !== undefined && theirsIds !== undefined && !(0, deep_equal_1.jsonEqual)(baseIds, theirsIds))
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
exports.OfflineChangeSetService = OfflineChangeSetService;
|
|
326
|
+
exports.OfflineChangeSetService = OfflineChangeSetService = OfflineChangeSetService_1 = __decorate([
|
|
327
|
+
(0, common_1.Injectable)(),
|
|
328
|
+
__metadata("design:paramtypes", [jsonapi_service_1.JsonApiService,
|
|
329
|
+
offline_change_set_repository_1.OfflineChangeSetRepository,
|
|
330
|
+
nestjs_cls_1.ClsService,
|
|
331
|
+
offline_route_runner_service_1.OfflineRouteRunner])
|
|
332
|
+
], OfflineChangeSetService);
|
|
333
|
+
//# sourceMappingURL=offline-change-set.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offline-change-set.service.js","sourceRoot":"","sources":["../../../../src/foundations/offline-change-set/services/offline-change-set.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { DiscoveryService, HttpAdapterHost, MetadataScanner, Reflector } from "@nestjs/core";
|
|
2
|
+
import type { FastifyRequest } from "fastify";
|
|
3
|
+
/**
|
|
4
|
+
* The per-process token every step of an offline change set carries in `x-offline-internal`.
|
|
5
|
+
* Random, generated on first use, never leaves the process: only requests this runner injects
|
|
6
|
+
* carry it, so the throttler can tell them from client requests (one package = one request).
|
|
7
|
+
*/
|
|
8
|
+
export declare function offlineInternalToken(): string;
|
|
9
|
+
/** True when the headers carry this process's `x-offline-internal` token. */
|
|
10
|
+
export declare function isOfflineInternalRequest(headers: Record<string, unknown> | undefined): boolean;
|
|
11
|
+
export type OfflineRouteMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
12
|
+
/** `ran: false` = refused without running (the route is not marked `@OfflineReplayable()`). */
|
|
13
|
+
export type OfflineRouteAnswer = {
|
|
14
|
+
ran: true;
|
|
15
|
+
status: number;
|
|
16
|
+
body: any;
|
|
17
|
+
} | {
|
|
18
|
+
ran: false;
|
|
19
|
+
detail: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Runs one step of an offline change set through the app's own route with Fastify `inject`,
|
|
23
|
+
* as the caller: the caller's `Authorization`, `x-language` and `x-companyid` headers, plus
|
|
24
|
+
* `x-offline-replay: 1` and the process token. Every read and write therefore goes through
|
|
25
|
+
* the app's controller → service → repository, with its guards, validation and checks.
|
|
26
|
+
*
|
|
27
|
+
* A write (POST/PUT/PATCH/DELETE) runs only when the route that would answer it carries
|
|
28
|
+
* `@OfflineReplayable()`; any other write is refused without running. A GET (reading the
|
|
29
|
+
* current record before a merge) needs no marker: it changes nothing.
|
|
30
|
+
*
|
|
31
|
+
* Infrastructure provider: it owns no entity and touches no Neo4j itself.
|
|
32
|
+
*/
|
|
33
|
+
export declare class OfflineRouteRunner {
|
|
34
|
+
private readonly adapterHost;
|
|
35
|
+
private readonly discovery;
|
|
36
|
+
private readonly metadataScanner;
|
|
37
|
+
private readonly reflector;
|
|
38
|
+
private routes;
|
|
39
|
+
constructor(adapterHost: HttpAdapterHost, discovery: DiscoveryService, metadataScanner: MetadataScanner, reflector: Reflector);
|
|
40
|
+
run(params: {
|
|
41
|
+
method: OfflineRouteMethod;
|
|
42
|
+
path: string;
|
|
43
|
+
body?: unknown;
|
|
44
|
+
request: FastifyRequest;
|
|
45
|
+
}): Promise<OfflineRouteAnswer>;
|
|
46
|
+
/**
|
|
47
|
+
* `npcs/n1`, `/npcs/n1` or an absolute URL → `/npcs/n1` (query string kept), with dot segments
|
|
48
|
+
* resolved the way the router resolves them, so the route checked is the route that runs.
|
|
49
|
+
* `undefined` (refused) for a path that climbs above the root, or that carries an encoded dot
|
|
50
|
+
* or separator (`%2e`, `%2f`, `%5c`), which a later decode could turn into another path.
|
|
51
|
+
*/
|
|
52
|
+
private normalise;
|
|
53
|
+
private parse;
|
|
54
|
+
/**
|
|
55
|
+
* The route that answers `method path`, with the router's precedence: a static segment
|
|
56
|
+
* beats a parameter, a parameter beats a wildcard, compared from the first segment.
|
|
57
|
+
*/
|
|
58
|
+
private match;
|
|
59
|
+
private knownRoutes;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=offline-route-runner.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offline-route-runner.service.d.ts","sourceRoot":"","sources":["../../../../src/foundations/offline-change-set/services/offline-route-runner.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE7F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAM9C;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAG7C;AAED,6EAA6E;AAC7E,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,OAAO,CAO9F;AAED,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE7E,+FAA+F;AAC/F,MAAM,MAAM,kBAAkB,GAAG;IAAE,GAAG,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAW3G;;;;;;;;;;;GAWG;AACH,qBACa,kBAAkB;IAI3B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS;IAN5B,OAAO,CAAC,MAAM,CAA2B;gBAGtB,WAAW,EAAE,eAAe,EAC5B,SAAS,EAAE,gBAAgB,EAC3B,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,SAAS;IAGjC,GAAG,CAAC,MAAM,EAAE;QAChB,MAAM,EAAE,kBAAkB,CAAC;QAC3B,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,OAAO,EAAE,cAAc,CAAC;KACzB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA+B/B;;;;;OAKG;IACH,OAAO,CAAC,SAAS;IAkBjB,OAAO,CAAC,KAAK;IASb;;;OAGG;IACH,OAAO,CAAC,KAAK;IA0Bb,OAAO,CAAC,WAAW;CA4BpB"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.OfflineRouteRunner = void 0;
|
|
13
|
+
exports.offlineInternalToken = offlineInternalToken;
|
|
14
|
+
exports.isOfflineInternalRequest = isOfflineInternalRequest;
|
|
15
|
+
const common_1 = require("@nestjs/common");
|
|
16
|
+
const constants_1 = require("@nestjs/common/constants");
|
|
17
|
+
const core_1 = require("@nestjs/core");
|
|
18
|
+
const crypto_1 = require("crypto");
|
|
19
|
+
const offline_constants_1 = require("../../../core/offline/offline.constants");
|
|
20
|
+
const offline_replayable_decorator_1 = require("../decorators/offline-replayable.decorator");
|
|
21
|
+
let processToken;
|
|
22
|
+
/**
|
|
23
|
+
* The per-process token every step of an offline change set carries in `x-offline-internal`.
|
|
24
|
+
* Random, generated on first use, never leaves the process: only requests this runner injects
|
|
25
|
+
* carry it, so the throttler can tell them from client requests (one package = one request).
|
|
26
|
+
*/
|
|
27
|
+
function offlineInternalToken() {
|
|
28
|
+
if (!processToken)
|
|
29
|
+
processToken = (0, crypto_1.randomBytes)(32).toString("hex");
|
|
30
|
+
return processToken;
|
|
31
|
+
}
|
|
32
|
+
/** True when the headers carry this process's `x-offline-internal` token. */
|
|
33
|
+
function isOfflineInternalRequest(headers) {
|
|
34
|
+
const raw = headers?.[offline_constants_1.OFFLINE_INTERNAL_HEADER];
|
|
35
|
+
const value = Array.isArray(raw) ? raw[0] : raw;
|
|
36
|
+
if (typeof value !== "string" || value.length === 0)
|
|
37
|
+
return false;
|
|
38
|
+
const expected = Buffer.from(offlineInternalToken());
|
|
39
|
+
const given = Buffer.from(value);
|
|
40
|
+
return given.length === expected.length && (0, crypto_1.timingSafeEqual)(given, expected);
|
|
41
|
+
}
|
|
42
|
+
/** Headers of the caller's request carried into every injected step. */
|
|
43
|
+
const FORWARDED_HEADERS = ["authorization", "x-language", "x-companyid"];
|
|
44
|
+
const splitPath = (path) => path.split("/").filter((s) => s.length > 0);
|
|
45
|
+
const firstPath = (value) => (Array.isArray(value) ? String(value[0] ?? "") : String(value ?? ""));
|
|
46
|
+
/**
|
|
47
|
+
* Runs one step of an offline change set through the app's own route with Fastify `inject`,
|
|
48
|
+
* as the caller: the caller's `Authorization`, `x-language` and `x-companyid` headers, plus
|
|
49
|
+
* `x-offline-replay: 1` and the process token. Every read and write therefore goes through
|
|
50
|
+
* the app's controller → service → repository, with its guards, validation and checks.
|
|
51
|
+
*
|
|
52
|
+
* A write (POST/PUT/PATCH/DELETE) runs only when the route that would answer it carries
|
|
53
|
+
* `@OfflineReplayable()`; any other write is refused without running. A GET (reading the
|
|
54
|
+
* current record before a merge) needs no marker: it changes nothing.
|
|
55
|
+
*
|
|
56
|
+
* Infrastructure provider: it owns no entity and touches no Neo4j itself.
|
|
57
|
+
*/
|
|
58
|
+
let OfflineRouteRunner = class OfflineRouteRunner {
|
|
59
|
+
constructor(adapterHost, discovery, metadataScanner, reflector) {
|
|
60
|
+
this.adapterHost = adapterHost;
|
|
61
|
+
this.discovery = discovery;
|
|
62
|
+
this.metadataScanner = metadataScanner;
|
|
63
|
+
this.reflector = reflector;
|
|
64
|
+
}
|
|
65
|
+
async run(params) {
|
|
66
|
+
const url = this.normalise(params.path);
|
|
67
|
+
if (url === undefined)
|
|
68
|
+
return { ran: false, detail: `${params.method} ${params.path} is not a path an offline change set can run` };
|
|
69
|
+
if (params.method !== "GET") {
|
|
70
|
+
const route = this.match(params.method, url.split("?")[0]);
|
|
71
|
+
if (!route?.replayable)
|
|
72
|
+
return { ran: false, detail: `${params.method} ${url} cannot be run from an offline change set` };
|
|
73
|
+
}
|
|
74
|
+
const headers = {};
|
|
75
|
+
const source = (params.request?.headers ?? {});
|
|
76
|
+
for (const name of FORWARDED_HEADERS) {
|
|
77
|
+
const value = source[name];
|
|
78
|
+
if (typeof value === "string" && value.length > 0)
|
|
79
|
+
headers[name] = value;
|
|
80
|
+
}
|
|
81
|
+
headers[offline_constants_1.OFFLINE_REPLAY_HEADER] = "1";
|
|
82
|
+
headers[offline_constants_1.OFFLINE_INTERNAL_HEADER] = offlineInternalToken();
|
|
83
|
+
if (params.body !== undefined)
|
|
84
|
+
headers["content-type"] = "application/json";
|
|
85
|
+
const response = await this.adapterHost.httpAdapter.getInstance().inject({
|
|
86
|
+
method: params.method,
|
|
87
|
+
url,
|
|
88
|
+
headers,
|
|
89
|
+
...(params.body !== undefined ? { payload: params.body } : {}),
|
|
90
|
+
});
|
|
91
|
+
return { ran: true, status: response.statusCode, body: this.parse(response.body) };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* `npcs/n1`, `/npcs/n1` or an absolute URL → `/npcs/n1` (query string kept), with dot segments
|
|
95
|
+
* resolved the way the router resolves them, so the route checked is the route that runs.
|
|
96
|
+
* `undefined` (refused) for a path that climbs above the root, or that carries an encoded dot
|
|
97
|
+
* or separator (`%2e`, `%2f`, `%5c`), which a later decode could turn into another path.
|
|
98
|
+
*/
|
|
99
|
+
normalise(path) {
|
|
100
|
+
const absolute = /^https?:\/\//i.test(path);
|
|
101
|
+
// The path as sent (an absolute URL's pathname is already resolved by URL, so read it raw).
|
|
102
|
+
const raw = (absolute ? path.replace(/^https?:\/\/[^/?#]*/i, "") : path).split(/[?#]/)[0];
|
|
103
|
+
if (/%2e|%2f|%5c/i.test(raw))
|
|
104
|
+
return undefined;
|
|
105
|
+
let depth = 0;
|
|
106
|
+
for (const segment of raw.split(/[\/\\]/)) {
|
|
107
|
+
if (segment === "" || segment === ".")
|
|
108
|
+
continue;
|
|
109
|
+
depth += segment === ".." ? -1 : 1;
|
|
110
|
+
if (depth < 0)
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
const parsed = absolute ? new URL(path) : new URL(`/${path.replace(/^[\/\\]+/, "")}`, "http://internal");
|
|
114
|
+
const pathname = parsed.pathname.replace(/\/{2,}/g, "/");
|
|
115
|
+
return `${pathname}${parsed.search}`;
|
|
116
|
+
}
|
|
117
|
+
parse(body) {
|
|
118
|
+
if (body === undefined || body === "")
|
|
119
|
+
return undefined;
|
|
120
|
+
try {
|
|
121
|
+
return JSON.parse(body);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return body;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The route that answers `method path`, with the router's precedence: a static segment
|
|
129
|
+
* beats a parameter, a parameter beats a wildcard, compared from the first segment.
|
|
130
|
+
*/
|
|
131
|
+
match(method, path) {
|
|
132
|
+
const segments = splitPath(path);
|
|
133
|
+
const rank = (segment) => (segment === "*" ? 0 : segment.startsWith(":") ? 1 : 2);
|
|
134
|
+
const candidates = this.knownRoutes().filter((route) => {
|
|
135
|
+
if (route.method !== method && route.method !== "ALL")
|
|
136
|
+
return false;
|
|
137
|
+
const wildcard = route.segments[route.segments.length - 1] === "*";
|
|
138
|
+
if (!wildcard && route.segments.length !== segments.length)
|
|
139
|
+
return false;
|
|
140
|
+
if (wildcard && segments.length < route.segments.length - 1)
|
|
141
|
+
return false;
|
|
142
|
+
return route.segments.every((segment, index) => segment === "*" || segment.startsWith(":") || segment === segments[index]);
|
|
143
|
+
});
|
|
144
|
+
candidates.sort((a, b) => {
|
|
145
|
+
const length = Math.max(a.segments.length, b.segments.length);
|
|
146
|
+
for (let index = 0; index < length; index++) {
|
|
147
|
+
const diff = rank(b.segments[index] ?? "*") - rank(a.segments[index] ?? "*");
|
|
148
|
+
if (diff !== 0)
|
|
149
|
+
return diff;
|
|
150
|
+
}
|
|
151
|
+
return 0;
|
|
152
|
+
});
|
|
153
|
+
return candidates[0];
|
|
154
|
+
}
|
|
155
|
+
knownRoutes() {
|
|
156
|
+
if (this.routes)
|
|
157
|
+
return this.routes;
|
|
158
|
+
const routes = [];
|
|
159
|
+
for (const wrapper of this.discovery.getControllers()) {
|
|
160
|
+
const controller = wrapper.metatype;
|
|
161
|
+
if (typeof controller !== "function" || !controller.prototype)
|
|
162
|
+
continue;
|
|
163
|
+
const prototype = controller.prototype;
|
|
164
|
+
const controllerPath = firstPath(this.reflector.get(constants_1.PATH_METADATA, controller));
|
|
165
|
+
for (const methodName of this.metadataScanner.getAllMethodNames(prototype)) {
|
|
166
|
+
const handler = prototype[methodName];
|
|
167
|
+
if (typeof handler !== "function")
|
|
168
|
+
continue;
|
|
169
|
+
const requestMethod = this.reflector.get(constants_1.METHOD_METADATA, handler);
|
|
170
|
+
const routePath = this.reflector.get(constants_1.PATH_METADATA, handler);
|
|
171
|
+
if (requestMethod === undefined || routePath === undefined)
|
|
172
|
+
continue;
|
|
173
|
+
routes.push({
|
|
174
|
+
method: common_1.RequestMethod[requestMethod] ?? String(requestMethod),
|
|
175
|
+
segments: [...splitPath(controllerPath), ...splitPath(firstPath(routePath))],
|
|
176
|
+
replayable: this.reflector.get(offline_replayable_decorator_1.OFFLINE_REPLAYABLE_METADATA, handler) === true,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
this.routes = routes;
|
|
181
|
+
return routes;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
exports.OfflineRouteRunner = OfflineRouteRunner;
|
|
185
|
+
exports.OfflineRouteRunner = OfflineRouteRunner = __decorate([
|
|
186
|
+
(0, common_1.Injectable)(),
|
|
187
|
+
__metadata("design:paramtypes", [core_1.HttpAdapterHost,
|
|
188
|
+
core_1.DiscoveryService,
|
|
189
|
+
core_1.MetadataScanner,
|
|
190
|
+
core_1.Reflector])
|
|
191
|
+
], OfflineRouteRunner);
|
|
192
|
+
//# sourceMappingURL=offline-route-runner.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offline-route-runner.service.js","sourceRoot":"","sources":["../../../../src/foundations/offline-change-set/services/offline-route-runner.service.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -16,4 +16,6 @@ export * from "./openapi";
|
|
|
16
16
|
export { RedisLockService } from "./core/redis/services/redis.lock.service";
|
|
17
17
|
export { TRUSTED_ORIGINS_RESOLVER } from "./core/cors/interfaces/trusted-origins.resolver.interface";
|
|
18
18
|
export type { TrustedOriginsResolver } from "./core/cors/interfaces/trusted-origins.resolver.interface";
|
|
19
|
+
export * from "./core/offline";
|
|
20
|
+
export * from "./foundations/offline-change-set";
|
|
19
21
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,cAAc,UAAU,CAAC;AAGzB,cAAc,UAAU,CAAC;AAGzB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAGhC,cAAc,eAAe,CAAC;AAG9B,cAAc,UAAU,CAAC;AAGzB,cAAc,OAAO,CAAC;AAGtB,cAAc,aAAa,CAAC;AAG5B,cAAc,WAAW,CAAC;AAG1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAG5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,2DAA2D,CAAC;AACrG,YAAY,EAAE,sBAAsB,EAAE,MAAM,2DAA2D,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,cAAc,UAAU,CAAC;AAGzB,cAAc,UAAU,CAAC;AAGzB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAGhC,cAAc,eAAe,CAAC;AAG9B,cAAc,UAAU,CAAC;AAGzB,cAAc,OAAO,CAAC;AAGtB,cAAc,aAAa,CAAC;AAG5B,cAAc,WAAW,CAAC;AAG1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAG5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,2DAA2D,CAAC;AACrG,YAAY,EAAE,sBAAsB,EAAE,MAAM,2DAA2D,CAAC;AAGxG,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kCAAkC,CAAC"}
|