@formbar/arbiter 0.2.0 → 0.3.0
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 +48 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +9 -7
- package/src/arbiter-plugin.ts +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# @formbar/arbiter
|
|
2
|
+
|
|
3
|
+
Formbar plugin bridge for Arbitre production rules. It syncs form data and `$ui` state into an Arbitre session, fires rules during Formbar evaluation, and applies resulting writes back to form state.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @formbar/arbiter @formbar/core @arbitre/core kuery
|
|
9
|
+
# or
|
|
10
|
+
npm install @formbar/arbiter @formbar/core @arbitre/core kuery
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Minimal usage
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { createArbiterPlugin } from "@formbar/arbiter";
|
|
17
|
+
import { createForm } from "@formbar/core";
|
|
18
|
+
|
|
19
|
+
const form = createForm({
|
|
20
|
+
initialData: { qty: 0 },
|
|
21
|
+
plugins: [
|
|
22
|
+
createArbiterPlugin({
|
|
23
|
+
rules: [
|
|
24
|
+
{
|
|
25
|
+
name: "showDiscount",
|
|
26
|
+
when: { qty: { $gte: 10 } },
|
|
27
|
+
then: [{ $set: { "$ui.showDiscount": true } }],
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
}),
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
form.setValue("qty", 12);
|
|
35
|
+
console.log(form.getState().uiState); // { showDiscount: true }
|
|
36
|
+
form.dispose();
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## When to use this package
|
|
40
|
+
|
|
41
|
+
- Use `@formbar/arbiter` when visibility, requiredness, computed values, or other form behavior should be governed by Arbitre production rules.
|
|
42
|
+
- Use `@formbar/core` plugins or middleware directly for simple imperative form behavior.
|
|
43
|
+
- Combine with `@formbar/react-schema` when schema-driven React layouts should react to rule-produced `$ui` state.
|
|
44
|
+
|
|
45
|
+
## Dependencies
|
|
46
|
+
|
|
47
|
+
- Depends on `@formbar/core`.
|
|
48
|
+
- Peer dependencies: `@arbitre/core >=0.1.0` and `kuery >=2.0.0`.
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal-paths.ts","../src/arbiter-plugin.ts","../src/expression-utils.ts"],"names":["createSession","evaluate"],"mappings":";;;;;;;;AAIO,SAAS,sBAAsB,IAAA,EAAuB;AAC5D,EAAA,OAAO,KAAK,UAAA,CAAW,GAAG,KAAK,CAAC,IAAA,CAAK,WAAW,MAAM,CAAA;AACvD;;;ACiBO,SAAS,oBAAoB,OAAA,EAA2C;AAC9E,EAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,eAAA,EAAgB,GAAI,OAAA;AAE5C,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,WAAA;AAEJ,EAAA,IAAI,eAAA,EAAiB;AACpB,IAAA,OAAA,GAAU,eAAA;AACV,IAAA,WAAA,GAAc,KAAA;AAAA,EACf,WAAW,KAAA,EAAO;AACjB,IAAA,OAAA,GAAUA,kBAAA,CAAc,EAAE,KAAA,EAAkC,CAAA;AAC5D,IAAA,WAAA,GAAc,IAAA;AAAA,EACf,CAAA,MAAO;AACN,IAAA,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAAA,EAC3E;AAEA,EAAA,OAAO;AAAA,IACN,EAAA,EAAI,SAAA;AAAA,IAEJ,SAAS,GAAA,
|
|
1
|
+
{"version":3,"sources":["../src/internal-paths.ts","../src/arbiter-plugin.ts","../src/expression-utils.ts"],"names":["createSession","evaluate"],"mappings":";;;;;;;;AAIO,SAAS,sBAAsB,IAAA,EAAuB;AAC5D,EAAA,OAAO,KAAK,UAAA,CAAW,GAAG,KAAK,CAAC,IAAA,CAAK,WAAW,MAAM,CAAA;AACvD;;;ACiBO,SAAS,oBAAoB,OAAA,EAA2C;AAC9E,EAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,eAAA,EAAgB,GAAI,OAAA;AAE5C,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,WAAA;AAEJ,EAAA,IAAI,eAAA,EAAiB;AACpB,IAAA,OAAA,GAAU,eAAA;AACV,IAAA,WAAA,GAAc,KAAA;AAAA,EACf,WAAW,KAAA,EAAO;AACjB,IAAA,OAAA,GAAUA,kBAAA,CAAc,EAAE,KAAA,EAAkC,CAAA;AAC5D,IAAA,WAAA,GAAc,IAAA;AAAA,EACf,CAAA,MAAO;AACN,IAAA,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAAA,EAC3E;AAEA,EAAA,OAAO;AAAA,IACN,EAAA,EAAI,SAAA;AAAA,IAEJ,SAAS,GAAA,EAA8D;AAEtE,MAAA,IAAI,GAAA,CAAI,MAAA,CAAO,UAAA,CAAW,gBAAgB,CAAA,EAAG;AAG7C,MAAA,IAAI,CAAC,GAAA,CAAI,MAAA,CAAO,eAAe,CAAC,GAAA,CAAI,OAAO,SAAA,EAAW;AAGtD,MAAA,MAAM,OAAO,GAAA,CAAI,IAAA;AACjB,MAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,EAAG;AACpC,QAAA,OAAA,CAAQ,MAAA,CAAO,GAAA,EAAK,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,MAC9B;AAGA,MAAA,MAAM,UAAU,GAAA,CAAI,OAAA;AACpB,MAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,EAAG;AACvC,QAAA,OAAA,CAAQ,OAAO,CAAA,IAAA,EAAO,GAAG,CAAA,CAAA,EAAI,OAAA,CAAQ,GAAG,CAAC,CAAA;AAAA,MAC1C;AAGA,MAAA,MAAM,MAAA,GAAuB,QAAQ,IAAA,EAAK;AAG1C,MAAA,MAAM,SAAwB,EAAC;AAC/B,MAAA,KAAA,MAAW,MAAA,IAAU,OAAO,OAAA,EAAS;AACpC,QAAA,IAAI,qBAAA,CAAsB,MAAA,CAAO,IAAI,CAAA,EAAG;AACxC,QAAA,MAAA,CAAO,IAAA,CAAK;AAAA,UACX,MAAM,MAAA,CAAO,IAAA;AAAA,UACb,OAAO,MAAA,CAAO,QAAA;AAAA,UACd,IAAA,EAAM;AAAA,SACN,CAAA;AAAA,MACF;AAGA,MAAA,MAAM,YAA6C,EAAC;AACpD,MAAA,MAAM,KAAA,GAAQ,QAAQ,QAAA,EAAS;AAC/B,MAAA,KAAA,MAAW,CAAC,IAAA,EAAM,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAClD,QAAA,IAAI,CAAC,IAAA,CAAK,UAAA,CAAW,QAAQ,CAAA,EAAG;AAEhC,QAAA,MAAM,SAAA,GAAY,IAAA,CAAK,KAAA,CAAM,QAAA,CAAS,MAAM,CAAA;AAC5C,QAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA,EAAM;AAChD,UAAA,SAAA,CAAU,SAAS,CAAA,GAAI,KAAA;AAAA,QACxB;AAAA,MACD;AAEA,MAAA,OAAO;AAAA,QACN,MAAA,EAAQ,MAAA,CAAO,MAAA,GAAS,CAAA,GAAI,MAAA,GAAS,MAAA;AAAA,QACrC,WAAW,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA,CAAE,MAAA,GAAS,IAAI,SAAA,GAAY;AAAA,OAC5D;AAAA,IACD,CAAA;AAAA,IAEA,SAAA,GAAY;AACX,MAAA,IAAI,WAAA,EAAa;AAChB,QAAA,OAAA,CAAQ,OAAA,EAAQ;AAAA,MACjB;AAAA,IACD;AAAA,GACD;AACD;AC5FO,SAAS,kBAAA,CAAmB,MAAgB,OAAA,EAA2C;AAC7F,EAAA,OAAOC,cAAA,CAAS,MAAM,OAAO,CAAA;AAC9B","file":"index.cjs","sourcesContent":["/**\n * Arbiter-internal paths start with $ and are not user-facing form data.\n * Filter them out of write intents.\n */\nexport function isArbiterInternalPath(path: string): boolean {\n\treturn path.startsWith(\"$\") && !path.startsWith(\"$ui.\");\n}\n","import { createSession } from \"@arbitre/core\";\nimport type { FiringResult, ProductionRule, RuleSession } from \"@arbitre/core\";\nimport type {\n\tFormPlugin,\n\tPluginEvaluateContext,\n\tPluginEvaluateResult,\n\tPluginFieldMeta,\n\tPluginWrite,\n} from \"@formbar/core\";\nimport { isArbiterInternalPath } from \"./internal-paths.js\";\n\nexport interface ArbiterPluginOptions {\n\t/** Provide raw rules — a session will be created internally. */\n\treadonly rules?: readonly ProductionRule[];\n\t/** Provide a pre-configured session instead of raw rules. */\n\treadonly session?: RuleSession;\n}\n\n/**\n * Creates a FormPlugin that bridges @arbitre/core into the formbar pipeline.\n * Syncs form data into the rule session, fires rules, and converts results\n * into PluginWrite[] and PluginFieldMeta records.\n */\nexport function createArbiterPlugin(options: ArbiterPluginOptions): FormPlugin {\n\tconst { rules, session: externalSession } = options;\n\n\tlet session: RuleSession;\n\tlet ownsSession: boolean;\n\n\tif (externalSession) {\n\t\tsession = externalSession;\n\t\townsSession = false;\n\t} else if (rules) {\n\t\tsession = createSession({ rules: rules as ProductionRule[] });\n\t\townsSession = true;\n\t} else {\n\t\tthrow new Error(\"createArbiterPlugin requires either `rules` or `session`\");\n\t}\n\n\treturn {\n\t\tid: \"arbiter\",\n\n\t\tevaluate(ctx: PluginEvaluateContext): PluginEvaluateResult | undefined {\n\t\t\t// Prevent re-entry from own writes\n\t\t\tif (ctx.origin.startsWith(\"plugin:arbiter\")) return;\n\n\t\t\t// Short-circuit when nothing relevant changed\n\t\t\tif (!ctx.change.dataChanged && !ctx.change.uiChanged) return;\n\n\t\t\t// Sync form data fields into the session\n\t\t\tconst data = ctx.data as Record<string, unknown>;\n\t\t\tfor (const key of Object.keys(data)) {\n\t\t\t\tsession.assert(key, data[key]);\n\t\t\t}\n\n\t\t\t// Sync $ui.* state\n\t\t\tconst uiState = ctx.uiState as Record<string, unknown>;\n\t\t\tfor (const key of Object.keys(uiState)) {\n\t\t\t\tsession.assert(`$ui.${key}`, uiState[key]);\n\t\t\t}\n\n\t\t\t// Fire rules\n\t\t\tconst result: FiringResult = session.fire();\n\n\t\t\t// Convert changes to PluginWrite[], filtering internal paths\n\t\t\tconst writes: PluginWrite[] = [];\n\t\t\tfor (const change of result.changes) {\n\t\t\t\tif (isArbiterInternalPath(change.path)) continue;\n\t\t\t\twrites.push({\n\t\t\t\t\tpath: change.path,\n\t\t\t\t\tvalue: change.newValue,\n\t\t\t\t\tmode: \"set\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Derive field meta from session state\n\t\t\tconst fieldMeta: Record<string, PluginFieldMeta> = {};\n\t\t\tconst state = session.getState();\n\t\t\tfor (const [path, value] of Object.entries(state)) {\n\t\t\t\tif (!path.startsWith(\"$meta.\")) continue;\n\t\t\t\t// Convention: $meta.<fieldPath> holds { visible, disabled, required, readOnly, label }\n\t\t\t\tconst fieldPath = path.slice(\"$meta.\".length);\n\t\t\t\tif (typeof value === \"object\" && value !== null) {\n\t\t\t\t\tfieldMeta[fieldPath] = value as PluginFieldMeta;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\twrites: writes.length > 0 ? writes : undefined,\n\t\t\t\tfieldMeta: Object.keys(fieldMeta).length > 0 ? fieldMeta : undefined,\n\t\t\t};\n\t\t},\n\n\t\tonDispose() {\n\t\t\tif (ownsSession) {\n\t\t\t\tsession.dispose();\n\t\t\t}\n\t\t},\n\t};\n}\n","import { assertSafeSegment, evaluate } from \"kuery\";\nimport type { ExprNode } from \"kuery\";\n\n/**\n * Evaluate a kuery expression against a data context.\n * This is a convenience re-export for consumers using expressions with arbiter rules.\n */\nexport function evaluateExpression(expr: ExprNode, context: Record<string, unknown>): unknown {\n\treturn evaluate(expr, context);\n}\n\nexport { assertSafeSegment };\nexport type { ExprNode };\n"]}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal-paths.ts","../src/arbiter-plugin.ts","../src/expression-utils.ts"],"names":[],"mappings":";;;;;;;AAIO,SAAS,sBAAsB,IAAA,EAAuB;AAC5D,EAAA,OAAO,KAAK,UAAA,CAAW,GAAG,KAAK,CAAC,IAAA,CAAK,WAAW,MAAM,CAAA;AACvD;;;ACiBO,SAAS,oBAAoB,OAAA,EAA2C;AAC9E,EAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,eAAA,EAAgB,GAAI,OAAA;AAE5C,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,WAAA;AAEJ,EAAA,IAAI,eAAA,EAAiB;AACpB,IAAA,OAAA,GAAU,eAAA;AACV,IAAA,WAAA,GAAc,KAAA;AAAA,EACf,WAAW,KAAA,EAAO;AACjB,IAAA,OAAA,GAAU,aAAA,CAAc,EAAE,KAAA,EAAkC,CAAA;AAC5D,IAAA,WAAA,GAAc,IAAA;AAAA,EACf,CAAA,MAAO;AACN,IAAA,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAAA,EAC3E;AAEA,EAAA,OAAO;AAAA,IACN,EAAA,EAAI,SAAA;AAAA,IAEJ,SAAS,GAAA,
|
|
1
|
+
{"version":3,"sources":["../src/internal-paths.ts","../src/arbiter-plugin.ts","../src/expression-utils.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Arbiter-internal paths start with $ and are not user-facing form data.\n * Filter them out of write intents.\n */\nexport function isArbiterInternalPath(path: string): boolean {\n\treturn path.startsWith(\"$\") && !path.startsWith(\"$ui.\");\n}\n","import { createSession } from \"@arbitre/core\";\nimport type { FiringResult, ProductionRule, RuleSession } from \"@arbitre/core\";\nimport type {\n\tFormPlugin,\n\tPluginEvaluateContext,\n\tPluginEvaluateResult,\n\tPluginFieldMeta,\n\tPluginWrite,\n} from \"@formbar/core\";\nimport { isArbiterInternalPath } from \"./internal-paths.js\";\n\nexport interface ArbiterPluginOptions {\n\t/** Provide raw rules — a session will be created internally. */\n\treadonly rules?: readonly ProductionRule[];\n\t/** Provide a pre-configured session instead of raw rules. */\n\treadonly session?: RuleSession;\n}\n\n/**\n * Creates a FormPlugin that bridges @arbitre/core into the formbar pipeline.\n * Syncs form data into the rule session, fires rules, and converts results\n * into PluginWrite[] and PluginFieldMeta records.\n */\nexport function createArbiterPlugin(options: ArbiterPluginOptions): FormPlugin {\n\tconst { rules, session: externalSession } = options;\n\n\tlet session: RuleSession;\n\tlet ownsSession: boolean;\n\n\tif (externalSession) {\n\t\tsession = externalSession;\n\t\townsSession = false;\n\t} else if (rules) {\n\t\tsession = createSession({ rules: rules as ProductionRule[] });\n\t\townsSession = true;\n\t} else {\n\t\tthrow new Error(\"createArbiterPlugin requires either `rules` or `session`\");\n\t}\n\n\treturn {\n\t\tid: \"arbiter\",\n\n\t\tevaluate(ctx: PluginEvaluateContext): PluginEvaluateResult | undefined {\n\t\t\t// Prevent re-entry from own writes\n\t\t\tif (ctx.origin.startsWith(\"plugin:arbiter\")) return;\n\n\t\t\t// Short-circuit when nothing relevant changed\n\t\t\tif (!ctx.change.dataChanged && !ctx.change.uiChanged) return;\n\n\t\t\t// Sync form data fields into the session\n\t\t\tconst data = ctx.data as Record<string, unknown>;\n\t\t\tfor (const key of Object.keys(data)) {\n\t\t\t\tsession.assert(key, data[key]);\n\t\t\t}\n\n\t\t\t// Sync $ui.* state\n\t\t\tconst uiState = ctx.uiState as Record<string, unknown>;\n\t\t\tfor (const key of Object.keys(uiState)) {\n\t\t\t\tsession.assert(`$ui.${key}`, uiState[key]);\n\t\t\t}\n\n\t\t\t// Fire rules\n\t\t\tconst result: FiringResult = session.fire();\n\n\t\t\t// Convert changes to PluginWrite[], filtering internal paths\n\t\t\tconst writes: PluginWrite[] = [];\n\t\t\tfor (const change of result.changes) {\n\t\t\t\tif (isArbiterInternalPath(change.path)) continue;\n\t\t\t\twrites.push({\n\t\t\t\t\tpath: change.path,\n\t\t\t\t\tvalue: change.newValue,\n\t\t\t\t\tmode: \"set\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Derive field meta from session state\n\t\t\tconst fieldMeta: Record<string, PluginFieldMeta> = {};\n\t\t\tconst state = session.getState();\n\t\t\tfor (const [path, value] of Object.entries(state)) {\n\t\t\t\tif (!path.startsWith(\"$meta.\")) continue;\n\t\t\t\t// Convention: $meta.<fieldPath> holds { visible, disabled, required, readOnly, label }\n\t\t\t\tconst fieldPath = path.slice(\"$meta.\".length);\n\t\t\t\tif (typeof value === \"object\" && value !== null) {\n\t\t\t\t\tfieldMeta[fieldPath] = value as PluginFieldMeta;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\twrites: writes.length > 0 ? writes : undefined,\n\t\t\t\tfieldMeta: Object.keys(fieldMeta).length > 0 ? fieldMeta : undefined,\n\t\t\t};\n\t\t},\n\n\t\tonDispose() {\n\t\t\tif (ownsSession) {\n\t\t\t\tsession.dispose();\n\t\t\t}\n\t\t},\n\t};\n}\n","import { assertSafeSegment, evaluate } from \"kuery\";\nimport type { ExprNode } from \"kuery\";\n\n/**\n * Evaluate a kuery expression against a data context.\n * This is a convenience re-export for consumers using expressions with arbiter rules.\n */\nexport function evaluateExpression(expr: ExprNode, context: Record<string, unknown>): unknown {\n\treturn evaluate(expr, context);\n}\n\nexport { assertSafeSegment };\nexport type { ExprNode };\n"]}
|
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@formbar/arbiter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Arbiter rule engine bridge for @formbar/core — declarative UI governance via production rules",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/surikaterna/formbar.git",
|
|
10
|
+
"directory": "packages/arbiter"
|
|
11
|
+
},
|
|
7
12
|
"main": "./dist/index.cjs",
|
|
8
13
|
"module": "./dist/index.js",
|
|
9
14
|
"types": "./dist/index.d.ts",
|
|
@@ -14,10 +19,7 @@
|
|
|
14
19
|
"require": "./dist/index.cjs"
|
|
15
20
|
}
|
|
16
21
|
},
|
|
17
|
-
"files": [
|
|
18
|
-
"dist",
|
|
19
|
-
"src"
|
|
20
|
-
],
|
|
22
|
+
"files": ["dist", "src"],
|
|
21
23
|
"sideEffects": false,
|
|
22
24
|
"scripts": {
|
|
23
25
|
"build": "tsc --noEmit",
|
|
@@ -25,14 +27,14 @@
|
|
|
25
27
|
"test": "vitest run"
|
|
26
28
|
},
|
|
27
29
|
"dependencies": {
|
|
28
|
-
"@formbar/core": "
|
|
30
|
+
"@formbar/core": "^0.3.0"
|
|
29
31
|
},
|
|
30
32
|
"peerDependencies": {
|
|
31
33
|
"@arbitre/core": ">=0.1.0",
|
|
32
34
|
"kuery": ">=2.0.0"
|
|
33
35
|
},
|
|
34
36
|
"devDependencies": {
|
|
35
|
-
"@arbitre/core": "
|
|
37
|
+
"@arbitre/core": "^0.2.0",
|
|
36
38
|
"kuery": "^2.0.0"
|
|
37
39
|
}
|
|
38
40
|
}
|
package/src/arbiter-plugin.ts
CHANGED
|
@@ -40,7 +40,7 @@ export function createArbiterPlugin(options: ArbiterPluginOptions): FormPlugin {
|
|
|
40
40
|
return {
|
|
41
41
|
id: "arbiter",
|
|
42
42
|
|
|
43
|
-
evaluate(ctx: PluginEvaluateContext): PluginEvaluateResult |
|
|
43
|
+
evaluate(ctx: PluginEvaluateContext): PluginEvaluateResult | undefined {
|
|
44
44
|
// Prevent re-entry from own writes
|
|
45
45
|
if (ctx.origin.startsWith("plugin:arbiter")) return;
|
|
46
46
|
|