@owlmeans/planning 0.1.18-rc.31 → 0.1.18-rc.32
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/planning/SKILL.md +1 -1
- package/agent-meta/skills/planning/parts/types.md +4 -1
- package/build/helpers/app/types.d.ts +3 -1
- package/build/helpers/app/types.d.ts.map +1 -1
- package/build/helpers/app.d.ts.map +1 -1
- package/build/helpers/app.js +10 -5
- package/build/helpers/app.js.map +1 -1
- package/package.json +1 -1
- package/src/helpers/app/types.ts +3 -1
- package/src/helpers/app.ts +10 -4
- package/tests/csp.spec.ts +122 -0
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ the executor with `@owlmeans/server-planning` and reads remotely with `@owlmeans
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
|
-
bun add @owlmeans/planning@^0.1.18-rc.
|
|
12
|
+
bun add @owlmeans/planning@^0.1.18-rc.32 ajv ajv-formats
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Concepts
|
|
@@ -251,7 +251,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
251
251
|
your project's skill store (`.agents/skills/`):
|
|
252
252
|
|
|
253
253
|
```sh
|
|
254
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
254
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.59
|
|
255
255
|
```
|
|
256
256
|
|
|
257
257
|
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": 3,
|
|
3
3
|
"package": "@owlmeans/planning",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.1.18-rc.32",
|
|
5
|
+
"generatedAt": "2026-10-27T08:58:03.612Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -8,7 +8,7 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/planning
|
|
9
9
|
|
|
10
10
|
**Layer:** Cross-cutting domain
|
|
11
|
-
**Install:** `"@owlmeans/planning": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/planning": "^0.1.18-rc.32"` in `dependencies` (`ajv` and `ajv-formats` are peers)
|
|
12
12
|
|
|
13
13
|
The contracts of project planning: record shapes, schemas, refusals, the protocol tree, the pure
|
|
14
14
|
fold and the models. No database, no fastify, no React. The executor, the plugin registry, the
|
|
@@ -70,7 +70,10 @@ schemas: { app: {
|
|
|
70
70
|
|
|
71
71
|
- **Closed form** (`appSchemaHelper.assertDeclarations` → `SchemaInvalid('app:<kind>:…')`): each
|
|
72
72
|
kind is `{ type?: 'object', properties, required? }` and nothing else; property names hold no
|
|
73
|
-
`.` or `$`; every `required` name is declared in the same declaration;
|
|
73
|
+
`.` or `$`; every `required` name is declared in the same declaration; outside a browser document
|
|
74
|
+
the schema compiles. A page never compiles (a strict `script-src` refuses Ajv's code generation):
|
|
75
|
+
building, loading or merging a registry there runs the closed-form checks only, and what it
|
|
76
|
+
registers is the bundle its server compiled when the plugins were registered.
|
|
74
77
|
- **Merge** (`appSchemaHelper.merge`, run by the server's plugin registry on every `use` and by
|
|
75
78
|
the client over the served bundle): the service's own `schemas.app` first, then each plugin's in
|
|
76
79
|
plugin order (`order` ascending, registration order among equals). Per kind `properties` are
|
|
@@ -20,7 +20,9 @@ export interface AppSchemaHelper {
|
|
|
20
20
|
merge: (sources: ReadonlyArray<PlanningAppDeclarations | undefined>) => PlanningAppDeclarations | undefined;
|
|
21
21
|
/**
|
|
22
22
|
* The closed form of declarations: per kind only `type` (`'object'`), `properties` (names without
|
|
23
|
-
* `.` or `$`) and `required` (each name declared), and a schema that
|
|
23
|
+
* `.` or `$`) and `required` (each name declared), and — outside a browser document — a schema that
|
|
24
|
+
* compiles. A page never compiles: a strict `script-src` refuses code generation, and what a page
|
|
25
|
+
* registers its server compiled when it registered it.
|
|
24
26
|
*
|
|
25
27
|
* @throws {SchemaInvalid} `app:<kind>:…`
|
|
26
28
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/helpers/app/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAA;AACpC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAE5E,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAA;AAElF;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;OAOG;IACH,KAAK,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,uBAAuB,GAAG,SAAS,CAAC,KAAK,uBAAuB,GAAG,SAAS,CAAA;IAC3G
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/helpers/app/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAA;AACpC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAE5E,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAA;AAElF;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;OAOG;IACH,KAAK,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,uBAAuB,GAAG,SAAS,CAAC,KAAK,uBAAuB,GAAG,SAAS,CAAA;IAC3G;;;;;;;OAOG;IACH,kBAAkB,EAAE,CAAC,GAAG,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAC1D;;;OAGG;IACH,WAAW,EAAE,CAAC,GAAG,EAAE,uBAAuB,GAAG,SAAS,EAAE,IAAI,EAAE,kBAAkB,KAAK,SAAS,GAAG,SAAS,CAAA;IAC1G;;;;;;OAMG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,uBAAuB,KAAK,IAAI,CAAA;IACvG;;;;;;;OAOG;IACH,cAAc,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE,uBAAuB,KAAK,SAAS,CAAA;CAClF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/helpers/app.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAsB,MAAM,gBAAgB,CAAA;AASzE,eAAO,MAAM,qBAAqB,QAAO,
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/helpers/app.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAsB,MAAM,gBAAgB,CAAA;AASzE,eAAO,MAAM,qBAAqB,QAAO,eA8IxC,CAAA;AAED,eAAO,MAAM,eAAe,iBAA0B,CAAA"}
|
package/build/helpers/app.js
CHANGED
|
@@ -8,6 +8,9 @@ export const createAppSchemaHelper = () => {
|
|
|
8
8
|
// Keyed by the declared kind object a registry keeps — a fresh ajv per entry, so a replaced
|
|
9
9
|
// declaration leaves nothing compiled behind.
|
|
10
10
|
const bags = new WeakMap();
|
|
11
|
+
// A page never compiles: under a strict `script-src` Ajv's code generation is refused, and the
|
|
12
|
+
// declarations a page registers are its server's, compiled there when they were registered.
|
|
13
|
+
const compiles = () => typeof globalThis.document === 'undefined';
|
|
11
14
|
const objectSchemaOf = (declared) => ({
|
|
12
15
|
type: 'object',
|
|
13
16
|
properties: declared.properties,
|
|
@@ -54,11 +57,13 @@ export const createAppSchemaHelper = () => {
|
|
|
54
57
|
if (missing != null) {
|
|
55
58
|
throw new SchemaInvalid(`app:${kind}:required:${missing}`);
|
|
56
59
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
if (compiles()) {
|
|
61
|
+
try {
|
|
62
|
+
makeAjv().compile(objectSchemaOf(declared));
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
throw new SchemaInvalid(`app:${kind}:${messageOf(error)}`);
|
|
66
|
+
}
|
|
62
67
|
}
|
|
63
68
|
}
|
|
64
69
|
};
|
package/build/helpers/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/helpers/app.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/helpers/app.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/planning",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.32",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Runtime-free project-planning contracts — the workcard super type, projects, specifications, typed relationships, status flows with three intrinsic states, the transition event and its pure fold, the schema registry, the models and the protocol tree.",
|
|
6
6
|
"type": "module",
|
package/src/helpers/app/types.ts
CHANGED
|
@@ -22,7 +22,9 @@ export interface AppSchemaHelper {
|
|
|
22
22
|
merge: (sources: ReadonlyArray<PlanningAppDeclarations | undefined>) => PlanningAppDeclarations | undefined
|
|
23
23
|
/**
|
|
24
24
|
* The closed form of declarations: per kind only `type` (`'object'`), `properties` (names without
|
|
25
|
-
* `.` or `$`) and `required` (each name declared), and a schema that
|
|
25
|
+
* `.` or `$`) and `required` (each name declared), and — outside a browser document — a schema that
|
|
26
|
+
* compiles. A page never compiles: a strict `script-src` refuses code generation, and what a page
|
|
27
|
+
* registers its server compiled when it registered it.
|
|
26
28
|
*
|
|
27
29
|
* @throws {SchemaInvalid} `app:<kind>:…`
|
|
28
30
|
*/
|
package/src/helpers/app.ts
CHANGED
|
@@ -16,6 +16,10 @@ export const createAppSchemaHelper = (): AppSchemaHelper => {
|
|
|
16
16
|
// declaration leaves nothing compiled behind.
|
|
17
17
|
const bags = new WeakMap<PlanningAppSchema, ValidateFunction>()
|
|
18
18
|
|
|
19
|
+
// A page never compiles: under a strict `script-src` Ajv's code generation is refused, and the
|
|
20
|
+
// declarations a page registers are its server's, compiled there when they were registered.
|
|
21
|
+
const compiles = (): boolean => typeof (globalThis as { document?: unknown }).document === 'undefined'
|
|
22
|
+
|
|
19
23
|
const objectSchemaOf = (declared: PlanningAppSchema): Record<string, unknown> => ({
|
|
20
24
|
type: 'object',
|
|
21
25
|
properties: declared.properties,
|
|
@@ -65,10 +69,12 @@ export const createAppSchemaHelper = (): AppSchemaHelper => {
|
|
|
65
69
|
if (missing != null) {
|
|
66
70
|
throw new SchemaInvalid(`app:${kind}:required:${missing}`)
|
|
67
71
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
if (compiles()) {
|
|
73
|
+
try {
|
|
74
|
+
makeAjv().compile(objectSchemaOf(declared as unknown as PlanningAppSchema))
|
|
75
|
+
} catch (error) {
|
|
76
|
+
throw new SchemaInvalid(`app:${kind}:${messageOf(error)}`)
|
|
77
|
+
}
|
|
72
78
|
}
|
|
73
79
|
}
|
|
74
80
|
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { afterEach, describe, expect, test } from 'bun:test'
|
|
2
|
+
import { IntrinsicStatus, WorkcardKind } from '../src/index.js'
|
|
3
|
+
import type {
|
|
4
|
+
PlanningAppDeclarations, PlanningSchemaBundle, ProjectTypeSchema, StatusFlowSchema, WorkcardTypeSchema,
|
|
5
|
+
} from '../src/index.js'
|
|
6
|
+
import { appSchemaHelper } from '../src/helpers/app.js'
|
|
7
|
+
import { scopedSchemaHelper } from '../src/helpers/scoped.js'
|
|
8
|
+
import { makeSchemaRegistry } from '../src/registry.js'
|
|
9
|
+
|
|
10
|
+
/** What a browser says when a page's `script-src` lacks `'unsafe-eval'`. */
|
|
11
|
+
const REFUSAL = "Evaluating a string as JavaScript violates the following Content Security Policy directive because 'unsafe-eval' is not an allowed source of script"
|
|
12
|
+
|
|
13
|
+
/** The work-management seed's declarations: every type and flow may carry a description. */
|
|
14
|
+
const APP: PlanningAppDeclarations = {
|
|
15
|
+
type: { properties: { description: { type: 'string', maxLength: 2000 } } },
|
|
16
|
+
flow: { properties: { description: { type: 'string', maxLength: 2000 } } },
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const WORK: StatusFlowSchema = {
|
|
20
|
+
id: 'wm:work-flow', version: 1, overridable: true, app: { description: 'Day-to-day work' },
|
|
21
|
+
statuses: [{ key: 'open', intrinsic: IntrinsicStatus.Planned, initial: true }, { key: 'done', intrinsic: IntrinsicStatus.Closed }],
|
|
22
|
+
transitions: [{ name: 'finish', from: ['open'], to: 'done' }],
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const TASK: WorkcardTypeSchema = {
|
|
26
|
+
type: 'wm:task', kind: WorkcardKind.Card, version: 1, flows: [WORK.id], specifications: [], overridable: true,
|
|
27
|
+
app: { description: 'Work items' },
|
|
28
|
+
fields: { type: 'object', properties: { priority: { type: 'string', enum: ['low', 'high'] } }, required: ['priority'] },
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const WORKSPACE: ProjectTypeSchema = {
|
|
32
|
+
type: 'wm:workspace', kind: WorkcardKind.Project, version: 1, fields: { type: 'object' },
|
|
33
|
+
flows: [WORK.id], specifications: [], cardTypes: [TASK.type],
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* A browser page under the publisher's policy: a `document` exists and every code generation is
|
|
38
|
+
* refused, the way a `script-src` without `'unsafe-eval'` refuses `new Function` and `eval`.
|
|
39
|
+
*/
|
|
40
|
+
const makeStrictPage = () => {
|
|
41
|
+
const scope = globalThis as unknown as Record<string, unknown>
|
|
42
|
+
const saved = { Function: scope.Function as FunctionConstructor, eval: scope.eval as typeof eval, error: console.error }
|
|
43
|
+
const counts = { generated: 0, logged: 0 }
|
|
44
|
+
const refuse = (): never => {
|
|
45
|
+
counts.generated++
|
|
46
|
+
throw new EvalError(REFUSAL)
|
|
47
|
+
}
|
|
48
|
+
const refusing = { Function: new Proxy(saved.Function, { construct: refuse, apply: refuse }), eval: new Proxy(saved.eval, { apply: refuse }) }
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
counts,
|
|
52
|
+
enter: () => {
|
|
53
|
+
scope.document = {}
|
|
54
|
+
scope.Function = refusing.Function
|
|
55
|
+
scope.eval = refusing.eval
|
|
56
|
+
console.error = () => { counts.logged++ }
|
|
57
|
+
},
|
|
58
|
+
leave: () => {
|
|
59
|
+
delete scope.document
|
|
60
|
+
scope.Function = saved.Function
|
|
61
|
+
scope.eval = saved.eval
|
|
62
|
+
console.error = saved.error
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const page = makeStrictPage()
|
|
68
|
+
|
|
69
|
+
/** What a server serves: compiled there, then a JSON body — no object a page could share with it. */
|
|
70
|
+
const served = (): PlanningSchemaBundle => JSON.parse(JSON.stringify(makeSchemaRegistry({
|
|
71
|
+
version: 1, types: [WORKSPACE, TASK], flows: [WORK], app: appSchemaHelper.merge([APP]),
|
|
72
|
+
}).bundle())) as PlanningSchemaBundle
|
|
73
|
+
|
|
74
|
+
afterEach(() => page.leave())
|
|
75
|
+
|
|
76
|
+
describe('planning schemas — a page under a strict script-src', () => {
|
|
77
|
+
test('a registry builds, loads and merges served declarations without generating code', () => {
|
|
78
|
+
const bundle = served()
|
|
79
|
+
const scoped = JSON.parse(JSON.stringify(scopedSchemaHelper.resolveScopedBundle(bundle, [], { entityId: 'org-1' })))
|
|
80
|
+
page.counts.generated = 0
|
|
81
|
+
page.counts.logged = 0
|
|
82
|
+
|
|
83
|
+
page.enter()
|
|
84
|
+
const registry = makeSchemaRegistry(bundle)
|
|
85
|
+
expect(registry.app()).toEqual(bundle.app!)
|
|
86
|
+
registry.load(bundle)
|
|
87
|
+
expect(registry.bundle()).toEqual(bundle)
|
|
88
|
+
expect(appSchemaHelper.merge([bundle.app])).toEqual(bundle.app!)
|
|
89
|
+
appSchemaHelper.assertDeclarations(bundle.app!)
|
|
90
|
+
const layer = scopedSchemaHelper.scopedRegistryOf(scoped)
|
|
91
|
+
expect(layer.app()).toEqual(bundle.app!)
|
|
92
|
+
expect((layer.type(TASK.type) as WorkcardTypeSchema).app).toEqual({ description: 'Work items' })
|
|
93
|
+
expect(layer.fieldsSchema(TASK.type)).toEqual(TASK.fields)
|
|
94
|
+
page.leave()
|
|
95
|
+
|
|
96
|
+
expect(page.counts).toEqual({ generated: 0, logged: 0 })
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
test('the closed form is still refused in a page; only the compile is the server\'s', () => {
|
|
100
|
+
const bundle = served()
|
|
101
|
+
const uncompilable = { type: { properties: { a: { type: 'nope' } } } } as unknown as PlanningAppDeclarations
|
|
102
|
+
expect(() => appSchemaHelper.assertDeclarations(uncompilable)).toThrow('app:type:')
|
|
103
|
+
|
|
104
|
+
page.enter()
|
|
105
|
+
expect(() => appSchemaHelper.assertDeclarations({ card: { properties: { 'a.b': {} } } })).toThrow('app:card:name:a.b')
|
|
106
|
+
expect(() => makeSchemaRegistry({ ...bundle, app: { type: { properties: { a: {} }, required: ['b'] } } }))
|
|
107
|
+
.toThrow('app:type:required:b')
|
|
108
|
+
expect(() => appSchemaHelper.assertDeclarations(uncompilable)).not.toThrow()
|
|
109
|
+
page.leave()
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
test('the page really refuses code generation: a native validator cannot be compiled in it', () => {
|
|
113
|
+
const bundle = served()
|
|
114
|
+
page.counts.generated = 0
|
|
115
|
+
|
|
116
|
+
page.enter()
|
|
117
|
+
expect(() => makeSchemaRegistry(bundle).validator(TASK.type)).toThrow(EvalError)
|
|
118
|
+
page.leave()
|
|
119
|
+
|
|
120
|
+
expect(page.counts.generated).toBeGreaterThan(0)
|
|
121
|
+
})
|
|
122
|
+
})
|