core-services-sdk 1.3.7 → 1.3.8

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 (36) hide show
  1. package/package.json +3 -2
  2. package/src/fastify/error-codes.js +11 -0
  3. package/src/http/HttpError.js +84 -10
  4. package/src/http/http.js +41 -31
  5. package/src/http/index.js +4 -0
  6. package/src/http/responseType.js +10 -0
  7. package/src/ids/index.js +2 -0
  8. package/src/index.js +7 -21
  9. package/src/mailer/transport.factory.js +19 -6
  10. package/src/mongodb/initialize-mongodb.js +9 -7
  11. package/src/rabbit-mq/index.js +1 -186
  12. package/src/rabbit-mq/rabbit-mq.js +189 -0
  13. package/src/templates/index.js +1 -0
  14. package/tests/fastify/error-handler.unit.test.js +39 -0
  15. package/tests/{with-error-handling.test.js → fastify/error-handlers/with-error-handling.test.js} +4 -3
  16. package/tests/http/HttpError.unit.test.js +112 -0
  17. package/tests/http/http-method.unit.test.js +29 -0
  18. package/tests/http/http.unit.test.js +167 -0
  19. package/tests/http/responseType.unit.test.js +45 -0
  20. package/tests/ids/prefixes.unit.test.js +1 -0
  21. package/tests/mailer/mailer.integration.test.js +95 -0
  22. package/tests/{mailer.unit.test.js → mailer/mailer.unit.test.js} +7 -11
  23. package/tests/mailer/transport.factory.unit.test.js +204 -0
  24. package/tests/mongodb/connect.unit.test.js +60 -0
  25. package/tests/mongodb/initialize-mongodb.unit.test.js +98 -0
  26. package/tests/mongodb/validate-mongo-uri.unit.test.js +52 -0
  27. package/tests/{rabbit-mq.test.js → rabbit-mq/rabbit-mq.test.js} +3 -2
  28. package/tests/{template-loader.integration.test.js → templates/template-loader.integration.test.js} +1 -1
  29. package/tests/{template-loader.unit.test.js → templates/template-loader.unit.test.js} +1 -1
  30. package/vitest.config.js +3 -0
  31. package/index.js +0 -3
  32. package/tests/HttpError.test.js +0 -80
  33. package/tests/core-util.js +0 -24
  34. package/tests/mailer.integration.test.js +0 -46
  35. package/tests/mongodb.test.js +0 -70
  36. package/tests/transport.factory.unit.test.js +0 -128
