@happyvertical/smrt-playbooks 0.51.32 → 0.51.34

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.
@@ -1,281 +1,147 @@
1
- import { CapabilityClassification } from '@happyvertical/smrt-types';
2
- import { CapabilityDeclaration } from '@happyvertical/smrt-types';
3
- import { SmrtClassOptions } from '@happyvertical/smrt-core';
4
-
5
- /**
6
- * Static layers a browser-plane step is evaluated against.
7
- *
8
- * Everything here is a build-time or configuration fact. The generated
9
- * `authMiddleware` is deliberately absent: it is request-bound, returns a
10
- * `Response` rather than a boolean, and may consult session stores, rate-limit,
11
- * or audit — so preflight never invokes it, synthetically or otherwise, and
12
- * `appAuthConfigured` is the only thing it is allowed to know about it.
13
- *
14
- * An `authPredicate` seam (option 1 in #2590) can later be added as an optional
15
- * member here, turning the `app-auth` layer's `unknown` into a real verdict
16
- * without changing the report contract.
17
- */
18
- export declare interface BrowserPreflightLayerSource {
19
- /** `isApiActionEnabled` for the referenced model operation. */
20
- isActionExposed(model: string, action: string): boolean;
21
- /** `isRoutePublic` for the HTTP method the action maps to. */
22
- isRoutePublic(model: string, action: string): boolean;
23
- /** Field-level read-permission slugs the step's model declares. */
24
- requiredFieldPermissions(model: string, action: string): readonly string[];
25
- /** Whether an app-level auth middleware is wired. Never invoked. */
26
- appAuthConfigured: boolean;
27
- }
28
-
29
- export declare interface BrowserPreflightOptions {
30
- layers: BrowserPreflightLayerSource;
31
- /**
32
- * The caller's published permission slugs, when the host publishes them.
33
- * `null`/absent makes the field layer report `unknown` rather than guess.
34
- */
35
- permissions?: Iterable<string> | null;
36
- }
37
-
38
- /**
39
- * A partial override from any layer above the code default. There is no
40
- * `steps` key, and supplying one is rejected rather than ignored.
41
- */
42
- declare interface PlaybookConfigOverrideInput {
43
- title?: string | null;
44
- description?: string | null;
45
- planes?: readonly PlaybookPlane[] | null;
46
- onStepFailure?: PlaybookFailurePolicy | null;
47
- enabled?: boolean | null;
48
- metadata?: PlaybookMetadata | null;
49
- [key: string]: unknown;
50
- }
51
-
52
- /**
53
- * What an agent does when a step fails partway through a plan. Playbooks are
54
- * scripts, never atomic units, so there is no compensation: the definition
55
- * says only whether the remainder of the plan is abandoned.
56
- */
57
- declare type PlaybookFailurePolicy = 'abort' | 'continue';
58
-
59
- /**
60
- * Record returned by an intent registry for a declared view intent.
61
- *
62
- * Seam for #2588: until an intent registry exists, no resolver is supplied and
63
- * an intent step fails resolution closed.
64
- */
65
- declare interface PlaybookIntentRecord {
66
- id: string;
67
- classification?: CapabilityDeclaration | null;
68
- planes?: readonly PlaybookPlane[] | null;
69
- }
70
-
71
- /** Seam for #2588. */
72
- declare type PlaybookIntentResolver = (id: string) => PlaybookIntentRecord | null | undefined;
73
-
74
- /**
75
- * A step naming a declared view intent by its identity (#2588). Valid only
76
- * where a surface is mounted.
77
- */
78
- declare interface PlaybookIntentStep {
79
- kind: 'intent';
80
- /** Declared intent identity from the #2588 intent registry. */
81
- id: string;
82
- label?: string;
83
- description?: string;
84
- optional?: boolean;
85
- }
86
-
87
- declare type PlaybookMetadata = Record<string, unknown>;
88
-
89
- /**
90
- * Resolves the capability classification of a referenced model operation.
91
- *
92
- * Playbooks never classify a step themselves. A host that knows the emitted
93
- * build-time classification (core's `tool-schema.ts` output, or the runtime
94
- * manifest) supplies it here; anything it does not know resolves fail-closed
95
- * to `{ effect: 'destructive', idempotent: false, openWorld: true }`.
96
- */
97
- declare type PlaybookOperationClassifier = (step: PlaybookOperationStep) => CapabilityDeclaration | null | undefined;
98
-
99
- /**
100
- * A step naming a model operation by qualified pair — the same qualified
101
- * form STI discriminators and `@crossPackageRef` already use. Never a
102
- * generated tool name: that is derived from model, action, and namespace and
103
- * would silently orphan stored tenant overrides on a namespace change.
104
- *
105
- * The step never classifies itself; classification is inherited from the
106
- * referenced operation (see {@link PlaybookOperationClassifier}).
107
- */
108
- declare interface PlaybookOperationStep {
109
- kind: 'operation';
110
- /** Qualified model name, e.g. `@happyvertical/smrt-commerce:Order`. */
111
- model: string;
112
- /** Operation name exposed by the model's `@smrt({ api })` surface. */
113
- action: string;
114
- /** Human-facing label for the agent's narration of this step. */
115
- label?: string;
116
- /** Longer human-facing description of the step. */
117
- description?: string;
118
- /** When true, an agent may skip this step without abandoning the plan. */
119
- optional?: boolean;
120
- }
121
-
122
- /**
123
- * Execution planes a playbook can declare validity for.
124
- *
125
- * `browser` covers WebMCP / in-page agents driving mounted surfaces;
126
- * `server` covers Node MCP, CLI, and in-app agents running under
127
- * `executeAsPrincipal`.
128
- */
129
- declare type PlaybookPlane = 'browser' | 'server';
130
-
131
- /** One step of a resolved plan, with its inherited classification. */
132
- declare interface PlaybookPlanStep {
133
- index: number;
134
- step: PlaybookStep;
135
- classification: CapabilityClassification;
136
- /** True when the classification is the fail-closed default. */
137
- classificationDeclared: boolean;
138
- }
139
-
140
- export declare interface PlaybookPreflightAvailableReport {
141
- available: true;
142
- /**
143
- * Literal `true` on every report, as a type-level reminder: a report is a
144
- * prediction, never a grant, and every step is authorized again where it
145
- * executes.
146
- */
147
- advisory: true;
148
- key: string;
149
- plane: PlaybookPlane;
150
- title: string;
151
- description: string;
152
- verdict: PreflightVerdict;
153
- steps: readonly PreflightStepReport[];
154
- summary: PreflightSummary;
155
- }
156
-
157
- /** A preflight result. Advisory only — see the two variants above. */
158
- export declare type PlaybookPreflightReport = PlaybookPreflightAvailableReport | PlaybookPreflightUnavailableReport;
159
-
160
- export declare interface PlaybookPreflightRequest {
161
- key: string;
162
- plane: PlaybookPlane;
163
- /**
164
- * Opaque, caller-scoped principal identity used to partition the cache. It is
165
- * never echoed in the report and never consulted for authority. The cache key
166
- * also folds in `resolve.tenantId`, so a principal string need not encode the
167
- * tenant to stay correct.
168
- */
169
- principal: string;
170
- /** Options handed to `resolvePlaybook()` — the caller's own layer chain. */
171
- resolve?: ResolvePlaybookOptions;
172
- /** Evaluates each resolved step. */
173
- evaluate: PreflightStepEvaluator;
174
- }
175
-
176
- /**
177
- * The single, uniform answer for every playbook the caller's own layer chain
178
- * cannot resolve. An unknown key and an unauthorized key produce this exact
179
- * frozen value, so preflight is not an enumeration oracle: it carries no key,
180
- * no plane, and no reason to tell the two apart.
181
- */
182
- export declare interface PlaybookPreflightUnavailableReport {
183
- available: false;
184
- advisory: true;
185
- verdict: 'deny';
186
- steps: readonly [];
187
- summary: PreflightSummary;
188
- }
189
-
190
- /** A playbook step. Exactly two kinds exist in v1; playbooks cannot nest. */
191
- declare type PlaybookStep = PlaybookOperationStep | PlaybookIntentStep;
192
-
193
- /**
194
- * The authority layers preflight reports on. The two planes are deliberately
195
- * asymmetric and report different layers:
196
- *
197
- * - server plane — `tool-allowlist`, `operation-permission`, and `plane` for an
198
- * intent step;
199
- * - browser plane — `action-exposure`, `public-access`, `field-permissions`,
200
- * `app-auth`, and `intent-mount` for an intent step.
201
- */
202
- export declare type PreflightLayer = 'tool-allowlist' | 'operation-permission' | 'plane' | 'action-exposure' | 'public-access' | 'field-permissions' | 'app-auth' | 'intent-mount';
203
-
204
- /** One authority layer's verdict for one step. */
205
- export declare interface PreflightLayerReport {
206
- layer: PreflightLayer;
207
- verdict: PreflightVerdict;
208
- reason: PreflightReason;
209
- /**
210
- * Permission slugs this layer found missing, when it knows them. Present only
211
- * on layers that evaluate a slug set.
212
- */
213
- missingPermissions?: readonly string[];
214
- }
215
-
216
- /** Why a layer reached its verdict. A stable code, never a free-form message. */
217
- export declare type PreflightReason = 'ok' | 'tool-not-allowed' | 'permission-denied' | 'permission-unknown' | 'plane' | 'action-not-exposed' | 'not-public' | 'auth-required' | 'app-auth-not-evaluated' | 'app-auth-not-configured' | 'fields-redacted' | 'field-permissions-unknown' | 'intent-not-mounted' | 'intent-bridge-not-evaluated' | 'not-evaluated';
218
-
219
- /** What a step evaluator returns; `preflightPlan` supplies `index` and `kind`. */
220
- export declare interface PreflightStepEvaluation {
221
- layers: readonly PreflightLayerReport[];
222
- }
223
-
224
- /** Evaluates one resolved plan step without executing any part of it. */
225
- export declare type PreflightStepEvaluator = (step: PlaybookPlanStep) => PreflightStepEvaluation | Promise<PreflightStepEvaluation>;
226
-
227
- /** A step's aggregate verdict plus the per-layer detail behind it. */
228
- export declare interface PreflightStepReport {
229
- index: number;
230
- kind: PlaybookStep['kind'];
231
- verdict: PreflightVerdict;
232
- /** Reason of the first layer that produced the step's aggregate verdict. */
233
- reason: PreflightReason;
234
- layers: readonly PreflightLayerReport[];
235
- }
236
-
237
- export declare interface PreflightSummary {
238
- allow: number;
239
- deny: number;
240
- unknown: number;
241
- }
242
-
243
- /**
244
- * Verdict for one authority layer, one step, or a whole plan.
245
- *
246
- * `unknown` is a first-class answer, never a rounded-down `allow`: a layer that
247
- * cannot be evaluated without executing something says so.
248
- */
249
- export declare type PreflightVerdict = 'allow' | 'deny' | 'unknown';
250
-
251
- declare interface ResolvePlaybookOptions {
252
- db?: SmrtClassOptions['db'];
253
- tenantId?: string | null;
254
- /** Plane the calling agent runs on. Defaults to `'server'`. */
255
- plane?: PlaybookPlane;
256
- /** Highest-precedence layer, supplied per call. */
257
- override?: PlaybookConfigOverrideInput;
258
- /** Host-supplied classification source for model-operation steps. */
259
- classifier?: PlaybookOperationClassifier;
260
- /** Host-supplied intent registry (#2588). */
261
- intents?: PlaybookIntentResolver;
262
- }
263
-
264
- export declare interface ServerPreflightOptions {
265
- /** `PrincipalRun.isToolAllowed` for the slug that gates this step. */
266
- isToolAllowed(step: PlaybookOperationStep): boolean;
267
- /**
268
- * The operation-permission predicate. Evaluates the catalog gate for the
269
- * step's `(collection, action)` without performing the operation.
270
- */
271
- checkOperationPermission(step: PlaybookOperationStep): PreflightVerdict | Promise<PreflightVerdict>;
272
- /** Declared plane validity of a view intent, from the #2588 registry. */
273
- intentPlanes?(id: string): readonly PlaybookPlane[] | null | undefined;
274
- }
275
-
276
- export { }
277
-
278
-
279
- declare global {
280
- var __smrtPlaybookRegistry: Map<string, PlaybookDefinition> | undefined;
1
+ /**
2
+ * Preflight contract (issue #2590) — the verdict vocabulary both planes share.
3
+ *
4
+ * Kept beside the resolution types rather than inside them because preflight is
5
+ * a *reader* of a resolved plan: nothing here changes what a playbook is, and
6
+ * nothing here executes, authorizes, or grants anything.
7
+ */
8
+ import type { PlaybookOperationStep, PlaybookPlane, PlaybookPlanStep, PlaybookStep, ResolvePlaybookOptions } from './types.js';
9
+ /**
10
+ * Verdict for one authority layer, one step, or a whole plan.
11
+ *
12
+ * `unknown` is a first-class answer, never a rounded-down `allow`: a layer that
13
+ * cannot be evaluated without executing something says so.
14
+ */
15
+ export type PreflightVerdict = 'allow' | 'deny' | 'unknown';
16
+ /**
17
+ * The authority layers preflight reports on. The two planes are deliberately
18
+ * asymmetric and report different layers:
19
+ *
20
+ * - server plane — `tool-allowlist`, `operation-permission`, and `plane` for an
21
+ * intent step;
22
+ * - browser plane — `action-exposure`, `public-access`, `field-permissions`,
23
+ * `app-auth`, and `intent-mount` for an intent step.
24
+ */
25
+ export type PreflightLayer = 'tool-allowlist' | 'operation-permission' | 'plane' | 'action-exposure' | 'public-access' | 'field-permissions' | 'app-auth' | 'intent-mount';
26
+ /** Why a layer reached its verdict. A stable code, never a free-form message. */
27
+ export type PreflightReason = 'ok' | 'tool-not-allowed' | 'permission-denied' | 'permission-unknown' | 'plane' | 'action-not-exposed' | 'not-public' | 'auth-required' | 'app-auth-not-evaluated' | 'app-auth-not-configured' | 'fields-redacted' | 'field-permissions-unknown' | 'intent-not-mounted' | 'intent-bridge-not-evaluated' | 'not-evaluated';
28
+ /** One authority layer's verdict for one step. */
29
+ export interface PreflightLayerReport {
30
+ layer: PreflightLayer;
31
+ verdict: PreflightVerdict;
32
+ reason: PreflightReason;
33
+ /**
34
+ * Permission slugs this layer found missing, when it knows them. Present only
35
+ * on layers that evaluate a slug set.
36
+ */
37
+ missingPermissions?: readonly string[];
281
38
  }
39
+ /** A step's aggregate verdict plus the per-layer detail behind it. */
40
+ export interface PreflightStepReport {
41
+ index: number;
42
+ kind: PlaybookStep['kind'];
43
+ verdict: PreflightVerdict;
44
+ /** Reason of the first layer that produced the step's aggregate verdict. */
45
+ reason: PreflightReason;
46
+ layers: readonly PreflightLayerReport[];
47
+ }
48
+ /** What a step evaluator returns; `preflightPlan` supplies `index` and `kind`. */
49
+ export interface PreflightStepEvaluation {
50
+ layers: readonly PreflightLayerReport[];
51
+ }
52
+ /** Evaluates one resolved plan step without executing any part of it. */
53
+ export type PreflightStepEvaluator = (step: PlaybookPlanStep) => PreflightStepEvaluation | Promise<PreflightStepEvaluation>;
54
+ export interface PreflightSummary {
55
+ allow: number;
56
+ deny: number;
57
+ unknown: number;
58
+ }
59
+ export interface PlaybookPreflightAvailableReport {
60
+ available: true;
61
+ /**
62
+ * Literal `true` on every report, as a type-level reminder: a report is a
63
+ * prediction, never a grant, and every step is authorized again where it
64
+ * executes.
65
+ */
66
+ advisory: true;
67
+ key: string;
68
+ plane: PlaybookPlane;
69
+ title: string;
70
+ description: string;
71
+ verdict: PreflightVerdict;
72
+ steps: readonly PreflightStepReport[];
73
+ summary: PreflightSummary;
74
+ }
75
+ /**
76
+ * The single, uniform answer for every playbook the caller's own layer chain
77
+ * cannot resolve. An unknown key and an unauthorized key produce this exact
78
+ * frozen value, so preflight is not an enumeration oracle: it carries no key,
79
+ * no plane, and no reason to tell the two apart.
80
+ */
81
+ export interface PlaybookPreflightUnavailableReport {
82
+ available: false;
83
+ advisory: true;
84
+ verdict: 'deny';
85
+ steps: readonly [];
86
+ summary: PreflightSummary;
87
+ }
88
+ /** A preflight result. Advisory only — see the two variants above. */
89
+ export type PlaybookPreflightReport = PlaybookPreflightAvailableReport | PlaybookPreflightUnavailableReport;
90
+ /**
91
+ * Static layers a browser-plane step is evaluated against.
92
+ *
93
+ * Everything here is a build-time or configuration fact. The generated
94
+ * `authMiddleware` is deliberately absent: it is request-bound, returns a
95
+ * `Response` rather than a boolean, and may consult session stores, rate-limit,
96
+ * or audit — so preflight never invokes it, synthetically or otherwise, and
97
+ * `appAuthConfigured` is the only thing it is allowed to know about it.
98
+ *
99
+ * An `authPredicate` seam (option 1 in #2590) can later be added as an optional
100
+ * member here, turning the `app-auth` layer's `unknown` into a real verdict
101
+ * without changing the report contract.
102
+ */
103
+ export interface BrowserPreflightLayerSource {
104
+ /** `isApiActionEnabled` for the referenced model operation. */
105
+ isActionExposed(model: string, action: string): boolean;
106
+ /** `isRoutePublic` for the HTTP method the action maps to. */
107
+ isRoutePublic(model: string, action: string): boolean;
108
+ /** Field-level read-permission slugs the step's model declares. */
109
+ requiredFieldPermissions(model: string, action: string): readonly string[];
110
+ /** Whether an app-level auth middleware is wired. Never invoked. */
111
+ appAuthConfigured: boolean;
112
+ }
113
+ export interface BrowserPreflightOptions {
114
+ layers: BrowserPreflightLayerSource;
115
+ /**
116
+ * The caller's published permission slugs, when the host publishes them.
117
+ * `null`/absent makes the field layer report `unknown` rather than guess.
118
+ */
119
+ permissions?: Iterable<string> | null;
120
+ }
121
+ export interface ServerPreflightOptions {
122
+ /** `PrincipalRun.isToolAllowed` for the slug that gates this step. */
123
+ isToolAllowed(step: PlaybookOperationStep): boolean;
124
+ /**
125
+ * The operation-permission predicate. Evaluates the catalog gate for the
126
+ * step's `(collection, action)` without performing the operation.
127
+ */
128
+ checkOperationPermission(step: PlaybookOperationStep): PreflightVerdict | Promise<PreflightVerdict>;
129
+ /** Declared plane validity of a view intent, from the #2588 registry. */
130
+ intentPlanes?(id: string): readonly PlaybookPlane[] | null | undefined;
131
+ }
132
+ export interface PlaybookPreflightRequest {
133
+ key: string;
134
+ plane: PlaybookPlane;
135
+ /**
136
+ * Opaque, caller-scoped principal identity used to partition the cache. It is
137
+ * never echoed in the report and never consulted for authority. The cache key
138
+ * also folds in `resolve.tenantId`, so a principal string need not encode the
139
+ * tenant to stay correct.
140
+ */
141
+ principal: string;
142
+ /** Options handed to `resolvePlaybook()` — the caller's own layer chain. */
143
+ resolve?: ResolvePlaybookOptions;
144
+ /** Evaluates each resolved step. */
145
+ evaluate: PreflightStepEvaluator;
146
+ }
147
+ //# sourceMappingURL=preflight-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight-types.d.ts","sourceRoot":"","sources":["../src/preflight-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Playbook preflight (issue #2590).
3
+ *
4
+ * Playbooks are not atomic and have no compensation, so the real failure mode
5
+ * is half-execution — five steps started, dead at four. Preflight is what
6
+ * prevents that, and secondarily lets a tool listing hide playbooks the caller
7
+ * cannot run.
8
+ *
9
+ * **Preflight predicts; it never grants.** Every step re-enforces at execution,
10
+ * unconditionally — at the REST boundary in the browser, and by
11
+ * `PrincipalRun.assertToolAllowed()` / `assertOperation()` server-side. Without
12
+ * that, a permission revoked mid-playbook would leave a cached "allowed"
13
+ * standing, which is a time-of-check/time-of-use bypass. Nothing in this module
14
+ * executes, authorizes, or caches an authorization.
15
+ *
16
+ * The two planes are deliberately asymmetric:
17
+ *
18
+ * - **Server** is a predicate that already exists. `PrincipalRun` exposes
19
+ * `isToolAllowed(tool): boolean` alongside the throwing `assertToolAllowed()`,
20
+ * and `assertOperation` wraps `assertOperationPermission`. Preflight is the
21
+ * intersection of each step against those two, evaluated and never executed.
22
+ * - **Browser** cannot reuse the generated REST auth contract at all.
23
+ * `authMiddleware` is `(objectName, action) => (req) => Promise<Request |
24
+ * Response>`: request-bound, `Response`-returning rather than boolean, and
25
+ * free to consult session stores, rate-limit, or audit. It is not a dry-run
26
+ * predicate, so preflight covers the **static layers only** — action exposure,
27
+ * `public` access, and field-level permission slugs — and reports the app-auth
28
+ * layer as `unknown`. It never invokes `authMiddleware`, synthetically or
29
+ * otherwise.
30
+ */
31
+ import type { BrowserPreflightOptions, PlaybookPreflightAvailableReport, PlaybookPreflightReport, PlaybookPreflightRequest, PlaybookPreflightUnavailableReport, PreflightStepEvaluator, PreflightVerdict, ServerPreflightOptions } from './preflight-types.js';
32
+ import type { PlaybookPlan } from './types.js';
33
+ /**
34
+ * The one response every unresolvable playbook produces.
35
+ *
36
+ * Frozen and shared so an unknown key and an unauthorized key are byte-for-byte
37
+ * identical: same shape, same values, no key echo, no reason code, no message.
38
+ * Preflight answers only for playbooks resolvable through the caller's own
39
+ * layer chain, and says nothing about anything else — including whether it
40
+ * exists.
41
+ */
42
+ export declare const PLAYBOOK_PREFLIGHT_UNAVAILABLE: PlaybookPreflightUnavailableReport;
43
+ /** Fail-closed combination: `deny` beats `unknown` beats `allow`. */
44
+ export declare function worstVerdict(left: PreflightVerdict, right: PreflightVerdict): PreflightVerdict;
45
+ /**
46
+ * Decomposes a resolved plan into per-step verdicts using `evaluate`.
47
+ *
48
+ * Every step is evaluated — evaluation does not short-circuit on the first
49
+ * denial, because the point of preflight is to show the caller *which* step of
50
+ * five would die, not merely that one would.
51
+ */
52
+ export declare function preflightPlan(plan: PlaybookPlan, evaluate: PreflightStepEvaluator): Promise<PlaybookPreflightAvailableReport>;
53
+ /**
54
+ * Preflights one playbook for one caller on one plane.
55
+ *
56
+ * Resolves through the **caller's own layer chain** (their tenant, their
57
+ * overrides, their plane), decomposes the plan, and evaluates each step with the
58
+ * plane's evaluator. Any playbook the chain cannot resolve — unknown, disabled,
59
+ * wrong plane, unresolvable intent — returns the single
60
+ * {@link PLAYBOOK_PREFLIGHT_UNAVAILABLE} value.
61
+ *
62
+ * Results are cached per `(principal, key, plane)` under the playbook cache's
63
+ * generation counter; see `preflight-cache.ts` for why that is safe.
64
+ */
65
+ export declare function preflightPlaybook(request: PlaybookPreflightRequest): Promise<PlaybookPreflightReport>;
66
+ /**
67
+ * Server-plane evaluator: the intersection of the persona tool allow-list and
68
+ * the operation-permission predicate, per step, with nothing executed.
69
+ *
70
+ * An intent step is reported against its **declared** plane validity: an intent
71
+ * that does not declare `server` is denied with reason `plane`, and one that
72
+ * does is `unknown`, because server validity rides the #2446 command/ack bridge
73
+ * whose acknowledgement is not statically knowable. This repeats a check
74
+ * resolution already made, deliberately — the same defense-in-depth shape as
75
+ * `assertToolAllowed()` gating both the tool offer and its execution.
76
+ */
77
+ export declare function createServerStepEvaluator(options: ServerPreflightOptions): PreflightStepEvaluator;
78
+ /**
79
+ * Browser-plane evaluator: the static layers only.
80
+ *
81
+ * - `action-exposure` — `isApiActionEnabled`. A disabled action is a hard,
82
+ * statically knowable deny (the route answers 405).
83
+ * - `public-access` — `isRoutePublic`. A non-public route with **no** app auth
84
+ * middleware wired is a hard deny (the generator's fail-closed 401); with one
85
+ * wired it is `unknown`, because whether that middleware passes is exactly
86
+ * what preflight refuses to guess.
87
+ * - `field-permissions` — the model's declared field read-permission slugs
88
+ * against the caller's published set. Missing slugs redact fields rather than
89
+ * fail the step, so the verdict stays `allow` and carries
90
+ * `reason: 'fields-redacted'` plus the missing slugs; an unpublished
91
+ * permission set reports `unknown`.
92
+ * - `app-auth` — `unknown` whenever a middleware is wired. This is the layer an
93
+ * `authPredicate` seam would later fill in.
94
+ *
95
+ * An intent step never crosses the REST boundary at all, so it is reported
96
+ * `unknown` against `intent-mount`: whether the surface is mounted and what its
97
+ * staged-control review does are runtime facts of the page, not of the build.
98
+ */
99
+ export declare function createBrowserStepEvaluator(options: BrowserPreflightOptions): PreflightStepEvaluator;
100
+ //# sourceMappingURL=preflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAUH,OAAO,KAAK,EACV,uBAAuB,EACvB,gCAAgC,EAChC,uBAAuB,EACvB,wBAAwB,EACxB,kCAAkC,EAElC,sBAAsB,EAGtB,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAEV,YAAY,EAGb,MAAM,YAAY,CAAC;AAEpB;;;;;;;;GAQG;AACH,eAAO,MAAM,8BAA8B,EAAE,kCAOH,CAAC;AAQ3C,qEAAqE;AACrE,wBAAgB,YAAY,CAC1B,IAAI,EAAE,gBAAgB,EACtB,KAAK,EAAE,gBAAgB,GACtB,gBAAgB,CAElB;AA6BD;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,sBAAsB,GAC/B,OAAO,CAAC,gCAAgC,CAAC,CA+B3C;AAgED;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,uBAAuB,CAAC,CAqDlC;AAkBD;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,sBAAsB,GAC9B,sBAAsB,CA+BxB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,uBAAuB,GAC/B,sBAAsB,CA2DxB"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Browser-plane preflight wiring for the generated REST surface (issue #2590).
3
+ *
4
+ * Binds the plane-agnostic evaluator in `preflight.ts` to the static layers
5
+ * `@happyvertical/smrt-core` exposes, and produces the provider the generated
6
+ * `_preflight` route takes as a seam. Core owns the route and the layer facts;
7
+ * this package owns resolution and the verdict vocabulary, so the dependency
8
+ * stays one-way (playbooks → core).
9
+ *
10
+ * Nothing here can reach `authMiddleware`: the provider is handed a boolean
11
+ * `appAuthConfigured` and no auth handle at all.
12
+ */
13
+ import type { BrowserPreflightLayerSource, PlaybookPreflightReport } from './preflight-types.js';
14
+ import type { ResolvePlaybookOptions } from './types.js';
15
+ /**
16
+ * A layer source reading the generated REST surface's own static rules.
17
+ *
18
+ * A model this build does not register resolves to no object name, and every
19
+ * layer then fails closed: an unregistered model has no route, so a step naming
20
+ * one can only die.
21
+ */
22
+ export declare function createRestPreflightLayerSource(options: {
23
+ appAuthConfigured: boolean;
24
+ }): BrowserPreflightLayerSource;
25
+ export interface BrowserPreflightProviderOptions {
26
+ /**
27
+ * Resolution options shared by every request — classifier, intent registry,
28
+ * and any host-level runtime override. The per-request database handle and
29
+ * tenant come from the route.
30
+ */
31
+ resolve?: Omit<ResolvePlaybookOptions, 'plane' | 'db'>;
32
+ /**
33
+ * Derives the cache-partitioning principal identity for a request. Opaque and
34
+ * never echoed; defaults to the caller's permission slugs, which is the only
35
+ * caller-distinguishing input the static layers actually read.
36
+ */
37
+ principal?: (request: {
38
+ permissions?: Iterable<string>;
39
+ appAuthConfigured: boolean;
40
+ }) => string;
41
+ }
42
+ /**
43
+ * Builds the provider wired into `APIConfig.playbookPreflight`.
44
+ *
45
+ * ```typescript
46
+ * const api = new APIGenerator(manifest, {
47
+ * playbookPreflight: createBrowserPlaybookPreflight(),
48
+ * });
49
+ * ```
50
+ *
51
+ * Every unresolvable key — unknown, disabled, browser-invalid, unresolvable
52
+ * intent — comes back as the single uniform unavailable report, so the endpoint
53
+ * is not an enumeration oracle.
54
+ */
55
+ export declare function createBrowserPlaybookPreflight(options?: BrowserPreflightProviderOptions): (request: {
56
+ key: string;
57
+ plane: 'browser';
58
+ permissions?: Iterable<string>;
59
+ appAuthConfigured: boolean;
60
+ db?: unknown;
61
+ }) => Promise<PlaybookPreflightReport>;
62
+ //# sourceMappingURL=rest-preflight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rest-preflight.d.ts","sourceRoot":"","sources":["../src/rest-preflight.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH,OAAO,KAAK,EACV,2BAA2B,EAC3B,uBAAuB,EACxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE;IACtD,iBAAiB,EAAE,OAAO,CAAC;CAC5B,GAAG,2BAA2B,CAgC9B;AAED,MAAM,WAAW,+BAA+B;IAC9C;;;;OAIG;IACH,OAAO,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC;IACvD;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE;QACpB,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/B,iBAAiB,EAAE,OAAO,CAAC;KAC5B,KAAK,MAAM,CAAC;CACd;AAsBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,GAAE,+BAAoC,GAC5C,CAAC,OAAO,EAAE;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,EAAE,CAAC,EAAE,OAAO,CAAC;CACd,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAqBrC"}
@@ -3,12 +3,12 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-playbooks",
6
- "packageVersion": "0.51.32",
6
+ "packageVersion": "0.51.34",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "542c58a25f647adf86852f1e902d8bbebb68f33a38b16be234e568892d0026d0",
11
- "packageJson": "69a3de2135e604032f30907770ef358d061238b7db1075e1706cf3fe4525a200",
10
+ "manifest": "02659cb7bb41840d2aca07706d580a6e628372d09605ac3f181726f0f3a6b945",
11
+ "packageJson": "5bdf32072411cd2d23269afac6c2df0ebee97d2e4b1f7714569d295f72776b5c",
12
12
  "agents": "24cc1ff7167bdb3f2c2b9350d6ba24fb0286013023c5cc49876f16811387e312"
13
13
  },
14
14
  "exports": [
@@ -24,7 +24,7 @@
24
24
  "@happyvertical/sql": "catalog:",
25
25
  "@happyvertical/smrt-vitest": "workspace:*",
26
26
  "@types/node": "24.13.6",
27
- "typescript": "5.9.3",
27
+ "typescript": "6.0.3",
28
28
  "vite": "8.1.4",
29
29
  "vitest": "4.1.10"
30
30
  },