@ossy/platform 1.39.0 → 1.39.2
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 +3 -3
- package/package.json +9 -9
- package/src/actions/action.service.js +14 -24
- package/src/server.js +12 -9
- package/src/site-loader.js +1 -1
- package/src/tasks/change-stream.js +2 -1
- package/src/tasks/task-service.js +32 -1
- package/src/test/e2e.util.js +3 -2
- package/src/test/test.util.js +55 -11
- package/src/users.middleware.js +3 -3
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ At startup `@ossy/platform`:
|
|
|
14
14
|
6. Rebuilds all **aggregates** (`*.aggregate.js`) from the event store.
|
|
15
15
|
7. Registers all **actions** (`*.action.js`) with `ActionService`.
|
|
16
16
|
8. Starts an Express server that routes requests to pages (`*.page.jsx`) and API handlers (`*.api.js`).
|
|
17
|
-
9. Auto-mounts every action at `POST /actions
|
|
17
|
+
9. Auto-mounts every action at `POST /actions` (`{ action, payload }`).
|
|
18
18
|
|
|
19
19
|
## Quick start
|
|
20
20
|
|
|
@@ -117,7 +117,7 @@ The platform is built around file conventions called **primitives**. Each primit
|
|
|
117
117
|
| Page | `*.page.jsx` | Routable UI (SSR + hydration) |
|
|
118
118
|
| API | `*.api.js` | HTTP endpoint (any method) |
|
|
119
119
|
| Task | `*.task.js` | Event-driven or scheduled async work |
|
|
120
|
-
| Action | `*.action.js` | Named
|
|
120
|
+
| Action | `*.action.js` | Named intent, auto-exposed at `POST /actions` |
|
|
121
121
|
| Integration | `*.integration.js` | Third-party client connected at startup |
|
|
122
122
|
| Email | `*.email.jsx` | Transactional React email template |
|
|
123
123
|
| Component | `*.component.jsx` | Injectable UI fragment |
|
|
@@ -130,7 +130,7 @@ The platform is built around file conventions called **primitives**. Each primit
|
|
|
130
130
|
```
|
|
131
131
|
Incoming request
|
|
132
132
|
│
|
|
133
|
-
├─ POST /actions
|
|
133
|
+
├─ POST /actions ──► ActionService.invoke() ──► TaskService.invoke() ──► task.run({ payload, sdk, log, integrations, req })
|
|
134
134
|
│
|
|
135
135
|
├─ Match API route ──► api.handle(req, res)
|
|
136
136
|
│
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ossy/platform",
|
|
3
|
-
"version": "1.39.
|
|
3
|
+
"version": "1.39.2",
|
|
4
4
|
"description": "Ossy application server runtime",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -40,13 +40,13 @@
|
|
|
40
40
|
"@aws-sdk/s3-request-presigner": "^3.1057.0",
|
|
41
41
|
"@aws-sdk/util-create-request": "^3.972.26",
|
|
42
42
|
"@aws-sdk/util-format-url": "^3.972.17",
|
|
43
|
-
"@ossy/event-store": "^1.8.
|
|
44
|
-
"@ossy/locale": "^1.40.
|
|
45
|
-
"@ossy/observability": "^1.8.
|
|
46
|
-
"@ossy/policies": "^1.13.
|
|
47
|
-
"@ossy/sdk": "^1.40.
|
|
48
|
-
"@ossy/tokens": "^1.13.
|
|
49
|
-
"@ossy/users": "^1.13.
|
|
43
|
+
"@ossy/event-store": "^1.8.2",
|
|
44
|
+
"@ossy/locale": "^1.40.2",
|
|
45
|
+
"@ossy/observability": "^1.8.2",
|
|
46
|
+
"@ossy/policies": "^1.13.2",
|
|
47
|
+
"@ossy/sdk": "^1.40.2",
|
|
48
|
+
"@ossy/tokens": "^1.13.2",
|
|
49
|
+
"@ossy/users": "^1.13.2",
|
|
50
50
|
"cookie-parser": "^1.4.7",
|
|
51
51
|
"dotenv": ">=16.0.0 <18.0.0",
|
|
52
52
|
"express": ">=5.0.0 <6.0.0",
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"src",
|
|
65
65
|
"Dockerfile"
|
|
66
66
|
],
|
|
67
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "2b8745d57fee8b6c08787e2755b4df489291a5cd"
|
|
68
68
|
}
|
|
@@ -1,65 +1,55 @@
|
|
|
1
1
|
import { createLogger } from '@ossy/observability'
|
|
2
|
+
import { TaskService } from '../tasks/task-service.js'
|
|
2
3
|
|
|
3
4
|
const log = createLogger('platform/actions')
|
|
4
5
|
|
|
5
|
-
/** @type {Map<string, { id: string, access: string
|
|
6
|
+
/** @type {Map<string, { id: string, access: string }>} */
|
|
6
7
|
const _actions = new Map()
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
|
-
* Registry
|
|
10
|
+
* Registry for action intent (`*.action.js` metadata only).
|
|
10
11
|
*
|
|
11
|
-
* Actions
|
|
12
|
-
*
|
|
13
|
-
* - `id` {string} — unique slug, e.g. `'authentication/request-sign-in'`
|
|
14
|
-
* - `access` {string} — `'public'` | `'authenticated'` | `'workspace'` (default `'authenticated'`)
|
|
15
|
-
* - `run` {Function} — async handler receiving `{ payload, sdk, log, integrations, req }`
|
|
12
|
+
* Actions name what callers want: `{ id, access }`. Implementation lives in
|
|
13
|
+
* a task with the same id — see `TaskService.invoke`.
|
|
16
14
|
*/
|
|
17
15
|
export const ActionService = {
|
|
18
16
|
/**
|
|
19
|
-
* Register
|
|
20
|
-
* Validates that `id` is a non-empty string and `run` is a function.
|
|
17
|
+
* Register action intent from a bundled `*.action.js` module.
|
|
21
18
|
*
|
|
22
|
-
* @param {{ id: string, access?: string
|
|
19
|
+
* @param {{ metadata: { id: string, access?: string } }} mod
|
|
23
20
|
*/
|
|
24
21
|
register (mod) {
|
|
25
|
-
const { id,
|
|
22
|
+
const { id, access = 'authenticated' } = mod?.metadata ?? {}
|
|
26
23
|
|
|
27
24
|
if (typeof id !== 'string' || id.trim() === '') {
|
|
28
|
-
throw new Error(`[ActionService] Action module must export a non-empty string "id" (got ${JSON.stringify(id)})`)
|
|
29
|
-
}
|
|
30
|
-
if (typeof run !== 'function') {
|
|
31
|
-
throw new Error(`[ActionService] Action "${id}" must export a "run" function`)
|
|
25
|
+
throw new Error(`[ActionService] Action module must export a non-empty string "metadata.id" (got ${JSON.stringify(id)})`)
|
|
32
26
|
}
|
|
33
27
|
|
|
34
28
|
if (_actions.has(id)) {
|
|
35
29
|
log.warn(`[ActionService] Action "${id}" already registered — overwriting`)
|
|
36
30
|
}
|
|
37
31
|
|
|
38
|
-
_actions.set(id, { id, access
|
|
32
|
+
_actions.set(id, { id, access })
|
|
39
33
|
log.info(`[ActionService] Registered action "${id}" (access: ${access})`)
|
|
40
34
|
},
|
|
41
35
|
|
|
42
36
|
/**
|
|
43
|
-
* Look up a registered action by id. Returns `null` when not found.
|
|
44
|
-
*
|
|
45
37
|
* @param {string} id
|
|
46
|
-
* @returns {{ id: string, access: string
|
|
38
|
+
* @returns {{ id: string, access: string } | null}
|
|
47
39
|
*/
|
|
48
40
|
get (id) {
|
|
49
41
|
return _actions.get(id) ?? null
|
|
50
42
|
},
|
|
51
43
|
|
|
52
44
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* @returns {{ id: string, access: string, run: Function }[]}
|
|
45
|
+
* @returns {{ id: string, access: string }[]}
|
|
56
46
|
*/
|
|
57
47
|
all () {
|
|
58
48
|
return [..._actions.values()]
|
|
59
49
|
},
|
|
60
50
|
|
|
61
51
|
/**
|
|
62
|
-
* Invoke an action by id,
|
|
52
|
+
* Invoke an action by id — enforces registration, delegates execution to TaskService.
|
|
63
53
|
*
|
|
64
54
|
* @param {string} id
|
|
65
55
|
* @param {{ payload?: unknown, sdk?: unknown, log?: unknown, integrations?: unknown, req?: unknown }} context
|
|
@@ -68,6 +58,6 @@ export const ActionService = {
|
|
|
68
58
|
async invoke (id, context = {}) {
|
|
69
59
|
const action = _actions.get(id)
|
|
70
60
|
if (!action) throw new Error(`[ActionService] Action not found: "${id}"`)
|
|
71
|
-
return
|
|
61
|
+
return TaskService.invoke(id, context)
|
|
72
62
|
},
|
|
73
63
|
}
|
package/src/server.js
CHANGED
|
@@ -6,8 +6,8 @@ import morgan from 'morgan'
|
|
|
6
6
|
import { Router as OssyRouter } from '@ossy/router'
|
|
7
7
|
import cookieParser from 'cookie-parser'
|
|
8
8
|
import { ProxyInternal } from './proxy-internal.js'
|
|
9
|
-
import { SDK } from '@ossy/sdk'
|
|
10
|
-
import { AggregateRebuild } from '@ossy/event-store'
|
|
9
|
+
import { SDK, resolveActionId } from '@ossy/sdk'
|
|
10
|
+
import { AggregateRebuild, resolveMongoUrl } from '@ossy/event-store'
|
|
11
11
|
import { TaskService } from './tasks/task-service.js'
|
|
12
12
|
import { ChangeStream } from './tasks/change-stream.js'
|
|
13
13
|
import { CONTENT_SLOT_NAME } from '@ossy/app/runtime/resolve-shell-slots'
|
|
@@ -224,7 +224,7 @@ export async function startServer (options = {}) {
|
|
|
224
224
|
TaskService.startScheduler()
|
|
225
225
|
|
|
226
226
|
if (process.env.DB_URL) {
|
|
227
|
-
ChangeStream.start(process.env.DB_URL)
|
|
227
|
+
ChangeStream.start(resolveMongoUrl(process.env.DB_URL))
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
const pageRouter = OssyRouter.of({
|
|
@@ -261,10 +261,11 @@ export async function startServer (options = {}) {
|
|
|
261
261
|
if (fs.existsSync(publicDir)) app.use(express.static(publicDir))
|
|
262
262
|
app.use(ProxyInternal())
|
|
263
263
|
|
|
264
|
-
// Actions endpoint —
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
264
|
+
// Actions endpoint — POST /actions with body { action, payload }.
|
|
265
|
+
app.post('/actions', async (req, res) => {
|
|
266
|
+
const actionId = resolveActionId(req.body?.action)
|
|
267
|
+
if (!actionId) return res.status(400).json({ error: 'Missing action' })
|
|
268
|
+
|
|
268
269
|
const action = ActionService.get(actionId)
|
|
269
270
|
if (!action) return res.status(404).json({ error: 'Action not found' })
|
|
270
271
|
|
|
@@ -275,10 +276,11 @@ export async function startServer (options = {}) {
|
|
|
275
276
|
return res.status(403).json({ error: 'Forbidden' })
|
|
276
277
|
}
|
|
277
278
|
|
|
279
|
+
const payload = req.body?.payload ?? {}
|
|
278
280
|
const actionLog = createLogger(actionId)
|
|
279
281
|
try {
|
|
280
282
|
const result = await ActionService.invoke(actionId, {
|
|
281
|
-
payload
|
|
283
|
+
payload,
|
|
282
284
|
sdk: req.sdk ?? null,
|
|
283
285
|
log: actionLog,
|
|
284
286
|
integrations: IntegrationService,
|
|
@@ -287,7 +289,8 @@ export async function startServer (options = {}) {
|
|
|
287
289
|
res.json(result ?? { ok: true })
|
|
288
290
|
} catch (err) {
|
|
289
291
|
actionLog.error('Action failed', { id: actionId }, err)
|
|
290
|
-
|
|
292
|
+
const status = err?.status ?? 500
|
|
293
|
+
res.status(status).json({ error: err?.message ?? 'Internal error' })
|
|
291
294
|
}
|
|
292
295
|
})
|
|
293
296
|
|
package/src/site-loader.js
CHANGED
|
@@ -54,7 +54,7 @@ async function collectFiles (sdk, location) {
|
|
|
54
54
|
|
|
55
55
|
while (queue.length > 0) {
|
|
56
56
|
const { location: loc, prefix } = queue.shift()
|
|
57
|
-
const resources = await sdk.
|
|
57
|
+
const resources = await sdk.invoke(ResourcesList, {
|
|
58
58
|
search: new URLSearchParams({ location: loc }).toString(),
|
|
59
59
|
})
|
|
60
60
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TaskService } from './task-service.js'
|
|
2
2
|
import { createLogger } from '@ossy/observability'
|
|
3
|
+
import { resolveMongoUrl } from '@ossy/event-store'
|
|
3
4
|
|
|
4
5
|
const log = createLogger('platform')
|
|
5
6
|
|
|
@@ -25,7 +26,7 @@ export class ChangeStream {
|
|
|
25
26
|
static start(dbUrl) {
|
|
26
27
|
ChangeStream._stopped = false
|
|
27
28
|
ChangeStream._reconnectAttempts = 0
|
|
28
|
-
ChangeStream._dbUrl = dbUrl
|
|
29
|
+
ChangeStream._dbUrl = resolveMongoUrl(dbUrl)
|
|
29
30
|
ChangeStream._open().catch((error) => {
|
|
30
31
|
log.error('[ChangeStream] Change stream could not be opened', undefined, error)
|
|
31
32
|
ChangeStream._scheduleReconnect()
|
|
@@ -13,6 +13,9 @@ export class TaskService {
|
|
|
13
13
|
/** @type {Array<{ metadata: object, handler: function }>} */
|
|
14
14
|
static _tasks = []
|
|
15
15
|
|
|
16
|
+
/** @type {Map<string, { metadata: object, handler: function }>} */
|
|
17
|
+
static _tasksById = new Map()
|
|
18
|
+
|
|
16
19
|
/** @type {ReturnType<typeof setInterval> | null} */
|
|
17
20
|
static _schedulerInterval = null
|
|
18
21
|
|
|
@@ -51,13 +54,41 @@ export class TaskService {
|
|
|
51
54
|
return
|
|
52
55
|
}
|
|
53
56
|
|
|
54
|
-
|
|
57
|
+
const entry = { metadata, handler }
|
|
58
|
+
TaskService._tasks.push(entry)
|
|
59
|
+
if (TaskService._tasksById.has(metadata.id)) {
|
|
60
|
+
_serviceLog.warn(`Task "${metadata.id}" already registered — overwriting`)
|
|
61
|
+
}
|
|
62
|
+
TaskService._tasksById.set(metadata.id, entry)
|
|
55
63
|
_serviceLog.info(
|
|
56
64
|
`Registered task "${metadata.id}" with ${metadata.triggers?.length ?? 0} trigger(s)` +
|
|
57
65
|
(metadata.schedule ? ` and schedule "${metadata.schedule}"` : ''),
|
|
58
66
|
)
|
|
59
67
|
}
|
|
60
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Look up a registered task by id.
|
|
71
|
+
*
|
|
72
|
+
* @param {string} id
|
|
73
|
+
* @returns {{ metadata: object, handler: function } | null}
|
|
74
|
+
*/
|
|
75
|
+
static get(id) {
|
|
76
|
+
return TaskService._tasksById.get(id) ?? null
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Synchronously invoke a task by id (HTTP / sdk.invoke path).
|
|
81
|
+
*
|
|
82
|
+
* @param {string} id
|
|
83
|
+
* @param {{ payload?: unknown, sdk?: unknown, log?: unknown, integrations?: unknown, req?: unknown }} context
|
|
84
|
+
* @returns {Promise<unknown>}
|
|
85
|
+
*/
|
|
86
|
+
static async invoke(id, context = {}) {
|
|
87
|
+
const task = TaskService._tasksById.get(id)
|
|
88
|
+
if (!task) throw new Error(`[TaskService] Task not found: "${id}"`)
|
|
89
|
+
return task.handler(context)
|
|
90
|
+
}
|
|
91
|
+
|
|
61
92
|
/**
|
|
62
93
|
* Dispatches a single event (fullDocument from the changestream) to all
|
|
63
94
|
* registered tasks whose triggers match.
|
package/src/test/e2e.util.js
CHANGED
|
@@ -3,6 +3,7 @@ import { MongoClient } from 'mongodb'
|
|
|
3
3
|
const DB_URL = process.env.DB_URL ?? 'mongodb://localhost:27017/'
|
|
4
4
|
const DB_NAME = process.env.DB_NAME ?? 'ossy-local'
|
|
5
5
|
export const API_URL = process.env.OSSY_API_URL ?? process.env.API_URL ?? 'http://localhost:3001/api/v0'
|
|
6
|
+
export const ACTIONS_URL = API_URL.replace(/\/api\/v0\/?$/, '')
|
|
6
7
|
export const APP_URL = process.env.OSSY_APP_URL ?? process.env.BASE_URL ?? 'http://localhost:3002'
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -80,10 +81,10 @@ export async function signUpAndGetToken(firstName = 'Test', lastName = 'User') {
|
|
|
80
81
|
await client.connect()
|
|
81
82
|
const db = client.db(DB_NAME)
|
|
82
83
|
|
|
83
|
-
const res = await fetch(`${
|
|
84
|
+
const res = await fetch(`${ACTIONS_URL}/actions`, {
|
|
84
85
|
method: 'POST',
|
|
85
86
|
headers: { 'content-type': 'application/json' },
|
|
86
|
-
body: JSON.stringify({ email, firstName, lastName }),
|
|
87
|
+
body: JSON.stringify({ action: 'authentication/sign-up', payload: { email, firstName, lastName } }),
|
|
87
88
|
})
|
|
88
89
|
if (!res.ok) throw new Error(`Sign-up failed with status ${res.status}`)
|
|
89
90
|
|
package/src/test/test.util.js
CHANGED
|
@@ -23,7 +23,13 @@ export function getApiTestBaseUrl() {
|
|
|
23
23
|
return process.env.API_TEST_BASE_URL ?? 'http://localhost:3000/api/v0'
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/** Server root for `POST /actions` (strips `/api/v0` suffix). */
|
|
27
|
+
export function getActionsTestBaseUrl() {
|
|
28
|
+
return getApiTestBaseUrl().replace(/\/api\/v0\/?$/, '')
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
const baseUrl = /* lazy */ () => getApiTestBaseUrl()
|
|
32
|
+
const actionsBaseUrl = /* lazy */ () => getActionsTestBaseUrl()
|
|
27
33
|
|
|
28
34
|
export class TestUtil {
|
|
29
35
|
|
|
@@ -32,6 +38,44 @@ export class TestUtil {
|
|
|
32
38
|
return JSON.stringify({ email, firstName, lastName })
|
|
33
39
|
}
|
|
34
40
|
|
|
41
|
+
static InvokeAction({ actionId, headers = {}, body, payload }) {
|
|
42
|
+
const requestBody = body ?? JSON.stringify({ action: actionId, payload: payload ?? {} })
|
|
43
|
+
return fetch(`${actionsBaseUrl()}/actions`, {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
46
|
+
body: requestBody,
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static AssertActionResponse(test) {
|
|
51
|
+
return TestUtil.InvokeAction(test).then(response => {
|
|
52
|
+
expect(response.status).toBe(test.expectedResponseStatus)
|
|
53
|
+
return response.json()
|
|
54
|
+
.then(data => expect(data).toEqual(test.expectedResponseBody))
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static AssertActionAuthenticationNeeded({ actionId, headers = {}, body, payload }) {
|
|
59
|
+
describe('given no auth token is provided', () => {
|
|
60
|
+
it('must return 401 Unauthorized', async () => {
|
|
61
|
+
const response = await TestUtil.InvokeAction({ actionId, headers, body, payload })
|
|
62
|
+
expect(response.status).toEqual(401)
|
|
63
|
+
await expect(response.json()).resolves.toEqual({ error: 'Unauthorized' })
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static AssertWorkspaceActionAuthenticationNeeded({ actionId, headers = {}, body, payload }) {
|
|
69
|
+
describe('given no auth token is provided', () => {
|
|
70
|
+
it('must return 403 Forbidden', async () => {
|
|
71
|
+
const response = await TestUtil.InvokeAction({ actionId, headers, body, payload })
|
|
72
|
+
expect(response.status).toEqual(403)
|
|
73
|
+
await expect(response.json()).resolves.toEqual({ error: 'Forbidden' })
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** @deprecated Prefer `InvokeAction` for platform actions. Kept for Tier-2 REST APIs (verify-sign-in, sign-off). */
|
|
35
79
|
static AssertResponse(test) {
|
|
36
80
|
return fetch(
|
|
37
81
|
`${baseUrl()}${test.endpoint}`,
|
|
@@ -48,6 +92,7 @@ export class TestUtil {
|
|
|
48
92
|
})
|
|
49
93
|
}
|
|
50
94
|
|
|
95
|
+
/** @deprecated Prefer `InvokeAction`. Kept for Tier-2 REST APIs. */
|
|
51
96
|
static AssertAuthenticationNeeded(request) {
|
|
52
97
|
describe('given no auth token is provided', () => {
|
|
53
98
|
it('must return 401 Unauthorized', async () => {
|
|
@@ -58,6 +103,7 @@ export class TestUtil {
|
|
|
58
103
|
})
|
|
59
104
|
}
|
|
60
105
|
|
|
106
|
+
/** @deprecated Prefer `InvokeAction`. Kept for Tier-2 REST APIs. */
|
|
61
107
|
static MakeRequest(request) {
|
|
62
108
|
return fetch(
|
|
63
109
|
`${baseUrl()}${request.endpoint}`,
|
|
@@ -128,10 +174,10 @@ export class TestUtil {
|
|
|
128
174
|
static GetVerificationToken() {
|
|
129
175
|
const email = `${casual.email}`
|
|
130
176
|
|
|
131
|
-
return
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
)
|
|
177
|
+
return TestUtil.InvokeAction({
|
|
178
|
+
actionId: 'authentication/sign-up',
|
|
179
|
+
body: TestUtil.signUpBody({ email }),
|
|
180
|
+
})
|
|
135
181
|
.then(() => EventStore.FindEvent({
|
|
136
182
|
aggregateType: 'User',
|
|
137
183
|
type: { $in: [ 'SignedUp' ] },
|
|
@@ -142,13 +188,11 @@ export class TestUtil {
|
|
|
142
188
|
|
|
143
189
|
static async GetAuthenticatedTestUser(email = casual.email) {
|
|
144
190
|
|
|
145
|
-
await TestUtil.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
expectedResponseStatus: 200,
|
|
151
|
-
expectedResponseBody: ''
|
|
191
|
+
await TestUtil.AssertActionResponse({
|
|
192
|
+
actionId: 'authentication/sign-up',
|
|
193
|
+
body: TestUtil.signUpBody({ email }),
|
|
194
|
+
expectedResponseStatus: 200,
|
|
195
|
+
expectedResponseBody: { ok: true }
|
|
152
196
|
})
|
|
153
197
|
|
|
154
198
|
const signedUpEvent = await TestUtil.GetEvent({
|
package/src/users.middleware.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { TokenService } from './token.service.js'
|
|
2
2
|
import { createLogger } from '@ossy/observability'
|
|
3
3
|
import { Aggregate } from '@ossy/event-store'
|
|
4
|
-
import { User } from '@ossy/users'
|
|
5
|
-
import { Token } from '@ossy/tokens'
|
|
4
|
+
import { User } from '@ossy/users/server'
|
|
5
|
+
import { Token } from '@ossy/tokens/server'
|
|
6
6
|
import { ConfigService } from './config.service.js'
|
|
7
|
-
import { PoliciesQueries } from '@ossy/policies'
|
|
7
|
+
import { PoliciesQueries } from '@ossy/policies/server'
|
|
8
8
|
|
|
9
9
|
const log = createLogger('users')
|
|
10
10
|
|