@@ -0,0 +1,189 @@
1
+ // @ts-nocheck
2
+ import * as amqp from 'amqplib'
3
+ import { v4 as uuidv4 } from 'uuid'
4
+
5
+ /**
6
+ * @typedef {Object} Log
7
+ * @property {(msg: string) => void} info
8
+ * @property {(msg: string, ...args: any[]) => void} error
9
+ */
10
+
11
+ /**
12
+ * Connects to RabbitMQ server.
13
+ * @param {{ host: string }} options
14
+ * @returns {Promise<amqp.Connection>}
15
+ */
16
+ export const connectQueueService = async ({ host }) => {
17
+ try {
18
+ return await amqp.connect(host)
19
+ } catch (error) {
20
+ console.error('Failed to connect to RabbitMQ:', error)
21
+ throw error
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Creates a channel from RabbitMQ connection.
27
+ * @param {{ host: string }} options
28
+ * @returns {Promise<amqp.Channel>}
29
+ */
30
+ export const createChannel = async ({ host }) => {
31
+ try {
32
+ const connection = /** @type {amqp.Connection} */ (
33
+ await connectQueueService({ host })
34
+ )
35
+ return await connection.createChannel()
36
+ } catch (error) {
37
+ console.error('Failed to create channel:', error)
38
+ throw error
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Parses a RabbitMQ message.
44
+ * @param {amqp.ConsumeMessage} msgInfo
45
+ * @returns {{ msgId: string, data: any }}
46
+ */
47
+ const parseMessage = (msgInfo) => {
48
+ return JSON.parse(msgInfo.content.toString())
49
+ }
50
+
51
+ /**
52
+ * Subscribes to a queue to receive messages.
53
+ *
54
+ * @param {Object} options
55
+ * @param {import('amqplib').Channel} options.channel - RabbitMQ channel
56
+ * @param {string} options.queue - Queue name to subscribe to
57
+ * @param {(data: any) => Promise<void>} options.onReceive - Async handler for incoming message
58
+ * @param {Log} options.log - Logging utility
59
+ * @param {boolean} [options.nackOnError=false] - Whether to nack the message on error (default: false)
60
+ * @param {number} [options.prefetch=1] - Max unacked messages per consumer (default: 1)
61
+ *
62
+ * @returns {Promise<void>}
63
+ */
64
+ export const subscribeToQueue = async ({
65
+ log,
66
+ queue,
67
+ channel,
68
+ prefetch = 1,
69
+ onReceive,
70
+ nackOnError = false,
71
+ }) => {
72
+ try {
73
+ await channel.assertQueue(queue, { durable: true })
74
+
75
+ !!prefetch && (await channel.prefetch(prefetch))
76
+
77
+ channel.consume(queue, async (msgInfo) => {
78
+ if (!msgInfo) return
79
+
80
+ try {
81
+ const { msgId, data } = parseMessage(msgInfo)
82
+ log.info(`Handling message from '${queue}' msgId: ${msgId}`)
83
+ await onReceive(data)
84
+ channel.ack(msgInfo)
85
+ } catch (error) {
86
+ const { msgId } = parseMessage(msgInfo)
87
+ log.error(`Error handling message: ${msgId} on queue '${queue}'`)
88
+ log.error(error)
89
+ nackOnError ? channel.nack(msgInfo) : channel.ack(msgInfo)
90
+ }
91
+ })
92
+ } catch (error) {
93
+ console.error('Failed to subscribe to queue:', error)
94
+ throw error
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Initializes RabbitMQ integration with publish and subscribe support.
100
+ *
101
+ * @param {Object} options
102
+ * @param {string} options.host - RabbitMQ connection URI (e.g., 'amqp://user:pass@localhost:5672')
103
+ * @param {Log} options.log - Logging utility with `info()` and `error()` methods
104
+ *
105
+ * @returns {Promise<{
106
+ * publish: (queue: string, data: any) => Promise<boolean>,
107
+ * subscribe: (options: {
108
+ * queue: string,
109
+ * onReceive: (data: any) => Promise<void>,
110
+ * nackOnError?: boolean
111
+ * }) => Promise<void>,
112
+ * channel: amqp.Channel
113
+ * }>}
114
+ *
115
+ * @example
116
+ * const rabbit = await initializeQueue({ host, log });
117
+ * await rabbit.publish('jobs', { task: 'sendEmail' });
118
+ * await rabbit.subscribe({
119
+ * queue: 'jobs',
120
+ * onReceive: async (data) => { console.log(data); },
121
+ * });
122
+ */
123
+ export const initializeQueue = async ({ host, log }) => {
124
+ const channel = await createChannel({ host })
125
+
126
+ /**
127
+ * Publishes a message to a queue.
128
+ * @param {string} queue
129
+ * @param {any} data
130
+ * @returns {Promise<boolean>}
131
+ */
132
+ const publish = async (queue, data) => {
133
+ const msgId = uuidv4()
134
+ try {
135
+ await channel.assertQueue(queue, { durable: true })
136
+ log.info(`Publishing to '${queue}' msgId: ${msgId}`)
137
+ return channel.sendToQueue(
138
+ queue,
139
+ Buffer.from(JSON.stringify({ msgId, data })),
140
+ )
141
+ } catch (error) {
142
+ log.error(`Error publishing to '${queue}' msgId: ${msgId}`)
143
+ log.error(error)
144
+ throw error
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Subscribes to a queue.
150
+ * @param {{
151
+ * queue: string,
152
+ * onReceive: (data: any) => Promise<void>,
153
+ * nackOnError?: boolean
154
+ * }} options
155
+ * @returns {Promise<void>}
156
+ */
157
+ const subscribe = async ({ queue, onReceive, nackOnError = false }) => {
158
+ return subscribeToQueue({ channel, queue, onReceive, log, nackOnError })
159
+ }
160
+
161
+ return {
162
+ channel,
163
+ publish,
164
+ subscribe,
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Builds RabbitMQ URI from environment variables.
170
+ * @param {{
171
+ * RABBIT_HOST: string,
172
+ * RABBIT_PORT: string | number,
173
+ * RABBIT_USERNAME: string,
174
+ * RABBIT_PASSWORD: string,
175
+ * RABBIT_PROTOCOL?: string
176
+ * }} env
177
+ * @returns {string}
178
+ */
179
+ export const rabbitUriFromEnv = (env) => {
180
+ const {
181
+ RABBIT_HOST,
182
+ RABBIT_PORT,
183
+ RABBIT_USERNAME,
184
+ RABBIT_PASSWORD,
185
+ RABBIT_PROTOCOL = 'amqp',
186
+ } = env
187
+
188
+ return `${RABBIT_PROTOCOL}://${RABBIT_USERNAME}:${RABBIT_PASSWORD}@${RABBIT_HOST}:${RABBIT_PORT}`
189
+ }
@@ -0,0 +1 @@
1
+ export * from './template-loader.js'
@@ -0,0 +1,39 @@
1
+ import httpStatus from 'http-status'
2
+ import { describe, it, expect } from 'vitest'
3
+
4
+ import { GENERAL_ERROR } from '../../src/fastify/error-codes.js'
5
+
6
+ describe('GENERAL_ERROR', () => {
7
+ it('should have correct status code', () => {
8
+ expect(GENERAL_ERROR.httpStatusCode).toBe(httpStatus.INTERNAL_SERVER_ERROR)
9
+ })
10
+
11
+ it('should have correct status text', () => {
12
+ expect(GENERAL_ERROR.httpStatusText).toBe(
13
+ httpStatus[httpStatus.INTERNAL_SERVER_ERROR],
14
+ )
15
+ })
16
+
17
+ it('should have correct code format', () => {
18
+ const expectedCode = `GENERAL.${
19
+ httpStatus[httpStatus.INTERNAL_SERVER_ERROR]
20
+ }`
21
+ expect(GENERAL_ERROR.code).toBe(expectedCode)
22
+ })
23
+
24
+ it('should have all required properties and types', () => {
25
+ expect(typeof GENERAL_ERROR.httpStatusCode).toBe('number')
26
+ expect(typeof GENERAL_ERROR.httpStatusText).toBe('string')
27
+ expect(typeof GENERAL_ERROR.code).toBe('string')
28
+ })
29
+
30
+ it('should match full expected structure', () => {
31
+ const expected = {
32
+ httpStatusCode: 500,
33
+ httpStatusText: 'Internal Server Error',
34
+ code: 'GENERAL.Internal Server Error',
35
+ }
36
+
37
+ expect(GENERAL_ERROR).toEqual(expected)
38
+ })
39
+ })
@@ -1,13 +1,14 @@
1
+ // @ts-nocheck
1
2
  import httpStatus from 'http-status'
2
3
  import { describe, it, expect, vi, beforeEach } from 'vitest'
3
4
 
4
- import { HttpError } from '../src/http/HttpError.js'
5
- import { GENERAL_ERROR } from '../src/fastify/error-codes.js'
5
+ import { HttpError } from '../../../src/http/HttpError.js'
6
+ import { GENERAL_ERROR } from '../../../src/fastify/error-codes.js'
6
7
  import {
7
8
  replyOnErrorOnly,
8
9
  withErrorHandling,
9
10
  withErrorHandlingReply,
10
- } from '../src/fastify/error-handlers/with-error-handling.js'
11
+ } from '../../../src/fastify/error-handlers/with-error-handling.js'
11
12
 
12
13
  describe('withErrorHandling', () => {
13
14
  const log = { error: vi.fn() }
@@ -0,0 +1,112 @@
1
+ import httpStatus from 'http-status'
2
+ import { describe, it, expect } from 'vitest'
3
+
4
+ import { HttpError } from '../../src/http/HttpError.js'
5
+
6
+ describe('HttpError', () => {
7
+ it('should create an instance with custom message, code, and extendInfo', () => {
8
+ const error = new HttpError({
9
+ code: 'INVALID_INPUT',
10
+ message: 'Invalid input provided',
11
+ httpStatusCode: 400,
12
+ extendInfo: { field: 'email', reason: 'missing' },
13
+ })
14
+
15
+ expect(error).toBeInstanceOf(HttpError)
16
+ expect(error.message).toBe('Invalid input provided')
17
+ expect(error.code).toBe('INVALID_INPUT')
18
+ expect(error.httpStatusCode).toBe(400)
19
+ expect(error.httpStatusText).toBe(httpStatus[400])
20
+ expect(error.extendInfo).toEqual({ field: 'email', reason: 'missing' })
21
+ })
22
+
23
+ it('should fallback to default message from status if message is missing', () => {
24
+ const error = new HttpError({
25
+ code: 'BAD_REQUEST',
26
+ httpStatusCode: 400,
27
+ })
28
+
29
+ expect(error.message).toBe(httpStatus[400])
30
+ expect(error.httpStatusText).toBe(httpStatus[400])
31
+ expect(error.extendInfo).toBeUndefined()
32
+ })
33
+
34
+ it('should fallback to code as message if message and status code missing', () => {
35
+ const error = new HttpError({ code: 'ERROR_CODE_ONLY' })
36
+
37
+ expect(error.message).toBe('ERROR_CODE_ONLY')
38
+ expect(error.httpStatusCode).toBeUndefined()
39
+ expect(error.extendInfo).toBeUndefined()
40
+ })
41
+
42
+ it('should fallback to "Unknown error" if no data provided', () => {
43
+ const error = new HttpError()
44
+
45
+ expect(error.message).toBe('Unknown error')
46
+ expect(error.extendInfo).toBeUndefined()
47
+ })
48
+
49
+ it('should return correct JSON representation without extendInfo', () => {
50
+ const error = new HttpError({
51
+ code: 'NOT_FOUND',
52
+ message: 'Resource not found',
53
+ httpStatusCode: 404,
54
+ })
55
+
56
+ expect(error.toJSON()).toEqual({
57
+ code: 'NOT_FOUND',
58
+ message: 'Resource not found',
59
+ httpStatusCode: 404,
60
+ httpStatusText: httpStatus[404],
61
+ })
62
+ })
63
+
64
+ it('should return correct JSON representation with extendInfo', () => {
65
+ const error = new HttpError({
66
+ code: 'NOT_FOUND',
67
+ message: 'Resource not found',
68
+ httpStatusCode: 404,
69
+ extendInfo: { resource: 'user', id: 123 },
70
+ })
71
+
72
+ expect(error.toJSON()).toEqual({
73
+ code: 'NOT_FOUND',
74
+ message: 'Resource not found',
75
+ httpStatusCode: 404,
76
+ httpStatusText: httpStatus[404],
77
+ extendInfo: { resource: 'user', id: 123 },
78
+ })
79
+ })
80
+
81
+ it('should detect instance using isHttpError', () => {
82
+ const error = new HttpError({
83
+ code: 'TEST',
84
+ httpStatusCode: 500,
85
+ })
86
+
87
+ expect(HttpError.isHttpError(error)).toBe(true)
88
+ expect(HttpError.isHttpError(new Error('x'))).toBe(false)
89
+ })
90
+
91
+ it('FromError should return same instance if already HttpError', () => {
92
+ const original = new HttpError({
93
+ code: 'ALREADY_HTTP',
94
+ httpStatusCode: 401,
95
+ })
96
+ const result = HttpError.FromError(original)
97
+
98
+ expect(result).toBe(original)
99
+ })
100
+
101
+ it('FromError should wrap generic Error', () => {
102
+ const err = new Error('Boom!')
103
+ const httpError = HttpError.FromError(err)
104
+
105
+ expect(httpError).toBeInstanceOf(HttpError)
106
+ expect(httpError.message).toBe('Boom!')
107
+ expect(httpError.code).toBe('UNHANDLED_ERROR')
108
+ expect(httpError.httpStatusCode).toBe(500)
109
+ expect(httpError.httpStatusText).toBe(httpStatus[500])
110
+ expect(httpError.extendInfo).toBeUndefined()
111
+ })
112
+ })
@@ -0,0 +1,29 @@
1
+ // @ts-nocheck
2
+ import { describe, it, expect } from 'vitest'
3
+
4
+ import { HTTP_METHODS } from '../../src/http/http-method.js'
5
+
6
+ describe('HTTP_METHODS constant', () => {
7
+ it('should include all standard HTTP methods', () => {
8
+ expect(HTTP_METHODS).toEqual({
9
+ GET: 'GET',
10
+ POST: 'POST',
11
+ PUT: 'PUT',
12
+ PATCH: 'PATCH',
13
+ DELETE: 'DELETE',
14
+ })
15
+ })
16
+
17
+ it('should be frozen (immutable)', () => {
18
+ expect(Object.isFrozen(HTTP_METHODS)).toBe(true)
19
+
20
+ // Attempt to mutate and verify it fails
21
+ try {
22
+ HTTP_METHODS.NEW = 'NEW'
23
+ } catch (err) {
24
+ // Ignore in strict mode
25
+ }
26
+
27
+ expect(HTTP_METHODS).not.toHaveProperty('NEW')
28
+ })
29
+ })
@@ -0,0 +1,167 @@
1
+ import { vi, it, expect, describe, afterEach } from 'vitest'
2
+
3
+ import fetch from 'node-fetch'
4
+ import { http } from '../../src/http/http.js'
5
+ import { HttpError } from '../../src/http/HttpError.js'
6
+ import { HTTP_METHODS } from '../../src/http/http-method.js'
7
+ import { ResponseType } from '../../src/http/responseType.js'
8
+
9
+ vi.mock('node-fetch', async () => {
10
+ const actual = await vi.importActual('node-fetch')
11
+ return {
12
+ ...actual,
13
+ default: vi.fn(),
14
+ }
15
+ })
16
+
17
+ const mockFetch = /** @type {typeof fetch} */ (fetch)
18
+
19
+ const createMockResponse = ({
20
+ body = '',
21
+ status = 200,
22
+ statusText = 'OK',
23
+ headers = {},
24
+ } = {}) => {
25
+ return {
26
+ ok: status >= 200 && status < 300,
27
+ status,
28
+ statusText,
29
+ text: vi.fn().mockResolvedValue(body),
30
+ headers: { get: vi.fn().mockImplementation((k) => headers[k]) },
31
+ }
32
+ }
33
+
34
+ describe('http client', () => {
35
+ afterEach(() => {
36
+ vi.clearAllMocks()
37
+ })
38
+
39
+ describe('GET', () => {
40
+ it('should return parsed JSON response', async () => {
41
+ // @ts-ignore
42
+ mockFetch.mockResolvedValueOnce(
43
+ createMockResponse({ body: JSON.stringify({ hello: 'world' }) }),
44
+ )
45
+
46
+ const result = await http.get({ url: 'http://test.com' })
47
+ expect(result).toEqual({ hello: 'world' })
48
+ expect(mockFetch).toHaveBeenCalledWith(
49
+ 'http://test.com',
50
+ expect.objectContaining({ method: HTTP_METHODS.GET }),
51
+ )
52
+ })
53
+
54
+ it('should throw HttpError on non-2xx status', async () => {
55
+ // @ts-ignore
56
+ mockFetch.mockResolvedValueOnce(
57
+ createMockResponse({
58
+ status: 404,
59
+ statusText: 'Not Found',
60
+ body: JSON.stringify({ error: 'not found' }),
61
+ }),
62
+ )
63
+
64
+ await expect(http.get({ url: 'http://fail.com' })).rejects.toThrow(
65
+ HttpError,
66
+ )
67
+ })
68
+ })
69
+
70
+ describe('POST', () => {
71
+ it('should send a JSON body and return parsed JSON', async () => {
72
+ // @ts-ignore
73
+ mockFetch.mockResolvedValueOnce(
74
+ createMockResponse({ body: JSON.stringify({ ok: true }) }),
75
+ )
76
+
77
+ const result = await http.post({
78
+ url: 'http://test.com',
79
+ body: { test: 123 },
80
+ })
81
+
82
+ expect(result).toEqual({ ok: true })
83
+ expect(mockFetch).toHaveBeenCalledWith(
84
+ 'http://test.com',
85
+ expect.objectContaining({
86
+ method: HTTP_METHODS.POST,
87
+ body: JSON.stringify({ test: 123 }),
88
+ }),
89
+ )
90
+ })
91
+ })
92
+
93
+ describe('PUT', () => {
94
+ it('should send a PUT request and return JSON', async () => {
95
+ // @ts-ignore
96
+ mockFetch.mockResolvedValueOnce(
97
+ createMockResponse({ body: JSON.stringify({ updated: true }) }),
98
+ )
99
+
100
+ const result = await http.put({
101
+ url: 'http://test.com',
102
+ body: { name: 'Updated' },
103
+ })
104
+
105
+ expect(result).toEqual({ updated: true })
106
+ })
107
+ })
108
+
109
+ describe('PATCH', () => {
110
+ it('should send a PATCH request and return JSON', async () => {
111
+ // @ts-ignore
112
+ mockFetch.mockResolvedValueOnce(
113
+ createMockResponse({ body: JSON.stringify({ patched: true }) }),
114
+ )
115
+
116
+ const result = await http.patch({
117
+ url: 'http://test.com',
118
+ body: { field: 'value' },
119
+ })
120
+
121
+ expect(result).toEqual({ patched: true })
122
+ })
123
+ })
124
+
125
+ describe('DELETE', () => {
126
+ it('should send a DELETE request with body and return JSON', async () => {
127
+ // @ts-ignore
128
+ mockFetch.mockResolvedValueOnce(
129
+ createMockResponse({ body: JSON.stringify({ deleted: true }) }),
130
+ )
131
+
132
+ const result = await http.deleteApi({
133
+ url: 'http://test.com',
134
+ body: { id: 1 },
135
+ })
136
+
137
+ expect(result).toEqual({ deleted: true })
138
+ })
139
+ })
140
+
141
+ describe('ResponseType', () => {
142
+ it('should return text if expectedType is text', async () => {
143
+ // @ts-ignore
144
+ mockFetch.mockResolvedValueOnce(createMockResponse({ body: 'hello' }))
145
+
146
+ const result = await http.get({
147
+ url: 'http://test.com',
148
+ expectedType: ResponseType.text,
149
+ })
150
+
151
+ expect(result).toBe('hello')
152
+ })
153
+
154
+ it('should return XML as parsed object if expectedType is xml', async () => {
155
+ const xml = `<note><to>User</to><from>ChatGPT</from></note>`
156
+ // @ts-ignore
157
+ mockFetch.mockResolvedValueOnce(createMockResponse({ body: xml }))
158
+
159
+ const result = await http.get({
160
+ url: 'http://test.com',
161
+ expectedType: ResponseType.xml,
162
+ })
163
+
164
+ expect(result).toHaveProperty('note')
165
+ })
166
+ })
167
+ })
@@ -0,0 +1,45 @@
1
+ // @ts-nocheck
2
+ import { describe, it, expect } from 'vitest'
3
+
4
+ import { ResponseType } from '../../src/http/responseType.js'
5
+
6
+ describe('ResponseType', () => {
7
+ it('should contain correct response type mappings', () => {
8
+ expect(ResponseType).toEqual({
9
+ xml: 'xml',
10
+ json: 'json',
11
+ text: 'text',
12
+ file: 'file',
13
+ })
14
+ })
15
+
16
+ it('should be frozen (immutable)', () => {
17
+ expect(Object.isFrozen(ResponseType)).toBe(true)
18
+
19
+ // Try to add new property
20
+ expect(() => {
21
+ ResponseType.newType = 'something'
22
+ }).toThrow(TypeError)
23
+
24
+ // Try to overwrite existing property
25
+ expect(() => {
26
+ ResponseType.json = 'override'
27
+ }).toThrow(TypeError)
28
+
29
+ // Ensure original value remains unchanged
30
+ expect(ResponseType.json).toBe('json')
31
+ })
32
+
33
+ it('should include expected keys', () => {
34
+ const keys = Object.keys(ResponseType)
35
+ expect(keys).toEqual(['xml', 'json', 'text', 'file'])
36
+ })
37
+
38
+ it('should include expected values', () => {
39
+ const values = Object.values(ResponseType)
40
+ expect(values).toContain('json')
41
+ expect(values).toContain('xml')
42
+ expect(values).toContain('text')
43
+ expect(values).toContain('file')
44
+ })
45
+ })
@@ -12,6 +12,7 @@ describe('ID_PREFIXES', () => {
12
12
  CORRELATION: 'crln',
13
13
  VERIFICATION: 'vrf',
14
14
  ROLE_PERMISSIONS: 'role',
15
+ ONBOARDING: 'onb',
15
16
  })
16
17
  })
17
18