@owlmeans/server-app 0.1.18-rc.20 → 0.1.18-rc.22
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 +17 -73
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/server-app/SKILL.md +29 -199
- package/build/entrypoints.d.ts +2 -1
- package/build/entrypoints.d.ts.map +1 -1
- package/build/entrypoints.js +4 -3
- package/build/entrypoints.js.map +1 -1
- package/build/exports.d.ts +9 -6
- package/build/exports.d.ts.map +1 -1
- package/build/exports.js +7 -4
- package/build/exports.js.map +1 -1
- package/build/index.d.ts +0 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +0 -1
- package/build/index.js.map +1 -1
- package/package.json +16 -16
- package/src/entrypoints.ts +4 -3
- package/src/exports.ts +9 -6
- package/src/index.ts +0 -1
- package/build/boot-state.d.ts +0 -55
- package/build/boot-state.d.ts.map +0 -1
- package/build/boot-state.js +0 -46
- package/build/boot-state.js.map +0 -1
- package/src/boot-state.ts +0 -78
package/README.md
CHANGED
|
@@ -6,7 +6,6 @@ The main entry point for OwlMeans backend services — aggregates server package
|
|
|
6
6
|
|
|
7
7
|
- `makeContext(cfg)` creates a fully initialized server context with Fastify, auth, WebSocket, and static resource support
|
|
8
8
|
- `main(ctx, entrypoints)` registers entrypoints, initializes the context, and starts the HTTP server
|
|
9
|
-
- `holdApiPort` + the boot-state module give a bind-first boot: the port answers for the app before it initializes
|
|
10
9
|
- Re-exports the most commonly used symbols from lower-level packages so backend code has a single import target
|
|
11
10
|
- Used by every service in the viable monorepo
|
|
12
11
|
|
|
@@ -34,56 +33,19 @@ const context = makeContext(appConfig)
|
|
|
34
33
|
await main(context, [...entrypoints, ...appEntrypoints])
|
|
35
34
|
```
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
Bind a shared protocol with a handler:
|
|
38
37
|
|
|
39
38
|
```typescript
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
`main()` is the short path. An app that must explain a **failed** boot binds the port first instead,
|
|
51
|
-
so a startup failure has somewhere to be reported from — without a listener the edge answers a bare
|
|
52
|
-
connect error that names neither the app nor the cause:
|
|
53
|
-
|
|
54
|
-
```typescript
|
|
55
|
-
import { holdApiPort, bootHold, setBootPhase, bootHealthPayload } from '@owlmeans/server-app'
|
|
56
|
-
|
|
57
|
-
const hold = await holdApiPort(ctx.cfg, bootHold(HEALTH_PATH)).catch((error: Error) => {
|
|
58
|
-
// A failure to BIND is fatal: carried past, the boot ends with nothing listening and exits 0
|
|
59
|
-
// while a predecessor keeps serving stale code. Exit non-zero so a supervisor reclaims the port.
|
|
60
|
-
console.error(`[boot] STARTUP FAILED — ${error.message}`)
|
|
61
|
-
process.exit(1)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
try {
|
|
65
|
-
await ctx.configure().init()
|
|
66
|
-
} catch (error) {
|
|
67
|
-
// Stay alive: the hold is the only thing that can explain why nothing is serving.
|
|
68
|
-
setBootPhase('failed', (error as Error).message)
|
|
69
|
-
return
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
await hold.release() // awaited — `listen()` throws while a predecessor holds the socket
|
|
73
|
-
setBootPhase('ready')
|
|
74
|
-
await ctx.getApiServer().listen()
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
The hold answers `HEALTH_PATH` with `bootHealthPayload()` and everything else with **503** (not 404
|
|
78
|
-
— the real routes do not exist yet). Once the app's own server takes the socket, its health handler
|
|
79
|
-
spreads the same `bootHealthPayload()` into its answer, so a consumer polling across the handover
|
|
80
|
-
never sees the body change under it:
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
export const handleHealtz = handleRequest(async (_req, ctx) => ({
|
|
84
|
-
...bootHealthPayload(),
|
|
85
|
-
db: await pingDb(ctx)
|
|
86
|
-
}))
|
|
39
|
+
import { bind } from '@owlmeans/server-entrypoint'
|
|
40
|
+
import { handlers } from '@owlmeans/server-api'
|
|
41
|
+
import { appEntrypoints as protocols } from 'my-app-common'
|
|
42
|
+
import type { Context } from 'my-app-backend'
|
|
43
|
+
|
|
44
|
+
const api = handlers<Context>()
|
|
45
|
+
const appEntrypoints = [
|
|
46
|
+
bind(protocols.api.projectCreate, api.request(protocols.api.projectCreate, async (req, ctx) =>
|
|
47
|
+
(ctx as Context).project().create(req.body))),
|
|
48
|
+
]
|
|
87
49
|
```
|
|
88
50
|
|
|
89
51
|
## API
|
|
@@ -96,30 +58,12 @@ Creates a server context with Fastify HTTP, WebSocket, static resources, and aut
|
|
|
96
58
|
|
|
97
59
|
Registers entrypoints, calls `configure().init()`, then starts the Fastify server.
|
|
98
60
|
|
|
99
|
-
### Boot state
|
|
100
|
-
|
|
101
|
-
Process-wide boot phase, shared by the port hold and the app's own health handler.
|
|
102
|
-
|
|
103
|
-
| Symbol | Description |
|
|
104
|
-
|---|---|
|
|
105
|
-
| `setBootPhase(phase, detail?)` | Record the phase; `detail` is free text kept for every phase |
|
|
106
|
-
| `getBootPhase(): BootPhase` / `getBootDetail()` | Current phase and its detail |
|
|
107
|
-
| `bootHealthPayload(): BootHealth` | `{ status, phase, ok, reason?, bootId, pid }` — the health body |
|
|
108
|
-
| `bootHold(okPath?): ApiPortHoldOptions` | `holdApiPort` options wired to this module |
|
|
109
|
-
| `BootPhase` | `'initializing' \| 'ready' \| 'failed'` |
|
|
110
|
-
| `BOOT_ID_ENV` | `'OWLMEANS_BOOT_ID'` — a supervisor stamps the child, `bootId` echoes it back |
|
|
111
|
-
|
|
112
|
-
`bootId` is identity, not health: an answer carrying an id other than the one the supervisor spawned
|
|
113
|
-
means a leftover process still owns the port and the health it reports describes code nobody asked
|
|
114
|
-
for.
|
|
115
|
-
|
|
116
61
|
### Re-exported symbols (for convenience)
|
|
117
62
|
|
|
118
63
|
| Symbol | Source |
|
|
119
64
|
|---|---|
|
|
120
|
-
| `
|
|
121
|
-
| `
|
|
122
|
-
| `celevate` | `@owlmeans/client-entrypoint` |
|
|
65
|
+
| `handlers` | `@owlmeans/server-api` |
|
|
66
|
+
| `bind`, `bindAll`, `guard` | `@owlmeans/server-entrypoint` |
|
|
123
67
|
| `route` | `@owlmeans/route` |
|
|
124
68
|
| `broute` | `@owlmeans/server-route` |
|
|
125
69
|
| `filter`, `body`, `params`, `EntrypointOutcome` | `@owlmeans/entrypoint` |
|
|
@@ -129,7 +73,7 @@ for.
|
|
|
129
73
|
| `GUARD_ED25519`, `BED255_CASHE_RESOURCE` | `@owlmeans/auth-common` |
|
|
130
74
|
| `klusterize` | `@owlmeans/kluster` |
|
|
131
75
|
| `createListSchema`, `filterObject` | `@owlmeans/resource` |
|
|
132
|
-
| `Request`, `Response`, `
|
|
76
|
+
| `Request`, `Response`, `RefedEntrypointHandler` | type re-exports |
|
|
133
77
|
| `Criteria`, `ListOptions`, `ListQuery`, `ListResult`, `Sort` | type re-exports from `@owlmeans/resource` |
|
|
134
78
|
|
|
135
79
|
### `entrypoints`
|
|
@@ -142,8 +86,8 @@ await main(context, [...entrypoints, ...myEntrypoints])
|
|
|
142
86
|
## Related Packages
|
|
143
87
|
|
|
144
88
|
- [`@owlmeans/server-context`](../server-context) — `makeServerContext` called internally by `makeContext`
|
|
145
|
-
- [`@owlmeans/server-api`](../server-api) — handler
|
|
146
|
-
- [`@owlmeans/server-entrypoint`](../server-entrypoint) —
|
|
89
|
+
- [`@owlmeans/server-api`](../server-api) — typed handler factories re-exported here
|
|
90
|
+
- [`@owlmeans/server-entrypoint`](../server-entrypoint) — protocol binding helpers
|
|
147
91
|
|
|
148
92
|
<!-- owlmeans:agent-guidance:start -->
|
|
149
93
|
## Agent guidance
|
|
@@ -153,7 +97,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
153
97
|
your project's skill store (`.agents/skills/`):
|
|
154
98
|
|
|
155
99
|
```sh
|
|
156
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
100
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.16
|
|
157
101
|
```
|
|
158
102
|
|
|
159
103
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/server-app",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-09-
|
|
4
|
+
"version": "0.1.18-rc.22",
|
|
5
|
+
"generatedAt": "2026-09-12T12:32:46.374Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,213 +1,43 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: server-app
|
|
3
|
-
description:
|
|
4
|
-
user-invocable: false
|
|
3
|
+
description: Build OwlMeans server applications from immutable entrypoint protocol declarations. Use when starting a server, binding endpoint implementations, configuring services, or registering server entrypoints.
|
|
5
4
|
---
|
|
6
5
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
7
6
|
|
|
8
|
-
#
|
|
7
|
+
# Server application entrypoints
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
Declare routes and request/response contracts in a shared package with `protocol()` or
|
|
10
|
+
`openProtocol()`. A server package supplies local implementations with `bind()` and `handlers()`;
|
|
11
|
+
it never changes a shared declaration by alias.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
```ts
|
|
14
|
+
import { bind, entrypoints, handlers } from '@owlmeans/server-app'
|
|
15
|
+
import { projectEntrypoints } from 'project-common'
|
|
16
|
+
import { createProject } from './app/project.js'
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
const api = handlers<Context>()
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
| `entrypoints` | Built-in system entrypoints — the auth endpoints plus the api-config advertise endpoint; spread into `appEntrypoints` |
|
|
25
|
-
|
|
26
|
-
### Building the config
|
|
27
|
-
|
|
28
|
-
| Export | Description |
|
|
29
|
-
|--------|-------------|
|
|
30
|
-
| `config(service, cfg?)` | Start a server config for this service |
|
|
31
|
-
| `sservice(service, cfg?)` | Declare a backend service route into `cfg.services` |
|
|
32
|
-
| `addWebService(service, alias?, cfg?)` | Declare a frontend service the app addresses |
|
|
33
|
-
| `service(route, cfg?)`, `toConfigRecord(obj)`, `PLUGINS` | Generic service declaration and config records |
|
|
34
|
-
| `AppType`, `BASE` | The app-type enum, and `base` — the alias of the intermediate area whose children require authentication |
|
|
35
|
-
| `PluginConfig` | Plugin config record shape |
|
|
36
|
-
|
|
37
|
-
### Declaring and elevating entrypoints
|
|
38
|
-
|
|
39
|
-
| Export | Description |
|
|
40
|
-
|--------|-------------|
|
|
41
|
-
| `entrypoint(...)`, `route(...)`, `broute(...)` | Declaration builders — `entrypoint` from server-entrypoint (it builds a `ServerEntrypoint`), `route` from route, `broute` from server-route |
|
|
42
|
-
| `elevate(entrypoints, alias, handler?, opts?)` | Attach a handler to an entrypoint declaration |
|
|
43
|
-
| `celevate(entrypoints, alias, handler?, opts?)` | Make a declaration client-callable from the server side |
|
|
44
|
-
| `guard(alias, opts?)` | Options requiring a guard |
|
|
45
|
-
| `DAUTH_GUARD` | Alias of the default auth guard (`auth`) |
|
|
46
|
-
| `GUARD_ED25519`, `BED255_CASHE_RESOURCE` | The service-to-service signature guard and its nonce cache |
|
|
47
|
-
| `filter`, `body`, `params`, `EntrypointOutcome` | Validators and the outcome enum |
|
|
48
|
-
|
|
49
|
-
### Writing handlers
|
|
50
|
-
|
|
51
|
-
| Export | Description |
|
|
52
|
-
|--------|-------------|
|
|
53
|
-
| `handleRequest(fn)` | Wrap an async function as a server handler `(req, context) => result` |
|
|
54
|
-
| `handleBody<T>(fn)` | Wrap an async function with validated body — `(payload, context, req) => result` |
|
|
55
|
-
| `handleParams<T>(fn)` | The same, over validated URL params |
|
|
56
|
-
| `Request`, `Response`, `Module`, `RefedEntrypointHandler`, `ClientEntrypoint` | Handler and entrypoint types |
|
|
57
|
-
| `createListSchema(schema)`, `filterObject(obj, keep?)` | List-result schema and object whitelisting |
|
|
58
|
-
| `Criteria`, `ListOptions`, `ListQuery`, `ListResult`, `Sort` | Resource query types |
|
|
59
|
-
| `assertContext(ctx, location?)` | Narrow a possibly-undefined context, throwing where it is missing |
|
|
60
|
-
|
|
61
|
-
### Booting
|
|
62
|
-
|
|
63
|
-
| Export | Description |
|
|
64
|
-
|--------|-------------|
|
|
65
|
-
| `holdApiPort(cfg, opts?)` | Own the app's port during boot |
|
|
66
|
-
| `ApiPortHold`, `ApiPortHoldOptions` | The hold handle and its options |
|
|
67
|
-
| `setBootPhase(phase, detail?)` | Record the process boot phase — `'initializing' \| 'ready' \| 'failed'` |
|
|
68
|
-
| `getBootPhase()` / `getBootDetail()` | Read it back |
|
|
69
|
-
| `bootHealthPayload()` | The health body: `{ status, phase, ok, reason?, bootId, pid }` |
|
|
70
|
-
| `bootHold(okPath?)` | `holdApiPort` options wired to the boot state |
|
|
71
|
-
| `BootPhase`, `BootHealth`, `BOOT_ID_ENV` | Boot-state types and the supervisor's boot-id env var |
|
|
72
|
-
| `klusterize(ctx, alias?)` | Register the cluster client and its config-directive middleware |
|
|
73
|
-
|
|
74
|
-
## Usage
|
|
75
|
-
|
|
76
|
-
### Entry point
|
|
77
|
-
```typescript
|
|
78
|
-
// index.ts
|
|
79
|
-
import { main } from '@owlmeans/server-app'
|
|
80
|
-
import config from './config.js'
|
|
81
|
-
import { makeContext } from './context.js'
|
|
82
|
-
import { appEntrypoints } from './entrypoints.js'
|
|
83
|
-
|
|
84
|
-
const context = makeContext(config)
|
|
85
|
-
main<{}, Config, Context>(context, appEntrypoints)
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
`makeContext(cfg, customize)` appends the API server, the API client, the socket service and its
|
|
89
|
-
middleware, and the static resource. Passing `customize: true` — or having already registered the
|
|
90
|
-
auth cache resource — leaves the auth service and its cache out, which is what an app that supplies
|
|
91
|
-
its own authentication does.
|
|
92
|
-
|
|
93
|
-
### Bind-first boot
|
|
94
|
-
|
|
95
|
-
An app that must be able to explain a *failed* boot does not call `main()`; it binds the port
|
|
96
|
-
first, so the failure has somewhere to be reported from. Never hand-roll the phase module —
|
|
97
|
-
`boot-state` is it.
|
|
98
|
-
|
|
99
|
-
```typescript
|
|
100
|
-
import { holdApiPort, bootHold, setBootPhase, bootHealthPayload } from '@owlmeans/server-app'
|
|
101
|
-
|
|
102
|
-
const hold = await holdApiPort(ctx.cfg, bootHold(HEALTH_PATH)).catch((error: Error) => {
|
|
103
|
-
console.error(`[boot] STARTUP FAILED — ${error.message}`)
|
|
104
|
-
process.exit(1) // a bind failure is fatal — see below
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
try {
|
|
108
|
-
await ctx.configure().init()
|
|
109
|
-
} catch (error) {
|
|
110
|
-
setBootPhase('failed', (error as Error).message)
|
|
111
|
-
return // stay alive: the hold is the only thing that can explain the failure
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
await hold.release()
|
|
115
|
-
setBootPhase('ready')
|
|
116
|
-
await ctx.getApiServer().listen()
|
|
20
|
+
export const appEntrypoints = [
|
|
21
|
+
...entrypoints,
|
|
22
|
+
bind(projectEntrypoints.base),
|
|
23
|
+
bind(projectEntrypoints.create, api.body(projectEntrypoints.create, createProject)),
|
|
24
|
+
]
|
|
117
25
|
```
|
|
118
26
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
invisible — the edge answers a bare connect error naming neither the app nor the reason.
|
|
123
|
-
- **A bind failure exits non-zero.** Carried past, the boot ends with nothing listening and nothing
|
|
124
|
-
holding the event loop: a clean exit 0 while a predecessor keeps serving stale code.
|
|
125
|
-
- **A failed init returns rather than exits.** The hold keeps answering `HEALTH_PATH` with
|
|
126
|
-
`phase: 'failed'` and the reason; everything else gets 503.
|
|
127
|
-
- **`hold.release()` is awaited** — `listen()` throws while a predecessor still owns the socket.
|
|
128
|
-
- **The app's own health handler spreads `bootHealthPayload()`**, so the body does not change shape
|
|
129
|
-
under a consumer polling across the handover:
|
|
130
|
-
|
|
131
|
-
```typescript
|
|
132
|
-
export const handleHealtz = handleRequest(async (_req, ctx) => ({
|
|
133
|
-
...bootHealthPayload(), db: await pingDb(ctx)
|
|
134
|
-
}))
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
`bootId` is identity, not health: a supervisor stamps the child it spawns via `BOOT_ID_ENV`
|
|
138
|
-
(`OWLMEANS_BOOT_ID`) and compares it here — another id means a leftover process holds the port.
|
|
139
|
-
|
|
140
|
-
### Handlers
|
|
141
|
-
```typescript
|
|
142
|
-
import { handleRequest, handleBody } from '@owlmeans/server-app'
|
|
143
|
-
import { requireEntityKey } from '@owlmeans/auth-common'
|
|
144
|
-
import type { ClientEntrypoint } from '@owlmeans/server-app'
|
|
145
|
-
|
|
146
|
-
export const list = handleRequest(async (req, context) => {
|
|
147
|
-
const ctx = context as Context
|
|
148
|
-
const { items } = await ctx.project().list({ entityId: requireEntityKey(req) })
|
|
149
|
-
return items
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
export const create = handleBody<CreateProject>(async (payload, context) => {
|
|
153
|
-
const ctx = context as Context
|
|
154
|
-
return await ctx.entrypoint<ClientEntrypoint<Project>>(agent.project.create).call({
|
|
155
|
-
body: { prompt: payload.prompt }
|
|
156
|
-
})
|
|
157
|
-
})
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
**Key organization-scoped records by `requireEntityKey(req)` / `entityKeyOf(req)` from
|
|
161
|
-
`@owlmeans/auth-common`.** The token carries only `entitySlug`, which is renameable — there is no id
|
|
162
|
-
on it. The guard resolves that slug once, at the boundary, and hands the result to the handler as
|
|
163
|
-
`req.entity` (`{ id, slug, iamKey }`); those two helpers return `req.entity.id` and fall back to the
|
|
164
|
-
slug for a deployment that registers no entity resolver, and `requireEntityKey` throws
|
|
165
|
-
`AuthorizationError` when the request names no organization at all. `requireEntity(req)` gives the
|
|
166
|
-
whole record when the slug or the frozen `iamKey` is wanted too.
|
|
167
|
-
|
|
168
|
-
The id stays inside the process: it is what records, grants and permission checks key on, and it
|
|
169
|
-
never goes onto the wire. A cross-service call carries the caller's token, so the peer resolves the
|
|
170
|
-
organization for itself; anything that must name one in a payload names it by `entitySlug`.
|
|
171
|
-
|
|
172
|
-
A cross-service call from a handler uses `call()` — it resolves to the value and throws whatever the
|
|
173
|
-
peer replied. Reach for `invoke()` only where the outcome decides what happens next.
|
|
174
|
-
|
|
175
|
-
### Entrypoint elevation
|
|
176
|
-
```typescript
|
|
177
|
-
// entrypoints.ts
|
|
178
|
-
import { elevate, entrypoints as systemEntrypoints } from '@owlmeans/server-app'
|
|
179
|
-
import { managerEntrypoints } from 'my-common'
|
|
180
|
-
import { create, list } from './app/project/index.js'
|
|
181
|
-
|
|
182
|
-
elevate(managerEntrypoints, manager.back.project.create, create)
|
|
183
|
-
elevate(managerEntrypoints, manager.back.project.list, list)
|
|
184
|
-
|
|
185
|
-
export const appEntrypoints = [...systemEntrypoints, ...paymentEntrypoints, ...managerEntrypoints]
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
Elevating is idempotent, so a later `elevate` of the same alias is legal and simply replaces the
|
|
189
|
-
element again; the guards it brings are added to the declared ones rather than replacing them.
|
|
190
|
-
|
|
191
|
-
A parent alias needs no elevation for its `guard()` to reach its children — `getGuards()` walks the
|
|
192
|
-
registered declarations whether or not they were elevated. A **bare** `elevate(entrypoints, alias)`
|
|
193
|
-
only turns the declaration into a server entrypoint; with no handler it is never bound as a route,
|
|
194
|
-
and it runs in the intermediate chain only when the same call passes `true` (or
|
|
195
|
-
`{ intermediate: true }`) along with a `handleIntermediate` handler from `@owlmeans/server-api`.
|
|
196
|
-
`guard()` is re-exported here; `gate()` is not — take it from `@owlmeans/entrypoint`.
|
|
197
|
-
|
|
198
|
-
## Depends On
|
|
199
|
-
|
|
200
|
-
Declared:
|
|
27
|
+
`handlers<Context>().body`, `.params` and `.request` infer request sections and response values
|
|
28
|
+
from the declaration. Use `.request` for a transport-level handler that needs the complete request
|
|
29
|
+
boundary.
|
|
201
30
|
|
|
202
|
-
|
|
203
|
-
- `@owlmeans/api`, `@owlmeans/static-resource`, `@owlmeans/kluster`
|
|
204
|
-
- `@owlmeans/entrypoint`, `@owlmeans/route`, `@owlmeans/config`, `@owlmeans/client-config`, `@owlmeans/client-entrypoint`, `@owlmeans/context`
|
|
31
|
+
## Rules
|
|
205
32
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
33
|
+
- Keep `protocol()` declarations in the common package shared by callers and servers.
|
|
34
|
+
- Bind parent/group declarations as well as leaves; parents establish inherited paths and access.
|
|
35
|
+
- Use direct protocol references in `context.entrypoint(protocol)`; do not supply a caller-side
|
|
36
|
+
response generic.
|
|
37
|
+
- Model validation belongs in `contract()` with `typed()` or `schema()`, not in a wrapper around a
|
|
38
|
+
handler.
|
|
39
|
+
- `entrypoints` contains framework registrations. Add local entrypoints to a new array and register
|
|
40
|
+
that array during context initialization.
|
|
211
41
|
|
|
212
|
-
|
|
213
|
-
|
|
42
|
+
`holdApiPort`, `config`, `sservice`, `service`, `AppType` and the context bootstrap exports remain
|
|
43
|
+
available from this package for process wiring.
|
package/build/entrypoints.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
/** Framework server entrypoints every application receives. */
|
|
2
|
+
export declare const entrypoints: import("@owlmeans/server-entrypoint").ServerProtocolEntrypoint<import("@owlmeans/entrypoint").EntrypointProtocolDeclaration>[];
|
|
2
3
|
//# sourceMappingURL=entrypoints.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../src/entrypoints.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../src/entrypoints.ts"],"names":[],"mappings":"AAGA,+DAA+D;AAC/D,eAAO,MAAM,WAAW,gIAA0C,CAAA"}
|
package/build/entrypoints.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { entrypoints as
|
|
2
|
-
import { entrypoints as
|
|
3
|
-
|
|
1
|
+
import { entrypoints as apiConfigBindings } from '@owlmeans/api-config-server';
|
|
2
|
+
import { entrypoints as authBindings } from '@owlmeans/server-auth';
|
|
3
|
+
/** Framework server entrypoints every application receives. */
|
|
4
|
+
export const entrypoints = [...authBindings, ...apiConfigBindings];
|
|
4
5
|
//# sourceMappingURL=entrypoints.js.map
|
package/build/entrypoints.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entrypoints.js","sourceRoot":"","sources":["../src/entrypoints.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,
|
|
1
|
+
{"version":3,"file":"entrypoints.js","sourceRoot":"","sources":["../src/entrypoints.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAC9E,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEnE,+DAA+D;AAC/D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAG,YAAY,EAAE,GAAG,iBAAiB,CAAC,CAAA"}
|
package/build/exports.d.ts
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
export { config } from '@owlmeans/server-context';
|
|
2
|
+
export { makeContext } from './context.js';
|
|
3
|
+
export { main } from './main.js';
|
|
4
|
+
export type { AppConfig, AppContext } from './types.js';
|
|
2
5
|
export { sservice } from '@owlmeans/server-config';
|
|
3
6
|
export { addWebService } from '@owlmeans/client-config';
|
|
4
7
|
export { service, toConfigRecord, PLUGINS } from '@owlmeans/config';
|
|
5
|
-
export { contract,
|
|
8
|
+
export { contract, protocol, typed, EntrypointOutcome } from '@owlmeans/entrypoint';
|
|
6
9
|
export type { AbstractRequest as Request, AbstractResponse as Response } from '@owlmeans/entrypoint';
|
|
7
10
|
export { createListSchema, filterObject } from '@owlmeans/resource';
|
|
8
11
|
export type { Criteria, ListOptions, ListQuery, ListResult, Sort } from '@owlmeans/resource';
|
|
9
12
|
export { AppType, BASE, assertContext } from '@owlmeans/context';
|
|
10
|
-
export {
|
|
11
|
-
export { elevate as celevate } from '@owlmeans/client-entrypoint';
|
|
12
|
-
export type { ServerEntrypoint as Module, RefedEntrypointHandler } from '@owlmeans/server-entrypoint';
|
|
13
|
-
export type { ClientEntrypoint } from '@owlmeans/client-entrypoint';
|
|
13
|
+
export { bind, bindAll } from '@owlmeans/server-entrypoint';
|
|
14
14
|
export { route as broute } from '@owlmeans/server-route';
|
|
15
|
-
export { handlers,
|
|
15
|
+
export { handlers, holdApiPort } from '@owlmeans/server-api';
|
|
16
|
+
export { handleIntermediate, handleBody, handleRequest, handleParams } from '@owlmeans/server-api';
|
|
16
17
|
export type { ApiPortHold, ApiPortHoldOptions } from '@owlmeans/server-api';
|
|
18
|
+
export type { ClientEntrypoint } from '@owlmeans/client-entrypoint';
|
|
17
19
|
export { route } from '@owlmeans/route';
|
|
18
20
|
export { DEFAULT_ALIAS as DAUTH_GUARD } from '@owlmeans/server-auth';
|
|
19
21
|
export { klusterize } from '@owlmeans/kluster';
|
|
20
22
|
export type { PluginConfig } from '@owlmeans/config';
|
|
21
23
|
export { GUARD_ED25519, BED255_CASHE_RESOURCE } from '@owlmeans/auth-common';
|
|
24
|
+
export { entrypoints } from './entrypoints.js';
|
|
22
25
|
//# sourceMappingURL=exports.d.ts.map
|
package/build/exports.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACnF,YAAY,EAAE,eAAe,IAAI,OAAO,EAAE,gBAAgB,IAAI,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AACpG,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACnE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAC5F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,KAAK,IAAI,MAAM,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAClG,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAC3E,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACnE,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AACvC,OAAO,EAAE,aAAa,IAAI,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA"}
|
package/build/exports.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
export { config } from '@owlmeans/server-context';
|
|
2
|
+
export { makeContext } from './context.js';
|
|
3
|
+
export { main } from './main.js';
|
|
2
4
|
export { sservice } from '@owlmeans/server-config';
|
|
3
5
|
export { addWebService } from '@owlmeans/client-config';
|
|
4
6
|
export { service, toConfigRecord, PLUGINS } from '@owlmeans/config';
|
|
5
|
-
export { contract,
|
|
7
|
+
export { contract, protocol, typed, EntrypointOutcome } from '@owlmeans/entrypoint';
|
|
6
8
|
export { createListSchema, filterObject } from '@owlmeans/resource';
|
|
7
9
|
export { AppType, BASE, assertContext } from '@owlmeans/context';
|
|
8
|
-
export {
|
|
9
|
-
export { elevate as celevate } from '@owlmeans/client-entrypoint';
|
|
10
|
+
export { bind, bindAll } from '@owlmeans/server-entrypoint';
|
|
10
11
|
export { route as broute } from '@owlmeans/server-route';
|
|
11
|
-
export { handlers,
|
|
12
|
+
export { handlers, holdApiPort } from '@owlmeans/server-api';
|
|
13
|
+
export { handleIntermediate, handleBody, handleRequest, handleParams } from '@owlmeans/server-api';
|
|
12
14
|
export { route } from '@owlmeans/route';
|
|
13
15
|
export { DEFAULT_ALIAS as DAUTH_GUARD } from '@owlmeans/server-auth';
|
|
14
16
|
export { klusterize } from '@owlmeans/kluster';
|
|
15
17
|
export { GUARD_ED25519, BED255_CASHE_RESOURCE } from '@owlmeans/auth-common';
|
|
18
|
+
export { entrypoints } from './entrypoints.js';
|
|
16
19
|
//# sourceMappingURL=exports.js.map
|
package/build/exports.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exports.js","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"exports.js","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACnE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAEnF,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEnE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,KAAK,IAAI,MAAM,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAGlG,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AACvC,OAAO,EAAE,aAAa,IAAI,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA"}
|
package/build/index.d.ts
CHANGED
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,mBAAmB,YAAY,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA"}
|
package/build/index.js
CHANGED
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AAEzB,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/server-app",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.22",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -21,21 +21,21 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@owlmeans/api": "^0.1.18-rc.
|
|
25
|
-
"@owlmeans/client-config": "^0.1.18-rc.
|
|
26
|
-
"@owlmeans/client-entrypoint": "^0.1.18-rc.
|
|
27
|
-
"@owlmeans/config": "^0.1.18-rc.
|
|
28
|
-
"@owlmeans/context": "^0.1.18-rc.
|
|
29
|
-
"@owlmeans/kluster": "^0.1.18-rc.
|
|
30
|
-
"@owlmeans/entrypoint": "^0.1.18-rc.
|
|
31
|
-
"@owlmeans/route": "^0.1.18-rc.
|
|
32
|
-
"@owlmeans/server-api": "^0.1.18-rc.
|
|
33
|
-
"@owlmeans/server-auth": "^0.1.18-rc.
|
|
34
|
-
"@owlmeans/server-context": "^0.1.18-rc.
|
|
35
|
-
"@owlmeans/server-entrypoint": "^0.1.18-rc.
|
|
36
|
-
"@owlmeans/server-route": "^0.1.18-rc.
|
|
37
|
-
"@owlmeans/server-socket": "^0.1.18-rc.
|
|
38
|
-
"@owlmeans/static-resource": "^0.1.18-rc.
|
|
24
|
+
"@owlmeans/api": "^0.1.18-rc.17",
|
|
25
|
+
"@owlmeans/client-config": "^0.1.18-rc.16",
|
|
26
|
+
"@owlmeans/client-entrypoint": "^0.1.18-rc.17",
|
|
27
|
+
"@owlmeans/config": "^0.1.18-rc.16",
|
|
28
|
+
"@owlmeans/context": "^0.1.18-rc.12",
|
|
29
|
+
"@owlmeans/kluster": "^0.1.18-rc.16",
|
|
30
|
+
"@owlmeans/entrypoint": "^0.1.18-rc.15",
|
|
31
|
+
"@owlmeans/route": "^0.1.18-rc.13",
|
|
32
|
+
"@owlmeans/server-api": "^0.1.18-rc.21",
|
|
33
|
+
"@owlmeans/server-auth": "^0.1.18-rc.22",
|
|
34
|
+
"@owlmeans/server-context": "^0.1.18-rc.16",
|
|
35
|
+
"@owlmeans/server-entrypoint": "^0.1.18-rc.15",
|
|
36
|
+
"@owlmeans/server-route": "^0.1.18-rc.13",
|
|
37
|
+
"@owlmeans/server-socket": "^0.1.18-rc.22",
|
|
38
|
+
"@owlmeans/static-resource": "^0.1.18-rc.13"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@owlmeans/dep-config": "workspace:*",
|
package/src/entrypoints.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { entrypoints as
|
|
2
|
-
import { entrypoints as
|
|
1
|
+
import { entrypoints as apiConfigBindings } from '@owlmeans/api-config-server'
|
|
2
|
+
import { entrypoints as authBindings } from '@owlmeans/server-auth'
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/** Framework server entrypoints every application receives. */
|
|
5
|
+
export const entrypoints = [...authBindings, ...apiConfigBindings]
|
package/src/exports.ts
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
|
|
2
2
|
export { config } from '@owlmeans/server-context'
|
|
3
|
+
export { makeContext } from './context.js'
|
|
4
|
+
export { main } from './main.js'
|
|
5
|
+
export type { AppConfig, AppContext } from './types.js'
|
|
3
6
|
export { sservice } from '@owlmeans/server-config'
|
|
4
7
|
export { addWebService } from '@owlmeans/client-config'
|
|
5
8
|
export { service, toConfigRecord, PLUGINS } from '@owlmeans/config'
|
|
6
|
-
export { contract,
|
|
9
|
+
export { contract, protocol, typed, EntrypointOutcome } from '@owlmeans/entrypoint'
|
|
7
10
|
export type { AbstractRequest as Request, AbstractResponse as Response } from '@owlmeans/entrypoint'
|
|
8
11
|
export { createListSchema, filterObject } from '@owlmeans/resource'
|
|
9
12
|
export type { Criteria, ListOptions, ListQuery, ListResult, Sort } from '@owlmeans/resource'
|
|
10
13
|
export { AppType, BASE, assertContext } from '@owlmeans/context'
|
|
11
|
-
export {
|
|
12
|
-
export { elevate as celevate } from '@owlmeans/client-entrypoint'
|
|
13
|
-
export type { ServerEntrypoint as Module, RefedEntrypointHandler } from '@owlmeans/server-entrypoint'
|
|
14
|
-
export type { ClientEntrypoint } from '@owlmeans/client-entrypoint'
|
|
14
|
+
export { bind, bindAll } from '@owlmeans/server-entrypoint'
|
|
15
15
|
export { route as broute } from '@owlmeans/server-route'
|
|
16
|
-
export { handlers,
|
|
16
|
+
export { handlers, holdApiPort } from '@owlmeans/server-api'
|
|
17
|
+
export { handleIntermediate, handleBody, handleRequest, handleParams } from '@owlmeans/server-api'
|
|
17
18
|
export type { ApiPortHold, ApiPortHoldOptions } from '@owlmeans/server-api'
|
|
19
|
+
export type { ClientEntrypoint } from '@owlmeans/client-entrypoint'
|
|
18
20
|
export { route } from '@owlmeans/route'
|
|
19
21
|
export { DEFAULT_ALIAS as DAUTH_GUARD } from '@owlmeans/server-auth'
|
|
20
22
|
export { klusterize } from '@owlmeans/kluster'
|
|
21
23
|
export type { PluginConfig } from '@owlmeans/config'
|
|
22
24
|
export { GUARD_ED25519, BED255_CASHE_RESOURCE } from '@owlmeans/auth-common'
|
|
25
|
+
export { entrypoints } from './entrypoints.js'
|
package/src/index.ts
CHANGED
package/build/boot-state.d.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { ApiPortHoldOptions } from '@owlmeans/server-api';
|
|
2
|
-
/**
|
|
3
|
-
* Boot phase of the process.
|
|
4
|
-
*
|
|
5
|
-
* An app binds its port before it initializes, so that a failure has somewhere to be reported
|
|
6
|
-
* from. Without a listener the only thing anyone sees is a connection refused at the edge — an
|
|
7
|
-
* opaque 503 that names neither the app nor the cause. This phase is what the health path answers
|
|
8
|
-
* with, and what the platform reads to tell "still starting" from "gave up, and here is why".
|
|
9
|
-
*/
|
|
10
|
-
export type BootPhase = 'initializing' | 'ready' | 'failed';
|
|
11
|
-
export interface BootHealth extends Record<string, unknown> {
|
|
12
|
-
status: 'OK' | 'FAILED';
|
|
13
|
-
phase: BootPhase;
|
|
14
|
-
ok: boolean;
|
|
15
|
-
/** Whatever `setBootPhase` was given — the failure message, or the step being waited on. */
|
|
16
|
-
reason?: string;
|
|
17
|
-
/**
|
|
18
|
-
* Identity, not health: a supervisor passes the id to the child it spawns and compares it
|
|
19
|
-
* here, so an answer carrying another id means the port is held by a leftover process and the
|
|
20
|
-
* health it reports describes code nobody asked for. Empty when nothing supplied one.
|
|
21
|
-
*/
|
|
22
|
-
bootId: string;
|
|
23
|
-
pid: number;
|
|
24
|
-
}
|
|
25
|
-
/** Env var a supervisor stamps the spawned process with; surfaced as `bootId`. */
|
|
26
|
-
export declare const BOOT_ID_ENV = "OWLMEANS_BOOT_ID";
|
|
27
|
-
export declare const getBootPhase: () => BootPhase;
|
|
28
|
-
export declare const getBootDetail: () => string | undefined;
|
|
29
|
-
/**
|
|
30
|
-
* `detail` is free text, and is kept for every phase — a boot that is merely slow is as worth
|
|
31
|
-
* explaining as one that failed.
|
|
32
|
-
*/
|
|
33
|
-
export declare const setBootPhase: (phase: BootPhase, detail?: string) => void;
|
|
34
|
-
/**
|
|
35
|
-
* The body the health path answers with, from either server.
|
|
36
|
-
*
|
|
37
|
-
* The port hold and the app's own handler both build it here, so a consumer polling through the
|
|
38
|
-
* handover never sees the shape change under it — which is why the keys are unconditional and
|
|
39
|
-
* only `reason` comes and goes with the state it describes.
|
|
40
|
-
*/
|
|
41
|
-
export declare const bootHealthPayload: () => BootHealth;
|
|
42
|
-
/**
|
|
43
|
-
* Hold options wired to this module — the bind-first boot in one line:
|
|
44
|
-
*
|
|
45
|
-
* const hold = await holdApiPort(ctx.cfg, bootHold(HEALTH_PATH))
|
|
46
|
-
* try { await init() } catch (e) { setBootPhase('failed', message); return }
|
|
47
|
-
* await hold.release()
|
|
48
|
-
* setBootPhase('ready')
|
|
49
|
-
* await ctx.getApiServer().listen()
|
|
50
|
-
*
|
|
51
|
-
* The hold evaluates `payload` per request, so the phase set after a failure is reported live by
|
|
52
|
-
* the listener that is already bound rather than needing a server that will never start.
|
|
53
|
-
*/
|
|
54
|
-
export declare const bootHold: (okPath?: string) => ApiPortHoldOptions;
|
|
55
|
-
//# sourceMappingURL=boot-state.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"boot-state.d.ts","sourceRoot":"","sources":["../src/boot-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAE9D;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAA;AAE3D,MAAM,WAAW,UAAW,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACzD,MAAM,EAAE,IAAI,GAAG,QAAQ,CAAA;IACvB,KAAK,EAAE,SAAS,CAAA;IAChB,EAAE,EAAE,OAAO,CAAA;IACX,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,kFAAkF;AAClF,eAAO,MAAM,WAAW,qBAAqB,CAAA;AAK7C,eAAO,MAAM,YAAY,QAAO,SAAmB,CAAA;AAEnD,eAAO,MAAM,aAAa,QAAO,MAAM,GAAG,SAAoB,CAAA;AAE9D;;;GAGG;AACH,eAAO,MAAM,YAAY,UAAW,SAAS,WAAW,MAAM,KAAG,IAGhE,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,QAAO,UAOnC,CAAA;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,QAAQ,YAAa,MAAM,KAAG,kBAGzC,CAAA"}
|
package/build/boot-state.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/** Env var a supervisor stamps the spawned process with; surfaced as `bootId`. */
|
|
2
|
-
export const BOOT_ID_ENV = 'OWLMEANS_BOOT_ID';
|
|
3
|
-
let _phase = 'initializing';
|
|
4
|
-
let _detail;
|
|
5
|
-
export const getBootPhase = () => _phase;
|
|
6
|
-
export const getBootDetail = () => _detail;
|
|
7
|
-
/**
|
|
8
|
-
* `detail` is free text, and is kept for every phase — a boot that is merely slow is as worth
|
|
9
|
-
* explaining as one that failed.
|
|
10
|
-
*/
|
|
11
|
-
export const setBootPhase = (phase, detail) => {
|
|
12
|
-
_phase = phase;
|
|
13
|
-
_detail = detail;
|
|
14
|
-
};
|
|
15
|
-
/**
|
|
16
|
-
* The body the health path answers with, from either server.
|
|
17
|
-
*
|
|
18
|
-
* The port hold and the app's own handler both build it here, so a consumer polling through the
|
|
19
|
-
* handover never sees the shape change under it — which is why the keys are unconditional and
|
|
20
|
-
* only `reason` comes and goes with the state it describes.
|
|
21
|
-
*/
|
|
22
|
-
export const bootHealthPayload = () => ({
|
|
23
|
-
status: _phase === 'failed' ? 'FAILED' : 'OK',
|
|
24
|
-
phase: _phase,
|
|
25
|
-
ok: _phase === 'ready',
|
|
26
|
-
...(_detail != null ? { reason: _detail } : {}),
|
|
27
|
-
bootId: process.env[BOOT_ID_ENV] ?? '',
|
|
28
|
-
pid: process.pid
|
|
29
|
-
});
|
|
30
|
-
/**
|
|
31
|
-
* Hold options wired to this module — the bind-first boot in one line:
|
|
32
|
-
*
|
|
33
|
-
* const hold = await holdApiPort(ctx.cfg, bootHold(HEALTH_PATH))
|
|
34
|
-
* try { await init() } catch (e) { setBootPhase('failed', message); return }
|
|
35
|
-
* await hold.release()
|
|
36
|
-
* setBootPhase('ready')
|
|
37
|
-
* await ctx.getApiServer().listen()
|
|
38
|
-
*
|
|
39
|
-
* The hold evaluates `payload` per request, so the phase set after a failure is reported live by
|
|
40
|
-
* the listener that is already bound rather than needing a server that will never start.
|
|
41
|
-
*/
|
|
42
|
-
export const bootHold = (okPath) => ({
|
|
43
|
-
...(okPath != null ? { okPath } : {}),
|
|
44
|
-
payload: bootHealthPayload
|
|
45
|
-
});
|
|
46
|
-
//# sourceMappingURL=boot-state.js.map
|
package/build/boot-state.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"boot-state.js","sourceRoot":"","sources":["../src/boot-state.ts"],"names":[],"mappings":"AA2BA,kFAAkF;AAClF,MAAM,CAAC,MAAM,WAAW,GAAG,kBAAkB,CAAA;AAE7C,IAAI,MAAM,GAAc,cAAc,CAAA;AACtC,IAAI,OAA2B,CAAA;AAE/B,MAAM,CAAC,MAAM,YAAY,GAAG,GAAc,EAAE,CAAC,MAAM,CAAA;AAEnD,MAAM,CAAC,MAAM,aAAa,GAAG,GAAuB,EAAE,CAAC,OAAO,CAAA;AAE9D;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAgB,EAAE,MAAe,EAAQ,EAAE;IACtE,MAAM,GAAG,KAAK,CAAA;IACd,OAAO,GAAG,MAAM,CAAA;AAClB,CAAC,CAAA;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAe,EAAE,CAAC,CAAC;IAClD,MAAM,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI;IAC7C,KAAK,EAAE,MAAM;IACb,EAAE,EAAE,MAAM,KAAK,OAAO;IACtB,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/C,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE;IACtC,GAAG,EAAE,OAAO,CAAC,GAAG;CACjB,CAAC,CAAA;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,MAAe,EAAsB,EAAE,CAAC,CAAC;IAChE,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACrC,OAAO,EAAE,iBAAiB;CAC3B,CAAC,CAAA"}
|
package/src/boot-state.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import type { ApiPortHoldOptions } from '@owlmeans/server-api'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Boot phase of the process.
|
|
5
|
-
*
|
|
6
|
-
* An app binds its port before it initializes, so that a failure has somewhere to be reported
|
|
7
|
-
* from. Without a listener the only thing anyone sees is a connection refused at the edge — an
|
|
8
|
-
* opaque 503 that names neither the app nor the cause. This phase is what the health path answers
|
|
9
|
-
* with, and what the platform reads to tell "still starting" from "gave up, and here is why".
|
|
10
|
-
*/
|
|
11
|
-
export type BootPhase = 'initializing' | 'ready' | 'failed'
|
|
12
|
-
|
|
13
|
-
export interface BootHealth extends Record<string, unknown> {
|
|
14
|
-
status: 'OK' | 'FAILED'
|
|
15
|
-
phase: BootPhase
|
|
16
|
-
ok: boolean
|
|
17
|
-
/** Whatever `setBootPhase` was given — the failure message, or the step being waited on. */
|
|
18
|
-
reason?: string
|
|
19
|
-
/**
|
|
20
|
-
* Identity, not health: a supervisor passes the id to the child it spawns and compares it
|
|
21
|
-
* here, so an answer carrying another id means the port is held by a leftover process and the
|
|
22
|
-
* health it reports describes code nobody asked for. Empty when nothing supplied one.
|
|
23
|
-
*/
|
|
24
|
-
bootId: string
|
|
25
|
-
pid: number
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** Env var a supervisor stamps the spawned process with; surfaced as `bootId`. */
|
|
29
|
-
export const BOOT_ID_ENV = 'OWLMEANS_BOOT_ID'
|
|
30
|
-
|
|
31
|
-
let _phase: BootPhase = 'initializing'
|
|
32
|
-
let _detail: string | undefined
|
|
33
|
-
|
|
34
|
-
export const getBootPhase = (): BootPhase => _phase
|
|
35
|
-
|
|
36
|
-
export const getBootDetail = (): string | undefined => _detail
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* `detail` is free text, and is kept for every phase — a boot that is merely slow is as worth
|
|
40
|
-
* explaining as one that failed.
|
|
41
|
-
*/
|
|
42
|
-
export const setBootPhase = (phase: BootPhase, detail?: string): void => {
|
|
43
|
-
_phase = phase
|
|
44
|
-
_detail = detail
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* The body the health path answers with, from either server.
|
|
49
|
-
*
|
|
50
|
-
* The port hold and the app's own handler both build it here, so a consumer polling through the
|
|
51
|
-
* handover never sees the shape change under it — which is why the keys are unconditional and
|
|
52
|
-
* only `reason` comes and goes with the state it describes.
|
|
53
|
-
*/
|
|
54
|
-
export const bootHealthPayload = (): BootHealth => ({
|
|
55
|
-
status: _phase === 'failed' ? 'FAILED' : 'OK',
|
|
56
|
-
phase: _phase,
|
|
57
|
-
ok: _phase === 'ready',
|
|
58
|
-
...(_detail != null ? { reason: _detail } : {}),
|
|
59
|
-
bootId: process.env[BOOT_ID_ENV] ?? '',
|
|
60
|
-
pid: process.pid
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Hold options wired to this module — the bind-first boot in one line:
|
|
65
|
-
*
|
|
66
|
-
* const hold = await holdApiPort(ctx.cfg, bootHold(HEALTH_PATH))
|
|
67
|
-
* try { await init() } catch (e) { setBootPhase('failed', message); return }
|
|
68
|
-
* await hold.release()
|
|
69
|
-
* setBootPhase('ready')
|
|
70
|
-
* await ctx.getApiServer().listen()
|
|
71
|
-
*
|
|
72
|
-
* The hold evaluates `payload` per request, so the phase set after a failure is reported live by
|
|
73
|
-
* the listener that is already bound rather than needing a server that will never start.
|
|
74
|
-
*/
|
|
75
|
-
export const bootHold = (okPath?: string): ApiPortHoldOptions => ({
|
|
76
|
-
...(okPath != null ? { okPath } : {}),
|
|
77
|
-
payload: bootHealthPayload
|
|
78
|
-
})
|