@fayegram-ai/decision-bridge 0.0.0-stage → 0.1.1

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 (113) hide show
  1. package/.env.example +10 -0
  2. package/CHANGELOG.md +79 -0
  3. package/CONTRIBUTING.md +57 -0
  4. package/LICENSE +21 -0
  5. package/README.md +313 -2
  6. package/SECURITY.md +88 -0
  7. package/bin/decision.mjs +15 -0
  8. package/docs/README.md +58 -0
  9. package/docs/development/ARCHITECTURE.md +139 -0
  10. package/docs/development/DESIGN.md +77 -0
  11. package/docs/development/README.md +12 -0
  12. package/docs/development/RELEASING.md +100 -0
  13. package/docs/development/REPOSITORY_LAYOUT.md +33 -0
  14. package/docs/development/TESTING.md +153 -0
  15. package/docs/guides/BROWSER.md +43 -0
  16. package/docs/guides/CLOUDFLARE_DECISIONS.md +374 -0
  17. package/docs/guides/CUSTOMIZATION.md +141 -0
  18. package/docs/guides/CUSTOM_DECISION.md +66 -0
  19. package/docs/guides/CUSTOM_GENERATIVE.md +164 -0
  20. package/docs/guides/CUSTOM_PROVIDERS.md +83 -0
  21. package/docs/guides/GETTING_STARTED.md +252 -0
  22. package/docs/guides/OPENAI_DECISIONS.md +252 -0
  23. package/docs/guides/PLATFORMS.md +107 -0
  24. package/docs/guides/SWITCHING_MODELS.md +208 -0
  25. package/docs/guides/TROUBLESHOOTING.md +96 -0
  26. package/docs/reference/CLI.md +213 -0
  27. package/docs/reference/CONFIGURATION.md +170 -0
  28. package/docs/reference/ERRORS.md +85 -0
  29. package/docs/reference/PROVIDERS.md +116 -0
  30. package/docs/reference/SDK.md +394 -0
  31. package/docs/reference/SOURCES.md +51 -0
  32. package/examples/basic.mjs +17 -0
  33. package/examples/batch.mjs +13 -0
  34. package/examples/cloudflare-decisions.mjs +22 -0
  35. package/examples/cloudflare-omni.mjs +32 -0
  36. package/examples/cloudflare-worker.mjs +21 -0
  37. package/examples/cloudflare.native.json +28 -0
  38. package/examples/configs/anthropic.json +9 -0
  39. package/examples/configs/cloudflare-decisions.json +8 -0
  40. package/examples/configs/custom-decision.json +9 -0
  41. package/examples/configs/custom-generative.json +14 -0
  42. package/examples/configs/jev.json +7 -0
  43. package/examples/configs/local.json +12 -0
  44. package/examples/configs/openai-decisions.json +7 -0
  45. package/examples/configs/openai.json +10 -0
  46. package/examples/configs/openrouter.json +10 -0
  47. package/examples/custom/decision-provider.mjs +15 -0
  48. package/examples/custom/generative-provider.mjs +13 -0
  49. package/examples/custom/openrouter.mjs +13 -0
  50. package/examples/customize.mjs +23 -0
  51. package/examples/decisions.native.json +19 -0
  52. package/examples/extended.mjs +43 -0
  53. package/examples/openai-decisions.mjs +20 -0
  54. package/examples/request.json +31 -0
  55. package/examples/requests.jsonl +2 -0
  56. package/package.json +87 -4
  57. package/schemas/decision.config.schema.json +553 -0
  58. package/src/async.mjs +63 -0
  59. package/src/batch.mjs +38 -0
  60. package/src/bridge.mjs +184 -0
  61. package/src/capabilities.mjs +92 -0
  62. package/src/cli/config-validation.mjs +89 -0
  63. package/src/cli/config.mjs +85 -0
  64. package/src/cli/decisions.mjs +21 -0
  65. package/src/cli/initialize.mjs +85 -0
  66. package/src/cli/io.mjs +171 -0
  67. package/src/cli/main.mjs +281 -0
  68. package/src/cli/ordered.mjs +43 -0
  69. package/src/cli/provider-loader.mjs +58 -0
  70. package/src/cloudflare-decisions.d.mts +78 -0
  71. package/src/custom/decision.d.mts +5 -0
  72. package/src/custom/decision.mjs +6 -0
  73. package/src/custom/definition.mjs +19 -0
  74. package/src/custom/generative/anthropic.mjs +75 -0
  75. package/src/custom/generative/index.d.mts +42 -0
  76. package/src/custom/generative/index.mjs +29 -0
  77. package/src/custom/generative/openai-compatible.mjs +101 -0
  78. package/src/custom/generative/schema.mjs +95 -0
  79. package/src/custom/generative/shared.mjs +39 -0
  80. package/src/decisions.d.mts +50 -0
  81. package/src/embedded.mjs +24 -0
  82. package/src/errors.mjs +49 -0
  83. package/src/index.d.mts +232 -0
  84. package/src/index.mjs +7 -0
  85. package/src/input.mjs +37 -0
  86. package/src/options.mjs +15 -0
  87. package/src/policy.mjs +44 -0
  88. package/src/probabilities.mjs +27 -0
  89. package/src/provider-contract.mjs +42 -0
  90. package/src/providers/cloudflare-audio.mjs +83 -0
  91. package/src/providers/cloudflare-codec.mjs +39 -0
  92. package/src/providers/cloudflare-decisions.mjs +81 -0
  93. package/src/providers/cloudflare-images.mjs +95 -0
  94. package/src/providers/cloudflare-media.mjs +36 -0
  95. package/src/providers/cloudflare-preflight.mjs +92 -0
  96. package/src/providers/cloudflare-profile.mjs +102 -0
  97. package/src/providers/cloudflare-transport.mjs +63 -0
  98. package/src/providers/cloudflare-validation.mjs +48 -0
  99. package/src/providers/cloudflare-video.mjs +84 -0
  100. package/src/providers/decisions-codec.mjs +61 -0
  101. package/src/providers/decisions-preflight.mjs +31 -0
  102. package/src/providers/decisions-validation.mjs +151 -0
  103. package/src/providers/index.mjs +26 -0
  104. package/src/providers/jev.mjs +51 -0
  105. package/src/providers/media-binary.mjs +51 -0
  106. package/src/providers/openai-decisions.mjs +58 -0
  107. package/src/providers/openai-profile.mjs +24 -0
  108. package/src/questions.mjs +15 -0
  109. package/src/response-transport.mjs +176 -0
  110. package/src/runtime-env.mjs +4 -0
  111. package/src/transport.mjs +51 -0
  112. package/src/validation.mjs +245 -0
  113. package/src/version.mjs +2 -0
