@genesislcap/mock-server 15.51.1 → 15.53.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/README.md +408 -39
- package/dist/db/criteria.d.ts +13 -0
- package/dist/db/criteria.js +60 -21
- package/dist/db/identity.d.ts +11 -0
- package/dist/db/identity.js +46 -0
- package/dist/db/ordering.d.ts +8 -0
- package/dist/db/ordering.js +49 -0
- package/dist/db/schema.d.ts +62 -0
- package/dist/db/schema.js +490 -0
- package/dist/db/store.d.ts +20 -3
- package/dist/db/store.js +300 -50
- package/dist/handlers/commitEvent.js +47 -9
- package/dist/handlers/crudEvents.d.ts +2 -0
- package/dist/handlers/crudEvents.js +138 -0
- package/dist/handlers/dataLogon.js +105 -6
- package/dist/handlers/eventValidation.d.ts +5 -0
- package/dist/handlers/eventValidation.js +29 -0
- package/dist/handlers/jsonSchema.d.ts +4 -2
- package/dist/handlers/jsonSchema.js +222 -61
- package/dist/handlers/meta.d.ts +6 -1
- package/dist/handlers/meta.js +168 -21
- package/dist/handlers/requestReply.js +519 -30
- package/dist/handlers/resourceAuth.d.ts +1 -0
- package/dist/handlers/resourceAuth.js +14 -0
- package/dist/handlers/resources.js +3 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/protocol/connection.d.ts +2 -0
- package/dist/protocol/errors.d.ts +100 -2
- package/dist/protocol/errors.js +300 -12
- package/dist/protocol/fieldTypes.d.ts +10 -0
- package/dist/protocol/fieldTypes.js +107 -0
- package/dist/protocol/gsfSchemas.d.ts +9 -0
- package/dist/protocol/gsfSchemas.js +423 -0
- package/dist/protocol/messageTypes.d.ts +1 -0
- package/dist/protocol/messageTypes.js +1 -0
- package/dist/protocol/msgNack.d.ts +2 -0
- package/dist/protocol/msgNack.js +10 -0
- package/dist/protocol/rowUpdate.d.ts +5 -3
- package/dist/protocol/rowUpdate.js +33 -15
- package/dist/protocol/schemaValidation.d.ts +11 -0
- package/dist/protocol/schemaValidation.js +186 -0
- package/dist/server.js +95 -29
- package/dist/types.d.ts +45 -0
- package/package.json +1 -1
- package/src/db/criteria.ts +72 -21
- package/src/db/identity.ts +53 -0
- package/src/db/ordering.ts +56 -0
- package/src/db/schema.ts +672 -0
- package/src/db/store.ts +343 -50
- package/src/handlers/commitEvent.ts +54 -10
- package/src/handlers/crudEvents.ts +181 -0
- package/src/handlers/dataLogon.ts +127 -7
- package/src/handlers/eventValidation.ts +43 -0
- package/src/handlers/jsonSchema.ts +302 -69
- package/src/handlers/meta.ts +227 -23
- package/src/handlers/requestReply.ts +626 -33
- package/src/handlers/resourceAuth.ts +18 -0
- package/src/handlers/resources.ts +3 -0
- package/src/index.ts +17 -1
- package/src/protocol/connection.ts +10 -2
- package/src/protocol/errors.ts +361 -13
- package/src/protocol/fieldTypes.ts +115 -0
- package/src/protocol/gsfSchemas.ts +505 -0
- package/src/protocol/messageTypes.ts +1 -0
- package/src/protocol/msgNack.ts +12 -0
- package/src/protocol/rowUpdate.ts +40 -20
- package/src/protocol/schemaValidation.ts +208 -0
- package/src/server.ts +106 -28
- package/src/types.ts +187 -5
package/src/types.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
6
6
|
import type { Store } from './db/store.ts';
|
|
7
|
+
import type { NackErrorInput } from './protocol/errors.ts';
|
|
7
8
|
|
|
8
9
|
export type Row = Record<string, any>;
|
|
9
10
|
|
|
@@ -14,6 +15,81 @@ export interface GenesisMessage {
|
|
|
14
15
|
[key: string]: any;
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
// The Genesis dictionary field types (global.genesis.dictionary.Field.Type).
|
|
19
|
+
export type GenesisFieldType =
|
|
20
|
+
| 'STRING'
|
|
21
|
+
| 'ENUM'
|
|
22
|
+
| 'INT'
|
|
23
|
+
| 'SHORT'
|
|
24
|
+
| 'LONG'
|
|
25
|
+
| 'DOUBLE'
|
|
26
|
+
| 'BIGDECIMAL'
|
|
27
|
+
| 'BOOLEAN'
|
|
28
|
+
| 'DATE'
|
|
29
|
+
| 'DATETIME'
|
|
30
|
+
| 'NANO_TIMESTAMP'
|
|
31
|
+
| 'RAW';
|
|
32
|
+
|
|
33
|
+
// One column of a table, as the project's tables dictionary declares it
|
|
34
|
+
// (`field("NAME", STRING(100)).notNull()`). META_REQUEST and
|
|
35
|
+
// JSON_SCHEMA_REQUEST are built from these when a table declares them; see the
|
|
36
|
+
// README's "Declared schema".
|
|
37
|
+
export interface FieldDef {
|
|
38
|
+
name: string;
|
|
39
|
+
type: GenesisFieldType;
|
|
40
|
+
// Default true, as in the dictionary (`.notNull()` makes it false). Primary
|
|
41
|
+
// key and generated fields default to false.
|
|
42
|
+
nullable?: boolean;
|
|
43
|
+
// ENUM values, in dictionary order.
|
|
44
|
+
values?: string[];
|
|
45
|
+
// The dictionary `.default(...)`. A non-null field with a default is
|
|
46
|
+
// optional in event schemas.
|
|
47
|
+
default?: unknown;
|
|
48
|
+
// STRING column size (`STRING(100)`): MAX_LENGTH / maxLength.
|
|
49
|
+
maxSize?: number;
|
|
50
|
+
// `metadata { minLength = 0 }`: MIN_LENGTH / minLength.
|
|
51
|
+
minLength?: number;
|
|
52
|
+
// Replaces the DESCRIPTION / description the real server fills with the
|
|
53
|
+
// field's JVM class (kotlin.String, org.joda.time.DateTime, ...). Leave it
|
|
54
|
+
// unset for DATE/DATETIME: foundation-forms recognises dates partly by that
|
|
55
|
+
// class name.
|
|
56
|
+
description?: string;
|
|
57
|
+
// Defaults to the name in title case ('COUNTERPARTY_ID' -> 'Counterparty Id').
|
|
58
|
+
title?: string;
|
|
59
|
+
// Whether an event payload may leave it out (OPTIONAL, and not in the JSON
|
|
60
|
+
// schema's `required`). The real server makes a field optional only when
|
|
61
|
+
// its class property has a default. Unset: a table field is optional when
|
|
62
|
+
// it is nullable, generated or has a default (the generated DAO defaults
|
|
63
|
+
// all of those); a custom DTO field only when it has a `default` — set
|
|
64
|
+
// `optional: true` for a Kotlin default the metadata can't show, such as
|
|
65
|
+
// `val enabled: Boolean? = true`.
|
|
66
|
+
optional?: boolean;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// A field the database fills on insert when the record leaves it out (a
|
|
70
|
+
// supplied value is kept). Metadata marks it NULLABLE:false, OPTIONAL:true
|
|
71
|
+
// and leaves it out of `required`. A SEQUENCE mints values like the key's
|
|
72
|
+
// sequence (`prefix`, else the table's sequencePrefix, in its
|
|
73
|
+
// sequenceFormat); an AUTO_INCREMENT counts up from the highest seeded value
|
|
74
|
+
// (1 when there is none). A table with `sequencePrefix` gets its key
|
|
75
|
+
// generated as a SEQUENCE without declaring it here.
|
|
76
|
+
export interface GeneratedFieldDef {
|
|
77
|
+
field: string;
|
|
78
|
+
kind: 'SEQUENCE' | 'AUTO_INCREMENT';
|
|
79
|
+
prefix?: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// The verbs of the generic CRUD events (see TableDef.events).
|
|
83
|
+
export type CrudEventVerb = 'INSERT' | 'MODIFY' | 'DELETE';
|
|
84
|
+
|
|
85
|
+
// A table or dataserver-query index (`indices { unique("A") }`). FIELDS is
|
|
86
|
+
// sent space-separated (`'A B'`).
|
|
87
|
+
export interface IndexDef {
|
|
88
|
+
name: string;
|
|
89
|
+
fields: string[];
|
|
90
|
+
unique?: boolean;
|
|
91
|
+
}
|
|
92
|
+
|
|
17
93
|
export interface TableDef {
|
|
18
94
|
// A single field, or several for composite-keyed tables (e.g. PRICE keyed
|
|
19
95
|
// by [RFQ_ID, SIDE]). Composite rows are identified by the fields' values
|
|
@@ -23,9 +99,40 @@ export interface TableDef {
|
|
|
23
99
|
pkField: string | string[];
|
|
24
100
|
sequencePrefix?: string;
|
|
25
101
|
sequenceWidth?: number;
|
|
102
|
+
// How generated pk values look. See SequenceFormat.
|
|
103
|
+
sequenceFormat?: SequenceFormat;
|
|
26
104
|
rows?: Row[];
|
|
105
|
+
// Declared columns, in dictionary order. When present they are the schema:
|
|
106
|
+
// metadata, JSON schemas and dataserver rows follow them (missing values go
|
|
107
|
+
// out as null), even with no rows at all. When absent, field metadata is
|
|
108
|
+
// inferred from the rows (src/db/metadata.ts).
|
|
109
|
+
fields?: FieldDef[];
|
|
110
|
+
generated?: GeneratedFieldDef[];
|
|
111
|
+
// Table indices. The generic CRUD events NACK DUPLICATE_KEY on a unique
|
|
112
|
+
// one, and a unique index over exactly the key fields names the primary
|
|
113
|
+
// key (else '<TABLE>_BY_<fields>'). A dataserver query only reports the
|
|
114
|
+
// indices on its own QueryDef.indexes, as the real dataserver does.
|
|
115
|
+
indexes?: IndexDef[];
|
|
116
|
+
// Registers generic CRUD event handlers for this table —
|
|
117
|
+
// EVENT_<TABLE>_INSERT, EVENT_<TABLE>_MODIFY, EVENT_<TABLE>_DELETE — the
|
|
118
|
+
// ones Genesis Create generates (entityDb.insert / modify / delete, no
|
|
119
|
+
// onValidate): insert the record (generating sequence and auto-increment
|
|
120
|
+
// fields, GENERATED listing them all; DUPLICATE_KEY on a taken key), modify
|
|
121
|
+
// or delete it by its primary key (RECORD_NOT_FOUND), ack VALIDATE without
|
|
122
|
+
// writing, push the change live. They are listed in RESOURCES and described
|
|
123
|
+
// by META_REQUEST / JSON_SCHEMA_REQUEST like any registered event. An
|
|
124
|
+
// eventHandlers entry of the same name wins. See the README's "Generic CRUD
|
|
125
|
+
// events".
|
|
126
|
+
events?: CrudEventVerb[];
|
|
27
127
|
}
|
|
28
128
|
|
|
129
|
+
// 'prefix' (the default): sequencePrefix + a counter padded to sequenceWidth
|
|
130
|
+
// ('TR001'). 'genesis': the platform's id format (genesis-db IdStrategy.java)
|
|
131
|
+
// — the counter padded to 15 digits, the sequence id (sequencePrefix, two
|
|
132
|
+
// characters in a GSF dictionary), then location 'LO' and system '1':
|
|
133
|
+
// '000000000000001TRLO1'.
|
|
134
|
+
export type SequenceFormat = 'prefix' | 'genesis';
|
|
135
|
+
|
|
29
136
|
export interface JoinDef {
|
|
30
137
|
table: string;
|
|
31
138
|
on: [string, string];
|
|
@@ -53,6 +160,16 @@ export interface ViewDef {
|
|
|
53
160
|
joins?: JoinDef[];
|
|
54
161
|
antiJoins?: AntiJoinDef[];
|
|
55
162
|
derived?: Record<string, (row: Row) => any>;
|
|
163
|
+
// Types of the `derived` fields (`derivedField("TOTAL", DOUBLE)`): a type,
|
|
164
|
+
// or a full field definition without its name. Columns from the base table
|
|
165
|
+
// and from `joins[].select` take their declared types from their source
|
|
166
|
+
// tables; a derived field with no entry here is inferred from the rows.
|
|
167
|
+
derivedTypes?: Record<string, GenesisFieldType | Omit<FieldDef, 'name'>>;
|
|
168
|
+
// The view's fields { } block: the only columns it exposes, in this order
|
|
169
|
+
// (base, joined and derived alike). Unset: every base column, then each
|
|
170
|
+
// join's select, then the derived fields. Keep the key fields in it — they
|
|
171
|
+
// are the ROW_REF.
|
|
172
|
+
fields?: string[];
|
|
56
173
|
}
|
|
57
174
|
|
|
58
175
|
// The authenticated identity a resource-level auth hook sees. userName is
|
|
@@ -76,7 +193,17 @@ export interface ResourceAuthDef {
|
|
|
76
193
|
|
|
77
194
|
export interface QueryDef {
|
|
78
195
|
source: string;
|
|
196
|
+
// Overrides the TYPE of named fields, declared or inferred.
|
|
79
197
|
fieldTypes?: Record<string, string>;
|
|
198
|
+
// The query's `fields { }` block: the only columns it exposes, in this
|
|
199
|
+
// order, in rows and in META_REQUEST. Names the source doesn't have are
|
|
200
|
+
// dropped from metadata. RECORD_ID and TIMESTAMP reach dataserver rows only
|
|
201
|
+
// when named here.
|
|
202
|
+
|
|
203
|
+
fields?: string[];
|
|
204
|
+
// The query's `indices { }` block, reported as META_REQUEST INDEXES. With
|
|
205
|
+
// none, INDEXES is the default [{NAME: null, FIELDS: 'RECORD_ID'}].
|
|
206
|
+
indexes?: IndexDef[];
|
|
80
207
|
// Server-side where-clause equivalent, applied before any client
|
|
81
208
|
// CRITERIA_MATCH — to both the DATA_LOGON snapshot and live pushes. Use it
|
|
82
209
|
// for things the real query's filter/where clause does (e.g. keep template
|
|
@@ -100,22 +227,60 @@ export interface RequestReplyDef {
|
|
|
100
227
|
// (`resolver`) — for request servers that calculate rather than read (date
|
|
101
228
|
// calculations, holiday validate/roll, premium schedules, composite
|
|
102
229
|
// lookups). A resolver receives the REQUEST fields and returns the REPLY
|
|
103
|
-
// rows verbatim; throw NackError for a protocol-correct error reply
|
|
104
|
-
// both are set, resolver wins. With resolver only, set
|
|
105
|
-
// representative sample reply) or `fieldTypes` so
|
|
106
|
-
// derive REPLY_FIELD metadata.
|
|
230
|
+
// rows verbatim; throw NackError for a protocol-correct error reply (a
|
|
231
|
+
// MSG_NACK). When both are set, resolver wins. With resolver only, set
|
|
232
|
+
// `metadataRows` (a representative sample reply) or `fieldTypes` so
|
|
233
|
+
// META_REQUEST can still derive REPLY_FIELD metadata.
|
|
107
234
|
source?: string;
|
|
108
235
|
resolver?: (ctx: RequestReplyResolverCtx) => Row[];
|
|
109
236
|
metadataRows?: Row[];
|
|
110
237
|
fieldTypes?: Record<string, string>;
|
|
238
|
+
// The request server's `filter { }` / `where { }` clause. With `filter` or
|
|
239
|
+
// `auth`, a criteria-only server reads past the rows they drop, and
|
|
240
|
+
// NEXT_OFFSET says where it stopped (README: Request servers).
|
|
111
241
|
filter?: (row: Row) => boolean;
|
|
112
242
|
auth?: ResourceAuthDef;
|
|
243
|
+
// `criteriaOnlyRequest = true` in the request server's config. REQUEST must
|
|
244
|
+
// then be present (an object; its fields are ignored), DETAILS.OFFSET pages,
|
|
245
|
+
// DETAILS.ORDER_BY sorts by fields, and every REP_ carries MORE_ROWS (plus
|
|
246
|
+
// NEXT_OFFSET while there are more). META_REQUEST reports REQUEST_FIELD: [],
|
|
247
|
+
// CRITERIA_ONLY_REQUEST: true, SORTABLE_FIELDS and CRITERIA_FIELDS. Without
|
|
248
|
+
// it, REQUEST's fields select rows (exact values, `*` wildcards,
|
|
249
|
+
// FIELD_FROM/FIELD_TO ranges; an array runs each) and OFFSET is ignored.
|
|
250
|
+
// See the README's "Request servers".
|
|
251
|
+
criteriaOnly?: boolean;
|
|
252
|
+
// The request block's fields (REQUEST_FIELD, and the JSON schema's REQUEST).
|
|
253
|
+
// Defaults to the source's primary key, as for a GPAL requestReply(TABLE).
|
|
254
|
+
requestFields?: string[];
|
|
255
|
+
// The reply block (`reply { }` in GPAL): REP_ rows carry exactly these
|
|
256
|
+
// columns, in this order, null when unset, and so do REPLY_FIELD and the JSON
|
|
257
|
+
// schema's REPLY. Names a declared source doesn't have are dropped.
|
|
258
|
+
// RECORD_ID and TIMESTAMP are sent only when named here. Unset: every column
|
|
259
|
+
// of the source followed by RECORD_ID and TIMESTAMP, as GSF sends a table
|
|
260
|
+
// entity. Ignored with a resolver.
|
|
261
|
+
fields?: string[];
|
|
262
|
+
// `config { maxRows = N }`: the most rows a REP_ carries when the request
|
|
263
|
+
// names no DETAILS.MAX_ROWS. Default 10000 (RequestReply.DEFAULT_MAXIMUM_ROWS).
|
|
264
|
+
rowLimit?: number;
|
|
113
265
|
}
|
|
114
266
|
|
|
267
|
+
// How META_REQUEST / JSON_SCHEMA_REQUEST describe an event whose name doesn't
|
|
268
|
+
// follow EVENT_<TABLE>_<VERB>: the table (or view) its DETAILS take, and
|
|
269
|
+
// whether only the key fields are sent (a delete).
|
|
115
270
|
export interface EventSchemaOverride {
|
|
116
271
|
table?: string;
|
|
117
272
|
pkOnly?: boolean;
|
|
118
273
|
fieldTypes?: Record<string, string>;
|
|
274
|
+
// The event's own DETAILS class, for an event that takes a custom DTO
|
|
275
|
+
// (`eventHandler<MyInput>`) rather than a table row. Described as the real
|
|
276
|
+
// server describes a non-table class: no titles, lengths, ranges or
|
|
277
|
+
// genesis types; `nullable`, `default` and `optional` as declared. A
|
|
278
|
+
// nullable field is still mandatory unless it has a default or
|
|
279
|
+
// `optional: true` (Kotlin `val x: T?` must be sent; `val x: T? = null`
|
|
280
|
+
// needn't be). `table` then only names where its ENUM columns come from.
|
|
281
|
+
fields?: FieldDef[];
|
|
282
|
+
// The DTO's class name, reported as the event's DESCRIPTION.
|
|
283
|
+
className?: string;
|
|
119
284
|
}
|
|
120
285
|
|
|
121
286
|
export interface ResourceItem {
|
|
@@ -179,9 +344,19 @@ export interface EventHandlerCtx {
|
|
|
179
344
|
message: GenesisMessage;
|
|
180
345
|
broadcast: BroadcastFn;
|
|
181
346
|
broadcastTableChange: BroadcastTableChangeFn;
|
|
347
|
+
// `VALIDATE: true` on the message: the client asks whether the event would
|
|
348
|
+
// succeed. GSF then runs only the handler's onValidate and answers its NACK,
|
|
349
|
+
// or an EVENT_ACK with GENERATED: [] — nothing is written. A handler that
|
|
350
|
+
// writes should run its checks and return before writing when this is set;
|
|
351
|
+
// the generic CRUD events do.
|
|
352
|
+
validate: boolean;
|
|
182
353
|
}
|
|
183
354
|
|
|
184
|
-
|
|
355
|
+
// `warnings` turns the reply into an EVENT_NACK carrying them in WARNING
|
|
356
|
+
// (with an empty ERROR), as a GSF handler's warning-only EventNack does.
|
|
357
|
+
// Return them from a handler that has not written anything yet: the mock has
|
|
358
|
+
// no transaction to roll back, and doesn't honour IGNORE_WARNINGS yet.
|
|
359
|
+
export type EventHandlerResult = { generated?: Row[]; warnings?: NackErrorInput[] } | void;
|
|
185
360
|
|
|
186
361
|
export type EventHandler = (details: Row, ctx: EventHandlerCtx) => EventHandlerResult;
|
|
187
362
|
|
|
@@ -245,11 +420,18 @@ export interface MockServerConfig {
|
|
|
245
420
|
httpRoutes?: HttpRouteDef[];
|
|
246
421
|
onMessage?: OnMessageHook;
|
|
247
422
|
productName?: string;
|
|
423
|
+
// The Genesis application name, as in the generated enum classes the real
|
|
424
|
+
// server names in event metadata
|
|
425
|
+
// (global.genesis.gen.dao.enums.<appName>.<table>.<Field>). Unset: the
|
|
426
|
+
// segment is left out. Nothing a client does depends on it.
|
|
427
|
+
appName?: string;
|
|
248
428
|
}
|
|
249
429
|
|
|
430
|
+
// A META_REQUEST FIELD / REQUEST_FIELD / REPLY_FIELD entry.
|
|
250
431
|
export interface FieldMetadata {
|
|
251
432
|
NAME: string;
|
|
252
433
|
TYPE: string;
|
|
434
|
+
VALID_VALUES?: string[];
|
|
253
435
|
}
|
|
254
436
|
|
|
255
437
|
// Minimal shape both `ws`'s WebSocket and Bun's ServerWebSocket satisfy —
|