@gp2f/server 0.1.1 → 0.1.3

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.
Files changed (3) hide show
  1. package/README.md +81 -0
  2. package/index.d.ts +0 -276
  3. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # @gp2f/server
2
+
3
+ Native Node.js bindings for the GP2F policy engine – powered by napi-rs.
4
+
5
+ ## Overview
6
+ This package provides native bindings to use the core functionality of the GP2F policy engine directly from Node.js applications. It allows for high-performance rule evaluation and state processing.
7
+
8
+ ## Installation
9
+ ```bash
10
+ npm install @gp2f/server
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### 1. Evaluating a Policy (Stateless)
16
+ You can evaluate a state document against a GP2F AST policy directly:
17
+
18
+ ```typescript
19
+ import { evaluate, evaluateWithTrace, AstNode } from '@gp2f/server';
20
+
21
+ const policy: AstNode = {
22
+ kind: 'And',
23
+ children: [
24
+ { kind: 'Field', path: '/role', value: 'admin' },
25
+ { kind: 'Exists', path: '/session/token' }
26
+ ]
27
+ };
28
+
29
+ const state = {
30
+ role: 'admin',
31
+ session: { token: 'abc-123' }
32
+ };
33
+
34
+ // Simple boolean evaluation
35
+ const isAllowed = evaluate(policy, state);
36
+ console.log('Allowed:', isAllowed); // true
37
+
38
+ // Evaluation with a step-by-step trace
39
+ const { result, trace } = evaluateWithTrace(policy, state);
40
+ ```
41
+
42
+ ### 2. Embedding the GP2F Server & Workflows
43
+ You can create a complete reconciliation server and define workflows in Node.js:
44
+
45
+ ```typescript
46
+ import { GP2FServer, Workflow } from '@gp2f/server';
47
+
48
+ async function main() {
49
+ const server = new GP2FServer({ port: 3000 });
50
+
51
+ // Define a new workflow
52
+ const wf = new Workflow('document-approval');
53
+
54
+ // Register an activity with a policy and a callback
55
+ wf.addActivity(
56
+ 'review-step',
57
+ { policy: { kind: 'LiteralTrue' } },
58
+ async (ctx) => {
59
+ console.log(`Executing ${ctx.activityName} for instance ${ctx.instanceId}`);
60
+ console.log('State:', JSON.parse(ctx.stateJson));
61
+ }
62
+ );
63
+
64
+ // Register workflow to the server
65
+ server.register(wf);
66
+
67
+ // Start handling HTTP requests
68
+ await server.start();
69
+ console.log(`GP2F Server listening on port ${server.port}`);
70
+ }
71
+
72
+ main().catch(console.error);
73
+ ```
74
+
75
+ ## Development
76
+ This package uses `napi-rs` to build the Rust bindings.
77
+
78
+ - Build cross-platform artifacts: `npm run artifacts`
79
+
80
+ ## License
81
+ MIT
package/index.d.ts CHANGED
@@ -1,276 +0,0 @@
1
- /* auto-generated TypeScript declarations for @gp2f/server (gp2f-node) */
2
-
3
- // ── Policy AST ─────────────────────────────────────────────────────────────
4
-
5
- /**
6
- * Every node kind supported by the GP2F AST policy evaluator.
7
- */
8
- export type NodeKind =
9
- | 'LiteralTrue'
10
- | 'LiteralFalse'
11
- | 'And'
12
- | 'Or'
13
- | 'Not'
14
- | 'Eq'
15
- | 'Neq'
16
- | 'Gt'
17
- | 'Gte'
18
- | 'Lt'
19
- | 'Lte'
20
- | 'In'
21
- | 'Contains'
22
- | 'Exists'
23
- | 'Field'
24
- | 'Call'
25
- | 'VibeCheck'
26
-
27
- /**
28
- * A node in the GP2F policy AST.
29
- *
30
- * Build a tree of these to express the policy that governs whether a given
31
- * activity is permitted.
32
- *
33
- * @example
34
- * ```typescript
35
- * const policy: AstNode = {
36
- * kind: 'And',
37
- * children: [
38
- * { kind: 'Field', path: '/user/role', value: 'admin' },
39
- * { kind: 'Exists', path: '/session/token' },
40
- * ],
41
- * };
42
- * ```
43
- */
44
- export interface AstNode {
45
- /** The operation this node performs (required). */
46
- kind: NodeKind
47
- /** Child nodes for composite operators (And, Or, Not, comparison, …). */
48
- children?: AstNode[]
49
- /** JSON-pointer path used by `Field` and `Exists` nodes. */
50
- path?: string
51
- /** String-encoded scalar value for leaf nodes, e.g. `"admin"` or `"42"`. */
52
- value?: string
53
- /** Name of the external function – used only by `Call` nodes. */
54
- callName?: string
55
- }
56
-
57
- /**
58
- * Result of a policy evaluation including the decision trace.
59
- */
60
- export interface EvalResult {
61
- /** `true` when the policy permits the operation. */
62
- result: boolean
63
- /** Human-readable trace of each evaluation step (useful for debugging). */
64
- trace: string[]
65
- }
66
-
67
- /**
68
- * Evaluate a policy AST against a JSON state object.
69
- *
70
- * @param policy - Root node of the policy AST.
71
- * @param state - Arbitrary JSON object representing the current state.
72
- * @returns `true` when the policy permits the operation, `false` otherwise.
73
- *
74
- * @example
75
- * ```typescript
76
- * import { evaluate } from '@gp2f/server';
77
- *
78
- * const allowed = evaluate(
79
- * { kind: 'Field', path: '/role', value: 'admin' },
80
- * { role: 'admin' }
81
- * );
82
- * // => true
83
- * ```
84
- */
85
- export function evaluate(policy: AstNode, state: unknown): boolean
86
-
87
- /**
88
- * Evaluate a policy AST and return the full evaluation trace.
89
- *
90
- * @param policy - Root node of the policy AST.
91
- * @param state - Arbitrary JSON object representing the current state.
92
- * @returns An {@link EvalResult} with the boolean decision and a trace array.
93
- */
94
- export function evaluateWithTrace(policy: AstNode, state: unknown): EvalResult
95
-
96
- // ── Workflow ────────────────────────────────────────────────────────────────
97
-
98
- /**
99
- * Context object passed to every `onExecute` callback.
100
- */
101
- export interface ExecutionContext {
102
- /** Unique workflow execution identifier. */
103
- instanceId: string
104
- /** Tenant/organisation this execution belongs to. */
105
- tenantId: string
106
- /** Name of the activity currently executing. */
107
- activityName: string
108
- /**
109
- * The JSON-encoded state document evaluated by the policy engine.
110
- *
111
- * Parse with `JSON.parse(ctx.stateJson)` to get the object.
112
- */
113
- stateJson: string
114
- }
115
-
116
- /**
117
- * Configuration object for a single workflow activity.
118
- */
119
- export interface ActivityConfig {
120
- /** Policy AST that governs whether this activity is permitted. */
121
- policy: AstNode
122
- /**
123
- * Optional name of a registered compensation handler to undo this activity
124
- * if a later step fails (Saga pattern).
125
- */
126
- compensationRef?: string
127
- /**
128
- * When `true`, this activity runs as a Local Activity (no Temporal
129
- * persistence round-trip). Use for short, idempotent operations.
130
- */
131
- isLocal?: boolean
132
- }
133
-
134
- /**
135
- * A GP2F workflow definition.
136
- *
137
- * Construct a workflow, register activities, then pass it to
138
- * {@link GP2FServer.register}.
139
- *
140
- * @example
141
- * ```typescript
142
- * import { Workflow } from '@gp2f/server';
143
- *
144
- * const wf = new Workflow('document-approval');
145
- * wf.addActivity(
146
- * 'review',
147
- * { policy: { kind: 'LiteralTrue' } },
148
- * async (ctx) => { console.log('executing', ctx.activityName); }
149
- * );
150
- * ```
151
- */
152
- export class Workflow {
153
- /**
154
- * Create a new workflow with the given identifier.
155
- * @param workflowId - Stable identifier for this workflow.
156
- */
157
- constructor(workflowId: string)
158
-
159
- /** The workflow identifier. */
160
- readonly id: string
161
-
162
- /** The number of registered activities. */
163
- readonly activityCount: number
164
-
165
- /**
166
- * Add an activity to this workflow.
167
- *
168
- * Activities are executed in the order they are added. Each activity has a
169
- * policy AST that determines whether the operation is permitted.
170
- *
171
- * The optional `onExecute` callback is invoked when the activity is
172
- * accepted. It receives an {@link ExecutionContext} and may be async; the
173
- * Rust runtime invokes it on the Node.js event loop via a threadsafe
174
- * function handle.
175
- *
176
- * @param name - Unique name for this activity within the workflow.
177
- * @param config - Activity configuration including the policy AST.
178
- * @param onExecute - Optional async callback invoked when the activity runs.
179
- * @returns The workflow identifier (for informational purposes).
180
- */
181
- addActivity(
182
- name: string,
183
- config: ActivityConfig,
184
- onExecute?: (ctx: ExecutionContext) => void | Promise<unknown>
185
- ): string
186
-
187
- /**
188
- * Evaluate the workflow against a state document without side-effects.
189
- *
190
- * @param state - JSON state document to evaluate against.
191
- * @returns `true` when *every* activity policy is satisfied.
192
- */
193
- dryRun(state: unknown): boolean
194
- }
195
-
196
- // ── Server ──────────────────────────────────────────────────────────────────
197
-
198
- /**
199
- * Configuration object for {@link GP2FServer}.
200
- */
201
- export interface ServerConfig {
202
- /** TCP port the server should listen on. Defaults to `3000`. */
203
- port?: number
204
- /** Hostname / bind address. Defaults to `"127.0.0.1"`. */
205
- host?: string
206
- }
207
-
208
- /**
209
- * The GP2F server.
210
- *
211
- * Hosts an Axum-backed HTTP server that makes the GP2F workflow engine
212
- * accessible from Node.js and other HTTP clients.
213
- *
214
- * ## HTTP API
215
- *
216
- * | Method | Path | Description |
217
- * |--------|-----------------------|------------------------------------------|
218
- * | GET | `/health` | Health-check, returns `"ok"`. |
219
- * | POST | `/workflow/run` | Execute the next activity of a workflow. |
220
- * | POST | `/workflow/dry-run` | Evaluate policies without side-effects. |
221
- *
222
- * @example
223
- * ```typescript
224
- * import { GP2FServer, Workflow } from '@gp2f/server';
225
- *
226
- * const server = new GP2FServer({ port: 3000 });
227
- *
228
- * const wf = new Workflow('my-workflow');
229
- * wf.addActivity('step1', { policy: { kind: 'LiteralTrue' } });
230
- *
231
- * server.register(wf);
232
- * await server.start();
233
- * // ... later:
234
- * await server.stop();
235
- * ```
236
- */
237
- export class GP2FServer {
238
- /**
239
- * Create a new server instance.
240
- *
241
- * The server is not started until {@link GP2FServer.start} is called.
242
- *
243
- * @param config - Optional server configuration.
244
- */
245
- constructor(config?: ServerConfig)
246
-
247
- /** The port the server is (or will be) listening on. */
248
- readonly port: number
249
-
250
- /** `true` while the server is running. */
251
- readonly isRunning: boolean
252
-
253
- /**
254
- * Register a workflow definition with the server.
255
- *
256
- * Workflows can be registered at any time, even while the server is running.
257
- *
258
- * @param workflow - The workflow to register.
259
- */
260
- register(workflow: Workflow): void
261
-
262
- /**
263
- * Start the HTTP server.
264
- *
265
- * Resolves once the TCP listener is bound and the server is ready to accept
266
- * connections.
267
- */
268
- start(): Promise<void>
269
-
270
- /**
271
- * Stop the server gracefully.
272
- *
273
- * Sends a shutdown signal and waits for in-flight requests to drain.
274
- */
275
- stop(): Promise<void>
276
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gp2f/server",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Native Node.js bindings for the GP2F policy engine – powered by napi-rs",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",