@seamward/collector 0.1.0-alpha.2
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 +307 -0
- package/dist/connect.d.ts +49 -0
- package/dist/connect.js +84 -0
- package/dist/connect.js.map +1 -0
- package/dist/deployment-context.d.ts +8 -0
- package/dist/deployment-context.js +43 -0
- package/dist/deployment-context.js.map +1 -0
- package/dist/envelope-builder.d.ts +51 -0
- package/dist/envelope-builder.js +72 -0
- package/dist/envelope-builder.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/observe.d.ts +110 -0
- package/dist/observe.js +294 -0
- package/dist/observe.js.map +1 -0
- package/dist/redact.d.ts +31 -0
- package/dist/redact.js +61 -0
- package/dist/redact.js.map +1 -0
- package/dist/shipper.d.ts +48 -0
- package/dist/shipper.js +79 -0
- package/dist/shipper.js.map +1 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# Seamward Node collector
|
|
2
|
+
|
|
3
|
+
The Seamward collector observes third-party HTTP API, webhook, queue, and
|
|
4
|
+
scheduled-feed behaviour from a Node.js backend. It batches redacted evidence
|
|
5
|
+
asynchronously and never sits on the application's critical request path.
|
|
6
|
+
|
|
7
|
+
This `0.1.0-alpha` release line is for pilot evaluation with Node.js 22 or newer.
|
|
8
|
+
TypeScript and server-side JavaScript are supported. PHP, Go, browser, and edge
|
|
9
|
+
runtime collectors are not shipped yet.
|
|
10
|
+
|
|
11
|
+
## 1. Create the Seamward connection
|
|
12
|
+
|
|
13
|
+
In Seamward:
|
|
14
|
+
|
|
15
|
+
1. Open the workspace and create an application environment under **Settings**.
|
|
16
|
+
2. Generate its ingest token and copy it immediately. The token is shown once.
|
|
17
|
+
3. Create or open an integration.
|
|
18
|
+
4. Copy the public Connection key from the integration's **Collector setup** tab.
|
|
19
|
+
|
|
20
|
+
The Connection key contains public routing identifiers and grants no access by
|
|
21
|
+
itself. The ingest token is a write-only secret: keep it in the backend secret
|
|
22
|
+
manager and never put it in browser code, Git, logs, screenshots, or support
|
|
23
|
+
messages.
|
|
24
|
+
|
|
25
|
+
## 2. Install the pilot release
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm add @seamward/collector
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
or `npm install @seamward/collector`. This is a prerelease; pin the version
|
|
32
|
+
through your lockfile as with any dependency.
|
|
33
|
+
|
|
34
|
+
## 3. Configure the backend
|
|
35
|
+
|
|
36
|
+
```ini
|
|
37
|
+
SEAMWARD_WEBHOOK_CONNECTION_KEY=sw_conn_v1.replace_webhook
|
|
38
|
+
SEAMWARD_HTTP_API_CONNECTION_KEY=sw_conn_v1.replace_http_api
|
|
39
|
+
SEAMWARD_QUEUE_PUBLISH_CONNECTION_KEY=sw_conn_v1.replace_queue_publish
|
|
40
|
+
SEAMWARD_QUEUE_CONSUME_CONNECTION_KEY=sw_conn_v1.replace_queue_consume
|
|
41
|
+
SEAMWARD_FEED_EXPORT_CONNECTION_KEY=sw_conn_v1.replace_feed_export
|
|
42
|
+
SEAMWARD_INGEST_TOKEN=sw_ing_replace_me
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`SEAMWARD_INGEST_URL` is optional and only needed for a self-hosted Seamward
|
|
46
|
+
deployment. For example, use `https://seamward.example/ingest`. The collector
|
|
47
|
+
otherwise uses `https://api.seamward.com/ingest`.
|
|
48
|
+
|
|
49
|
+
Create one collector per Integration boundary. An Integration has one direction
|
|
50
|
+
and one protocol. Processes that observe multiple boundaries create a collector
|
|
51
|
+
for each Connection key and may share the application environment's ingest
|
|
52
|
+
token:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { createSeamwardCollector } from "@seamward/collector";
|
|
56
|
+
|
|
57
|
+
const connected = (connectionKey: string) =>
|
|
58
|
+
createSeamwardCollector({
|
|
59
|
+
connectionKey,
|
|
60
|
+
ingestToken: process.env.SEAMWARD_INGEST_TOKEN!,
|
|
61
|
+
endpoint: process.env.SEAMWARD_INGEST_URL,
|
|
62
|
+
deployment: {
|
|
63
|
+
service: "candidate-api",
|
|
64
|
+
release: process.env.RELEASE_VERSION,
|
|
65
|
+
commitSha: process.env.GITHUB_SHA,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
export const webhookCollector = connected(
|
|
70
|
+
process.env.SEAMWARD_WEBHOOK_CONNECTION_KEY!,
|
|
71
|
+
);
|
|
72
|
+
export const httpApiCollector = connected(
|
|
73
|
+
process.env.SEAMWARD_HTTP_API_CONNECTION_KEY!,
|
|
74
|
+
);
|
|
75
|
+
export const queuePublisherCollector = connected(
|
|
76
|
+
process.env.SEAMWARD_QUEUE_PUBLISH_CONNECTION_KEY!,
|
|
77
|
+
);
|
|
78
|
+
export const queueConsumerCollector = connected(
|
|
79
|
+
process.env.SEAMWARD_QUEUE_CONSUME_CONNECTION_KEY!,
|
|
80
|
+
);
|
|
81
|
+
export const feedExportCollector = connected(
|
|
82
|
+
process.env.SEAMWARD_FEED_EXPORT_CONNECTION_KEY!,
|
|
83
|
+
);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Release and commit metadata are optional. The collector also recognises
|
|
87
|
+
`SEAMWARD_COMMIT_SHA`, `VERCEL_GIT_COMMIT_SHA`, `RENDER_GIT_COMMIT`,
|
|
88
|
+
`RAILWAY_GIT_COMMIT_SHA`, and `GITHUB_SHA`. Invalid values are ignored instead
|
|
89
|
+
of breaking the host application.
|
|
90
|
+
|
|
91
|
+
## 4. Observe an inbound webhook
|
|
92
|
+
|
|
93
|
+
Wrap the existing business handler; do not send the inbound request headers to
|
|
94
|
+
Seamward.
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
const handleCandidateWebhook = webhookCollector.observeWebhook(
|
|
98
|
+
{
|
|
99
|
+
routeTemplate: "/webhooks/candidates",
|
|
100
|
+
},
|
|
101
|
+
async (payload) => {
|
|
102
|
+
const candidate = await candidateService.accept(payload);
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
statusCode: 202,
|
|
106
|
+
eventType: "candidate.create",
|
|
107
|
+
outcome: {
|
|
108
|
+
accepted: true,
|
|
109
|
+
businessObjectType: "candidate",
|
|
110
|
+
businessObjectId: candidate.id,
|
|
111
|
+
},
|
|
112
|
+
correlation: { sourceEventId: candidate.providerEventId },
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
fastify.post("/webhooks/candidates", async (request, reply) => {
|
|
118
|
+
const result = await handleCandidateWebhook(
|
|
119
|
+
request.body as Record<string, unknown>,
|
|
120
|
+
);
|
|
121
|
+
return reply.code(result.statusCode ?? 200).send();
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Use stable route templates such as `/webhooks/candidates`, never concrete IDs,
|
|
126
|
+
query strings, email addresses, or other high-cardinality values.
|
|
127
|
+
|
|
128
|
+
## 5. Observe an outbound API call
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
const providerFetch = httpApiCollector.observeFetch({
|
|
132
|
+
routeTemplate: "/v1/candidates",
|
|
133
|
+
eventType: "candidate.create",
|
|
134
|
+
payloadLocation: "response",
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const response = await providerFetch("https://provider.example/v1/candidates", {
|
|
138
|
+
method: "POST",
|
|
139
|
+
headers: {
|
|
140
|
+
authorization: `Bearer ${process.env.PROVIDER_TOKEN}`,
|
|
141
|
+
"content-type": "application/json",
|
|
142
|
+
},
|
|
143
|
+
body: JSON.stringify(candidate),
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The collector never receives the request headers. By default, it clones the
|
|
148
|
+
response and inspects JSON asynchronously, so consuming the original response
|
|
149
|
+
is not delayed. Set `payloadLocation: "request"` to observe the JSON request
|
|
150
|
+
shape instead. String bodies and cloned `Request` bodies are inspected safely.
|
|
151
|
+
For another body type, pass a local-only `requestPayload`; its values remain in
|
|
152
|
+
the process and only its redacted structural shape enters the envelope.
|
|
153
|
+
|
|
154
|
+
## 6. Observe a queue boundary
|
|
155
|
+
|
|
156
|
+
Use the broker-neutral wrappers around the publish and consume functions you
|
|
157
|
+
already own. Seamward does not acknowledge, retry, or otherwise control the
|
|
158
|
+
broker operation.
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
const publishCandidate = queuePublisherCollector.observeQueuePublish(
|
|
162
|
+
{
|
|
163
|
+
queueName: "candidate-events",
|
|
164
|
+
eventType: "candidate.published",
|
|
165
|
+
},
|
|
166
|
+
async (message) => {
|
|
167
|
+
await broker.publish("candidate-events", message);
|
|
168
|
+
return { disposition: "acknowledged" as const };
|
|
169
|
+
},
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
const consumeCandidate = queueConsumerCollector.observeQueueConsumer(
|
|
173
|
+
{
|
|
174
|
+
queueName: "candidate-events",
|
|
175
|
+
eventType: "candidate.received",
|
|
176
|
+
},
|
|
177
|
+
async (message) => {
|
|
178
|
+
await candidateService.accept(message);
|
|
179
|
+
return { disposition: "acknowledged" as const };
|
|
180
|
+
},
|
|
181
|
+
);
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Use a stable queue, topic, or subscription label. Never use a message ID.
|
|
185
|
+
Broker-specific adapters are not shipped in this pilot.
|
|
186
|
+
|
|
187
|
+
## 7. Observe a scheduled feed
|
|
188
|
+
|
|
189
|
+
Wrap one scheduled import or export run. The wrapper records completion,
|
|
190
|
+
rejection, duration, attempt, and correlation evidence without changing the
|
|
191
|
+
job's return value or error behaviour.
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
const exportCandidates = feedExportCollector.observeScheduledFeed(
|
|
195
|
+
{
|
|
196
|
+
feedName: "nightly-candidate-export",
|
|
197
|
+
direction: "outbound",
|
|
198
|
+
eventType: "candidate.exported",
|
|
199
|
+
},
|
|
200
|
+
async (payload) => {
|
|
201
|
+
await provider.upload(payload);
|
|
202
|
+
return { disposition: "completed" as const };
|
|
203
|
+
},
|
|
204
|
+
);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The v0.2 wire envelope retains `method`, `routeTemplate`, and `statusCode` for
|
|
208
|
+
backward compatibility. Queue and feed wrappers project their native concepts
|
|
209
|
+
into those fields, so application code does not supply synthetic HTTP values.
|
|
210
|
+
|
|
211
|
+
## 8. Redaction and correlation
|
|
212
|
+
|
|
213
|
+
Payload values and headers are never included in the observation envelope. The
|
|
214
|
+
collector derives only the structural shape (`string`, `number`, object fields,
|
|
215
|
+
and so on) and its fingerprint before the envelope leaves the process. Field
|
|
216
|
+
names remain visible because they are required for contract-drift detection.
|
|
217
|
+
|
|
218
|
+
The default policy identifies these common secret-bearing fields:
|
|
219
|
+
|
|
220
|
+
```text
|
|
221
|
+
password, access_token, refresh_token, authorization, cookie, set-cookie
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Give an application-specific policy version so evidence can be traced to the
|
|
225
|
+
configuration that produced it:
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
const seamward = createSeamwardCollector({
|
|
229
|
+
connectionKey: process.env.SEAMWARD_CONNECTION_KEY!,
|
|
230
|
+
ingestToken: process.env.SEAMWARD_INGEST_TOKEN!,
|
|
231
|
+
policy: {
|
|
232
|
+
version: "candidate-api-v1",
|
|
233
|
+
dropFields: [
|
|
234
|
+
"password",
|
|
235
|
+
"access_token",
|
|
236
|
+
"refresh_token",
|
|
237
|
+
"authorization",
|
|
238
|
+
"cookie",
|
|
239
|
+
"set-cookie",
|
|
240
|
+
"full_name",
|
|
241
|
+
"email",
|
|
242
|
+
"phone_number",
|
|
243
|
+
],
|
|
244
|
+
hashFields: [],
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Do not place identifiers in `eventType`, `routeTemplate`, release labels, or
|
|
250
|
+
service names. Put only identifiers needed for reconciliation into
|
|
251
|
+
`correlation.sourceEventId`, `correlation.idempotencyKey`, or
|
|
252
|
+
`outcome.businessObjectId`. The collector converts those values to keyed
|
|
253
|
+
SHA-256 hashes locally; Seamward receives no original identifier.
|
|
254
|
+
|
|
255
|
+
## 9. Shutdown and health
|
|
256
|
+
|
|
257
|
+
Flush before a controlled process shutdown:
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
process.once("SIGTERM", async () => {
|
|
261
|
+
await Promise.all([
|
|
262
|
+
webhookCollector.stop(),
|
|
263
|
+
httpApiCollector.stop(),
|
|
264
|
+
queuePublisherCollector.stop(),
|
|
265
|
+
queueConsumerCollector.stop(),
|
|
266
|
+
feedExportCollector.stop(),
|
|
267
|
+
]);
|
|
268
|
+
process.exit(0);
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
`stop()` clears the timer and attempts one final flush. `flush()` and `stop()`
|
|
273
|
+
never reject because Seamward telemetry must not break the host application.
|
|
274
|
+
Inspect bounded operational counters without logging observations or tokens:
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
const { enqueued, shipped, dropped, failedBatches, queueLength, buildErrors } =
|
|
278
|
+
httpApiCollector.stats();
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Defaults:
|
|
282
|
+
|
|
283
|
+
- flush interval: 5 seconds;
|
|
284
|
+
- batch size: 50 observations;
|
|
285
|
+
- in-memory queue: 1,000 observations;
|
|
286
|
+
- overflow policy: drop oldest and increment `dropped`;
|
|
287
|
+
- failed request policy: retain the batch and retry on the next flush;
|
|
288
|
+
- application errors: preserve the application's original error behaviour.
|
|
289
|
+
|
|
290
|
+
## 10. Verify the connection
|
|
291
|
+
|
|
292
|
+
1. Start the backend with the Connection key and ingest token configured.
|
|
293
|
+
2. Exercise one synthetic HTTP request, webhook, queue message, or feed run.
|
|
294
|
+
3. Wait for the five-second automatic flush, or call `await httpApiCollector.flush()` for the collector you exercised.
|
|
295
|
+
4. Return to the integration in Seamward and select **Check for observation**.
|
|
296
|
+
5. Confirm the first observation time and deployment metadata.
|
|
297
|
+
|
|
298
|
+
If the integration remains unobserved:
|
|
299
|
+
|
|
300
|
+
- confirm the collector is running in the backend rather than the browser;
|
|
301
|
+
- copy the Connection key again from the integration you are testing;
|
|
302
|
+
- confirm the ingest token belongs to that integration's application environment;
|
|
303
|
+
- inspect the relevant collector's `stats()` result for `failedBatches`, `dropped`, or `buildErrors`;
|
|
304
|
+
- verify the local API is reachable at the configured ingest URL;
|
|
305
|
+
- generate a new ingest token if the original was not saved or may be exposed.
|
|
306
|
+
|
|
307
|
+
Do not disable redaction or log request bodies to troubleshoot the connection.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type Json } from "@seamward/contracts";
|
|
2
|
+
import { type Collector, type CollectorConfig, type FetchMeta, type ObservedFetch, type QueueMeta, type QueueResult, type RecordInput, type ScheduledFeedMeta, type ScheduledFeedResult, type WebhookMeta, type WebhookResult } from "./observe.js";
|
|
3
|
+
import type { RedactionPolicy } from "./redact.js";
|
|
4
|
+
export interface ConnectOptions extends Pick<CollectorConfig, "deployment" | "builderDeps" | "maxBatchSize" | "flushIntervalMs" | "maxQueueSize" | "fetchFn" | "nowSec"> {
|
|
5
|
+
/** Override for self-hosted and local Seamward ingestion. */
|
|
6
|
+
endpoint?: string;
|
|
7
|
+
policy?: Omit<RedactionPolicy, "hashKey">;
|
|
8
|
+
}
|
|
9
|
+
export type CreateSeamwardCollectorConfig = ConnectOptions & {
|
|
10
|
+
/** Write-only server credential. Store this in an environment variable. */
|
|
11
|
+
ingestToken: string;
|
|
12
|
+
} & ({
|
|
13
|
+
/** Public key that binds one source and integration. Grants no access by itself. */
|
|
14
|
+
connectionKey: string;
|
|
15
|
+
sourceKey?: never;
|
|
16
|
+
} | {
|
|
17
|
+
/** Legacy public application/environment identifier. */
|
|
18
|
+
sourceKey: string;
|
|
19
|
+
connectionKey?: never;
|
|
20
|
+
});
|
|
21
|
+
export type ConnectedRecordInput = Omit<RecordInput, "integrationId"> & {
|
|
22
|
+
integrationKey?: string;
|
|
23
|
+
};
|
|
24
|
+
export type ConnectedWebhookMeta = Omit<WebhookMeta, "integrationId"> & {
|
|
25
|
+
integrationKey?: string;
|
|
26
|
+
};
|
|
27
|
+
export type ConnectedFetchMeta = Omit<FetchMeta, "integrationId"> & {
|
|
28
|
+
integrationKey?: string;
|
|
29
|
+
};
|
|
30
|
+
export type ConnectedQueueMeta = Omit<QueueMeta, "integrationId"> & {
|
|
31
|
+
integrationKey?: string;
|
|
32
|
+
};
|
|
33
|
+
export type ConnectedScheduledFeedMeta = Omit<ScheduledFeedMeta, "integrationId"> & {
|
|
34
|
+
integrationKey?: string;
|
|
35
|
+
};
|
|
36
|
+
export interface ConnectedCollector extends Omit<Collector, "record" | "observeWebhook" | "observeFetch"> {
|
|
37
|
+
record(input: ConnectedRecordInput): void;
|
|
38
|
+
observeWebhook<R extends WebhookResult | void>(meta: ConnectedWebhookMeta, handler: (payload: Json) => R | Promise<R>): (payload: Json) => Promise<R>;
|
|
39
|
+
observeFetch(meta: ConnectedFetchMeta, fetchFn?: typeof fetch): ObservedFetch;
|
|
40
|
+
observeQueuePublish<R extends QueueResult | void>(meta: ConnectedQueueMeta, publisher: (message: Json) => R | Promise<R>): (message: Json) => Promise<R>;
|
|
41
|
+
observeQueueConsumer<R extends QueueResult | void>(meta: ConnectedQueueMeta, consumer: (message: Json) => R | Promise<R>): (message: Json) => Promise<R>;
|
|
42
|
+
observeScheduledFeed<R extends ScheduledFeedResult | void>(meta: ConnectedScheduledFeedMeta, handler: (payload: Json) => R | Promise<R>): (payload: Json) => Promise<R>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Backend collector setup. The public Source key identifies the deployed
|
|
46
|
+
* application; Integration keys route its observations, and the write-only
|
|
47
|
+
* ingest token authenticates and signs every batch.
|
|
48
|
+
*/
|
|
49
|
+
export declare function createSeamwardCollector(config: CreateSeamwardCollectorConfig): ConnectedCollector;
|
package/dist/connect.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { parseIngestToken, parseConnectionKey, parseIntegrationKey, parseSourceKey, } from "@seamward/contracts";
|
|
3
|
+
import { createCollector, } from "./observe.js";
|
|
4
|
+
const defaultPolicy = {
|
|
5
|
+
version: "seamward-default-v1",
|
|
6
|
+
dropFields: [
|
|
7
|
+
"password",
|
|
8
|
+
"access_token",
|
|
9
|
+
"refresh_token",
|
|
10
|
+
"authorization",
|
|
11
|
+
"cookie",
|
|
12
|
+
"set-cookie",
|
|
13
|
+
],
|
|
14
|
+
hashFields: [],
|
|
15
|
+
};
|
|
16
|
+
function defaultIngestEndpoint() {
|
|
17
|
+
return process.env.SEAMWARD_INGEST_URL ?? "https://api.seamward.com/ingest";
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Backend collector setup. The public Source key identifies the deployed
|
|
21
|
+
* application; Integration keys route its observations, and the write-only
|
|
22
|
+
* ingest token authenticates and signs every batch.
|
|
23
|
+
*/
|
|
24
|
+
export function createSeamwardCollector(config) {
|
|
25
|
+
const { connectionKey: rawConnectionKey, ingestToken: rawIngestToken, endpoint = defaultIngestEndpoint(), policy = defaultPolicy, sourceKey: rawSourceKey, ...options } = config;
|
|
26
|
+
let sourceKey;
|
|
27
|
+
let boundIntegrationKey = null;
|
|
28
|
+
let ingestToken;
|
|
29
|
+
try {
|
|
30
|
+
if (rawConnectionKey) {
|
|
31
|
+
const parsed = parseConnectionKey(rawConnectionKey);
|
|
32
|
+
sourceKey = parsed.sourceKey;
|
|
33
|
+
boundIntegrationKey = parsed.integrationKey;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
sourceKey = parseSourceKey(rawSourceKey ?? "");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
throw new Error("Seamward connection key or source key is invalid");
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
ingestToken = parseIngestToken(rawIngestToken);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
throw new Error("Seamward ingest token is invalid");
|
|
47
|
+
}
|
|
48
|
+
const collector = createCollector({
|
|
49
|
+
endpoint,
|
|
50
|
+
sourceKey,
|
|
51
|
+
ingestToken,
|
|
52
|
+
// These placeholders satisfy the local strict envelope contract. The API
|
|
53
|
+
// replaces them with the token-bound scope before validation/persistence.
|
|
54
|
+
tenantId: "ten_authenticated",
|
|
55
|
+
environmentId: "env_authenticated",
|
|
56
|
+
policy: {
|
|
57
|
+
...policy,
|
|
58
|
+
hashKey: createHash("sha256").update(ingestToken).digest("base64url"),
|
|
59
|
+
},
|
|
60
|
+
...options,
|
|
61
|
+
});
|
|
62
|
+
function integrationId(value) {
|
|
63
|
+
const selected = value ?? boundIntegrationKey;
|
|
64
|
+
if (!selected) {
|
|
65
|
+
throw new Error("Seamward integration key is required when using a legacy source key");
|
|
66
|
+
}
|
|
67
|
+
return parseIntegrationKey(selected);
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
record: ({ integrationKey, ...input }) => collector.record({
|
|
71
|
+
...input,
|
|
72
|
+
integrationId: integrationId(integrationKey),
|
|
73
|
+
}),
|
|
74
|
+
observeWebhook: ({ integrationKey, ...meta }, handler) => collector.observeWebhook({ ...meta, integrationId: integrationId(integrationKey) }, handler),
|
|
75
|
+
observeFetch: ({ integrationKey, ...meta }, fetchFn) => collector.observeFetch({ ...meta, integrationId: integrationId(integrationKey) }, fetchFn),
|
|
76
|
+
observeQueuePublish: ({ integrationKey, ...meta }, publisher) => collector.observeQueuePublish({ ...meta, integrationId: integrationId(integrationKey) }, publisher),
|
|
77
|
+
observeQueueConsumer: ({ integrationKey, ...meta }, consumer) => collector.observeQueueConsumer({ ...meta, integrationId: integrationId(integrationKey) }, consumer),
|
|
78
|
+
observeScheduledFeed: ({ integrationKey, ...meta }, handler) => collector.observeScheduledFeed({ ...meta, integrationId: integrationId(integrationKey) }, handler),
|
|
79
|
+
flush: () => collector.flush(),
|
|
80
|
+
stop: () => collector.stop(),
|
|
81
|
+
stats: () => collector.stats(),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=connect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type DeploymentContext } from "@seamward/contracts";
|
|
2
|
+
export type DeploymentEnvironment = Readonly<Record<string, string | undefined>>;
|
|
3
|
+
/**
|
|
4
|
+
* Resolve bounded, low-cardinality deployment evidence without making it a
|
|
5
|
+
* collector requirement. Explicit SDK values win; known runtime variables are
|
|
6
|
+
* fallbacks. Invalid values are ignored rather than breaking host telemetry.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveDeploymentContext(explicit?: Partial<DeploymentContext>, environment?: DeploymentEnvironment): DeploymentContext | undefined;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { deploymentContextSchema, } from "@seamward/contracts";
|
|
2
|
+
const commitEnvironmentKeys = [
|
|
3
|
+
"SEAMWARD_COMMIT_SHA",
|
|
4
|
+
"VERCEL_GIT_COMMIT_SHA",
|
|
5
|
+
"RENDER_GIT_COMMIT",
|
|
6
|
+
"RAILWAY_GIT_COMMIT_SHA",
|
|
7
|
+
"GITHUB_SHA",
|
|
8
|
+
];
|
|
9
|
+
function validField(key, candidates) {
|
|
10
|
+
for (const candidate of candidates) {
|
|
11
|
+
if (candidate === undefined || candidate.length === 0)
|
|
12
|
+
continue;
|
|
13
|
+
const parsed = deploymentContextSchema.safeParse({ [key]: candidate });
|
|
14
|
+
if (parsed.success)
|
|
15
|
+
return parsed.data[key];
|
|
16
|
+
}
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolve bounded, low-cardinality deployment evidence without making it a
|
|
21
|
+
* collector requirement. Explicit SDK values win; known runtime variables are
|
|
22
|
+
* fallbacks. Invalid values are ignored rather than breaking host telemetry.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveDeploymentContext(explicit = {}, environment = process.env) {
|
|
25
|
+
const service = validField("service", [explicit.service, environment.SEAMWARD_SERVICE]);
|
|
26
|
+
const commitSha = validField("commitSha", [
|
|
27
|
+
explicit.commitSha?.toLowerCase(),
|
|
28
|
+
...commitEnvironmentKeys.map((key) => environment[key]?.toLowerCase()),
|
|
29
|
+
]);
|
|
30
|
+
const release = validField("release", [
|
|
31
|
+
explicit.release,
|
|
32
|
+
environment.SEAMWARD_RELEASE,
|
|
33
|
+
commitSha?.slice(0, 12),
|
|
34
|
+
]);
|
|
35
|
+
const context = {
|
|
36
|
+
...(service ? { service } : {}),
|
|
37
|
+
...(release ? { release } : {}),
|
|
38
|
+
...(commitSha ? { commitSha } : {}),
|
|
39
|
+
};
|
|
40
|
+
const parsed = deploymentContextSchema.safeParse(context);
|
|
41
|
+
return parsed.success ? parsed.data : undefined;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=deployment-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment-context.js","sourceRoot":"","sources":["../src/deployment-context.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,GAExB,MAAM,qBAAqB,CAAC;AAI7B,MAAM,qBAAqB,GAAG;IAC5B,qBAAqB;IACrB,uBAAuB;IACvB,mBAAmB;IACnB,wBAAwB;IACxB,YAAY;CACJ,CAAC;AAEX,SAAS,UAAU,CACjB,GAAM,EACN,UAAqC;IAErC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAChE,MAAM,MAAM,GAAG,uBAAuB,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;QACvE,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,WAAuC,EAAE,EACzC,cAAqC,OAAO,CAAC,GAAG;IAEhD,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACxF,MAAM,SAAS,GAAG,UAAU,CAAC,WAAW,EAAE;QACxC,QAAQ,CAAC,SAAS,EAAE,WAAW,EAAE;QACjC,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,WAAW,EAAE,CAAC;KACvE,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,EAAE;QACpC,QAAQ,CAAC,OAAO;QAChB,WAAW,CAAC,gBAAgB;QAC5B,SAAS,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;KACxB,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG;QACd,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/B,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/B,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACpC,CAAC;IACF,MAAM,MAAM,GAAG,uBAAuB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC1D,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type DeploymentContext, type Json, type ObservationEnvelope } from "@seamward/contracts";
|
|
2
|
+
import { type RedactionPolicy } from "./redact.js";
|
|
3
|
+
/**
|
|
4
|
+
* Builds a valid ObservationEnvelope from one observed request/response.
|
|
5
|
+
*
|
|
6
|
+
* Privacy order of operations (the load-bearing design):
|
|
7
|
+
* 1. The structural fingerprint is computed from the RAW payload - signatures
|
|
8
|
+
* are shape-only (field names + types, never values), so this is safe and
|
|
9
|
+
* keeps drift detection faithful to what the provider actually sent, even
|
|
10
|
+
* for fields the policy would drop from any stored content.
|
|
11
|
+
* 2. Correlation identifiers leave the process only as keyed hashes.
|
|
12
|
+
* 3. The envelope schema is strict and has NO field for headers or bodies:
|
|
13
|
+
* a leak would require changing @seamward/contracts, not a builder bug.
|
|
14
|
+
*
|
|
15
|
+
* Pure: clock and id generation are injected for determinism. The built
|
|
16
|
+
* envelope is validated through the strict schema before it is returned.
|
|
17
|
+
*/
|
|
18
|
+
export interface ObservationInput {
|
|
19
|
+
tenantId: string;
|
|
20
|
+
environmentId: string;
|
|
21
|
+
integrationId: string;
|
|
22
|
+
direction: "inbound" | "outbound";
|
|
23
|
+
protocol: "http-webhook" | "http-api" | "scheduled-feed" | "queue";
|
|
24
|
+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
25
|
+
routeTemplate: string;
|
|
26
|
+
payloadLocation?: "request" | "response" | "message";
|
|
27
|
+
statusCode: number;
|
|
28
|
+
durationMs: number;
|
|
29
|
+
attempt?: number;
|
|
30
|
+
/** Low-cardinality provider event label; never put identifiers or PII here. */
|
|
31
|
+
eventType?: string;
|
|
32
|
+
/** Raw payload - used for shape-only fingerprinting; never shipped. */
|
|
33
|
+
payload?: Json;
|
|
34
|
+
declaredContractVersion?: string;
|
|
35
|
+
deployment?: DeploymentContext;
|
|
36
|
+
correlation?: {
|
|
37
|
+
traceId?: string;
|
|
38
|
+
sourceEventId?: string;
|
|
39
|
+
idempotencyKey?: string;
|
|
40
|
+
};
|
|
41
|
+
outcome?: {
|
|
42
|
+
accepted: boolean;
|
|
43
|
+
businessObjectType?: string;
|
|
44
|
+
businessObjectId?: string;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export interface BuilderDeps {
|
|
48
|
+
now?: () => Date;
|
|
49
|
+
newId?: () => string;
|
|
50
|
+
}
|
|
51
|
+
export declare function buildEnvelope(input: ObservationInput, policy: RedactionPolicy, deps?: BuilderDeps): ObservationEnvelope;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createHmac, randomUUID } from "node:crypto";
|
|
2
|
+
import { ENVELOPE_VERSION, OPERATION_IDENTITY_VERSION, defaultPayloadLocation, parseEnvelope, schemaFingerprint, shapeOf, } from "@seamward/contracts";
|
|
3
|
+
import { keyedHash } from "./redact.js";
|
|
4
|
+
export function buildEnvelope(input, policy, deps = {}) {
|
|
5
|
+
const now = deps.now ?? (() => new Date());
|
|
6
|
+
const newId = deps.newId ?? (() => randomUUID().replaceAll("-", ""));
|
|
7
|
+
const fingerprint = schemaFingerprint(input.payload ?? null);
|
|
8
|
+
const correlation = {};
|
|
9
|
+
if (input.correlation?.traceId)
|
|
10
|
+
correlation.traceId = input.correlation.traceId;
|
|
11
|
+
if (input.correlation?.sourceEventId) {
|
|
12
|
+
correlation.sourceEventIdHash = keyedHash(input.correlation.sourceEventId, policy.hashKey);
|
|
13
|
+
}
|
|
14
|
+
if (input.correlation?.idempotencyKey) {
|
|
15
|
+
correlation.idempotencyKeyHash = keyedHash(input.correlation.idempotencyKey, policy.hashKey);
|
|
16
|
+
}
|
|
17
|
+
correlation.hashNamespace =
|
|
18
|
+
policy.hashNamespace ??
|
|
19
|
+
`key:${createHmac("sha256", policy.hashKey)
|
|
20
|
+
.update("seamward-hash-namespace-v1", "utf8")
|
|
21
|
+
.digest("hex")
|
|
22
|
+
.slice(0, 32)}`;
|
|
23
|
+
const outcome = input.outcome
|
|
24
|
+
? {
|
|
25
|
+
accepted: input.outcome.accepted,
|
|
26
|
+
...(input.outcome.businessObjectType
|
|
27
|
+
? { businessObjectType: input.outcome.businessObjectType }
|
|
28
|
+
: {}),
|
|
29
|
+
...(input.outcome.businessObjectId
|
|
30
|
+
? {
|
|
31
|
+
businessObjectIdHash: keyedHash(input.outcome.businessObjectId, policy.hashKey),
|
|
32
|
+
}
|
|
33
|
+
: {}),
|
|
34
|
+
}
|
|
35
|
+
: { accepted: input.statusCode !== 0 && input.statusCode < 400 };
|
|
36
|
+
return parseEnvelope({
|
|
37
|
+
envelopeVersion: ENVELOPE_VERSION,
|
|
38
|
+
eventId: `evt_${newId()}`,
|
|
39
|
+
tenantId: input.tenantId,
|
|
40
|
+
environmentId: input.environmentId,
|
|
41
|
+
integrationId: input.integrationId,
|
|
42
|
+
direction: input.direction,
|
|
43
|
+
protocol: input.protocol,
|
|
44
|
+
occurredAt: now().toISOString(),
|
|
45
|
+
operationIdentityVersion: OPERATION_IDENTITY_VERSION,
|
|
46
|
+
...(input.deployment ? { deployment: input.deployment } : {}),
|
|
47
|
+
...(input.eventType ? { eventType: input.eventType } : {}),
|
|
48
|
+
correlation,
|
|
49
|
+
contract: {
|
|
50
|
+
...(input.declaredContractVersion
|
|
51
|
+
? { declaredVersion: input.declaredContractVersion }
|
|
52
|
+
: {}),
|
|
53
|
+
observedFingerprint: fingerprint,
|
|
54
|
+
},
|
|
55
|
+
transport: {
|
|
56
|
+
method: input.method,
|
|
57
|
+
routeTemplate: input.routeTemplate,
|
|
58
|
+
payloadLocation: input.payloadLocation ?? defaultPayloadLocation(input),
|
|
59
|
+
statusCode: input.statusCode,
|
|
60
|
+
durationMs: input.durationMs,
|
|
61
|
+
attempt: input.attempt ?? 1,
|
|
62
|
+
},
|
|
63
|
+
payload: {
|
|
64
|
+
storage: "none",
|
|
65
|
+
schemaFingerprint: fingerprint,
|
|
66
|
+
schemaShape: shapeOf(input.payload ?? null),
|
|
67
|
+
redactionPolicyVersion: policy.version,
|
|
68
|
+
},
|
|
69
|
+
outcome,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=envelope-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope-builder.js","sourceRoot":"","sources":["../src/envelope-builder.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { redactPayload, redactHeaders, keyedHash, ALWAYS_DROPPED_HEADERS, } from "./redact.js";
|
|
2
|
+
export type { RedactionPolicy } from "./redact.js";
|
|
3
|
+
export { buildEnvelope } from "./envelope-builder.js";
|
|
4
|
+
export type { ObservationInput, BuilderDeps } from "./envelope-builder.js";
|
|
5
|
+
export { createShipper } from "./shipper.js";
|
|
6
|
+
export type { Shipper, ShipperConfig, ShipperStats } from "./shipper.js";
|
|
7
|
+
export { createCollector } from "./observe.js";
|
|
8
|
+
export type { Collector, CollectorConfig, CollectorStats, FetchMeta, ObservedFetch, QueueMeta, QueueResult, RecordInput, ScheduledFeedMeta, ScheduledFeedResult, WebhookMeta, WebhookResult, } from "./observe.js";
|
|
9
|
+
export { resolveDeploymentContext } from "./deployment-context.js";
|
|
10
|
+
export type { DeploymentEnvironment } from "./deployment-context.js";
|
|
11
|
+
export { createSeamwardCollector } from "./connect.js";
|
|
12
|
+
export type { CreateSeamwardCollectorConfig, ConnectedCollector, ConnectedFetchMeta, ConnectedQueueMeta, ConnectedRecordInput, ConnectedScheduledFeedMeta, ConnectedWebhookMeta, ConnectOptions, } from "./connect.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { redactPayload, redactHeaders, keyedHash, ALWAYS_DROPPED_HEADERS, } from "./redact.js";
|
|
2
|
+
export { buildEnvelope } from "./envelope-builder.js";
|
|
3
|
+
export { createShipper } from "./shipper.js";
|
|
4
|
+
export { createCollector } from "./observe.js";
|
|
5
|
+
export { resolveDeploymentContext } from "./deployment-context.js";
|
|
6
|
+
export { createSeamwardCollector } from "./connect.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,SAAS,EACT,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAgB/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAGnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC"}
|