@lucaapp/service-utils 5.30.0 → 5.32.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.
@@ -13,6 +13,17 @@ type ApiConstructorOptions = {
13
13
  * stays hidden. Routing is unaffected; this only controls documentation.
14
14
  */
15
15
  hidden?: boolean;
16
+ /**
17
+ * Paths kept out of the generated OpenAPI spec, matched against the full
18
+ * registered path including the prefix. A string must match exactly; a
19
+ * RegExp is tested against it. Inherited by children.
20
+ *
21
+ * This is the central place to keep routes undocumented, so the decision
22
+ * lives in one list next to the Api rather than spread across the route
23
+ * files it applies to. `hidden` on a single endpoint does the same thing at
24
+ * the definition site; prefer this list when the routes share a reason.
25
+ */
26
+ excludeFromSpec?: ReadonlyArray<string | RegExp>;
16
27
  openApiVersion?: OpenApiVersion;
17
28
  apiVersion?: string;
18
29
  apiTitle?: string;
@@ -39,6 +50,7 @@ export declare class Api {
39
50
  debug: boolean;
40
51
  tags: string[];
41
52
  private hidden;
53
+ private excludeFromSpec;
42
54
  constructor(options?: ApiConstructorOptions);
43
55
  child(options: ApiChildOptions): Api;
44
56
  get<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBodySchema extends ZodObjectSchemaOrUndefined = undefined, TRequestParamsSchema extends ZodObjectSchemaOrUndefined = undefined, TRequestQuerySchema extends ZodObjectSchemaOrUndefined = undefined, TRequestHeadersSchema extends ZodObjectSchemaOrUndefined = undefined, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined = undefined>(path: string, summary: string, options: EndpointOptions<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>): void;
@@ -31,6 +31,7 @@ class Api {
31
31
  this.debug = options.debug || false;
32
32
  this.tags = options.tags || [];
33
33
  this.hidden = options.hidden || false;
34
+ this.excludeFromSpec = options.excludeFromSpec || [];
34
35
  this.router.use(body_parser_1.default.json({ verify: rawBodySaver, limit: '2mb' }));
35
36
  }
36
37
  child(options) {
@@ -42,29 +43,30 @@ class Api {
42
43
  router: this.router,
43
44
  // Once hidden, always hidden: a child cannot re-expose its parent's tree.
44
45
  hidden: this.hidden || options.hidden || false,
46
+ excludeFromSpec: this.excludeFromSpec,
45
47
  });
46
48
  child.rootPrefixPath = this.rootPrefixPath;
47
49
  return child;
48
50
  }
49
51
  get(path, summary, options, handler) {
50
52
  (0, endpoint_1.mountEndpoint)(this.router, 'get', path, options, handler, this.debug);
51
- (0, openapi_1.registerEndpoint)(this.registry, 'get', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug, this.hidden);
53
+ (0, openapi_1.registerEndpoint)(this.registry, 'get', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug, this.hidden, this.excludeFromSpec);
52
54
  }
53
55
  post(path, summary, options, handler) {
54
56
  (0, endpoint_1.mountEndpoint)(this.router, 'post', path, options, handler, this.debug);
55
- (0, openapi_1.registerEndpoint)(this.registry, 'post', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug, this.hidden);
57
+ (0, openapi_1.registerEndpoint)(this.registry, 'post', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug, this.hidden, this.excludeFromSpec);
56
58
  }
57
59
  patch(path, summary, options, handler) {
58
60
  (0, endpoint_1.mountEndpoint)(this.router, 'patch', path, options, handler, this.debug);
59
- (0, openapi_1.registerEndpoint)(this.registry, 'patch', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug, this.hidden);
61
+ (0, openapi_1.registerEndpoint)(this.registry, 'patch', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug, this.hidden, this.excludeFromSpec);
60
62
  }
61
63
  put(path, summary, options, handler) {
62
64
  (0, endpoint_1.mountEndpoint)(this.router, 'put', path, options, handler, this.debug);
63
- (0, openapi_1.registerEndpoint)(this.registry, 'put', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug, this.hidden);
65
+ (0, openapi_1.registerEndpoint)(this.registry, 'put', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug, this.hidden, this.excludeFromSpec);
64
66
  }
65
67
  delete(path, summary, options, handler) {
66
68
  (0, endpoint_1.mountEndpoint)(this.router, 'delete', path, options, handler, this.debug);
67
- (0, openapi_1.registerEndpoint)(this.registry, 'delete', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug, this.hidden);
69
+ (0, openapi_1.registerEndpoint)(this.registry, 'delete', this.prefixPath, this.rootPrefixPath, path, summary, options, this.tags, this.debug, this.hidden, this.excludeFromSpec);
68
70
  }
69
71
  generateOpenAPISpec() {
70
72
  let generator;
@@ -25,5 +25,5 @@ export declare const hoistCombinatorRequiredFields: (spec: {
25
25
  schemas?: Record<string, unknown>;
26
26
  };
27
27
  }) => void;
28
- export declare const registerEndpoint: (registry: OpenAPIRegistry, method: HttpMethod, prefixPath: string, rootPrefixPath: string, path: string, summary: string, options: EndpointOptions<any, any, any, any, any, any>, tags: string[], debug: boolean, hiddenApi?: boolean) => void;
28
+ export declare const registerEndpoint: (registry: OpenAPIRegistry, method: HttpMethod, prefixPath: string, rootPrefixPath: string, path: string, summary: string, options: EndpointOptions<any, any, any, any, any, any>, tags: string[], debug: boolean, hiddenApi?: boolean, excludeFromSpec?: ReadonlyArray<string | RegExp>) => void;
29
29
  export {};
@@ -227,11 +227,16 @@ const hoistCombinatorRequiredFields = (spec) => {
227
227
  exports.hoistCombinatorRequiredFields = hoistCombinatorRequiredFields;
228
228
  const registerEndpoint = (registry, method, prefixPath, rootPrefixPath, path, summary,
229
229
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
230
- options, tags, debug, hiddenApi = false) => {
230
+ options, tags, debug, hiddenApi = false, excludeFromSpec = []) => {
231
231
  // Hidden endpoints are never registered, so they leave no path, no
232
232
  // operationId and no security behind. Checked before any schema work: there
233
233
  // is nothing to build for an operation that will not be published.
234
- if (hiddenApi || options.hidden) {
234
+ //
235
+ // The exclusion list is matched against the same path string the spec would
236
+ // have used, so an entry can be copied straight out of a generated spec.
237
+ const specPath = mapExpressParamsToOpenAPIParams(prefixPath + path);
238
+ const excluded = excludeFromSpec.some(pattern => typeof pattern === 'string' ? pattern === specPath : pattern.test(specPath));
239
+ if (hiddenApi || options.hidden || excluded) {
235
240
  return;
236
241
  }
237
242
  let bodySchema = options.schemas?.body || undefined;
@@ -0,0 +1,48 @@
1
+ import { SupportedCurrencies } from '../../money/supportedCurrencies';
2
+ export declare const ORDER_EVENT_VERSION = 1;
3
+ export type OrderEventVersion = typeof ORDER_EVENT_VERSION;
4
+ /**
5
+ * luca-web order types mirrored to downstream consumers (LUCA-36037).
6
+ * String-typed on the wire to stay decoupled from backend-pay's OrderType enum;
7
+ * these are the currently-produced values.
8
+ */
9
+ export type OrderEventType = 'HOTEL_SPECIAL_OFFER' | 'HOTEL_MINI_BAR' | 'IN_ROOM_ORDER' | 'QR_CODE_ORDER' | 'SELF_SERVICE_SHOP_ORDER' | 'PRE_ORDER' | 'TERMINAL_ORDER';
10
+ export type OrderEventStatus = 'OPEN' | 'PAID' | 'REFUNDED';
11
+ /**
12
+ * Localised display text keyed by locale; `de` is always present.
13
+ * Mirrors the menu snapshot backend-pay stores on the order line.
14
+ */
15
+ export type OrderEventTranslatableName = {
16
+ de: string;
17
+ en?: string;
18
+ [locale: string]: string | undefined;
19
+ };
20
+ export type OrderEventItem = {
21
+ name: OrderEventTranslatableName;
22
+ quantity: number;
23
+ /** Unit price in minor units (cents). */
24
+ price: number;
25
+ /** VAT rate in percent, when known. */
26
+ tax?: number;
27
+ subItems?: OrderEventItem[];
28
+ };
29
+ /**
30
+ * Emitted by backend-pay when a luca-web order is created (LUCA-36037).
31
+ * Carries the full order snapshot so consumers can mirror it without a callback.
32
+ */
33
+ export type OrderEvent = {
34
+ version: OrderEventVersion;
35
+ uuid: string;
36
+ orderRef: string;
37
+ type: OrderEventType | null;
38
+ status: OrderEventStatus;
39
+ locationId: string;
40
+ locationGroupId: string;
41
+ currency: SupportedCurrencies;
42
+ /** Invoice total in minor units (cents). */
43
+ invoiceAmount: number;
44
+ table: string | null;
45
+ note: string | null;
46
+ createdAt: Date;
47
+ items: OrderEventItem[];
48
+ };
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ORDER_EVENT_VERSION = void 0;
4
+ exports.ORDER_EVENT_VERSION = 1;
@@ -70,6 +70,12 @@ export type PaymentEvent = {
70
70
  paymentVerifier: string;
71
71
  checkoutId?: string;
72
72
  orderId?: string;
73
+ /**
74
+ * backend-pay Orders.uuid[] linked to this payment's checkout (LUCA-36037).
75
+ * Distinct from the singular `orderId` (the luca-POS order id). A checkout can
76
+ * cover multiple orders, so this is a list. Absent for non-web payments.
77
+ */
78
+ payOrderIds?: string[] | null;
73
79
  statusCompleteAt?: Date | null;
74
80
  merchantDetails?: PaymentMerchantDetails;
75
81
  } & PaymentEventCardAcquirerFields;
@@ -27,4 +27,6 @@ export type RefundEvent = {
27
27
  checkoutId?: string | null;
28
28
  /** Payment method of the original payment (e.g. CARD). */
29
29
  method?: string | null;
30
+ /** Optional on the wire for in-flight events produced before this field existed. */
31
+ reason?: string | null;
30
32
  };
@@ -1,4 +1,5 @@
1
1
  import type { Payment, PaymentEvent } from './events/payment';
2
+ import type { OrderEvent } from './events/order';
2
3
  import type { RefundEvent } from './events/refund';
3
4
  import type { Consumer } from './events/consumer';
4
5
  import type { Operator } from './events/operator';
@@ -20,6 +21,7 @@ import { TokenizationJobItem } from './events/tokenizationJobItem';
20
21
  import { Organization, OperatorOrganization } from '../../types/organization';
21
22
  declare enum KafkaTopic {
22
23
  PAYMENTS = "payments",
24
+ ORDERS = "orders",
23
25
  REFUNDS = "refunds",
24
26
  CONSUMERS = "consumers",
25
27
  OPERATORS = "operators",
@@ -44,6 +46,7 @@ declare enum KafkaTopic {
44
46
  }
45
47
  type MessageFormats = {
46
48
  [KafkaTopic.PAYMENTS]: Payment | PaymentEvent;
49
+ [KafkaTopic.ORDERS]: OrderEvent;
47
50
  [KafkaTopic.REFUNDS]: RefundEvent;
48
51
  [KafkaTopic.CONSUMERS]: Consumer;
49
52
  [KafkaTopic.OPERATORS]: Operator;
@@ -68,6 +71,7 @@ type MessageFormats = {
68
71
  };
69
72
  declare const MessageIssuer: {
70
73
  payments: Service;
74
+ orders: Service;
71
75
  refunds: Service;
72
76
  consumers: Service;
73
77
  operators: Service;
@@ -5,6 +5,7 @@ const serviceIdentity_1 = require("../serviceIdentity");
5
5
  var KafkaTopic;
6
6
  (function (KafkaTopic) {
7
7
  KafkaTopic["PAYMENTS"] = "payments";
8
+ KafkaTopic["ORDERS"] = "orders";
8
9
  KafkaTopic["REFUNDS"] = "refunds";
9
10
  KafkaTopic["CONSUMERS"] = "consumers";
10
11
  KafkaTopic["OPERATORS"] = "operators";
@@ -29,6 +30,7 @@ var KafkaTopic;
29
30
  })(KafkaTopic || (exports.KafkaTopic = KafkaTopic = {}));
30
31
  const MessageIssuer = {
31
32
  [KafkaTopic.PAYMENTS]: serviceIdentity_1.Service.BACKEND_PAY,
33
+ [KafkaTopic.ORDERS]: serviceIdentity_1.Service.BACKEND_PAY,
32
34
  [KafkaTopic.REFUNDS]: serviceIdentity_1.Service.BACKEND_PAY,
33
35
  [KafkaTopic.CONSUMERS]: serviceIdentity_1.Service.BACKEND,
34
36
  [KafkaTopic.OPERATORS]: serviceIdentity_1.Service.BACKEND,
@@ -54,5 +56,6 @@ const MessageIssuer = {
54
56
  exports.MessageIssuer = MessageIssuer;
55
57
  const MessageSignatureIssuers = {
56
58
  [KafkaTopic.PAYMENTS]: [serviceIdentity_1.Service.BACKEND_PAY, serviceIdentity_1.Service.BACKEND_TSE],
59
+ [KafkaTopic.ORDERS]: [serviceIdentity_1.Service.BACKEND_PAY],
57
60
  };
58
61
  exports.MessageSignatureIssuers = MessageSignatureIssuers;
@@ -3,4 +3,6 @@ export { KafkaTopic } from './events';
3
3
  export type { ConversationMessage } from './events/conversationMessage';
4
4
  export type { RefundEvent } from './events/refund';
5
5
  export { REFUND_EVENT_VERSION } from './events/refund';
6
+ export type { OrderEvent, OrderEventItem, OrderEventType, OrderEventStatus, OrderEventTranslatableName, } from './events/order';
7
+ export { ORDER_EVENT_VERSION } from './events/order';
6
8
  export type { KafkaEvent, GenericKafkaEvent, EventPayloadHandler, GenericEventPayloadHandler, KafkaConfiguration, CustomTopicConfig, CustomTopicPoisonContext, CustomTopicPoisonHandler, } from './types';
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.REFUND_EVENT_VERSION = exports.KafkaTopic = exports.KafkaClient = void 0;
3
+ exports.ORDER_EVENT_VERSION = exports.REFUND_EVENT_VERSION = exports.KafkaTopic = exports.KafkaClient = void 0;
4
4
  var kafkaClient_1 = require("./kafkaClient");
5
5
  Object.defineProperty(exports, "KafkaClient", { enumerable: true, get: function () { return kafkaClient_1.KafkaClient; } });
6
6
  var events_1 = require("./events");
7
7
  Object.defineProperty(exports, "KafkaTopic", { enumerable: true, get: function () { return events_1.KafkaTopic; } });
8
8
  var refund_1 = require("./events/refund");
9
9
  Object.defineProperty(exports, "REFUND_EVENT_VERSION", { enumerable: true, get: function () { return refund_1.REFUND_EVENT_VERSION; } });
10
+ var order_1 = require("./events/order");
11
+ Object.defineProperty(exports, "ORDER_EVENT_VERSION", { enumerable: true, get: function () { return order_1.ORDER_EVENT_VERSION; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucaapp/service-utils",
3
- "version": "5.30.0",
3
+ "version": "5.32.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [
@@ -105,7 +105,7 @@
105
105
  "fast-xml-builder": "^1.1.7",
106
106
  "brace-expansion": "2.1.4",
107
107
  "form-data": "4.0.6",
108
- "js-yaml": "4.3.1",
108
+ "js-yaml": "4.3.2",
109
109
  "@opentelemetry/core": "2.8.0"
110
110
  }
111
111
  }