@owlmeans/viable-log 0.1.18-rc.2 → 0.1.18-rc.3

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 CHANGED
@@ -1,3 +1,150 @@
1
+ # @owlmeans/viable-log
2
+
3
+ A generated (target) application's link to the OwlMeans platform (viable), expressed as two
4
+ `@owlmeans/log` plugins plus the wire contract the platform reads them with. `viablePreviewPlugin`
5
+ sends the target web's analytics events to the manager frame that embeds the preview;
6
+ `viableSlotPlugin` writes the target backend's error records and analytics events as marked JSON
7
+ lines on stdout, where the platform's publisher picks them up. A generated app registers both
8
+ unconditionally — each is inert wherever the platform is absent — and the platform side imports the
9
+ same package to parse what the app emits. An application that is not generated and run by viable has
10
+ no use for it: count events with `@owlmeans/web-log` (tag manager) instead. The `viable-log` skill
11
+ covers this package; the `logging` skill sets the policy for the log calls that feed it.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ bun add @owlmeans/viable-log@^0.1.18-rc.3
17
+ ```
18
+
19
+ ## Concepts
20
+
21
+ - **Target application** — an app generated and hosted by viable. It logs only through
22
+ `@owlmeans/log`; these plugins decide what reaches the platform.
23
+ - **Preview channel** — `window[PREVIEW_REPORTER_FLAG]`, an object with `post(type, payload)`
24
+ installed by the platform's injected reporter in a framed preview. Absent in production.
25
+ - **Slot events** — a backend process run by the publisher with `OWLMEANS_SLOT_EVENTS=1`
26
+ (`SLOT_EVENTS_ENV`). Without that variable the slot plugin writes nothing.
27
+ - **Target event line** — `TARGET_EVENT_MARKER` (`'[owl:event] '`) followed by one JSON `TargetEvent`,
28
+ capped at `TARGET_EVENT_MAX` (16 KiB). Versioned by `TARGET_EVENT_VERSION`.
29
+ - **Untrusted input** — the platform treats every line as written by generated code: it validates
30
+ marker, JSON, version, kind and level, clips text fields and drops unknown ones.
31
+
32
+ ## Usage
33
+
34
+ ### 1. Target web — register the preview plugin
35
+
36
+ ```typescript
37
+ import { addLogPlugin, logger } from '@owlmeans/log'
38
+ import { viablePreviewPlugin } from '@owlmeans/viable-log'
39
+
40
+ addLogPlugin(viablePreviewPlugin())
41
+
42
+ logger('ui').info('Opened', { page: 'home' }, { analytics: 'page_view' })
43
+ // in a framed preview: channel.post('OWLMEANS_PREVIEW_ANALYTICS', { event: 'page_view', scope: 'ui', data: { page: 'home' }, ... })
44
+ // anywhere else: nothing
45
+ ```
46
+
47
+ Browser errors need no plugin: a record carrying an `Error` reaches the reporter's own
48
+ `console.error` hook through the logger's console sink.
49
+
50
+ ### 2. Target backend — register the slot plugin
51
+
52
+ ```typescript
53
+ import { addLogPlugin, logger } from '@owlmeans/log'
54
+ import { viableSlotPlugin } from '@owlmeans/viable-log'
55
+
56
+ addLogPlugin(viableSlotPlugin())
57
+
58
+ const log = logger('api')
59
+ log.error('Request failed', error) // → kind 'error' line
60
+ log.info('Signed up', { plan: 'free' }, { analytics: 'signup' }) // → kind 'analytics' line
61
+ log.warn('Slow query') // → no line (not error, not analytics)
62
+ ```
63
+
64
+ ### 3. Platform side — read a stdout line
65
+
66
+ ```typescript
67
+ import { targetEventHelper } from '@owlmeans/viable-log'
68
+
69
+ for (const line of chunk.split('\n')) {
70
+ const event = targetEventHelper.parseTargetEventLine(line) // marker may appear anywhere in the line
71
+ if (event == null) {
72
+ continue // ordinary output, or a rejected line
73
+ }
74
+ relay(event)
75
+ }
76
+ ```
77
+
78
+ ### 4. Platform side — detect the preview channel
79
+
80
+ ```typescript
81
+ import { previewChannel, PREVIEW_ANALYTICS_TYPE } from '@owlmeans/viable-log'
82
+
83
+ previewChannel()?.post(PREVIEW_ANALYTICS_TYPE, payload)
84
+ ```
85
+
86
+ `previewChannel()` returns `undefined` outside a browser and whenever the flag is not an object with
87
+ a `post` function.
88
+
89
+ ## API
90
+
91
+ ### Plugins and helpers
92
+
93
+ | Symbol | Kind | Purpose |
94
+ |---|---|---|
95
+ | `viablePreviewPlugin()` | function → `LogPlugin` | Name `'viable-preview'`; `track` posts each `AnalyticsEvent` as `PREVIEW_ANALYTICS_TYPE` through the preview channel |
96
+ | `viableSlotPlugin()` | function → `LogPlugin` | Name `'viable-slot'`; `log` emits error-level records, `track` emits analytics events, both as target event lines on `process.stdout` when `SLOT_EVENTS_ENV` is `'1'` |
97
+ | `previewChannel()` | function | The current document's `PreviewChannel`, or `undefined` |
98
+ | `targetEventHelper` | `TargetEventHelper` | Default instance of the line protocol |
99
+ | `createTargetEventHelper()` | function | Builds a `TargetEventHelper` |
100
+ | `targetEventHelper.targetEventLine(event)` | member | Serialise an event; an over-long one loses its stack, then its data, then is cut at `TARGET_EVENT_MAX` |
101
+ | `targetEventHelper.parseTargetEventLine(line)` | member | Validate and clip an untrusted line → `TargetEvent \| undefined` |
102
+ | `targetEventLine`, `parseTargetEventLine` | functions | Deprecated wrappers; use `targetEventHelper` |
103
+
104
+ ### Constants
105
+
106
+ | Symbol | Value | Purpose |
107
+ |---|---|---|
108
+ | `PREVIEW_REPORTER_FLAG` | `'__owlmeansPreviewReporter'` | `window` property holding the preview channel |
109
+ | `PREVIEW_ANALYTICS_TYPE` | `'OWLMEANS_PREVIEW_ANALYTICS'` | Message type of a preview analytics post |
110
+ | `TARGET_EVENT_MARKER` | `'[owl:event] '` | Prefix of a target event line |
111
+ | `SLOT_EVENTS_ENV` | `'OWLMEANS_SLOT_EVENTS'` | Environment variable the publisher sets to `1` |
112
+ | `TARGET_EVENT_VERSION` | `1` | Format version of `TargetEvent` |
113
+ | `TARGET_EVENT_MAX` | `16384` | Longest line written and accepted |
114
+
115
+ ### Types
116
+
117
+ | Symbol | Shape |
118
+ |---|---|
119
+ | `TargetEvent` | `{ v, kind, ts, level, scope, message, event?, data?, error?: { name, message, stack?, incidentId? } }` |
120
+ | `TargetEventKind` | `'error' \| 'analytics'` |
121
+ | `PreviewChannel` | `{ v: number, post(type, payload) }` |
122
+ | `PreviewAnalyticsPayload` | the `AnalyticsEvent` from `@owlmeans/log` |
123
+ | `TargetEventHelper` | `{ targetEventLine, parseTargetEventLine }` |
124
+
125
+ On parse, text fields are clipped: `scope` and `event` to 200 characters (`scope` falls back to
126
+ `'target'`), `message` to 2000, `error.stack` to 8000, `error.incidentId` to 100.
127
+
128
+ ## Common pitfalls
129
+
130
+ - Never build a marked line or post a preview message from application code — log through
131
+ `@owlmeans/log` and let the plugins emit.
132
+ - Do not gate plugin registration on the environment; both plugins are already inert without the
133
+ channel or `OWLMEANS_SLOT_EVENTS=1`.
134
+ - The slot plugin forwards only `error` records; `warn` and lower reach the platform only when the
135
+ call also carries an `analytics` option.
136
+ - A stack or a large `data` may be dropped to fit `TARGET_EVENT_MAX` — keep the message meaningful
137
+ on its own.
138
+ - Changing any `TargetEvent` field shape requires a new `TARGET_EVENT_VERSION`; the parser rejects
139
+ every other version.
140
+ - Anything read from `parseTargetEventLine` is still user-generated content — do not render or log
141
+ it as trusted text.
142
+
143
+ ## Related packages
144
+
145
+ - [`@owlmeans/log`](../log) — `logger`, `addLogPlugin`, `LogPlugin` and the analytics call option
146
+ - [`@owlmeans/web-log`](../web-log) — consent-gated analytics plugins for a tag manager
147
+
1
148
  <!-- owlmeans:agent-guidance:start -->
2
149
  ## Agent guidance
3
150
 
@@ -6,7 +153,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
6
153
  your project's skill store (`.agents/skills/`):
7
154
 
8
155
  ```sh