@@ -0,0 +1,139 @@
1
+ # Architecture
2
+
3
+ ## Bridge and provider responsibilities
4
+
5
+ Decision Bridge exposes one application contract for structured decisions. The
6
+ bridge owns request snapshots, common validation, extension sequencing, the total
7
+ deadline, final result validation, immutable results, and bounded observations.
8
+ A provider owns its API encoding, transport, decoding, model selection,
9
+ capabilities, and native operations. Multiple models sharing a protocol can use
10
+ one provider implementation.
11
+
12
+ `createBridge` requires an explicitly selected provider or the Jev shortcut.
13
+ `createProvider` requires an explicit native type. `custom/decision` and
14
+ `custom/generative` expose classified extension helpers; maintained generative
15
+ adapters are loaded only through their opt-in subpath. The CLI resolves its own configuration
16
+ and Jev default before constructing the SDK bridge.
17
+
18
+ ```text
19
+ Application / CLI
20
+ state or ordered input + question definitions + optional model
21
+ |
22
+ v
23
+ request snapshot, common validation, capabilities, provider preflight
24
+ |
25
+ ordered prepareState or prepareInput extensions + revalidation
26
+ |
27
+ Provider.evaluate (explicit decision/generative kind)
28
+ +-- Jev: native systemone
29
+ +-- OpenAI Decisions: native /v1/decisions
30
+ +-- Cloudflare Clef / Clef-flash / Clef-omni: REST or Workers AI binding
31
+ +-- custom/decision: new native decision protocol
32
+ +-- custom/generative: OpenAI-compatible / OpenRouter / Anthropic or new protocol
33
+ |
34
+ canonical result validation using provider precision policy
35
+ |
36
+ immutable result + bounded observation
37
+ |
38
+ application policy / storage / downstream action
39
+ ```
40
+
41
+ Native OpenAI and Cloudflare providers also expose `createDecision` directly.
42
+ Common and native paths share provider validation, codecs, and bounded transport.
43
+ Direct native calls use provider deadlines; bridge calls additionally enforce the
44
+ shared evaluation deadline and extension lifecycle.
45
+
46
+ Application policy decides whether a downstream action is permitted. The SDK
47
+ returns decisions without executing actions or maintaining an agent loop.
48
+
49
+ ## Model selection and request preparation
50
+
51
+ The bridge applies the provider's configured default when a request omits `model`.
52
+ Its validated request and extension context retain that selected string. A provider
53
+ may resolve a selection to an upstream ID while preparing its outgoing request;
54
+ the shared provider contract has no selector-resolution hook.
55
+
56
+ OpenAI's `openai-profile.mjs` owns the `default` selection, accepted selectors,
57
+ upstream targets, and capabilities. Common and native preparation retain the
58
+ validated selection separately from the resolved native request. Preflight returns
59
+ the selected request, while serialization and byte-limit checks use the resolved
60
+ request. Common evaluation and native `createDecision()` share dispatch, which
61
+ sends only that resolved request.
62
+
63
+ Successful OpenAI calls report the selected string in `meta.requestedModel` and
64
+ the outgoing ID in `meta.resolvedModel`. The response's `model` retains the
65
+ service-reported identity. CLI offline validation and execution use the same
66
+ preflight, and generated OpenAI requests inherit selection from configuration.
67
+ See [OpenAI model selection](../guides/OPENAI_DECISIONS.md#model-selection).
68
+
69
+ ## Module map
70
+
71
+ | Module | Responsibility |
72
+ | --- | --- |
73
+ | `src/index.mjs`, `src/index.d.mts` | Public runtime exports and TypeScript contract |
74
+ | `src/bridge.mjs` | Orchestration, extension lifecycle, total deadline, immutable results |
75
+ | `src/validation.mjs`, `src/input.mjs` | Lossless snapshots, common input and result invariants |
76
+ | `src/questions.mjs` | Immutable typed question builders, independent of inference selection |
77
+ | `src/capabilities.mjs` | Provider/model capability checks and common schema versions |
78
+ | `src/probabilities.mjs` | Provider-selected precision allowance without normalization |
79
+ | `src/provider-contract.mjs` | Required classification, authoritative metadata, and generative provenance |
80
+ | `src/custom/decision.mjs` | Explicit native decision definition helper |
81
+ | `src/custom/generative/` | Opt-in protocol presets, schema, prompts, and result derivation |
82
+ | `schemas/decision.config.schema.json` | Shipped CLI configuration structure and editor support |
83
+ | `src/providers/` | API orchestration, model profiles, preflight, codecs, bounded image/audio/video inspection, and transports |
84
+ | `src/providers/openai-profile.mjs`, `src/providers/decisions-preflight.mjs` | Release-owned OpenAI selection, capabilities, and preparation of selected and outgoing requests |
85
+ | `src/embedded.mjs` | Shared embedded data URL and canonical base64 checks |
86
+ | `src/transport.mjs`, `src/response-transport.mjs` | Credential destinations, bounded bodies, safe errors, retries |
87
+ | `src/async.mjs` | Deadlines and cancellation races |
88
+ | `src/options.mjs` | Unknown-field/accessor rejection for options |
89
+ | `src/errors.mjs` | DecisionError and safe public diagnostics |
90
+ | `src/batch.mjs` | Ordered bounded-concurrency SDK arrays |
91
+ | `src/policy.mjs` | Explicit choice thresholds, without action execution |
92
+ | `src/cli/ordered.mjs` | Concurrent JSONL processing with a bounded ordered window |
93
+ | `src/cli/`, `bin/decision.mjs` | Configuration, input/output, commands, process signals |
94
+
95
+ ## Results and precision
96
+
97
+ Generative providers elicit distributions and derive argmax choices, weighted
98
+ scores, and rubric legends in code. Native decision providers validate and retain
99
+ their returned values, confidence, and reported usage. No path repairs malformed
100
+ distributions or invents confidence. The common shape preserves provenance without
101
+ claiming equivalent statistical semantics across models.
102
+
103
+ The bridge takes result-validation policy from the provider contract. Cloudflare
104
+ uses an allowance for four-decimal distributions; other built-ins retain the
105
+ baseline. Response metadata cannot relax validation. See the [SDK reference](../reference/SDK.md).
106
+ Application code passes that precision explicitly when using `decideChoice`; the
107
+ policy helper does not infer it from the answer or its metadata.
108
+
109
+ ## Reliability and configuration
110
+
111
+ Provider deadlines include dispatch, configured retries, backoff, and bounded body
112
+ reading. The bridge deadline additionally covers validation, preparation, provider
113
+ waiting, and result processing. Expired synchronous work cannot dispatch a call.
114
+ Cancellation bounds waiting for custom promises; custom code must honor signals
115
+ to release its own resources. Observations use a separate bounded budget.
116
+
117
+ Retries cover selected explicit transient responses. Ambiguous failures and failed
118
+ observers do not trigger another inference. CLI atomic files protect previous
119
+ output but cannot undo remote work or emitted stdout.
120
+
121
+ JSON configuration is explicit. Custom ESM executes only when selected. Custom
122
+ origins do not inherit unrelated ambient credentials. Gateway settings remain
123
+ provider configuration, and do not replace the bridge's total deadline.
124
+
125
+ ## Extension boundaries
126
+
127
+ Use preparation hooks for context, observation hooks for metrics, classified custom providers
128
+ for another API, and application code for policy. Ordered images and richer
129
+ questions require declared capabilities. Native provider guides document limits.
130
+ Cloudflare Omni supports grouped embedded images/audio/video before text. Model
131
+ profiles resolve request byte limits per call; transport instances share no
132
+ mutable request limit or response identifiers. Header/container inspection is
133
+ bounded and does not perform full media decoding.
134
+
135
+ The SDK does not host models or provide a server API, persistent state, autonomous
136
+ actions, streaming, transcription, transcoding, frame extraction,
137
+ provider-side asynchronous batch jobs, platform
138
+ management, automatic model search, or automatic provider failover. SDK arrays and
139
+ CLI JSONL batches provide bounded client-side concurrency.
@@ -0,0 +1,77 @@
1
+ # Design rationale
2
+
3
+ ## Native decisions as the application contract
4
+
5
+ Use shared state or ordered input and independent typed questions as the public
6
+ contract. The bridge owns orchestration; providers own their model API protocols.
7
+ This gives applications a stable decision interface and makes customization
8
+ explicit at each call. Native decision models are the main package scope;
9
+ generative protocols are opt-in custom strategies with their own public subpath.
10
+ Every provider declares its decision/generative kind. Consequence: not every model can satisfy this contract
11
+ reliably; compatibility and quality must be tested separately.
12
+
13
+ ## ESM JavaScript with declarations and no runtime dependencies
14
+
15
+ Use standard fetch, streams, and JSON in the SDK; keep Node's test runner,
16
+ argument parser, and filesystem APIs in development tools and the optional CLI.
17
+ Ship ESM source plus `.d.mts` types without a transpilation build. Consequence:
18
+ Node 22.16+ is required for Node use, while browser use depends on modern web
19
+ APIs and the provider's CORS policy. TypeScript declaration synchronization needs
20
+ its own tests. A CommonJS entry point is not claimed.
21
+
22
+ ## Provenance is part of the result
23
+
24
+ Native versus elicited probabilities are tagged. Native codecs preserve reported
25
+ probabilities, confidence, and scores. Generative strategies derive choice/score
26
+ from their elicited distributions and do not supply native confidence;
27
+ unreported token counts are null. Consequence: applications must handle optional
28
+ confidence/usage, and identical output schemas do not imply interchangeable
29
+ calibration or correctness.
30
+
31
+ ## Fail explicitly instead of silently repairing or falling back
32
+
33
+ Reject invalid JSON, extra fields, wrong labels, distributions outside the provider
34
+ precision allowance, explicit output truncation, and refusals. Require explicit
35
+ output modes and models. Services may truncate input without reporting it; local
36
+ byte limits do not guarantee token fit. Consequence:
37
+ some calls fail that a permissive wrapper might guess at, but failures remain
38
+ observable and cannot silently change budgets or decision policies.
39
+
40
+ ## Trusted extensions and explicit configuration
41
+
42
+ Read JSON config only when named. Load custom ESM only when explicitly selected.
43
+ Protect credential destinations and expose bounded callbacks. Consequence: plugins
44
+ are powerful and must be trusted; cancellation is not a JavaScript sandbox.
45
+
46
+ ## Release-owned model selectors
47
+
48
+ OpenAI Decisions offers `default` for the provider's default supported model and
49
+ `luna` for the supported Luna-family model, alongside explicit supported upstream
50
+ IDs. The installed package fixes the target and capability profile for each
51
+ selector. The provider resolves it locally before serialization; no discovery,
52
+ automatic upgrade, or fallback occurs during a call. Consequence: applications can
53
+ use a stable selection string while inspecting selected, outgoing, and reported
54
+ model identities separately. A future target change requires an intentional
55
+ package update and verification of that model's protocol and capabilities.
56
+
57
+ ## Conservative retries and independent observations
58
+
59
+ Retry selected explicit transient HTTP statuses within a deadline. Do not retry
60
+ ambiguous network failures, malformed decisions, or observer failures. Consequence:
61
+ users can choose manual retry policies, but exactly-once billing cannot be promised.
62
+
63
+ ## MIT licensing and coordinated distribution
64
+
65
+ Publish the maintained source under the MIT License, with the copyright notice
66
+ in `LICENSE` and matching SPDX identifiers in package metadata. Release the source
67
+ repository and npm package together. Consequence: source and package recipients
68
+ have the same MIT permissions and obligations; building an archive alone does not
69
+ publish a release.
70
+
71
+ ## Verified npm package artifact
72
+
73
+ Build a versioned npm tarball from the source package and retain it only after an
74
+ offline installation check of the exact archive. Publish that verified artifact
75
+ to the public npm registry as part of the coordinated source and package release;
76
+ building alone never publishes it. Consequence: consumers install the release from
77
+ npm, while maintainers verify the exact archive before publication.
@@ -0,0 +1,12 @@
1
+ # Contributor documentation
2
+
3
+ This directory contains maintained documentation for contributors to the public
4
+ repository. Start with [CONTRIBUTING.md](../../CONTRIBUTING.md).
5
+
6
+ | Document | Purpose |
7
+ | --- | --- |
8
+ | [Architecture](ARCHITECTURE.md) | Runtime ownership, evaluation flow, and boundaries |
9
+ | [Design rationale](DESIGN.md) | Public contract choices and their consequences |
10
+ | [Testing](TESTING.md) | Local tests, type checks, packaging checks, and live smoke tests |
11
+ | [Packaging and release](RELEASING.md) | Source/package verification and separate publication instructions |
12
+ | [Repository layout](REPOSITORY_LAYOUT.md) | Source and package boundaries |
@@ -0,0 +1,100 @@
1
+ # Packaging and release
2
+
3
+ The npm package build archives ESM source without compilation. The versioned
4
+ tarball contains the runtime, TypeScript declarations, examples, and maintained
5
+ docs. Tests and development scripts remain in the source repository.
6
+
7
+ ## Verify source and package contents
8
+
9
+ From a clean source checkout, verify the code and build the installable artifact:
10
+
11
+ ```text
12
+ npm run check
13
+ npm run test:coverage
14
+ npm run typecheck
15
+ npm run build
16
+ ```
17
+
18
+ `npm run build` packs the source with lifecycle scripts disabled, installs and
19
+ checks that exact tarball in a clean offline consumer, and retains it at
20
+ `release/fayegram-ai-decision-bridge-VERSION.tgz`. The `release/` directory is Git-ignored.
21
+ Packing and individual verification commands have 120-second bounds; the combined
22
+ installed-consumer verification stage has a separate 600-second bound and streams
23
+ its progress. This accommodates CLI startup across multiple verification commands.
24
+ To check that archive again, run:
25
+
26
+ ```text
27
+ node scripts/package-smoke.mjs --tarball release/fayegram-ai-decision-bridge-VERSION.tgz
28
+ ```
29
+
30
+ Check public documentation against the implementation, including supported API
31
+ shapes, examples, limits, errors, and service compatibility notes. Inspect the MIT
32
+ copyright notice and package contents. Complete hosted checks relevant to changed
33
+ features using an authorized account/runtime;
34
+ fixture and declaration checks do not establish hosted binding/Gateway behavior.
35
+ Keep completed verification evidence separate from maintained consumer guidance.
36
+ These content and verification checks do not depend on publication account setup.
37
+
38
+ ## Confirm publication prerequisites
39
+
40
+ Before publication, confirm the repository exists at the metadata destination and
41
+ inspect CI results for the exact release commit. Make sure the hosted repository
42
+ has a private vulnerability-reporting route as described in
43
+ [SECURITY.md](../../SECURITY.md). Confirm that the npm login can publish under
44
+ `@fayegram-ai`. Direct publication requires account 2FA or a granular token
45
+ permitted to bypass it; see [npm's requirements](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages/).
46
+
47
+ Building only creates and checks the artifact; it does not publish it. The package
48
+ name and registry are `@fayegram-ai/decision-bridge` and the public npm registry.
49
+ Coordinate the GitHub source release and publication of the verified tarball to
50
+ npm as one release. The source release commit and archive must contain the same
51
+ intended files, including README and documentation. A packed or uploaded archive
52
+ is a snapshot: subsequent source edits do not change its contents.
53
+
54
+ The tracked `.npmrc` routes this scope to npm in this checkout without changing
55
+ the user's npm configuration. Keep credentials in the user configuration, never
56
+ in the repository. Verify the target with `npm config get @fayegram-ai:registry`
57
+ before staging or publishing. Replace `VERSION` and `STAGE_ID` below with the
58
+ package version and the returned stage identifier. The `./` prefix identifies a
59
+ local archive path to npm.
60
+
61
+ ## Stage, inspect, and approve an archive
62
+
63
+ With npm CLI 11.15.0+ and package write access, stage the verified archive:
64
+
65
+ ```text
66
+ npm stage publish ./release/fayegram-ai-decision-bridge-VERSION.tgz --access public --tag latest
67
+ npm stage view STAGE_ID --json
68
+ npm stage download STAGE_ID
69
+ ```
70
+
71
+ Compare the downloaded archive's checksum with the retained artifact, then verify
72
+ that exact download using `node scripts/package-smoke.mjs --tarball PATH_TO_DOWNLOAD`.
73
+ The staged version becomes publicly installable when a maintainer approves it
74
+ with 2FA:
75
+
76
+ ```text
77
+ npm stage approve STAGE_ID
78
+ ```
79
+
80
+ Approval publishes that version; no additional `npm publish` is needed. A first
81
+ stage for a new package creates a public `0.0.0-stage` placeholder, which is not
82
+ the staged SDK. See [npm's staged publishing guide](https://docs.npmjs.com/staged-publishing/).
83
+
84
+ If packaged files change before approval, build and verify a fresh archive.
85
+ Reject the old stage with `npm stage reject STAGE_ID` (requires 2FA), then stage
86
+ the new archive and repeat inspection. A pending stage reserves its version, so
87
+ remove it before staging a replacement with the same unpublished version. See
88
+ the [npm stage reference](https://docs.npmjs.com/cli/v12/commands/npm-stage/).
89
+
90
+ ## Direct publication alternative
91
+
92
+ For a version without a pending stage, publish the verified archive directly:
93
+
94
+ ```text
95
+ npm publish ./release/fayegram-ai-decision-bridge-VERSION.tgz --access public --tag latest
96
+ ```
97
+
98
+ After the coordinated release, confirm that the package page
99
+ links to the source repository and `npm install @fayegram-ai/decision-bridge` works.
100
+ Keep generated archives and verification logs outside tracked source.
@@ -0,0 +1,33 @@
1
+ # Repository layout
2
+
3
+ The source repository contains the SDK, CLI, examples, functional tests, CI, and
4
+ maintained documentation. The installable npm tarball contains the SDK and CLI
5
+ with declarations, examples, and docs; it excludes tests and development scripts.
6
+
7
+ ```text
8
+ README.md Product overview and quick start
9
+ CONTRIBUTING.md Contributor entry point
10
+ CHANGELOG.md User-visible changes
11
+ SECURITY.md Security boundaries and reporting guidance
12
+ LICENSE MIT license
13
+ package.json Package identity, exports, commands, and file allowlist
14
+ package-lock.json Pinned development dependency metadata
15
+ .env.example Provider credential placeholders
16
+ src/ Common SDK, native providers, CLI, declarations
17
+ src/custom/ Explicit decision definitions and generative presets
18
+ bin/ Node.js CLI entry point
19
+ examples/ Native SDK examples and request profiles
20
+ examples/custom/ Opt-in generative and native delegation examples
21
+ schemas/ Packaged CLI configuration JSON Schema
22
+ docs/guides/ User guides
23
+ docs/reference/ SDK, CLI, configuration, and provider contracts
24
+ docs/development/ Architecture, tests, and packaging guidance
25
+ test/ Functional and type-contract tests
26
+ scripts/ Source, type, and package checks
27
+ .github/ CI and dependency update configuration
28
+ ```
29
+
30
+ The `package.json` `files` allowlist defines the npm tarball.
31
+ `npm run test:package` verifies the installed files and offline CLI commands. `npm run build`
32
+ retains its verified tarball under the ignored `release/` directory. Credentials
33
+ belong in local environment files, not in source or package contents.
@@ -0,0 +1,153 @@
1
+ # Testing
2
+
3
+ Run these commands from a source checkout. An installed npm package contains
4
+ runtime code and documentation, but does not contain tests or development scripts.
5
+
6
+ ## Automated code and package checks
7
+
8
+ Use Node.js 22.16 or newer. Runtime code has zero npm dependencies. Run
9
+ `npm ci --ignore-scripts` to install the pinned development tools: TypeScript
10
+ 5.8.3, the official Workers declarations, and the configuration-schema validator.
11
+ Source and installed-consumer type checks use the same local compiler.
12
+
13
+ | Command | Verification |
14
+ | --- | --- |
15
+ | `npm run check` | Public-source layout, JavaScript syntax, JSON, formatting, local doc links, versions |
16
+ | `npm test` | SDK, CLI, provider, and file/transport behavior using fixtures and loopback servers |
17
+ | `npm run test:coverage` | The functional suite with production source/bin coverage floors |
18
+ | `npm run typecheck` | Positive and expected-negative TypeScript API contracts |
19
+ | `npm run test:package` | Pack, offline install, root/custom exports and types, browser-safe imports, presets/modules, contents and docs |
20
+ | `npm run build` | Retain a versioned npm tarball after checking its offline installation |
21
+ | `npm run verify` | Source checks, tests, type contracts, and package smoke check |
22
+
23
+ `verify` is a convenience command for routine changes. It already runs `npm test`
24
+ and `test:package`; running coverage and build immediately after it repeats
25
+ those checks. CI and the release guide run `check`, `test:coverage`,
26
+ `typecheck`, and `build` once each.
27
+
28
+ These commands validate code behavior and package integrity. Model-quality
29
+ evaluation is a separate activity, not part of the test suite: these commands do
30
+ not score model answers, measure provider speed, or use paid inference. Coverage
31
+ floors are 90% lines, 80% branches, and 85% functions. Coverage does not establish model
32
+ quality, correctness of every path, or current hosted compatibility.
33
+ The CI configuration targets Linux, Windows, and macOS on Node 22.16 and Node 24;
34
+ consult actual run results for a particular commit instead of treating the matrix
35
+ as evidence that every environment passed.
36
+
37
+ ## Suite ownership
38
+
39
+ - `contract.test.mjs`: request/result contracts, builders, decision policy, and JSON safety.
40
+ - `bridge.test.mjs`: SDK evaluation, extensions, observers, deadlines, and batches.
41
+ - `providers.test.mjs`: provider wire formats, response parsing, model listing, and configuration.
42
+ - `transport.test.mjs`: HTTP policy, limits, retries, cancellation, and deadlines.
43
+ - `deadlines.test.mjs`: synchronous preparation/dispatch/completion and inherited budgets.
44
+ - `result-validation.test.mjs`: provider-selected precision and policy-hook boundaries.
45
+ - `decisions*.test.mjs`: native/common OpenAI codecs, selectors and model identities, boundaries, preflight, CLI, and smoke-helper fixtures.
46
+ - `cloudflare*.test.mjs`: models, images, codecs, REST/binding/Gateway arguments, errors, and CLI limits.
47
+ - `custom-providers.test.mjs`, `custom-config.test.mjs`: classified SDK paths, provenance, presets/modules, schema and initialization.
48
+ - `generative-helpers.test.mjs`: exported prompt/normalization helper contracts and unsupported input rejection.
49
+ - `config.test.mjs`: file/environment/flag precedence and provider transitions.
50
+ - `cli.test.mjs`: commands, streams, exit codes, modules, and signals.
51
+ - `io.test.mjs`: atomic output, file aliases, and cancellation.
52
+ - `ordered.test.mjs`: ordered streaming and bounded concurrency.
53
+ - `support.mjs` and `fixtures.mjs`: local test setup and synthetic domain data.
54
+ - `types.mts`, `providers.types.mts`, `custom.types.mts`: public type inference and rejected API usage.
55
+ - `decisions.types.mts`, `cloudflare.types.mts`: richer questions, native APIs, and precision settings.
56
+ - `cloudflare-worker.types.mts`: compatibility with official Workers binding declarations.
57
+
58
+ Node's reported test count includes each row of a parameterized input table. It
59
+ is not a count of independent features; retain separate rows when they protect
60
+ different contract or protocol paths.
61
+
62
+ All model responses used by ordinary tests are synthetic. HTTP integration servers
63
+ listen on loopback. Tests do not require account keys or make paid model calls.
64
+ Test workspaces are temporary.
65
+
66
+ ### OpenAI model-selector coverage
67
+
68
+ For changes to OpenAI selection or preparation, run the focused suites from the
69
+ source root:
70
+
71
+ ```text
72
+ node --test test/decisions-selectors.test.mjs test/decisions-preflight.test.mjs test/decisions-cli.test.mjs
73
+ ```
74
+
75
+ These cover omitted, `default`, `luna`, and explicit upstream selection; unsupported
76
+ and malformed values; independently selected, outgoing, and reported identities;
77
+ capabilities and extension context; immutable input; SDK batch preflight; resolved
78
+ wire-byte limits; CLI precedence and mixed-selector rows; and generated requests
79
+ that inherit later configuration changes. Existing Decisions suites also cover
80
+ revalidation after input preparation, refusals, retries, and deadlines.
81
+
82
+ Type and installed-package checks exercise metadata declarations, SDK/CLI
83
+ selection, and browser execution without Node globals. Use `npm run verify` for
84
+ the complete integration check. A selector mapping change must be verified against
85
+ the target model's protocol and capabilities; local fixtures alone do not establish
86
+ compatibility with a newly selected upstream model.
87
+
88
+ ## Optional authenticated provider smoke check
89
+
90
+ Live inference is explicitly opted in and can incur charges. Configure credentials
91
+ locally, then on POSIX shells:
92
+
93
+ ```bash
94
+ RUN_LIVE_TESTS=1 npm run smoke:live -- --env-file .env
95
+ ```
96
+
97
+ On PowerShell:
98
+
99
+ ```powershell
100
+ $env:RUN_LIVE_TESTS = '1'
101
+ npm run smoke:live -- --env-file .env
102
+ Remove-Item Env:RUN_LIVE_TESTS
103
+ ```
104
+
105
+ Forward provider/model/config options for the selected account. The helper refuses
106
+ to infer without the opt-in flag and returns real results or errors. It checks a
107
+ configured inference path, not model quality or throughput. For model listing
108
+ alone, use `node bin/decision.mjs models --env-file .env`.
109
+ Model listing is unsupported for OpenAI Decisions and Cloudflare Clef.
110
+
111
+ The OpenAI Decisions helper performs four bounded common/native requests when
112
+ invoked with `--decisions`. It includes a valid embedded PNG, typed choices, and
113
+ labelled scores. For example, after setting the same opt-in variable:
114
+
115
+ ```text
116
+ npm run smoke:live -- --decisions --env-file .env
117
+ ```
118
+
119
+ Cloudflare REST can use the ordinary smoke command with
120
+ `--provider cloudflare-decisions --model clef`, `--model clef-flash`, or
121
+ `--model clef-omni`, loading its
122
+ account/token environment explicitly. These invocations each check one common
123
+ request. Native, image, large-distribution, binding, and Gateway checks require
124
+ separate bounded cases; test the latter two in the intended existing runtime and
125
+ Gateway. REST busy rejection has a documented
126
+ [service limitation](../guides/CLOUDFLARE_DECISIONS.md#capacity-rejection-and-ai-gateway).
127
+ Test all three models and both access shapes when changing those paths. Include typed
128
+ string/boolean identity, labelled scores, reported confidence/usage, and distinct
129
+ request/Gateway IDs from concurrent calls. Enabling binding busy mode verifies
130
+ option acceptance; it does not establish behavior under exhausted capacity.
131
+ Header/dimension preflight does not fully decode images, so live image fixtures
132
+ must also contain valid encoded image data.
133
+ Omni fixtures must contain genuinely decodable WAV/MP3 and MP4/WebM media for
134
+ hosted tests. Local authored container fixtures verify inspection and protocol
135
+ behavior without claiming codec validity. Include grouped modalities, duration
136
+ and size boundaries, effective-model overrides, request bodies above 13 MiB,
137
+ and explicit smaller ceilings. Gateway caching/logging should be disabled for
138
+ test payloads, and each bounded run should have a request and total time budget.
139
+
140
+ The SDK, CLI, and ordinary checks do not create Workers or Gateways. Provisioning
141
+ and cleanup belong to the application's separately authorized environment setup.
142
+
143
+ ## Package verification
144
+
145
+ To test a specific local tarball against this source checkout:
146
+
147
+ ```text
148
+ node scripts/package-smoke.mjs --tarball /path/to/fayegram-ai-decision-bridge-VERSION.tgz
149
+ ```
150
+
151
+ The check installs the specified archive offline and compares installed bytes,
152
+ documentation links, exports, CLI shims, and the bundled sample. It also rejects
153
+ local archives and development-only files leaking into the runtime package.
@@ -0,0 +1,43 @@
1
+ # Browser integration
2
+
3
+ The SDK exports browser-compatible ESM. Follow the
4
+ [installation guide](GETTING_STARTED.md#install-into-your-application), then import
5
+ `@fayegram-ai/decision-bridge` through your browser application's module bundler. The
6
+ optional `decision-bridge` command still requires Node.js.
7
+ Omni's embedded audio/video validation is browser-safe and adds no runtime media
8
+ library. Build data URLs in the application; the SDK does not fetch remote media.
9
+
10
+ Built-in REST providers need explicitly supplied credentials in browser code;
11
+ Node environment-variable defaults and `.env` files are not available. Cloudflare
12
+ REST also needs `accountId`; its Workers AI binding is configured inside a Worker,
13
+ as described in the [Cloudflare guide](CLOUDFLARE_DECISIONS.md#workers-ai-binding).
14
+ A compatible loopback endpoint can explicitly use `apiKey: null`.
15
+ The following example requires TypeSafe to permit your application's origin and
16
+ provide a credential suitable for client exposure. `browserCredential` is supplied
17
+ by your application's credential flow:
18
+
19
+ ```javascript
20
+ import { createBridge, JevProvider, noul } from '@fayegram-ai/decision-bridge';
21
+
22
+ const bridge = createBridge({
23
+ provider: new JevProvider({ apiKey: browserCredential }),
24
+ });
25
+ const result = await bridge.evaluate({
26
+ state: 'A user-supplied statement',
27
+ questions: { relevant: noul('Is this relevant?') },
28
+ });
29
+ console.log(result.answers.relevant.noul);
30
+ ```
31
+
32
+ This sends the request **directly from the browser**. The provider's server must
33
+ accept the page's origin in its CORS preflight response and allow the method and
34
+ headers used by the SDK. For Jev evaluation those include `POST`, `Authorization`,
35
+ and `Content-Type`. If the preflight is rejected, the browser sends no evaluation
36
+ request; neither the SDK nor a browser setting can override that server policy.
37
+ Check your intended origin with TypeSafe before relying on direct Jev calls.
38
+
39
+ Any key delivered to browser JavaScript can be read by the app's users. Only use
40
+ a credential that the provider explicitly permits for browser exposure. If an
41
+ account key must remain private, keep the provider call in your own backend and
42
+ invoke that backend from the browser. This is a credential boundary, separate
43
+ from whether the SDK's modules can run in a browser.