@nexart/signals 0.1.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/CHANGELOG.md +17 -0
- package/README.md +230 -0
- package/dist/index.cjs +84 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +209 -0
- package/dist/index.d.ts +209 -0
- package/dist/index.mjs +55 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +41 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## v0.1.0
|
|
4
|
+
|
|
5
|
+
> Initial release. Fully independent of `@nexart/ai-execution` — no shared dependencies.
|
|
6
|
+
|
|
7
|
+
- **`createSignal(input)`**: normalizes a `CreateSignalInput` into a fully-populated `NexArtSignal`. Only `type` and `source` are required. All other fields default safely (`step: 0`, `actor: "unknown"`, `status: "ok"`, `payload: {}`, `timestamp: now`). No undefined values in output.
|
|
8
|
+
|
|
9
|
+
- **`createSignalCollector(options?)`**: ordered signal buffer. Auto-assigns step values in insertion order when signals omit `step`. Supports `defaultSource` and `defaultActor` collector-level options. `export()` sorts by step and is non-destructive. `size` property for quick count.
|
|
10
|
+
|
|
11
|
+
- **Types**: `NexArtSignal`, `CreateSignalInput`, `CollectorOptions`, `SignalCollection`, `SignalCollector` — all exported from package root.
|
|
12
|
+
|
|
13
|
+
- **Build**: dual ESM/CJS with tsup, full TypeScript declaration files.
|
|
14
|
+
|
|
15
|
+
- **Tests**: 45 tests across 9 describe blocks covering normalization, defaults, insertion order, step sorting, collector options, non-destructive export, size, package exports, and determinism.
|
|
16
|
+
|
|
17
|
+
- **Example**: `examples/basic.ts` — standalone signal, collected pipeline run, explicit step sorting, CER binding preview.
|
package/README.md
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# @nexart/signals v0.1.0
|
|
2
|
+
|
|
3
|
+
Minimal, protocol-agnostic signal capture SDK.
|
|
4
|
+
|
|
5
|
+
Captures and normalizes structured upstream signals so they can be bound into **Certified Execution Records (CERs)** as optional context evidence.
|
|
6
|
+
|
|
7
|
+
- Does **not** define governance semantics or enforce policy
|
|
8
|
+
- Does **not** interpret the meaning of signals
|
|
9
|
+
- Validates structure only and provides normalization helpers
|
|
10
|
+
- Fully optional and independent of `@nexart/ai-execution`
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @nexart/signals
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Quick start
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { createSignal, createSignalCollector } from '@nexart/signals';
|
|
26
|
+
|
|
27
|
+
// ── Standalone signal ──────────────────────────────────────────────────────
|
|
28
|
+
|
|
29
|
+
const signal = createSignal({
|
|
30
|
+
type: 'approval',
|
|
31
|
+
source: 'github-actions',
|
|
32
|
+
actor: 'ci-bot',
|
|
33
|
+
status: 'ok',
|
|
34
|
+
payload: { pr: 42, approved_by: 'alice' },
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// {
|
|
38
|
+
// type: 'approval',
|
|
39
|
+
// source: 'github-actions',
|
|
40
|
+
// step: 0,
|
|
41
|
+
// timestamp: '2026-...',
|
|
42
|
+
// actor: 'ci-bot',
|
|
43
|
+
// status: 'ok',
|
|
44
|
+
// payload: { pr: 42, approved_by: 'alice' }
|
|
45
|
+
// }
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
// ── Collected signals ──────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
const collector = createSignalCollector({ defaultSource: 'my-pipeline' });
|
|
51
|
+
|
|
52
|
+
collector.add({ type: 'fetch', source: 'my-pipeline', payload: { url: '...' } });
|
|
53
|
+
collector.add({ type: 'transform', source: 'my-pipeline', actor: 'etl-bot' });
|
|
54
|
+
collector.add({ type: 'store', source: 'my-pipeline', status: 'ok' });
|
|
55
|
+
|
|
56
|
+
const collection = collector.export();
|
|
57
|
+
// {
|
|
58
|
+
// signals: [
|
|
59
|
+
// { type: 'fetch', step: 0, ... },
|
|
60
|
+
// { type: 'transform', step: 1, ... },
|
|
61
|
+
// { type: 'store', step: 2, ... },
|
|
62
|
+
// ],
|
|
63
|
+
// count: 3,
|
|
64
|
+
// exportedAt: '2026-...'
|
|
65
|
+
// }
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Signal shape
|
|
71
|
+
|
|
72
|
+
Every `NexArtSignal` has exactly these fields — all always present, no undefined values:
|
|
73
|
+
|
|
74
|
+
| Field | Type | Default | Description |
|
|
75
|
+
|---|---|---|---|
|
|
76
|
+
| `type` | `string` | required | Signal category — free-form (e.g. `"approval"`, `"deploy"`, `"audit"`) |
|
|
77
|
+
| `source` | `string` | required | Upstream system or protocol — free-form (e.g. `"github-actions"`, `"linear"`) |
|
|
78
|
+
| `step` | `number` | `0` / auto | Position in sequence. Auto-assigned in insertion order by the collector |
|
|
79
|
+
| `timestamp` | `string` | current time | ISO 8601 |
|
|
80
|
+
| `actor` | `string` | `"unknown"` | Who produced this signal — free-form |
|
|
81
|
+
| `status` | `string` | `"ok"` | Outcome — free-form (e.g. `"ok"`, `"error"`, `"pending"`, `"skipped"`) |
|
|
82
|
+
| `payload` | `Record<string, unknown>` | `{}` | Opaque upstream data — NexArt does not interpret this |
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## API
|
|
87
|
+
|
|
88
|
+
### `createSignal(input)`
|
|
89
|
+
|
|
90
|
+
Creates a single normalized signal. `type` and `source` are required. All other fields are optional with safe defaults.
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
const signal = createSignal({
|
|
94
|
+
type: 'review',
|
|
95
|
+
source: 'linear',
|
|
96
|
+
step: 2,
|
|
97
|
+
actor: 'alice',
|
|
98
|
+
status: 'ok',
|
|
99
|
+
payload: { issue: 'NX-123', verdict: 'approved' },
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### `createSignalCollector(options?)`
|
|
104
|
+
|
|
105
|
+
Creates an ordered signal buffer. Returns a `SignalCollector` with three members:
|
|
106
|
+
|
|
107
|
+
#### `collector.add(input)`
|
|
108
|
+
|
|
109
|
+
Adds a signal. Returns the normalized `NexArtSignal` that was stored.
|
|
110
|
+
|
|
111
|
+
- If `step` is omitted, it is auto-assigned using the insertion index (0, 1, 2, …)
|
|
112
|
+
- If `step` is explicitly provided, that value is used and the signal is sorted correctly on export
|
|
113
|
+
|
|
114
|
+
#### `collector.export()`
|
|
115
|
+
|
|
116
|
+
Returns a `SignalCollection`:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
interface SignalCollection {
|
|
120
|
+
signals: NexArtSignal[]; // sorted by step (ascending)
|
|
121
|
+
count: number;
|
|
122
|
+
exportedAt: string; // ISO 8601, time of export() call
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Non-destructive — calling `export()` multiple times is safe. The internal buffer is not cleared.
|
|
127
|
+
|
|
128
|
+
#### `collector.size`
|
|
129
|
+
|
|
130
|
+
Returns the current number of collected signals.
|
|
131
|
+
|
|
132
|
+
#### Collector options
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
interface CollectorOptions {
|
|
136
|
+
defaultSource?: string; // applied when signal source is empty/omitted
|
|
137
|
+
defaultActor?: string; // applied when signal actor is omitted
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Step ordering
|
|
144
|
+
|
|
145
|
+
Signals without an explicit `step` get steps assigned in insertion order:
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
collector.add({ type: 'a', source: 's' }); // step = 0
|
|
149
|
+
collector.add({ type: 'b', source: 's' }); // step = 1
|
|
150
|
+
collector.add({ type: 'c', source: 's' }); // step = 2
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Signals with an explicit `step` are sorted by that value on export, regardless of insertion order:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
collector.add({ type: 'deploy', source: 's', step: 10 });
|
|
157
|
+
collector.add({ type: 'build', source: 's', step: 0 });
|
|
158
|
+
collector.add({ type: 'test', source: 's', step: 5 });
|
|
159
|
+
|
|
160
|
+
collector.export().signals.map(s => s.type);
|
|
161
|
+
// ['build', 'test', 'deploy']
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Determinism
|
|
167
|
+
|
|
168
|
+
Pin `timestamp` and `step` for deterministic output that can be hashed:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
const signal = createSignal({
|
|
172
|
+
type: 'approval',
|
|
173
|
+
source: 'ci',
|
|
174
|
+
step: 0,
|
|
175
|
+
timestamp: '2026-03-17T00:00:00.000Z', // pinned
|
|
176
|
+
actor: 'bot',
|
|
177
|
+
payload: { pr: 42 },
|
|
178
|
+
});
|
|
179
|
+
// same input → identical object every time
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Integration with @nexart/ai-execution (v0.10.0+)
|
|
185
|
+
|
|
186
|
+
`NexArtSignal[]` is structurally identical to `CerContextSignal[]` in `@nexart/ai-execution` — no casting or conversion needed. Pass `collection.signals` directly to any certify call and it will be sealed into the `certificateHash` alongside the execution record.
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
import { createSignalCollector } from '@nexart/signals';
|
|
190
|
+
import { certifyDecision, certifyLangChainRun, verifyCer } from '@nexart/ai-execution';
|
|
191
|
+
|
|
192
|
+
const collector = createSignalCollector({ defaultSource: 'github-actions' });
|
|
193
|
+
collector.add({ type: 'approval', actor: 'alice', status: 'ok', payload: { pr: 42 } });
|
|
194
|
+
collector.add({ type: 'deploy', actor: 'ci-bot', status: 'ok', payload: { env: 'prod' } });
|
|
195
|
+
|
|
196
|
+
const { signals } = collector.export();
|
|
197
|
+
|
|
198
|
+
// ── certifyDecision ──────────────────────────────────────────
|
|
199
|
+
const bundle = certifyDecision({
|
|
200
|
+
provider: 'openai',
|
|
201
|
+
model: 'gpt-4o-mini',
|
|
202
|
+
prompt: 'Summarise.',
|
|
203
|
+
input: userQuery,
|
|
204
|
+
output: llmResponse,
|
|
205
|
+
parameters: { temperature: 0, maxTokens: 512, topP: null, seed: null },
|
|
206
|
+
signals, // ← sealed into certificateHash; omit = identical hash as before
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
verifyCer(bundle).ok; // true
|
|
210
|
+
bundle.context?.signals.length; // 2
|
|
211
|
+
|
|
212
|
+
// ── certifyLangChainRun ──────────────────────────────────────
|
|
213
|
+
const { bundle: lcBundle } = certifyLangChainRun({
|
|
214
|
+
provider: 'openai',
|
|
215
|
+
model: 'gpt-4o-mini',
|
|
216
|
+
input: { messages: [{ role: 'user', content: 'Summarise.' }] },
|
|
217
|
+
output: { text: 'Summary...' },
|
|
218
|
+
signals, // ← same field, same semantics
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Signals are evidence-only — they do not affect execution behavior or parameters. See `@nexart/ai-execution` README for the full `CerContextSignal` shape and tamper-detection guarantees.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Version history
|
|
227
|
+
|
|
228
|
+
| Version | Description |
|
|
229
|
+
|---|---|
|
|
230
|
+
| v0.1.0 | Initial release: `createSignal`, `createSignalCollector`, `NexArtSignal`, `SignalCollection`, `CollectorOptions`, `SignalCollector` types |
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
SIGNALS_VERSION: () => SIGNALS_VERSION,
|
|
24
|
+
createSignal: () => createSignal,
|
|
25
|
+
createSignalCollector: () => createSignalCollector
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(src_exports);
|
|
28
|
+
|
|
29
|
+
// src/create.ts
|
|
30
|
+
function createSignal(input) {
|
|
31
|
+
return normalize(input, input.step ?? 0);
|
|
32
|
+
}
|
|
33
|
+
function normalize(input, resolvedStep) {
|
|
34
|
+
return {
|
|
35
|
+
type: input.type,
|
|
36
|
+
source: input.source,
|
|
37
|
+
step: resolvedStep,
|
|
38
|
+
timestamp: input.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
39
|
+
actor: input.actor ?? "unknown",
|
|
40
|
+
status: input.status ?? "ok",
|
|
41
|
+
payload: input.payload ?? {}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/collector.ts
|
|
46
|
+
function createSignalCollector(options) {
|
|
47
|
+
const buffer = [];
|
|
48
|
+
let insertionIndex = 0;
|
|
49
|
+
return {
|
|
50
|
+
add(input) {
|
|
51
|
+
const resolvedStep = input.step ?? insertionIndex;
|
|
52
|
+
const resolved = {
|
|
53
|
+
...input,
|
|
54
|
+
source: input.source !== void 0 && input.source !== "" ? input.source : options?.defaultSource ?? input.source ?? "",
|
|
55
|
+
actor: input.actor !== void 0 && input.actor !== "" ? input.actor : options?.defaultActor ?? input.actor
|
|
56
|
+
};
|
|
57
|
+
const signal = normalize(resolved, resolvedStep);
|
|
58
|
+
buffer.push(signal);
|
|
59
|
+
insertionIndex++;
|
|
60
|
+
return signal;
|
|
61
|
+
},
|
|
62
|
+
export() {
|
|
63
|
+
const sorted = [...buffer].sort((a, b) => a.step - b.step);
|
|
64
|
+
return {
|
|
65
|
+
signals: sorted,
|
|
66
|
+
count: sorted.length,
|
|
67
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
get size() {
|
|
71
|
+
return buffer.length;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/index.ts
|
|
77
|
+
var SIGNALS_VERSION = "0.1.0";
|
|
78
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
79
|
+
0 && (module.exports = {
|
|
80
|
+
SIGNALS_VERSION,
|
|
81
|
+
createSignal,
|
|
82
|
+
createSignalCollector
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/create.ts","../src/collector.ts"],"sourcesContent":["/**\n * @nexart/signals v0.1.0\n *\n * Minimal, protocol-agnostic signal capture SDK.\n *\n * Captures and normalizes structured upstream signals so they can be bound\n * into Certified Execution Records (CERs) as optional context evidence.\n *\n * Does NOT define governance semantics, enforce policy, or interpret meaning.\n * Only validates structure and provides normalization helpers.\n *\n * @example\n * ```ts\n * import { createSignal, createSignalCollector } from '@nexart/signals';\n *\n * // Standalone signal\n * const signal = createSignal({\n * type: 'approval',\n * source: 'github-actions',\n * actor: 'ci-bot',\n * payload: { pr: 42 },\n * });\n *\n * // Collected signals\n * const collector = createSignalCollector();\n * collector.add({ type: 'fetch', source: 'pipeline', payload: { url: '...' } });\n * collector.add({ type: 'store', source: 'pipeline', actor: 'etl-bot' });\n * const collection = collector.export();\n * ```\n */\n\nexport { createSignal } from './create.js';\nexport { createSignalCollector } from './collector.js';\n\nexport type {\n NexArtSignal,\n CreateSignalInput,\n CollectorOptions,\n SignalCollection,\n SignalCollector,\n} from './types.js';\n\nexport const SIGNALS_VERSION = '0.1.0' as const;\n","/**\n * @nexart/signals — createSignal()\n *\n * Normalizes a CreateSignalInput into a fully-populated NexArtSignal.\n * Every field is always present — no undefined values in the output.\n */\n\nimport type { CreateSignalInput, NexArtSignal } from './types.js';\n\n/**\n * Create a single normalized NexArtSignal from a CreateSignalInput.\n *\n * - type and source are required.\n * - step defaults to 0 if omitted (use a collector for auto-incrementing step).\n * - timestamp defaults to the current time (ISO 8601).\n * - actor defaults to \"unknown\".\n * - status defaults to \"ok\".\n * - payload defaults to {}.\n *\n * @example\n * ```ts\n * const signal = createSignal({\n * type: 'approval',\n * source: 'github-actions',\n * actor: 'ci-bot',\n * status: 'ok',\n * payload: { pr: 42, approved_by: 'alice' },\n * });\n * ```\n */\nexport function createSignal(input: CreateSignalInput): NexArtSignal {\n return normalize(input, input.step ?? 0);\n}\n\n/**\n * Internal normalization helper — shared by createSignal() and the collector.\n * Applies all field defaults deterministically.\n *\n * @internal\n */\nexport function normalize(input: CreateSignalInput, resolvedStep: number): NexArtSignal {\n return {\n type: input.type,\n source: input.source,\n step: resolvedStep,\n timestamp: input.timestamp ?? new Date().toISOString(),\n actor: input.actor ?? 'unknown',\n status: input.status ?? 'ok',\n payload: input.payload ?? {},\n };\n}\n","/**\n * @nexart/signals — createSignalCollector()\n *\n * A lightweight, ordered buffer for collecting signals from multiple\n * upstream sources before exporting them as a single SignalCollection.\n *\n * Auto-assigns step values in insertion order when signals do not\n * carry an explicit step. Signals with explicit steps are sorted\n * by step on export.\n */\n\nimport { normalize } from './create.js';\nimport type {\n CollectorOptions,\n CreateSignalInput,\n NexArtSignal,\n SignalCollection,\n SignalCollector,\n} from './types.js';\n\n/**\n * Create a signal collector.\n *\n * The collector maintains insertion order and auto-assigns step values.\n * When a signal provides an explicit step, that value is used as-is.\n * On export(), all signals are sorted by step (ascending).\n *\n * @example\n * ```ts\n * const collector = createSignalCollector({ defaultSource: 'my-pipeline' });\n *\n * collector.add({ type: 'fetch', source: 'my-pipeline', payload: { url: '...' } });\n * collector.add({ type: 'transform', source: 'my-pipeline', status: 'ok' });\n * collector.add({ type: 'store', source: 'my-pipeline', actor: 'etl-bot' });\n *\n * const collection = collector.export();\n * // collection.signals[0].step === 0\n * // collection.signals[1].step === 1\n * // collection.signals[2].step === 2\n * ```\n */\nexport function createSignalCollector(options?: CollectorOptions): SignalCollector {\n const buffer: NexArtSignal[] = [];\n let insertionIndex = 0;\n\n return {\n add(input: CreateSignalInput): NexArtSignal {\n const resolvedStep = input.step ?? insertionIndex;\n\n const resolved: CreateSignalInput = {\n ...input,\n source: input.source !== undefined && input.source !== ''\n ? input.source\n : (options?.defaultSource ?? input.source ?? ''),\n actor: input.actor !== undefined && input.actor !== ''\n ? input.actor\n : (options?.defaultActor ?? input.actor),\n };\n\n const signal = normalize(resolved, resolvedStep);\n buffer.push(signal);\n insertionIndex++;\n return signal;\n },\n\n export(): SignalCollection {\n const sorted = [...buffer].sort((a, b) => a.step - b.step);\n return {\n signals: sorted,\n count: sorted.length,\n exportedAt: new Date().toISOString(),\n };\n },\n\n get size(): number {\n return buffer.length;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC8BO,SAAS,aAAa,OAAwC;AACnE,SAAO,UAAU,OAAO,MAAM,QAAQ,CAAC;AACzC;AAQO,SAAS,UAAU,OAA0B,cAAoC;AACtF,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,QAAQ,MAAM;AAAA,IACd,MAAM;AAAA,IACN,WAAW,MAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACrD,OAAO,MAAM,SAAS;AAAA,IACtB,QAAQ,MAAM,UAAU;AAAA,IACxB,SAAS,MAAM,WAAW,CAAC;AAAA,EAC7B;AACF;;;ACTO,SAAS,sBAAsB,SAA6C;AACjF,QAAM,SAAyB,CAAC;AAChC,MAAI,iBAAiB;AAErB,SAAO;AAAA,IACL,IAAI,OAAwC;AAC1C,YAAM,eAAe,MAAM,QAAQ;AAEnC,YAAM,WAA8B;AAAA,QAClC,GAAG;AAAA,QACH,QAAQ,MAAM,WAAW,UAAa,MAAM,WAAW,KACnD,MAAM,SACL,SAAS,iBAAiB,MAAM,UAAU;AAAA,QAC/C,OAAO,MAAM,UAAU,UAAa,MAAM,UAAU,KAChD,MAAM,QACL,SAAS,gBAAgB,MAAM;AAAA,MACtC;AAEA,YAAM,SAAS,UAAU,UAAU,YAAY;AAC/C,aAAO,KAAK,MAAM;AAClB;AACA,aAAO;AAAA,IACT;AAAA,IAEA,SAA2B;AACzB,YAAM,SAAS,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI;AACzD,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,OAAO;AAAA,QACd,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACrC;AAAA,IACF;AAAA,IAEA,IAAI,OAAe;AACjB,aAAO,OAAO;AAAA,IAChB;AAAA,EACF;AACF;;;AFpCO,IAAM,kBAAkB;","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nexart/signals — Core signal types
|
|
3
|
+
*
|
|
4
|
+
* All types are intentionally protocol-agnostic.
|
|
5
|
+
* The SDK validates structure only — it does not interpret meaning.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* A normalized upstream signal captured for optional inclusion in a CER.
|
|
9
|
+
*
|
|
10
|
+
* Fields are normalized at creation time — all fields are always present
|
|
11
|
+
* (no undefined values) to make hashing and downstream consumption reliable.
|
|
12
|
+
*/
|
|
13
|
+
interface NexArtSignal {
|
|
14
|
+
/** Signal category. Free-form — examples: "approval", "review", "deploy", "audit". */
|
|
15
|
+
type: string;
|
|
16
|
+
/** Upstream system or protocol that produced this signal. Free-form. */
|
|
17
|
+
source: string;
|
|
18
|
+
/**
|
|
19
|
+
* Position of this signal in a sequence.
|
|
20
|
+
* Auto-assigned (0-based insertion order) when not explicitly provided.
|
|
21
|
+
*/
|
|
22
|
+
step: number;
|
|
23
|
+
/** ISO 8601 timestamp. Defaults to the time createSignal() was called. */
|
|
24
|
+
timestamp: string;
|
|
25
|
+
/** Actor that produced this signal. Free-form — defaults to "unknown". */
|
|
26
|
+
actor: string;
|
|
27
|
+
/**
|
|
28
|
+
* Outcome or state of the signal. Free-form — defaults to "ok".
|
|
29
|
+
* Examples: "ok", "error", "pending", "skipped".
|
|
30
|
+
*/
|
|
31
|
+
status: string;
|
|
32
|
+
/**
|
|
33
|
+
* Opaque payload from the upstream system.
|
|
34
|
+
* NexArt does not interpret, validate, or modify this field.
|
|
35
|
+
* Defaults to {} if omitted.
|
|
36
|
+
*/
|
|
37
|
+
payload: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Input to createSignal(). Only type and source are required.
|
|
41
|
+
* All other fields are optional and normalized to safe defaults.
|
|
42
|
+
*/
|
|
43
|
+
interface CreateSignalInput {
|
|
44
|
+
/** Signal category. Required. */
|
|
45
|
+
type: string;
|
|
46
|
+
/** Upstream system or protocol. Required. */
|
|
47
|
+
source: string;
|
|
48
|
+
/**
|
|
49
|
+
* Explicit step index. When omitted on a collector, auto-assigned
|
|
50
|
+
* in insertion order. When omitted on standalone createSignal(), defaults to 0.
|
|
51
|
+
*/
|
|
52
|
+
step?: number;
|
|
53
|
+
/** ISO 8601 timestamp. Defaults to current time if omitted. */
|
|
54
|
+
timestamp?: string;
|
|
55
|
+
/** Actor that produced this signal. Defaults to "unknown". */
|
|
56
|
+
actor?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Outcome or state. Defaults to "ok".
|
|
59
|
+
* Examples: "ok", "error", "pending", "skipped".
|
|
60
|
+
*/
|
|
61
|
+
status?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Opaque payload. NexArt does not interpret this.
|
|
64
|
+
* Defaults to {} if omitted.
|
|
65
|
+
*/
|
|
66
|
+
payload?: Record<string, unknown>;
|
|
67
|
+
}
|
|
68
|
+
/** Options for createSignalCollector(). */
|
|
69
|
+
interface CollectorOptions {
|
|
70
|
+
/**
|
|
71
|
+
* Default source applied to every signal added via collector.add()
|
|
72
|
+
* when the signal does not supply its own source.
|
|
73
|
+
*/
|
|
74
|
+
defaultSource?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Default actor applied to every signal added via collector.add()
|
|
77
|
+
* when the signal does not supply its own actor.
|
|
78
|
+
*/
|
|
79
|
+
defaultActor?: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Exported signal collection produced by collector.export().
|
|
83
|
+
* Stable, deterministic, and ready to be hashed or bound into a CER.
|
|
84
|
+
*/
|
|
85
|
+
interface SignalCollection {
|
|
86
|
+
/** Signals sorted by step (ascending). */
|
|
87
|
+
signals: NexArtSignal[];
|
|
88
|
+
/** Total number of signals in this collection. */
|
|
89
|
+
count: number;
|
|
90
|
+
/** ISO 8601 timestamp of when export() was called. */
|
|
91
|
+
exportedAt: string;
|
|
92
|
+
}
|
|
93
|
+
/** A signal collector returned by createSignalCollector(). */
|
|
94
|
+
interface SignalCollector {
|
|
95
|
+
/**
|
|
96
|
+
* Add a signal to the collector.
|
|
97
|
+
* Returns the normalized NexArtSignal that was stored.
|
|
98
|
+
*/
|
|
99
|
+
add(input: CreateSignalInput): NexArtSignal;
|
|
100
|
+
/**
|
|
101
|
+
* Export all collected signals as a stable SignalCollection.
|
|
102
|
+
* Signals are sorted by step (ascending).
|
|
103
|
+
* Does not clear the internal buffer — calling export() twice is safe.
|
|
104
|
+
*/
|
|
105
|
+
export(): SignalCollection;
|
|
106
|
+
/**
|
|
107
|
+
* Return the current number of signals in the collector.
|
|
108
|
+
*/
|
|
109
|
+
readonly size: number;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @nexart/signals — createSignal()
|
|
114
|
+
*
|
|
115
|
+
* Normalizes a CreateSignalInput into a fully-populated NexArtSignal.
|
|
116
|
+
* Every field is always present — no undefined values in the output.
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Create a single normalized NexArtSignal from a CreateSignalInput.
|
|
121
|
+
*
|
|
122
|
+
* - type and source are required.
|
|
123
|
+
* - step defaults to 0 if omitted (use a collector for auto-incrementing step).
|
|
124
|
+
* - timestamp defaults to the current time (ISO 8601).
|
|
125
|
+
* - actor defaults to "unknown".
|
|
126
|
+
* - status defaults to "ok".
|
|
127
|
+
* - payload defaults to {}.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* const signal = createSignal({
|
|
132
|
+
* type: 'approval',
|
|
133
|
+
* source: 'github-actions',
|
|
134
|
+
* actor: 'ci-bot',
|
|
135
|
+
* status: 'ok',
|
|
136
|
+
* payload: { pr: 42, approved_by: 'alice' },
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
declare function createSignal(input: CreateSignalInput): NexArtSignal;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* @nexart/signals — createSignalCollector()
|
|
144
|
+
*
|
|
145
|
+
* A lightweight, ordered buffer for collecting signals from multiple
|
|
146
|
+
* upstream sources before exporting them as a single SignalCollection.
|
|
147
|
+
*
|
|
148
|
+
* Auto-assigns step values in insertion order when signals do not
|
|
149
|
+
* carry an explicit step. Signals with explicit steps are sorted
|
|
150
|
+
* by step on export.
|
|
151
|
+
*/
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Create a signal collector.
|
|
155
|
+
*
|
|
156
|
+
* The collector maintains insertion order and auto-assigns step values.
|
|
157
|
+
* When a signal provides an explicit step, that value is used as-is.
|
|
158
|
+
* On export(), all signals are sorted by step (ascending).
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* const collector = createSignalCollector({ defaultSource: 'my-pipeline' });
|
|
163
|
+
*
|
|
164
|
+
* collector.add({ type: 'fetch', source: 'my-pipeline', payload: { url: '...' } });
|
|
165
|
+
* collector.add({ type: 'transform', source: 'my-pipeline', status: 'ok' });
|
|
166
|
+
* collector.add({ type: 'store', source: 'my-pipeline', actor: 'etl-bot' });
|
|
167
|
+
*
|
|
168
|
+
* const collection = collector.export();
|
|
169
|
+
* // collection.signals[0].step === 0
|
|
170
|
+
* // collection.signals[1].step === 1
|
|
171
|
+
* // collection.signals[2].step === 2
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
declare function createSignalCollector(options?: CollectorOptions): SignalCollector;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @nexart/signals v0.1.0
|
|
178
|
+
*
|
|
179
|
+
* Minimal, protocol-agnostic signal capture SDK.
|
|
180
|
+
*
|
|
181
|
+
* Captures and normalizes structured upstream signals so they can be bound
|
|
182
|
+
* into Certified Execution Records (CERs) as optional context evidence.
|
|
183
|
+
*
|
|
184
|
+
* Does NOT define governance semantics, enforce policy, or interpret meaning.
|
|
185
|
+
* Only validates structure and provides normalization helpers.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```ts
|
|
189
|
+
* import { createSignal, createSignalCollector } from '@nexart/signals';
|
|
190
|
+
*
|
|
191
|
+
* // Standalone signal
|
|
192
|
+
* const signal = createSignal({
|
|
193
|
+
* type: 'approval',
|
|
194
|
+
* source: 'github-actions',
|
|
195
|
+
* actor: 'ci-bot',
|
|
196
|
+
* payload: { pr: 42 },
|
|
197
|
+
* });
|
|
198
|
+
*
|
|
199
|
+
* // Collected signals
|
|
200
|
+
* const collector = createSignalCollector();
|
|
201
|
+
* collector.add({ type: 'fetch', source: 'pipeline', payload: { url: '...' } });
|
|
202
|
+
* collector.add({ type: 'store', source: 'pipeline', actor: 'etl-bot' });
|
|
203
|
+
* const collection = collector.export();
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
|
|
207
|
+
declare const SIGNALS_VERSION: "0.1.0";
|
|
208
|
+
|
|
209
|
+
export { type CollectorOptions, type CreateSignalInput, type NexArtSignal, SIGNALS_VERSION, type SignalCollection, type SignalCollector, createSignal, createSignalCollector };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nexart/signals — Core signal types
|
|
3
|
+
*
|
|
4
|
+
* All types are intentionally protocol-agnostic.
|
|
5
|
+
* The SDK validates structure only — it does not interpret meaning.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* A normalized upstream signal captured for optional inclusion in a CER.
|
|
9
|
+
*
|
|
10
|
+
* Fields are normalized at creation time — all fields are always present
|
|
11
|
+
* (no undefined values) to make hashing and downstream consumption reliable.
|
|
12
|
+
*/
|
|
13
|
+
interface NexArtSignal {
|
|
14
|
+
/** Signal category. Free-form — examples: "approval", "review", "deploy", "audit". */
|
|
15
|
+
type: string;
|
|
16
|
+
/** Upstream system or protocol that produced this signal. Free-form. */
|
|
17
|
+
source: string;
|
|
18
|
+
/**
|
|
19
|
+
* Position of this signal in a sequence.
|
|
20
|
+
* Auto-assigned (0-based insertion order) when not explicitly provided.
|
|
21
|
+
*/
|
|
22
|
+
step: number;
|
|
23
|
+
/** ISO 8601 timestamp. Defaults to the time createSignal() was called. */
|
|
24
|
+
timestamp: string;
|
|
25
|
+
/** Actor that produced this signal. Free-form — defaults to "unknown". */
|
|
26
|
+
actor: string;
|
|
27
|
+
/**
|
|
28
|
+
* Outcome or state of the signal. Free-form — defaults to "ok".
|
|
29
|
+
* Examples: "ok", "error", "pending", "skipped".
|
|
30
|
+
*/
|
|
31
|
+
status: string;
|
|
32
|
+
/**
|
|
33
|
+
* Opaque payload from the upstream system.
|
|
34
|
+
* NexArt does not interpret, validate, or modify this field.
|
|
35
|
+
* Defaults to {} if omitted.
|
|
36
|
+
*/
|
|
37
|
+
payload: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Input to createSignal(). Only type and source are required.
|
|
41
|
+
* All other fields are optional and normalized to safe defaults.
|
|
42
|
+
*/
|
|
43
|
+
interface CreateSignalInput {
|
|
44
|
+
/** Signal category. Required. */
|
|
45
|
+
type: string;
|
|
46
|
+
/** Upstream system or protocol. Required. */
|
|
47
|
+
source: string;
|
|
48
|
+
/**
|
|
49
|
+
* Explicit step index. When omitted on a collector, auto-assigned
|
|
50
|
+
* in insertion order. When omitted on standalone createSignal(), defaults to 0.
|
|
51
|
+
*/
|
|
52
|
+
step?: number;
|
|
53
|
+
/** ISO 8601 timestamp. Defaults to current time if omitted. */
|
|
54
|
+
timestamp?: string;
|
|
55
|
+
/** Actor that produced this signal. Defaults to "unknown". */
|
|
56
|
+
actor?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Outcome or state. Defaults to "ok".
|
|
59
|
+
* Examples: "ok", "error", "pending", "skipped".
|
|
60
|
+
*/
|
|
61
|
+
status?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Opaque payload. NexArt does not interpret this.
|
|
64
|
+
* Defaults to {} if omitted.
|
|
65
|
+
*/
|
|
66
|
+
payload?: Record<string, unknown>;
|
|
67
|
+
}
|
|
68
|
+
/** Options for createSignalCollector(). */
|
|
69
|
+
interface CollectorOptions {
|
|
70
|
+
/**
|
|
71
|
+
* Default source applied to every signal added via collector.add()
|
|
72
|
+
* when the signal does not supply its own source.
|
|
73
|
+
*/
|
|
74
|
+
defaultSource?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Default actor applied to every signal added via collector.add()
|
|
77
|
+
* when the signal does not supply its own actor.
|
|
78
|
+
*/
|
|
79
|
+
defaultActor?: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Exported signal collection produced by collector.export().
|
|
83
|
+
* Stable, deterministic, and ready to be hashed or bound into a CER.
|
|
84
|
+
*/
|
|
85
|
+
interface SignalCollection {
|
|
86
|
+
/** Signals sorted by step (ascending). */
|
|
87
|
+
signals: NexArtSignal[];
|
|
88
|
+
/** Total number of signals in this collection. */
|
|
89
|
+
count: number;
|
|
90
|
+
/** ISO 8601 timestamp of when export() was called. */
|
|
91
|
+
exportedAt: string;
|
|
92
|
+
}
|
|
93
|
+
/** A signal collector returned by createSignalCollector(). */
|
|
94
|
+
interface SignalCollector {
|
|
95
|
+
/**
|
|
96
|
+
* Add a signal to the collector.
|
|
97
|
+
* Returns the normalized NexArtSignal that was stored.
|
|
98
|
+
*/
|
|
99
|
+
add(input: CreateSignalInput): NexArtSignal;
|
|
100
|
+
/**
|
|
101
|
+
* Export all collected signals as a stable SignalCollection.
|
|
102
|
+
* Signals are sorted by step (ascending).
|
|
103
|
+
* Does not clear the internal buffer — calling export() twice is safe.
|
|
104
|
+
*/
|
|
105
|
+
export(): SignalCollection;
|
|
106
|
+
/**
|
|
107
|
+
* Return the current number of signals in the collector.
|
|
108
|
+
*/
|
|
109
|
+
readonly size: number;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @nexart/signals — createSignal()
|
|
114
|
+
*
|
|
115
|
+
* Normalizes a CreateSignalInput into a fully-populated NexArtSignal.
|
|
116
|
+
* Every field is always present — no undefined values in the output.
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Create a single normalized NexArtSignal from a CreateSignalInput.
|
|
121
|
+
*
|
|
122
|
+
* - type and source are required.
|
|
123
|
+
* - step defaults to 0 if omitted (use a collector for auto-incrementing step).
|
|
124
|
+
* - timestamp defaults to the current time (ISO 8601).
|
|
125
|
+
* - actor defaults to "unknown".
|
|
126
|
+
* - status defaults to "ok".
|
|
127
|
+
* - payload defaults to {}.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* const signal = createSignal({
|
|
132
|
+
* type: 'approval',
|
|
133
|
+
* source: 'github-actions',
|
|
134
|
+
* actor: 'ci-bot',
|
|
135
|
+
* status: 'ok',
|
|
136
|
+
* payload: { pr: 42, approved_by: 'alice' },
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
declare function createSignal(input: CreateSignalInput): NexArtSignal;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* @nexart/signals — createSignalCollector()
|
|
144
|
+
*
|
|
145
|
+
* A lightweight, ordered buffer for collecting signals from multiple
|
|
146
|
+
* upstream sources before exporting them as a single SignalCollection.
|
|
147
|
+
*
|
|
148
|
+
* Auto-assigns step values in insertion order when signals do not
|
|
149
|
+
* carry an explicit step. Signals with explicit steps are sorted
|
|
150
|
+
* by step on export.
|
|
151
|
+
*/
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Create a signal collector.
|
|
155
|
+
*
|
|
156
|
+
* The collector maintains insertion order and auto-assigns step values.
|
|
157
|
+
* When a signal provides an explicit step, that value is used as-is.
|
|
158
|
+
* On export(), all signals are sorted by step (ascending).
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* const collector = createSignalCollector({ defaultSource: 'my-pipeline' });
|
|
163
|
+
*
|
|
164
|
+
* collector.add({ type: 'fetch', source: 'my-pipeline', payload: { url: '...' } });
|
|
165
|
+
* collector.add({ type: 'transform', source: 'my-pipeline', status: 'ok' });
|
|
166
|
+
* collector.add({ type: 'store', source: 'my-pipeline', actor: 'etl-bot' });
|
|
167
|
+
*
|
|
168
|
+
* const collection = collector.export();
|
|
169
|
+
* // collection.signals[0].step === 0
|
|
170
|
+
* // collection.signals[1].step === 1
|
|
171
|
+
* // collection.signals[2].step === 2
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
declare function createSignalCollector(options?: CollectorOptions): SignalCollector;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @nexart/signals v0.1.0
|
|
178
|
+
*
|
|
179
|
+
* Minimal, protocol-agnostic signal capture SDK.
|
|
180
|
+
*
|
|
181
|
+
* Captures and normalizes structured upstream signals so they can be bound
|
|
182
|
+
* into Certified Execution Records (CERs) as optional context evidence.
|
|
183
|
+
*
|
|
184
|
+
* Does NOT define governance semantics, enforce policy, or interpret meaning.
|
|
185
|
+
* Only validates structure and provides normalization helpers.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```ts
|
|
189
|
+
* import { createSignal, createSignalCollector } from '@nexart/signals';
|
|
190
|
+
*
|
|
191
|
+
* // Standalone signal
|
|
192
|
+
* const signal = createSignal({
|
|
193
|
+
* type: 'approval',
|
|
194
|
+
* source: 'github-actions',
|
|
195
|
+
* actor: 'ci-bot',
|
|
196
|
+
* payload: { pr: 42 },
|
|
197
|
+
* });
|
|
198
|
+
*
|
|
199
|
+
* // Collected signals
|
|
200
|
+
* const collector = createSignalCollector();
|
|
201
|
+
* collector.add({ type: 'fetch', source: 'pipeline', payload: { url: '...' } });
|
|
202
|
+
* collector.add({ type: 'store', source: 'pipeline', actor: 'etl-bot' });
|
|
203
|
+
* const collection = collector.export();
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
|
|
207
|
+
declare const SIGNALS_VERSION: "0.1.0";
|
|
208
|
+
|
|
209
|
+
export { type CollectorOptions, type CreateSignalInput, type NexArtSignal, SIGNALS_VERSION, type SignalCollection, type SignalCollector, createSignal, createSignalCollector };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/create.ts
|
|
2
|
+
function createSignal(input) {
|
|
3
|
+
return normalize(input, input.step ?? 0);
|
|
4
|
+
}
|
|
5
|
+
function normalize(input, resolvedStep) {
|
|
6
|
+
return {
|
|
7
|
+
type: input.type,
|
|
8
|
+
source: input.source,
|
|
9
|
+
step: resolvedStep,
|
|
10
|
+
timestamp: input.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
11
|
+
actor: input.actor ?? "unknown",
|
|
12
|
+
status: input.status ?? "ok",
|
|
13
|
+
payload: input.payload ?? {}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/collector.ts
|
|
18
|
+
function createSignalCollector(options) {
|
|
19
|
+
const buffer = [];
|
|
20
|
+
let insertionIndex = 0;
|
|
21
|
+
return {
|
|
22
|
+
add(input) {
|
|
23
|
+
const resolvedStep = input.step ?? insertionIndex;
|
|
24
|
+
const resolved = {
|
|
25
|
+
...input,
|
|
26
|
+
source: input.source !== void 0 && input.source !== "" ? input.source : options?.defaultSource ?? input.source ?? "",
|
|
27
|
+
actor: input.actor !== void 0 && input.actor !== "" ? input.actor : options?.defaultActor ?? input.actor
|
|
28
|
+
};
|
|
29
|
+
const signal = normalize(resolved, resolvedStep);
|
|
30
|
+
buffer.push(signal);
|
|
31
|
+
insertionIndex++;
|
|
32
|
+
return signal;
|
|
33
|
+
},
|
|
34
|
+
export() {
|
|
35
|
+
const sorted = [...buffer].sort((a, b) => a.step - b.step);
|
|
36
|
+
return {
|
|
37
|
+
signals: sorted,
|
|
38
|
+
count: sorted.length,
|
|
39
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
get size() {
|
|
43
|
+
return buffer.length;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/index.ts
|
|
49
|
+
var SIGNALS_VERSION = "0.1.0";
|
|
50
|
+
export {
|
|
51
|
+
SIGNALS_VERSION,
|
|
52
|
+
createSignal,
|
|
53
|
+
createSignalCollector
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/create.ts","../src/collector.ts","../src/index.ts"],"sourcesContent":["/**\n * @nexart/signals — createSignal()\n *\n * Normalizes a CreateSignalInput into a fully-populated NexArtSignal.\n * Every field is always present — no undefined values in the output.\n */\n\nimport type { CreateSignalInput, NexArtSignal } from './types.js';\n\n/**\n * Create a single normalized NexArtSignal from a CreateSignalInput.\n *\n * - type and source are required.\n * - step defaults to 0 if omitted (use a collector for auto-incrementing step).\n * - timestamp defaults to the current time (ISO 8601).\n * - actor defaults to \"unknown\".\n * - status defaults to \"ok\".\n * - payload defaults to {}.\n *\n * @example\n * ```ts\n * const signal = createSignal({\n * type: 'approval',\n * source: 'github-actions',\n * actor: 'ci-bot',\n * status: 'ok',\n * payload: { pr: 42, approved_by: 'alice' },\n * });\n * ```\n */\nexport function createSignal(input: CreateSignalInput): NexArtSignal {\n return normalize(input, input.step ?? 0);\n}\n\n/**\n * Internal normalization helper — shared by createSignal() and the collector.\n * Applies all field defaults deterministically.\n *\n * @internal\n */\nexport function normalize(input: CreateSignalInput, resolvedStep: number): NexArtSignal {\n return {\n type: input.type,\n source: input.source,\n step: resolvedStep,\n timestamp: input.timestamp ?? new Date().toISOString(),\n actor: input.actor ?? 'unknown',\n status: input.status ?? 'ok',\n payload: input.payload ?? {},\n };\n}\n","/**\n * @nexart/signals — createSignalCollector()\n *\n * A lightweight, ordered buffer for collecting signals from multiple\n * upstream sources before exporting them as a single SignalCollection.\n *\n * Auto-assigns step values in insertion order when signals do not\n * carry an explicit step. Signals with explicit steps are sorted\n * by step on export.\n */\n\nimport { normalize } from './create.js';\nimport type {\n CollectorOptions,\n CreateSignalInput,\n NexArtSignal,\n SignalCollection,\n SignalCollector,\n} from './types.js';\n\n/**\n * Create a signal collector.\n *\n * The collector maintains insertion order and auto-assigns step values.\n * When a signal provides an explicit step, that value is used as-is.\n * On export(), all signals are sorted by step (ascending).\n *\n * @example\n * ```ts\n * const collector = createSignalCollector({ defaultSource: 'my-pipeline' });\n *\n * collector.add({ type: 'fetch', source: 'my-pipeline', payload: { url: '...' } });\n * collector.add({ type: 'transform', source: 'my-pipeline', status: 'ok' });\n * collector.add({ type: 'store', source: 'my-pipeline', actor: 'etl-bot' });\n *\n * const collection = collector.export();\n * // collection.signals[0].step === 0\n * // collection.signals[1].step === 1\n * // collection.signals[2].step === 2\n * ```\n */\nexport function createSignalCollector(options?: CollectorOptions): SignalCollector {\n const buffer: NexArtSignal[] = [];\n let insertionIndex = 0;\n\n return {\n add(input: CreateSignalInput): NexArtSignal {\n const resolvedStep = input.step ?? insertionIndex;\n\n const resolved: CreateSignalInput = {\n ...input,\n source: input.source !== undefined && input.source !== ''\n ? input.source\n : (options?.defaultSource ?? input.source ?? ''),\n actor: input.actor !== undefined && input.actor !== ''\n ? input.actor\n : (options?.defaultActor ?? input.actor),\n };\n\n const signal = normalize(resolved, resolvedStep);\n buffer.push(signal);\n insertionIndex++;\n return signal;\n },\n\n export(): SignalCollection {\n const sorted = [...buffer].sort((a, b) => a.step - b.step);\n return {\n signals: sorted,\n count: sorted.length,\n exportedAt: new Date().toISOString(),\n };\n },\n\n get size(): number {\n return buffer.length;\n },\n };\n}\n","/**\n * @nexart/signals v0.1.0\n *\n * Minimal, protocol-agnostic signal capture SDK.\n *\n * Captures and normalizes structured upstream signals so they can be bound\n * into Certified Execution Records (CERs) as optional context evidence.\n *\n * Does NOT define governance semantics, enforce policy, or interpret meaning.\n * Only validates structure and provides normalization helpers.\n *\n * @example\n * ```ts\n * import { createSignal, createSignalCollector } from '@nexart/signals';\n *\n * // Standalone signal\n * const signal = createSignal({\n * type: 'approval',\n * source: 'github-actions',\n * actor: 'ci-bot',\n * payload: { pr: 42 },\n * });\n *\n * // Collected signals\n * const collector = createSignalCollector();\n * collector.add({ type: 'fetch', source: 'pipeline', payload: { url: '...' } });\n * collector.add({ type: 'store', source: 'pipeline', actor: 'etl-bot' });\n * const collection = collector.export();\n * ```\n */\n\nexport { createSignal } from './create.js';\nexport { createSignalCollector } from './collector.js';\n\nexport type {\n NexArtSignal,\n CreateSignalInput,\n CollectorOptions,\n SignalCollection,\n SignalCollector,\n} from './types.js';\n\nexport const SIGNALS_VERSION = '0.1.0' as const;\n"],"mappings":";AA8BO,SAAS,aAAa,OAAwC;AACnE,SAAO,UAAU,OAAO,MAAM,QAAQ,CAAC;AACzC;AAQO,SAAS,UAAU,OAA0B,cAAoC;AACtF,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,QAAQ,MAAM;AAAA,IACd,MAAM;AAAA,IACN,WAAW,MAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACrD,OAAO,MAAM,SAAS;AAAA,IACtB,QAAQ,MAAM,UAAU;AAAA,IACxB,SAAS,MAAM,WAAW,CAAC;AAAA,EAC7B;AACF;;;ACTO,SAAS,sBAAsB,SAA6C;AACjF,QAAM,SAAyB,CAAC;AAChC,MAAI,iBAAiB;AAErB,SAAO;AAAA,IACL,IAAI,OAAwC;AAC1C,YAAM,eAAe,MAAM,QAAQ;AAEnC,YAAM,WAA8B;AAAA,QAClC,GAAG;AAAA,QACH,QAAQ,MAAM,WAAW,UAAa,MAAM,WAAW,KACnD,MAAM,SACL,SAAS,iBAAiB,MAAM,UAAU;AAAA,QAC/C,OAAO,MAAM,UAAU,UAAa,MAAM,UAAU,KAChD,MAAM,QACL,SAAS,gBAAgB,MAAM;AAAA,MACtC;AAEA,YAAM,SAAS,UAAU,UAAU,YAAY;AAC/C,aAAO,KAAK,MAAM;AAClB;AACA,aAAO;AAAA,IACT;AAAA,IAEA,SAA2B;AACzB,YAAM,SAAS,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI;AACzD,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,OAAO;AAAA,QACd,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACrC;AAAA,IACF;AAAA,IAEA,IAAI,OAAe;AACjB,aAAO,OAAO;AAAA,IAChB;AAAA,EACF;AACF;;;ACpCO,IAAM,kBAAkB;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nexart/signals",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Minimal, protocol-agnostic signal capture SDK for optional CER context evidence",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.mjs"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md",
|
|
24
|
+
"CHANGELOG.md"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsup",
|
|
28
|
+
"build:tsc": "tsc --project tsconfig.json --outDir dist-tsc",
|
|
29
|
+
"test": "npm run build:tsc && node --test --test-concurrency 1 dist-tsc/__tests__/signals.test.js",
|
|
30
|
+
"prepublishOnly": "npm run build"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"nexart",
|
|
34
|
+
"signals",
|
|
35
|
+
"cer",
|
|
36
|
+
"ai",
|
|
37
|
+
"audit",
|
|
38
|
+
"tracing"
|
|
39
|
+
],
|
|
40
|
+
"license": "MIT"
|
|
41
|
+
}
|