9
- npx @owlmeans/agent-skills@^0.1.18-rc.49
156
+ npx @owlmeans/agent-skills@^0.1.18-rc.52
10
157
  ```
11
158
 
12
159
  The embedded files are version-matched to this package release. Do not edit them
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/viable-log",
4
- "version": "0.1.18-rc.2",
5
- "generatedAt": "2026-10-05T21:03:06.378Z",
4
+ "version": "0.1.18-rc.3",
5
+ "generatedAt": "2026-10-08T21:27:54.291Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -8,7 +8,7 @@ user-invocable: false
8
8
  # @owlmeans/viable-log
9
9
 
10
10
  **Layer:** Domain (depends on `@owlmeans/log` only)
11
- **Install:** `"@owlmeans/viable-log": "^0.1.18-rc.2"` in `dependencies`
11
+ **Install:** `"@owlmeans/viable-log": "^0.1.18-rc.3"` in `dependencies`
12
12
 
13
13
  The platform is "just one of the plugins" of a target's logging: a generated app logs through
14
14
  `@owlmeans/log`, and registers these two plugins so what it says reaches Viable. Both are inert
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/viable-log",
3
- "version": "0.1.18-rc.2",
3
+ "version": "0.1.18-rc.3",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -22,7 +22,7 @@
22
22
  }
23
23
  },
24
24
  "dependencies": {
25
- "@owlmeans/log": "^0.1.18-rc.2"
25
+ "@owlmeans/log": "^0.1.18-rc.3"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@owlmeans/dep-config": "workspace:*",