@owlmeans/server-planning 0.1.18-rc.20 → 0.1.18-rc.21
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 +2 -2
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/server-planning/SKILL.md +1 -1
- package/build/actions/cards.d.ts +3 -5
- package/build/actions/cards.d.ts.map +1 -1
- package/build/actions/cards.js +1 -1
- package/build/actions/cards.js.map +1 -1
- package/build/actions/schemas.d.ts +3 -5
- package/build/actions/schemas.d.ts.map +1 -1
- package/build/actions/schemas.js.map +1 -1
- package/build/actions/specs.d.ts +2 -4
- package/build/actions/specs.d.ts.map +1 -1
- package/build/actions/specs.js.map +1 -1
- package/build/actions/types.d.ts +4 -0
- package/build/actions/types.d.ts.map +1 -0
- package/build/actions/types.js +2 -0
- package/build/actions/types.js.map +1 -0
- package/build/actions/watch.d.ts.map +1 -1
- package/build/actions/watch.js +4 -2
- package/build/actions/watch.js.map +1 -1
- package/build/conformance/cases.d.ts +2 -17
- package/build/conformance/cases.d.ts.map +1 -1
- package/build/conformance/cases.js +3 -2
- package/build/conformance/cases.js.map +1 -1
- package/build/conformance/consts.d.ts +19 -0
- package/build/conformance/consts.d.ts.map +1 -0
- package/build/conformance/consts.js +42 -0
- package/build/conformance/consts.js.map +1 -0
- package/build/conformance/fixtures.d.ts +1 -18
- package/build/conformance/fixtures.d.ts.map +1 -1
- package/build/conformance/fixtures.js +3 -41
- package/build/conformance/fixtures.js.map +1 -1
- package/build/conformance/index.d.ts +2 -0
- package/build/conformance/index.d.ts.map +1 -1
- package/build/conformance/index.js +1 -0
- package/build/conformance/index.js.map +1 -1
- package/build/conformance/types.d.ts +18 -0
- package/build/conformance/types.d.ts.map +1 -0
- package/build/conformance/types.js +2 -0
- package/build/conformance/types.js.map +1 -0
- package/build/definitions.d.ts +2 -18
- package/build/definitions.d.ts.map +1 -1
- package/build/definitions.js +1 -1
- package/build/definitions.js.map +1 -1
- package/build/executor/changes.d.ts +2 -2
- package/build/executor/changes.d.ts.map +1 -1
- package/build/executor/changes.js.map +1 -1
- package/build/executor/code.d.ts +3 -3
- package/build/executor/code.d.ts.map +1 -1
- package/build/executor/code.js +1 -1
- package/build/executor/code.js.map +1 -1
- package/build/executor/consts.local.d.ts +5 -0
- package/build/executor/consts.local.d.ts.map +1 -0
- package/build/executor/consts.local.js +6 -0
- package/build/executor/consts.local.js.map +1 -0
- package/build/executor/creator.d.ts +1 -1
- package/build/executor/creator.d.ts.map +1 -1
- package/build/executor/creator.js +1 -2
- package/build/executor/creator.js.map +1 -1
- package/build/executor/resolve.d.ts +23 -28
- package/build/executor/resolve.d.ts.map +1 -1
- package/build/executor/resolve.js +9 -7
- package/build/executor/resolve.js.map +1 -1
- package/build/executor/types.d.ts +24 -0
- package/build/executor/types.d.ts.map +1 -0
- package/build/executor/types.js +2 -0
- package/build/executor/types.js.map +1 -0
- package/build/executor/validate.d.ts +3 -3
- package/build/executor/validate.d.ts.map +1 -1
- package/build/executor/validate.js +4 -4
- package/build/executor/validate.js.map +1 -1
- package/build/executor.d.ts +2 -2
- package/build/executor.d.ts.map +1 -1
- package/build/executor.js +6 -6
- package/build/executor.js.map +1 -1
- package/build/facade.d.ts +2 -2
- package/build/facade.d.ts.map +1 -1
- package/build/facade.js +1 -1
- package/build/facade.js.map +1 -1
- package/build/projection.d.ts +2 -10
- package/build/projection.d.ts.map +1 -1
- package/build/projection.js +1 -1
- package/build/projection.js.map +1 -1
- package/build/queue/consts.d.ts +5 -0
- package/build/queue/consts.d.ts.map +1 -0
- package/build/queue/consts.js +5 -0
- package/build/queue/consts.js.map +1 -0
- package/build/queue/index.d.ts +4 -16
- package/build/queue/index.d.ts.map +1 -1
- package/build/queue/index.js +2 -4
- package/build/queue/index.js.map +1 -1
- package/build/queue/types.d.ts +13 -0
- package/build/queue/types.d.ts.map +1 -0
- package/build/queue/types.js +2 -0
- package/build/queue/types.js.map +1 -0
- package/build/registry.d.ts +2 -21
- package/build/registry.d.ts.map +1 -1
- package/build/registry.js +3 -1
- package/build/registry.js.map +1 -1
- package/build/service.d.ts +3 -25
- package/build/service.d.ts.map +1 -1
- package/build/service.js.map +1 -1
- package/build/store/commits.d.ts.map +1 -1
- package/build/store/commits.js +3 -1
- package/build/store/commits.js.map +1 -1
- package/build/store/consts.local.d.ts +2 -0
- package/build/store/consts.local.d.ts.map +1 -0
- package/build/store/consts.local.js +2 -0
- package/build/store/consts.local.js.map +1 -0
- package/build/store/fold.d.ts +1 -2
- package/build/store/fold.d.ts.map +1 -1
- package/build/store/fold.js +6 -4
- package/build/store/fold.js.map +1 -1
- package/build/store/memory.d.ts.map +1 -1
- package/build/store/memory.js +0 -0
- package/build/store/memory.js.map +1 -1
- package/build/store/types.local.d.ts +3 -0
- package/build/store/types.local.d.ts.map +1 -0
- package/build/store/types.local.js +2 -0
- package/build/store/types.local.js.map +1 -0
- package/build/types.d.ts +65 -1
- package/build/types.d.ts.map +1 -1
- package/build/types.local.d.ts +7 -0
- package/build/types.local.d.ts.map +1 -0
- package/build/types.local.js +2 -0
- package/build/types.local.js.map +1 -0
- package/build/utils/index.d.ts +1 -0
- package/build/utils/index.d.ts.map +1 -1
- package/build/utils/scope.d.ts +2 -6
- package/build/utils/scope.d.ts.map +1 -1
- package/build/utils/scope.js.map +1 -1
- package/build/utils/types.d.ts +8 -0
- package/build/utils/types.d.ts.map +1 -0
- package/build/utils/types.js +2 -0
- package/build/utils/types.js.map +1 -0
- package/package.json +21 -20
- package/src/actions/cards.ts +2 -6
- package/src/actions/schemas.ts +2 -6
- package/src/actions/specs.ts +1 -2
- package/src/actions/types.ts +4 -0
- package/src/actions/watch.ts +5 -2
- package/src/conformance/cases.ts +4 -29
- package/src/conformance/consts.ts +44 -0
- package/src/conformance/fixtures.ts +3 -50
- package/src/conformance/index.ts +2 -0
- package/src/conformance/types.ts +20 -0
- package/src/definitions.ts +3 -35
- package/src/executor/changes.ts +2 -6
- package/src/executor/code.ts +3 -9
- package/src/executor/consts.local.ts +8 -0
- package/src/executor/creator.ts +2 -5
- package/src/executor/resolve.ts +13 -39
- package/src/executor/types.ts +25 -0
- package/src/executor/validate.ts +7 -16
- package/src/executor.ts +9 -13
- package/src/facade.ts +2 -9
- package/src/projection.ts +4 -14
- package/src/queue/consts.ts +5 -0
- package/src/queue/index.ts +6 -21
- package/src/queue/types.ts +14 -0
- package/src/registry.ts +5 -29
- package/src/service.ts +3 -32
- package/src/store/commits.ts +5 -4
- package/src/store/consts.local.ts +1 -0
- package/src/store/fold.ts +7 -10
- package/src/store/memory.ts +0 -0
- package/src/store/types.local.ts +3 -0
- package/src/types.local.ts +7 -0
- package/src/types.ts +76 -4
- package/src/utils/index.ts +1 -0
- package/src/utils/scope.ts +2 -8
- package/src/utils/types.ts +8 -0
- package/tests/plugins.spec.ts +4 -3
package/src/registry.ts
CHANGED
|
@@ -1,34 +1,10 @@
|
|
|
1
1
|
import type { BasicConfig, BasicContext } from '@owlmeans/context'
|
|
2
2
|
import { ResilientError } from '@owlmeans/error'
|
|
3
|
-
import {
|
|
4
|
-
import type
|
|
5
|
-
|
|
6
|
-
PlanningStore, TransitionExecution, WorkcardDraft,
|
|
7
|
-
} from '@owlmeans/planning'
|
|
8
|
-
import type { StoreRoute } from './store/types.js'
|
|
3
|
+
import { logger } from '@owlmeans/log'
|
|
4
|
+
import { DEFAULT_PLUGIN_ORDER, PlanningRefused, type PlanningPlugin, type PlanningSchemaRegistry, type PlanningStore } from '@owlmeans/planning'
|
|
5
|
+
import type { PluginRegistry } from './types.js'
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
/** Register, or replace the plugin of the same `name`. Its schemas are contributed now. */
|
|
12
|
-
use: (plugin: PlanningPlugin) => void
|
|
13
|
-
/** Every plugin, `order` ascending (registration order among equals). */
|
|
14
|
-
plugins: () => PlanningPlugin[]
|
|
15
|
-
/** The owning plugins that supply a store, in plugin order, each store resolved once. */
|
|
16
|
-
routes: (ctx?: BasicContext<BasicConfig>) => StoreRoute[]
|
|
17
|
-
/** The first owning plugin's store for a type, else `fallback`. */
|
|
18
|
-
storeFor: (type: string | undefined, fallback: PlanningStore, ctx?: BasicContext<BasicConfig>) => PlanningStore
|
|
19
|
-
/** The first plugin answering a code wins. */
|
|
20
|
-
mintCode: (
|
|
21
|
-
draft: WorkcardDraft, taken: (code: string) => Promise<boolean>, contextOf: (plugin: PlanningPlugin) => PlanningExecContext
|
|
22
|
-
) => Promise<string | undefined>
|
|
23
|
-
/** The `before` chain; answers the execution the chain left. */
|
|
24
|
-
before: (
|
|
25
|
-
exec: TransitionExecution, contextOf: (plugin: PlanningPlugin) => PlanningExecContext
|
|
26
|
-
) => Promise<TransitionExecution>
|
|
27
|
-
/** The `after` chain; a failing hook is logged and the chain goes on. */
|
|
28
|
-
after: (event: CommitEvent, contextOf: (plugin: PlanningPlugin) => PlanningHookContext) => Promise<void>
|
|
29
|
-
/** Bumps on every `use` — what a cached composite store is keyed by. */
|
|
30
|
-
version: () => number
|
|
31
|
-
}
|
|
7
|
+
const log = logger('planning')
|
|
32
8
|
|
|
33
9
|
const messageOf = (error: unknown): string => error instanceof Error ? error.message : `${error}`
|
|
34
10
|
|
|
@@ -131,7 +107,7 @@ export const makePluginRegistry = (
|
|
|
131
107
|
try {
|
|
132
108
|
await plugin.after(event, contextOf(plugin))
|
|
133
109
|
} catch (error) {
|
|
134
|
-
|
|
110
|
+
log.error('Planning after hook failed', { plugin: plugin.name, transition: event.transition, error })
|
|
135
111
|
}
|
|
136
112
|
}
|
|
137
113
|
},
|
package/src/service.ts
CHANGED
|
@@ -1,42 +1,13 @@
|
|
|
1
|
-
import { createLazyService } from '@owlmeans/context'
|
|
2
|
-
import type
|
|
3
|
-
import { makeSchemaRegistry, PlanningError } from '@owlmeans/planning'
|
|
4
|
-
import type {
|
|
5
|
-
PlanningSchemaRegistry, PlanningService, PlanningStore, SchemaStore, ScopedSchemaRegistry, Transition,
|
|
6
|
-
WithPlanningService,
|
|
7
|
-
} from '@owlmeans/planning'
|
|
1
|
+
import { createLazyService, type BasicConfig, type BasicContext } from '@owlmeans/context'
|
|
2
|
+
import { makeSchemaRegistry, PlanningError, type PlanningService, type PlanningStore, type Transition, type WithPlanningService } from '@owlmeans/planning'
|
|
8
3
|
import { DEFAULT_ALIAS } from './consts.js'
|
|
9
4
|
import { makeSchemaViews } from './definitions.js'
|
|
10
5
|
import { makeStoreFacade } from './facade.js'
|
|
11
6
|
import { makePluginRegistry } from './registry.js'
|
|
12
|
-
import type { PluginRegistry } from './registry.js'
|
|
13
7
|
import { makeCompositeStore } from './store/composite.js'
|
|
14
8
|
import { makeMemoryPlanningStore } from './store/memory.js'
|
|
15
9
|
import type { BindablePlanningStore } from './store/types.js'
|
|
16
|
-
import type { PlanningHostService, PlanningServiceOptions } from './types.js'
|
|
17
|
-
|
|
18
|
-
export type PlanningServiceApi = Pick<PlanningService, 'use' | 'plugins' | 'schemas' | 'store' | 'for' | 'committed'>
|
|
19
|
-
|
|
20
|
-
/** What the facade and the executor reach the service through. */
|
|
21
|
-
export interface PlanningRuntime {
|
|
22
|
-
service: () => PlanningService
|
|
23
|
-
registry: PluginRegistry
|
|
24
|
-
options: PlanningServiceOptions
|
|
25
|
-
context: () => BasicContext<BasicConfig> | undefined
|
|
26
|
-
/** The composite store reads and commits go through. */
|
|
27
|
-
reader: () => PlanningStore
|
|
28
|
-
/** Every distinct store: the default one first, then each plugin's. */
|
|
29
|
-
stores: () => PlanningStore[]
|
|
30
|
-
/** The default store's data-defined schema port, when it has one. */
|
|
31
|
-
schemaStore: () => SchemaStore | undefined
|
|
32
|
-
/**
|
|
33
|
-
* The registry a card of this organization (and project) resolves through. Without a schema
|
|
34
|
-
* port it is the service's code registry itself — the very same object.
|
|
35
|
-
*/
|
|
36
|
-
schemasFor: (entityId: string, project?: string) => Promise<PlanningSchemaRegistry>
|
|
37
|
-
/** The resolved layer. @throws {PlanningUnsupported} without a schema port */
|
|
38
|
-
scopedSchemas: (entityId: string, project?: string) => Promise<ScopedSchemaRegistry>
|
|
39
|
-
}
|
|
10
|
+
import type { PlanningHostService, PlanningServiceOptions, PlanningRuntime, PlanningServiceApi } from './types.js'
|
|
40
11
|
|
|
41
12
|
const contextOf = (service: PlanningService): BasicContext<BasicConfig> | undefined =>
|
|
42
13
|
(service as Partial<PlanningHostService>).ctx as BasicContext<BasicConfig> | undefined
|
package/src/store/commits.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type
|
|
1
|
+
import { logger } from '@owlmeans/log'
|
|
2
|
+
import { CommitFailed, CommitState, CommitTimeout, DEFAULT_COMMIT_TIMEOUT, WorkcardNotFound, type CommitEvent, type CommitFilter, type CommitStatus, type Unsubscribe, type Workcard } from '@owlmeans/planning'
|
|
3
3
|
import { COMMIT_POLL_LADDER, DEFAULT_COMMIT_MEMORY } from '../consts.js'
|
|
4
4
|
import type { CommitHub, CommitHubOptions } from './types.js'
|
|
5
|
+
import type { Listener } from './types.local.js'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
const log = logger('planning:store')
|
|
7
8
|
|
|
8
9
|
const matches = (event: CommitEvent, filter?: CommitFilter): boolean =>
|
|
9
10
|
filter == null || (
|
|
@@ -58,7 +59,7 @@ export const makeCommitHub = (options: CommitHubOptions): CommitHub => {
|
|
|
58
59
|
const results = await Promise.allSettled(targets.map(async entry => await entry.listener(event)))
|
|
59
60
|
results.forEach(result => {
|
|
60
61
|
if (result.status === 'rejected') {
|
|
61
|
-
|
|
62
|
+
log.error('Planning commit listener failed', { transition: event.transition, error: result.reason })
|
|
62
63
|
}
|
|
63
64
|
})
|
|
64
65
|
},
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const CONTENT_KEYS = ['body', 'ref', 'format', 'version'] as const
|
package/src/store/fold.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
} from '@owlmeans/planning'
|
|
4
|
-
import type {
|
|
5
|
-
CommitEvent, PlanningStore, Relationship, SpecificationRevision, Transition, Workcard,
|
|
6
|
-
} from '@owlmeans/planning'
|
|
1
|
+
import { logger } from '@owlmeans/log'
|
|
2
|
+
import { applyRelationship, applyTransition, CommitState, isProject, PlanningUnsupported, TransitionAction, type CommitEvent, type PlanningStore, type Relationship, type SpecificationRevision, type Transition, type Workcard } from '@owlmeans/planning'
|
|
7
3
|
import type { FoldOptions, FoldResult } from './types.js'
|
|
4
|
+
import { CONTENT_KEYS } from './consts.local.js'
|
|
5
|
+
|
|
6
|
+
const log = logger('planning:store')
|
|
8
7
|
|
|
9
8
|
const isoNow = (): string => new Date().toISOString()
|
|
10
9
|
|
|
@@ -18,7 +17,7 @@ const safely = async (label: string, run: () => Promise<void> | void | undefined
|
|
|
18
17
|
try {
|
|
19
18
|
await run()
|
|
20
19
|
} catch (error) {
|
|
21
|
-
|
|
20
|
+
log.error('Planning store step failed', { step: label, error })
|
|
22
21
|
}
|
|
23
22
|
}
|
|
24
23
|
|
|
@@ -161,7 +160,7 @@ export const foldPending = async (
|
|
|
161
160
|
} catch (advance) {
|
|
162
161
|
// The store itself refuses writes: leave the rest pending for a retry rather than
|
|
163
162
|
// failing every later transition as out of order.
|
|
164
|
-
|
|
163
|
+
log.error('Planning cannot advance a card past a failed transition', { cardId, seq: transition.seq, error: advance })
|
|
165
164
|
await safely('commit failure', () => transitions.commit(transition.id!, { state: CommitState.Failed, at, error: message }))
|
|
166
165
|
await safely('publish', () => opts.publish?.(commitEventOf(transition, CommitState.Failed, at, { error: message })))
|
|
167
166
|
return { card, folded, failed, followUp: true }
|
|
@@ -210,8 +209,6 @@ export const failPending = async (
|
|
|
210
209
|
return pending.items.length
|
|
211
210
|
}
|
|
212
211
|
|
|
213
|
-
const CONTENT_KEYS = ['body', 'ref', 'format', 'version'] as const
|
|
214
|
-
|
|
215
212
|
/**
|
|
216
213
|
* A specification's history, replayed from its log: one entry per create and per committed
|
|
217
214
|
* content change, newest first. The fold is `applyTransition` itself, so an entry's `body` is the
|
package/src/store/memory.ts
CHANGED
|
Binary file
|
package/src/types.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { BasicConfig, BasicContext, LazyService } from '@owlmeans/context'
|
|
2
2
|
import type { AbstractRequest } from '@owlmeans/entrypoint'
|
|
3
|
-
import type {
|
|
4
|
-
AnyTypeSchema, PlanningPlugin, PlanningScope, PlanningService, PlanningStore, StatusFlowSchema,
|
|
5
|
-
WithPlanningService,
|
|
6
|
-
} from '@owlmeans/planning'
|
|
3
|
+
import type { AnyTypeSchema, PlanningPlugin, PlanningScope, PlanningService, PlanningStore, StatusFlowSchema, WithPlanningService, PlanningSchemaRegistry, SchemaStore, ScopedSchemaRegistry, CommitEvent, PlanningExecContext, PlanningHookContext, TransitionExecution, WorkcardDraft } from '@owlmeans/planning'
|
|
7
4
|
import type { ApiServerAppend } from '@owlmeans/server-api'
|
|
8
5
|
import type { ServerConfig, ServerContext } from '@owlmeans/server-context'
|
|
6
|
+
import type { StoreRoute } from './store/types.js'
|
|
7
|
+
|
|
9
8
|
|
|
10
9
|
export interface Config extends ServerConfig { }
|
|
11
10
|
|
|
@@ -96,3 +95,76 @@ export interface PlanningHandlerOptions {
|
|
|
96
95
|
*/
|
|
97
96
|
access?: PlanningAccessResolver
|
|
98
97
|
}
|
|
98
|
+
|
|
99
|
+
export interface SchemaViewsOptions {
|
|
100
|
+
/** The code registry every layer starts from. */
|
|
101
|
+
code: () => PlanningSchemaRegistry
|
|
102
|
+
/** Bumps whenever the code registry changes (a plugin's `use`). */
|
|
103
|
+
version: () => number
|
|
104
|
+
/** The schema port, when the store has one. */
|
|
105
|
+
port: () => SchemaStore | undefined
|
|
106
|
+
/** How many resolved layers are kept. */
|
|
107
|
+
limit?: number
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface SchemaViews {
|
|
111
|
+
/** The code registry itself without a port; the resolved layer with one. */
|
|
112
|
+
of: (entityId: string, project?: string) => Promise<PlanningSchemaRegistry>
|
|
113
|
+
/** @throws {PlanningUnsupported} without a port */
|
|
114
|
+
scoped: (entityId: string, project?: string) => Promise<ScopedSchemaRegistry>
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface ProjectionOptions {
|
|
118
|
+
/** The planning service alias. */
|
|
119
|
+
service?: string
|
|
120
|
+
/** The store the queue folds — the service's default store when omitted. */
|
|
121
|
+
store?: (service: PlanningService) => PlanningStore
|
|
122
|
+
/** Where events go — the store's commit hub `publish` when it has one. */
|
|
123
|
+
publish?: (event: CommitEvent) => Promise<void>
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface PluginRegistry {
|
|
127
|
+
/** Register, or replace the plugin of the same `name`. Its schemas are contributed now. */
|
|
128
|
+
use: (plugin: PlanningPlugin) => void
|
|
129
|
+
/** Every plugin, `order` ascending (registration order among equals). */
|
|
130
|
+
plugins: () => PlanningPlugin[]
|
|
131
|
+
/** The owning plugins that supply a store, in plugin order, each store resolved once. */
|
|
132
|
+
routes: (ctx?: BasicContext<BasicConfig>) => StoreRoute[]
|
|
133
|
+
/** The first owning plugin's store for a type, else `fallback`. */
|
|
134
|
+
storeFor: (type: string | undefined, fallback: PlanningStore, ctx?: BasicContext<BasicConfig>) => PlanningStore
|
|
135
|
+
/** The first plugin answering a code wins. */
|
|
136
|
+
mintCode: (
|
|
137
|
+
draft: WorkcardDraft, taken: (code: string) => Promise<boolean>, contextOf: (plugin: PlanningPlugin) => PlanningExecContext
|
|
138
|
+
) => Promise<string | undefined>
|
|
139
|
+
/** The `before` chain; answers the execution the chain left. */
|
|
140
|
+
before: (
|
|
141
|
+
exec: TransitionExecution, contextOf: (plugin: PlanningPlugin) => PlanningExecContext
|
|
142
|
+
) => Promise<TransitionExecution>
|
|
143
|
+
/** The `after` chain; a failing hook is logged and the chain goes on. */
|
|
144
|
+
after: (event: CommitEvent, contextOf: (plugin: PlanningPlugin) => PlanningHookContext) => Promise<void>
|
|
145
|
+
/** Bumps on every `use` — what a cached composite store is keyed by. */
|
|
146
|
+
version: () => number
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export type PlanningServiceApi = Pick<PlanningService, 'use' | 'plugins' | 'schemas' | 'store' | 'for' | 'committed'>
|
|
150
|
+
|
|
151
|
+
/** What the facade and the executor reach the service through. */
|
|
152
|
+
export interface PlanningRuntime {
|
|
153
|
+
service: () => PlanningService
|
|
154
|
+
registry: PluginRegistry
|
|
155
|
+
options: PlanningServiceOptions
|
|
156
|
+
context: () => BasicContext<BasicConfig> | undefined
|
|
157
|
+
/** The composite store reads and commits go through. */
|
|
158
|
+
reader: () => PlanningStore
|
|
159
|
+
/** Every distinct store: the default one first, then each plugin's. */
|
|
160
|
+
stores: () => PlanningStore[]
|
|
161
|
+
/** The default store's data-defined schema port, when it has one. */
|
|
162
|
+
schemaStore: () => SchemaStore | undefined
|
|
163
|
+
/**
|
|
164
|
+
* The registry a card of this organization (and project) resolves through. Without a schema
|
|
165
|
+
* port it is the service's code registry itself — the very same object.
|
|
166
|
+
*/
|
|
167
|
+
schemasFor: (entityId: string, project?: string) => Promise<PlanningSchemaRegistry>
|
|
168
|
+
/** The resolved layer. @throws {PlanningUnsupported} without a schema port */
|
|
169
|
+
scopedSchemas: (entityId: string, project?: string) => Promise<ScopedSchemaRegistry>
|
|
170
|
+
}
|
package/src/utils/index.ts
CHANGED
package/src/utils/scope.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { requireEntityKey } from '@owlmeans/auth-common'
|
|
2
2
|
import type { BasicConfig, BasicContext } from '@owlmeans/context'
|
|
3
3
|
import type { AbstractRequest } from '@owlmeans/entrypoint'
|
|
4
|
-
import { PLANNING_SERVICE, PlanningForbidden } from '@owlmeans/planning'
|
|
5
|
-
import type { PlanningFacade, PlanningScope, PlanningService, TransitionActor, Workcard } from '@owlmeans/planning'
|
|
4
|
+
import { PLANNING_SERVICE, PlanningForbidden, type PlanningFacade, type PlanningScope, type PlanningService, type TransitionActor, type Workcard } from '@owlmeans/planning'
|
|
6
5
|
import type {
|
|
7
6
|
PlanningAccess, PlanningAccessGrants, PlanningHandlerOptions, PlanningHostService,
|
|
8
7
|
} from '../types.js'
|
|
8
|
+
import type { HandlerScope } from './types.js'
|
|
9
9
|
|
|
10
10
|
const clean = <T extends object>(record: T): T =>
|
|
11
11
|
Object.fromEntries(Object.entries(record).filter(([, value]) => value != null && value !== '')) as T
|
|
@@ -58,12 +58,6 @@ export const planningServiceOf = (
|
|
|
58
58
|
ctx: BasicContext<BasicConfig>, opts?: Pick<PlanningHandlerOptions, 'service'>
|
|
59
59
|
): PlanningService => ctx.service<PlanningHostService>(opts?.service ?? PLANNING_SERVICE)
|
|
60
60
|
|
|
61
|
-
export interface HandlerScope {
|
|
62
|
-
facade: PlanningFacade
|
|
63
|
-
/** The resolver's answer, when the handler options carry one. */
|
|
64
|
-
access?: PlanningAccess
|
|
65
|
-
}
|
|
66
|
-
|
|
67
61
|
/**
|
|
68
62
|
* The facade a handler works through, and the access it was resolved under.
|
|
69
63
|
*
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PlanningFacade } from '@owlmeans/planning'
|
|
2
|
+
import type { PlanningAccess } from '../types.js'
|
|
3
|
+
|
|
4
|
+
export interface HandlerScope {
|
|
5
|
+
facade: PlanningFacade
|
|
6
|
+
/** The resolver's answer, when the handler options carry one. */
|
|
7
|
+
access?: PlanningAccess
|
|
8
|
+
}
|
package/tests/plugins.spec.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { configureLog, logConfig } from '@owlmeans/log'
|
|
1
2
|
import { describe, expect, test } from 'bun:test'
|
|
2
3
|
import { CommitState, PlanningRefused, TransitionAction, WorkcardKind } from '@owlmeans/planning'
|
|
3
4
|
import { makeMemoryPlanningStore } from '../src/store/memory.js'
|
|
@@ -66,8 +67,8 @@ describe('@owlmeans/server-planning — plugins', () => {
|
|
|
66
67
|
],
|
|
67
68
|
}, { sync: false })
|
|
68
69
|
const planning = facade()
|
|
69
|
-
const
|
|
70
|
-
|
|
70
|
+
const { level } = logConfig()
|
|
71
|
+
configureLog({ level: 'silent' })
|
|
71
72
|
try {
|
|
72
73
|
const receipt = await planning.execute({ card: { kind: WorkcardKind.Project, type: PROJECT, title: 'Later' }, action: TransitionAction.Create })
|
|
73
74
|
expect(receipt.transition.commit.state).toBe(CommitState.Pending)
|
|
@@ -80,7 +81,7 @@ describe('@owlmeans/server-planning — plugins', () => {
|
|
|
80
81
|
expect(seen).toEqual([`${receipt.transition.card}:committed:test`])
|
|
81
82
|
expect((await receipt.committed({ timeout: 100 }))!.title).toBe('Later')
|
|
82
83
|
} finally {
|
|
83
|
-
|
|
84
|
+
configureLog({ level })
|
|
84
85
|
}
|
|
85
86
|
})
|
|
86
87
|
})
|