@gp2f/server 0.1.6 → 0.1.7

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/index.d.ts CHANGED
@@ -1,30 +1,200 @@
1
- // Auto-resolve library typings for GP2F
1
+ /* eslint-disable */
2
+ /* tslint:disable */
3
+ /* auto-generated – mirrors gp2f-node/src/*.rs napi exports */
2
4
 
3
- export interface PolicyNode {
4
- kind: string;
5
- path?: string;
6
- value?: string;
7
- children?: PolicyNode[];
5
+ // ── Node kinds ────────────────────────────────────────────────────────────────
6
+
7
+ export type NodeKind =
8
+ | 'LiteralTrue'
9
+ | 'LiteralFalse'
10
+ | 'And'
11
+ | 'Or'
12
+ | 'Not'
13
+ | 'Eq'
14
+ | 'Neq'
15
+ | 'Gt'
16
+ | 'Gte'
17
+ | 'Lt'
18
+ | 'Lte'
19
+ | 'In'
20
+ | 'Contains'
21
+ | 'Exists'
22
+ | 'Field'
23
+ | 'Call'
24
+ | 'VibeCheck'
25
+
26
+ // ── Core AST ──────────────────────────────────────────────────────────────────
27
+
28
+ /** A node in the GP2F policy AST. */
29
+ export interface AstNode {
30
+ /** The operation this node performs (required). */
31
+ kind: string
32
+ /** Child nodes for composite operators (AND, OR, NOT, comparison, …). */
33
+ children?: AstNode[]
34
+ /** JSON-pointer path used by `FIELD` and `EXISTS` nodes (e.g. `/user/role`). */
35
+ path?: string
36
+ /** String-encoded scalar value for leaf nodes (e.g. `"admin"`, `"42"`). */
37
+ value?: string
38
+ /** Name of the external function – used only by `CALL` nodes. */
39
+ callName?: string
8
40
  }
9
41
 
42
+ // ── Activity & server configuration ──────────────────────────────────────────
43
+
44
+ /** Configuration object for a single workflow activity. */
10
45
  export interface ActivityConfig {
11
- policy: PolicyNode;
46
+ /** Policy AST that governs whether this activity is permitted. */
47
+ policy: AstNode | PolicyInput
48
+ /** Optional name of a registered compensation handler. */
49
+ compensationRef?: string
50
+ /** When `true`, this activity runs as a Local Activity. */
51
+ isLocal?: boolean
52
+ }
53
+
54
+ /** Server startup configuration. */
55
+ export interface ServerConfig {
56
+ /** TCP port to listen on. Defaults to 3000. */
57
+ port?: number
58
+ /** Bind address. Defaults to `"0.0.0.0"`. */
59
+ host?: string
60
+ }
61
+
62
+ /** Context passed to every `onExecute` callback. */
63
+ export interface ExecutionContext {
64
+ /** Unique workflow execution identifier. */
65
+ instanceId: string
66
+ /** Tenant/organisation this execution belongs to. */
67
+ tenantId: string
68
+ /** Name of the activity currently executing. */
69
+ activityName: string
70
+ /** The JSON-encoded state document. Use `JSON.parse(ctx.stateJson)`. */
71
+ stateJson: string
12
72
  }
13
73
 
14
- export class JsGp2FServer {
15
- constructor(config: { port?: number; host?: string });
16
- register(workflow: JsWorkflow): void;
17
- start(): Promise<void>;
74
+ /** Result of a policy evaluation including the decision trace. */
75
+ export interface EvalResult {
76
+ /** `true` when the policy permits the operation. */
77
+ result: boolean
78
+ /** Human-readable trace of each evaluation step (for debugging). */
79
+ trace: string[]
18
80
  }
19
81
 
82
+ // ── Native functions ──────────────────────────────────────────────────────────
83
+
84
+ /**
85
+ * Evaluate a policy AST against a JSON state object.
86
+ *
87
+ * Returns `true` when the policy permits the operation.
88
+ */
89
+ export function evaluate(policy: AstNode, state: object): boolean
90
+
91
+ /**
92
+ * Evaluate a policy AST and return the full evaluation trace.
93
+ *
94
+ * Useful for debugging policies.
95
+ */
96
+ export function evaluateWithTrace(policy: AstNode, state: object): EvalResult
20
97
 
21
- export class JsWorkflow {
22
- constructor(id: string);
98
+ // ── Workflow class ────────────────────────────────────────────────────────────
99
+
100
+ export class Workflow {
101
+ constructor(workflowId: string)
102
+
103
+ /** Add an activity to this workflow. */
23
104
  addActivity(
24
105
  name: string,
25
106
  config: ActivityConfig,
26
- handler: (ctx: any) => Promise<void>
27
- ): void;
28
- activityCount(): number;
29
- id(): string;
107
+ onExecute?: (ctx: ExecutionContext) => Promise<void> | void,
108
+ ): string
109
+
110
+ /** The workflow identifier. */
111
+ readonly id: string
112
+
113
+ /** Number of registered activities. */
114
+ readonly activityCount: number
115
+
116
+ /** Evaluate all activity policies against `state` (no side-effects). */
117
+ dryRun(state: object): boolean
118
+ }
119
+
120
+ // ── GP2FServer class ──────────────────────────────────────────────────────────
121
+
122
+ export class GP2FServer {
123
+ constructor(config?: ServerConfig)
124
+
125
+ /** Register a workflow with this server. */
126
+ register(workflow: Workflow): void
127
+
128
+ /** Start the HTTP server. */
129
+ start(): Promise<void>
130
+
131
+ /** Stop the HTTP server. */
132
+ stop(): Promise<void>
133
+
134
+ /** The configured TCP port. */
135
+ readonly port: number
136
+
137
+ /** `true` when the server is currently accepting connections. */
138
+ readonly isRunning: boolean
139
+ }
140
+
141
+ // ── Fluent Policy Builder ─────────────────────────────────────────────────────
142
+
143
+ /** Shared interface for all builder objects that can produce an AstNode. */
144
+ export interface Builder {
145
+ build(): AstNode
146
+ toJSON(): AstNode
147
+ }
148
+
149
+ /** A policy value that is either a raw AstNode or a Builder. */
150
+ export type PolicyInput = AstNode | Builder
151
+
152
+ /** Builder for field-specific policy assertions. */
153
+ export declare class FieldBuilder implements Builder {
154
+ constructor(path: string)
155
+
156
+ equal(value: string | number): AstNode
157
+ eq(value: string | number): AstNode
158
+ notEqual(value: string | number): AstNode
159
+ neq(value: string | number): AstNode
160
+
161
+ greaterThan(value: string | number): AstNode
162
+ gt(value: string | number): AstNode
163
+ greaterThanOrEqual(value: string | number): AstNode
164
+ gte(value: string | number): AstNode
165
+ lessThan(value: string | number): AstNode
166
+ lt(value: string | number): AstNode
167
+ lessThanOrEqual(value: string | number): AstNode
168
+ lte(value: string | number): AstNode
169
+
170
+ in(values: string[]): AstNode
171
+ contains(value: string): AstNode
172
+
173
+ build(): AstNode
174
+ toJSON(): AstNode
175
+ }
176
+
177
+ /** Builder for Semantic Vibe Engine checks. */
178
+ export declare class VibeBuilder implements Builder {
179
+ constructor(intent: string)
180
+
181
+ withConfidence(threshold: number): this
182
+
183
+ build(): AstNode
184
+ toJSON(): AstNode
30
185
  }
186
+
187
+ /** Entry point for the fluent policy builder API. */
188
+ export declare class PolicyBuilder {
189
+ static field(path: string): FieldBuilder
190
+ static and(...nodes: PolicyInput[]): AstNode
191
+ static or(...nodes: PolicyInput[]): AstNode
192
+ static not(node: PolicyInput): AstNode
193
+ static exists(path: string): AstNode
194
+ static literalTrue(): AstNode
195
+ static literalFalse(): AstNode
196
+ static vibe(intent: string): VibeBuilder
197
+ }
198
+
199
+ /** Shorthand alias for {@link PolicyBuilder}. */
200
+ export declare const p: typeof PolicyBuilder
package/index.js CHANGED
@@ -38,14 +38,25 @@ function loadNative() {
38
38
  )
39
39
  }
40
40
 
41
- const nativeAddon = loadNative()
41
+ const { p, PolicyBuilder, FieldBuilder, VibeBuilder } = require('./lib/policy-builder')
42
42
 
43
- module.exports = nativeAddon
43
+ let native
44
+ try {
45
+ native = loadNative()
46
+ } catch (_) {
47
+ native = {}
48
+ }
49
+
50
+ module.exports = { ...native, p, PolicyBuilder, FieldBuilder, VibeBuilder }
44
51
 
45
52
  // Explicitly assign named exports so Node.js CJS-ESM bridge can statically analyze them
46
- module.exports.JsGp2FServer = nativeAddon.JsGp2FServer
47
- module.exports.JsWorkflow = nativeAddon.JsWorkflow
48
- module.exports.NodeKind = nativeAddon.NodeKind
49
- module.exports.JsServerConfig = nativeAddon.JsServerConfig
50
- module.exports.JsActivityConfig = nativeAddon.JsActivityConfig
51
- module.exports.JsAstNode = nativeAddon.JsAstNode
53
+ module.exports.GP2FServer = native.JsGp2FServer || native.GP2FServer
54
+ module.exports.Workflow = native.JsWorkflow || native.Workflow
55
+ module.exports.AstNode = native.JsAstNode || native.AstNode
56
+ module.exports.NodeKind = native.JsNodeKind || native.NodeKind
57
+ module.exports.evaluate = native.evaluate
58
+ module.exports.evaluateWithTrace = native.evaluateWithTrace
59
+ module.exports.p = p
60
+ module.exports.PolicyBuilder = PolicyBuilder
61
+ module.exports.FieldBuilder = FieldBuilder
62
+ module.exports.VibeBuilder = VibeBuilder
@@ -0,0 +1,154 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * Fluent Policy Builder API for constructing GP2F policy AST nodes.
5
+ *
6
+ * Provides a chainable alternative to writing raw JSON AST objects.
7
+ *
8
+ * @example
9
+ * ```js
10
+ * const { p } = require('@gp2f/server');
11
+ *
12
+ * const policy = p.and(
13
+ * p.field('/user/role').eq('admin'),
14
+ * p.exists('/session/token'),
15
+ * );
16
+ * ```
17
+ */
18
+
19
+ // ── Internal helper ───────────────────────────────────────────────────────────
20
+
21
+ function resolve(node) {
22
+ return node && typeof node.build === 'function' ? node.build() : node
23
+ }
24
+
25
+ // ── FieldBuilder ──────────────────────────────────────────────────────────────
26
+
27
+ class FieldBuilder {
28
+ constructor(path) {
29
+ this._path = path
30
+ }
31
+
32
+ _op(kind, value) {
33
+ return {
34
+ kind,
35
+ children: [
36
+ { kind: 'Field', path: this._path },
37
+ { kind: 'Literal', value },
38
+ ],
39
+ }
40
+ }
41
+
42
+ // Equality
43
+ equal(value) { return this._op('Eq', String(value)) }
44
+ eq(value) { return this.equal(value) }
45
+ notEqual(value) { return this._op('Neq', String(value)) }
46
+ neq(value) { return this.notEqual(value) }
47
+
48
+ // Comparisons
49
+ greaterThan(value) { return this._op('Gt', String(value)) }
50
+ gt(value) { return this.greaterThan(value) }
51
+ greaterThanOrEqual(value) { return this._op('Gte', String(value)) }
52
+ gte(value) { return this.greaterThanOrEqual(value) }
53
+ lessThan(value) { return this._op('Lt', String(value)) }
54
+ lt(value) { return this.lessThan(value) }
55
+ lessThanOrEqual(value) { return this._op('Lte', String(value)) }
56
+ lte(value) { return this.lessThanOrEqual(value) }
57
+
58
+ // Collection
59
+ in(values) {
60
+ return {
61
+ kind: 'In',
62
+ children: [
63
+ { kind: 'Field', path: this._path },
64
+ { kind: 'Literal', value: JSON.stringify(values) },
65
+ ],
66
+ }
67
+ }
68
+
69
+ contains(value) {
70
+ return {
71
+ kind: 'Contains',
72
+ children: [
73
+ { kind: 'Field', path: this._path },
74
+ { kind: 'Literal', value },
75
+ ],
76
+ }
77
+ }
78
+
79
+ build() {
80
+ throw new Error(
81
+ 'FieldBuilder must be terminated with an operator (e.g. .eq(), .gt())'
82
+ )
83
+ }
84
+
85
+ toJSON() {
86
+ return this.build()
87
+ }
88
+ }
89
+
90
+ // ── VibeBuilder ───────────────────────────────────────────────────────────────
91
+
92
+ class VibeBuilder {
93
+ constructor(intent) {
94
+ this._intent = intent
95
+ this._threshold = undefined
96
+ }
97
+
98
+ withConfidence(threshold) {
99
+ this._threshold = threshold
100
+ return this
101
+ }
102
+
103
+ build() {
104
+ const node = { kind: 'VibeCheck', value: this._intent }
105
+ if (this._threshold !== undefined) {
106
+ node.path = String(this._threshold)
107
+ }
108
+ return node
109
+ }
110
+
111
+ toJSON() {
112
+ return this.build()
113
+ }
114
+ }
115
+
116
+ // ── PolicyBuilder ─────────────────────────────────────────────────────────────
117
+
118
+ class PolicyBuilder {
119
+ static field(path) {
120
+ return new FieldBuilder(path)
121
+ }
122
+
123
+ static and(...nodes) {
124
+ return { kind: 'And', children: nodes.map(resolve) }
125
+ }
126
+
127
+ static or(...nodes) {
128
+ return { kind: 'Or', children: nodes.map(resolve) }
129
+ }
130
+
131
+ static not(node) {
132
+ return { kind: 'Not', children: [resolve(node)] }
133
+ }
134
+
135
+ static exists(path) {
136
+ return { kind: 'Exists', path }
137
+ }
138
+
139
+ static literalTrue() {
140
+ return { kind: 'LiteralTrue' }
141
+ }
142
+
143
+ static literalFalse() {
144
+ return { kind: 'LiteralFalse' }
145
+ }
146
+
147
+ static vibe(intent) {
148
+ return new VibeBuilder(intent)
149
+ }
150
+ }
151
+
152
+ const p = PolicyBuilder
153
+
154
+ module.exports = { p, PolicyBuilder, FieldBuilder, VibeBuilder }
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@gp2f/server",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
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",
7
7
  "files": [
8
8
  "index.js",
9
9
  "index.d.ts",
10
+ "lib",
10
11
  "gp2f_node.*.node"
11
12
  ],
12
13
  "scripts": {