@snowplow/signals-browser-plugin 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +29 -0
- package/README.md +131 -0
- package/dist/index.module.d.ts +187 -0
- package/dist/index.module.js +649 -0
- package/dist/index.module.js.map +1 -0
- package/dist/index.umd.js +951 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/index.umd.min.js +13 -0
- package/dist/index.umd.min.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Snowplow Analytics Ltd
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Snowplow Signals Interventions Plugin
|
|
2
|
+
|
|
3
|
+
[![npm version][npm-image]][npm-url]
|
|
4
|
+
[![License][license-image]](LICENSE)
|
|
5
|
+
|
|
6
|
+
Browser Plugin to be used with [`@snowplow/browser-tracker`](https://github.com/snowplow/snowplow-javascript-tracker).
|
|
7
|
+
|
|
8
|
+
This plugin allows receiving and reacting to [Snowplow Signals](https://docs.snowplow.io/docs/signals/) interventions.
|
|
9
|
+
|
|
10
|
+
## Maintainer quick start
|
|
11
|
+
|
|
12
|
+
Build with [Node.js](https://nodejs.org/).
|
|
13
|
+
|
|
14
|
+
### Setup repository
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
git clone https://github.com/snowplow-incubator/signals-browser-plugin.git
|
|
18
|
+
npm install
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Package Installation
|
|
22
|
+
|
|
23
|
+
With npm:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @snowplow/signals-browser-plugin
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
Initialize your tracker with the `SignalsInterventionsPlugin`, add a handler, and request interventions:
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
import { newTracker } from '@snowplow/browser-tracker';
|
|
35
|
+
import {
|
|
36
|
+
SignalsInterventionsPlugin,
|
|
37
|
+
addInterventionHandlers,
|
|
38
|
+
subscribeToInterventions,
|
|
39
|
+
} from '@snowplow/signals-browser-plugin';
|
|
40
|
+
|
|
41
|
+
newTracker('sp1', '{{collector_url}}', {
|
|
42
|
+
appId: 'my-app-id',
|
|
43
|
+
plugins: [SignalsInterventionsPlugin()],
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
addInterventionHandlers({
|
|
47
|
+
myHandler(intervention) {
|
|
48
|
+
console.log('intervention received!', intervention);
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
subscribeToInterventions({
|
|
53
|
+
endpoint: '00000000-0000-0000-0000-000000000000.svc.snplow.net',
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Configuration
|
|
58
|
+
|
|
59
|
+
#### Plugin Configuration
|
|
60
|
+
|
|
61
|
+
The plugin can be configured with the following options:
|
|
62
|
+
|
|
63
|
+
- `handlers`: Object containing handler functions to be called when interventions are received
|
|
64
|
+
- `measurement`: Configure defaults for the built-in events the plugin generates when interventions are received
|
|
65
|
+
- `delivery`, `dispatch_accept`, `dispatch_error`: Set to `false` or a boolean-returning function to disable tracking events when interventions are received or handled
|
|
66
|
+
- `context`: Set to an array of entities or entity-generating callbacks to add custom context to events generated by the plugin
|
|
67
|
+
|
|
68
|
+
#### Handlers
|
|
69
|
+
|
|
70
|
+
Handlers can be provided in the initial configuration via the `handlers` setting, or added dynamically after configuration using `addInterventionHandlers()`.
|
|
71
|
+
|
|
72
|
+
Each handler function will receive the intervention instance payload and the associated `BrowserTracker` instance.
|
|
73
|
+
|
|
74
|
+
Handlers can also be removed via `removeInterventionHandlers()`, which takes an array of handler IDs.
|
|
75
|
+
|
|
76
|
+
#### Subscribing
|
|
77
|
+
|
|
78
|
+
Call `subscribeToInterventions()` to configure the fetcher and make a request for interventions.
|
|
79
|
+
|
|
80
|
+
It will automatically adjust its subscription to account for updated entity IDs; by default it extracts the standard `domain_userid` and `domain_sessionid` entities.
|
|
81
|
+
|
|
82
|
+
It takes the following options:
|
|
83
|
+
|
|
84
|
+
- `endpoint` (required): your Signals API URI to connect to; until this option is provided no connection will be made and no interventions will be received
|
|
85
|
+
- `apiPath`: The path to request from `endpoint` when fetching interventions. Defaults to `/api/v1/interventions`
|
|
86
|
+
- `entityTargets`: Configures how to extract entity IDs from Snowplow events that get observed (see below)
|
|
87
|
+
- `entityIds`: Object mapping explicit entity ID configurations to request, as an object
|
|
88
|
+
- `connectionTimeoutMs`: How long to wait for the initial network request to be accepted before aborting (default 2500 milliseconds)
|
|
89
|
+
|
|
90
|
+
You can call this function multiple times to update these settings, previous connections will be closed if necessary.
|
|
91
|
+
|
|
92
|
+
#### Entity Targets
|
|
93
|
+
|
|
94
|
+
The `entityTargets` setting lets you declare rules for entity IDs to extract from events that the Snowplow tracker generates.
|
|
95
|
+
|
|
96
|
+
You specify a map of entity name to a string (or array of strings) containing [JSON Pointers](https://datatracker.ietf.org/doc/html/rfc6901) that configure how to find the value to use as an ID.
|
|
97
|
+
For arrays, if a JSON Pointer does not return a result, the next pointer in the array is tried until a value is found.
|
|
98
|
+
|
|
99
|
+
The JSON pointers are evaluated against `Payload` instances, so the fields use their [Tracker Protocol](https://docs.snowplow.io/docs/events/going-deeper/event-parameters/) names.
|
|
100
|
+
|
|
101
|
+
For convenience, the plugin will map enriched field-names to their Tracker Protocol equivalents so either work.
|
|
102
|
+
The fields available are only those present in the actual event however, so values added during enrichment like `geo_country` will not work, beyond basic examples like `event_name` or `page_urlpath` which will be computed and work.
|
|
103
|
+
|
|
104
|
+
Entities and self-describing event payloads are mapped in a version independent manner, accessible under their tracker protocol fields, followed by vendor and name.
|
|
105
|
+
Single-element arrays will be treated as scalars for convenience.
|
|
106
|
+
|
|
107
|
+
For example, the default entity IDs could alternatively be explicitly configured via:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"domain_userid": ["duid", "domain_userid", "/context/com.snowplowanalytics.snowplow/client_session/userId"],
|
|
112
|
+
"domain_sessionid": ["sid", "domain_sessionid", "/cx/com.snowplowanalytics.snowplow/client_session/sessionId"]
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`duid` and `domain_userid` would both lookup the `duid` field so are redundant, but if not found the `client_session` entity will be examined.
|
|
117
|
+
If the found value is `null` or `undefined`, the entity will be ignored until a later event supplies a matching value to use as ID.
|
|
118
|
+
|
|
119
|
+
## Copyright and license
|
|
120
|
+
|
|
121
|
+
Licensed and distributed under the [BSD 3-Clause License](LICENSE) ([An OSI Approved License][osi]).
|
|
122
|
+
|
|
123
|
+
Copyright (c) 2025 Snowplow Analytics Ltd.
|
|
124
|
+
|
|
125
|
+
All rights reserved.
|
|
126
|
+
|
|
127
|
+
[npm-url]: https://www.npmjs.com/package/@snowplow/browser-plugin-signals-interventions
|
|
128
|
+
[npm-image]: https://img.shields.io/npm/v/@snowplow/browser-plugin-signals-interventions
|
|
129
|
+
[docs]: https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-tracker/
|
|
130
|
+
[osi]: https://opensource.org/licenses/BSD-3-Clause
|
|
131
|
+
[license-image]: https://img.shields.io/npm/l/@snowplow/browser-plugin-signals-interventions
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { Payload, BrowserTracker, BrowserPlugin } from '@snowplow/browser-tracker-core';
|
|
2
|
+
import { DynamicContext } from '@snowplow/tracker-core';
|
|
3
|
+
|
|
4
|
+
declare const MEASUREMENT_EVENTS: {
|
|
5
|
+
readonly delivery: "iglu:com.snowplowanalytics.signals/intervention_receive/jsonschema/1-0-0";
|
|
6
|
+
readonly dispatch_accept: "iglu:com.snowplowanalytics.signals/intervention_handle/jsonschema/1-0-0";
|
|
7
|
+
readonly dispatch_error: "iglu:com.snowplowanalytics.signals/intervention_handle_error/jsonschema/1-0-0";
|
|
8
|
+
};
|
|
9
|
+
type MeasurementEvents = keyof typeof MEASUREMENT_EVENTS;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* An Intervention payload received from the Signals API.
|
|
13
|
+
*/
|
|
14
|
+
type Intervention = {
|
|
15
|
+
/**
|
|
16
|
+
* Unique identifier for this triggered Intervention instance. Interventions triggered against different Entities should be deduped by this ID.
|
|
17
|
+
*/
|
|
18
|
+
intervention_id: string;
|
|
19
|
+
/**
|
|
20
|
+
* The unique name/identifier for the Intervention (or its definition).
|
|
21
|
+
*/
|
|
22
|
+
name: string;
|
|
23
|
+
/**
|
|
24
|
+
* Version number for this intervention's definition if applicable.
|
|
25
|
+
*/
|
|
26
|
+
version: number;
|
|
27
|
+
/**
|
|
28
|
+
* The complete or requested set of attributes for the Entity this intervention was triggered against an their values when it was triggered.
|
|
29
|
+
*/
|
|
30
|
+
attributes: Record<string, OneOrMore<string | number | boolean>>;
|
|
31
|
+
/**
|
|
32
|
+
* Information about the Entity that triggered this intervention or is intended to receive it.
|
|
33
|
+
*/
|
|
34
|
+
target_entity?: {
|
|
35
|
+
/**
|
|
36
|
+
* The name/type of Entity that is the target/triggerer of this intervention.
|
|
37
|
+
*/
|
|
38
|
+
name: EntityName;
|
|
39
|
+
/**
|
|
40
|
+
* The specific identifier for the instance of type `entityName` that is the target/triggerer of this intervention.
|
|
41
|
+
*/
|
|
42
|
+
id?: EntityId;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Convenience utility, allowing a single scalar or array of multiple scalar values of type T.
|
|
47
|
+
*/
|
|
48
|
+
type OneOrMore<T> = T | T[];
|
|
49
|
+
/**
|
|
50
|
+
* A JSON Pointer is a slash-separated path of key segments for identifying a single JSON value within a complex JSON document. (see RFC 6901)
|
|
51
|
+
*/
|
|
52
|
+
type JSONPointer = '' | `/${string}`;
|
|
53
|
+
/**
|
|
54
|
+
* A single or array of JSON Pointers. The first to return a non-undefined result is the value used.
|
|
55
|
+
*/
|
|
56
|
+
type JSONPointerList = OneOrMore<JSONPointer>;
|
|
57
|
+
/**
|
|
58
|
+
* Handle for an entity type to request Interventions for. The name is paired with an EntityId as URL parameters in the request for Interventions.
|
|
59
|
+
*/
|
|
60
|
+
type EntityName = string;
|
|
61
|
+
/**
|
|
62
|
+
* An identifier for a specific Entity instance.
|
|
63
|
+
*/
|
|
64
|
+
type EntityId = string;
|
|
65
|
+
/**
|
|
66
|
+
* Unique name/identifier for an Intervention handler.
|
|
67
|
+
*/
|
|
68
|
+
type HandlerId = string;
|
|
69
|
+
/**
|
|
70
|
+
* Unique ID/namespace for a Snowplow tracker instance.
|
|
71
|
+
*/
|
|
72
|
+
type TrackerId = string;
|
|
73
|
+
/**
|
|
74
|
+
* Configuration the API to request interventions from.
|
|
75
|
+
*/
|
|
76
|
+
type SignalsInterventionConfiguration = {
|
|
77
|
+
/**
|
|
78
|
+
* The Signals API endpoint to request from. Should be a hostname, with optional scheme or path prefix.
|
|
79
|
+
*/
|
|
80
|
+
endpoint: string;
|
|
81
|
+
/**
|
|
82
|
+
* The API call path to append to `endpoint`, if required. Defaults to `/api/v1/interventions`.
|
|
83
|
+
*/
|
|
84
|
+
apiPath?: string;
|
|
85
|
+
/**
|
|
86
|
+
* A definition of entity types and JSON Pointers to extract the ID values from. These will be extracted from events as they are tracked to update the Intervention request as values are updated.
|
|
87
|
+
*/
|
|
88
|
+
entityTargets?: Record<EntityName, JSONPointerList>;
|
|
89
|
+
/**
|
|
90
|
+
* An explicit set of entity types and corresponding IDs to request interventions for.
|
|
91
|
+
*/
|
|
92
|
+
entityIds?: Record<EntityName, EntityId>;
|
|
93
|
+
/**
|
|
94
|
+
* Timeout duration to wait for the initial API to accept the Intervention request.
|
|
95
|
+
*/
|
|
96
|
+
connectionTimeoutMs?: number;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Configuration for the events generated by the plugin when interventions are received/handled.
|
|
100
|
+
* Each type of event can be enabled/disabled, or decided dynamically via a callback.
|
|
101
|
+
*/
|
|
102
|
+
type MeasurementSettings = Record<MeasurementEvents, boolean | ((_: Intervention) => boolean)>;
|
|
103
|
+
/**
|
|
104
|
+
* Initial plugin configuration for receiving Interventions.
|
|
105
|
+
* Controls initial handlers, measurement settings, and optionally a custom fetcher may be provided.
|
|
106
|
+
*/
|
|
107
|
+
type SignalsHandlerConfiguration = {
|
|
108
|
+
/**
|
|
109
|
+
* Custom function to build a `Fetcher` given a `BrowserTracker` instance and `dispatch` callback to deliver any received interventions to registered handlers.
|
|
110
|
+
* @private
|
|
111
|
+
*/
|
|
112
|
+
fetcher?: FetcherFactory;
|
|
113
|
+
/**
|
|
114
|
+
* Map of custom handlers to call with custom Interventions received. If not provided here, they can be added later via `addInterventionHandlers`.
|
|
115
|
+
*/
|
|
116
|
+
handlers?: Record<HandlerId, Handler>;
|
|
117
|
+
/**
|
|
118
|
+
* Settings for changing the events automatically tracked by this plugin when interventions are delivered, successfully processed by a handler, or unsuccessfully processed by a handler.
|
|
119
|
+
*/
|
|
120
|
+
measurement?: Partial<MeasurementSettings> & {
|
|
121
|
+
/**
|
|
122
|
+
* Custom entities to attach to the events generated by the plugin.
|
|
123
|
+
* Callbacks will receive a label for the type of event, the intervention itself, and the event payload.
|
|
124
|
+
*/
|
|
125
|
+
context?: DynamicContext;
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* A `FetcherFactory` function is called when the plugin is activated and should construct and return a `Fetcher` instance that calls the provided `dispatch` callback when Interventions are received.
|
|
130
|
+
* The plugin provides its own `DefaultFetcher` if not provided.
|
|
131
|
+
*/
|
|
132
|
+
interface FetcherFactory {
|
|
133
|
+
(tracker: BrowserTracker, dispatch: (intervention: Intervention, tracker: BrowserTracker) => void): Fetcher;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* A `Fetcher` is expected to react to calls to `configure()` and use the provided information to subscribe to Interventions.
|
|
137
|
+
* When interventions are received, a `Fetcher` is expected to call the `dispatch` callback that was provided to the `FetchFactory` that constructed the `Fetcher` and provide the `BrowserTracker` to measure events with.
|
|
138
|
+
* `update()` will be called when new Snowplow events are observed, or explicit entity IDs are provided. It should update the connection so Interventions may be received for new entities described in the event.
|
|
139
|
+
*/
|
|
140
|
+
interface Fetcher {
|
|
141
|
+
/**
|
|
142
|
+
* Accept a configuration for an interventions endpoint, and set up a connection to subscribe for Interventions on any configured entities.
|
|
143
|
+
* @param config Endpoint/entity configuration information.
|
|
144
|
+
*/
|
|
145
|
+
configure(config: SignalsInterventionConfiguration): void;
|
|
146
|
+
/**
|
|
147
|
+
* Called when a new Snowplow event has been observed or entity IDs provided. Entity IDs should be extracted and intervention subscription updated to accommodate new IDs if found.
|
|
148
|
+
* @param payload A Snowplow event payload observed.
|
|
149
|
+
* @param explicitEntities An explicit set of entity names/IDs to subscribe for.
|
|
150
|
+
*/
|
|
151
|
+
update(payload?: Payload, explicitEntities?: Record<EntityName, EntityId>): void;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* `Handler`s are delivered Intervention instanced as they are received.
|
|
155
|
+
* They receive the Intervention payload and the tracker instance if needed to pull other state if required.
|
|
156
|
+
* The function may `return` to be considered successfully handled, or `throw` to be considered a failure, which the plugin will track as an event.
|
|
157
|
+
* Async functions or functions that return Promises will be awaited and resolve/reject are treated as success/failure.
|
|
158
|
+
*/
|
|
159
|
+
type Handler = (intervention: Intervention, tracker: BrowserTracker) => Promise<unknown> | unknown;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Create an instance of the Signals Interventions plugin.
|
|
163
|
+
* @param configuration Configuration for the plugin
|
|
164
|
+
* @returns Configured plugin instance
|
|
165
|
+
*/
|
|
166
|
+
declare function SignalsInterventionsPlugin({ fetcher, measurement, handlers }?: SignalsHandlerConfiguration): BrowserPlugin;
|
|
167
|
+
/**
|
|
168
|
+
* Configure the endpoint information for the plugin's `Fetcher` to subscribe to events from
|
|
169
|
+
* @param config Configuration about the endpoint and entity IDs/definitions to configure
|
|
170
|
+
* @param trackers List of tracker IDs that have activated the plugin to configure a `Fetcher` for
|
|
171
|
+
*/
|
|
172
|
+
declare function subscribeToInterventions(config: SignalsInterventionConfiguration, trackers?: TrackerId[]): void;
|
|
173
|
+
/**
|
|
174
|
+
* Start calling the given handlers when new interventions are received
|
|
175
|
+
* @param handlers Map of handler IDs to handler functions to call with new interventions
|
|
176
|
+
* @param trackers List of tracker IDs that have activated the plugin to add these handlers to
|
|
177
|
+
*/
|
|
178
|
+
declare function addInterventionHandlers(handlers: Record<HandlerId, Handler>, trackers?: TrackerId[]): void;
|
|
179
|
+
/**
|
|
180
|
+
* Stop calling handlers with the given IDs with new interventions
|
|
181
|
+
* @param handlerIds One or more handler IDs to remove
|
|
182
|
+
* @param trackers List of trackers to remove the handlers for; defaults to all trackers that have activated the plugin.
|
|
183
|
+
*/
|
|
184
|
+
declare function removeInterventionHandlers(handlerIds: OneOrMore<HandlerId>, trackers?: TrackerId[]): void;
|
|
185
|
+
|
|
186
|
+
export { SignalsInterventionsPlugin, addInterventionHandlers, removeInterventionHandlers, subscribeToInterventions };
|
|
187
|
+
export type { EntityId, EntityName, Fetcher, FetcherFactory, Handler, HandlerId, Intervention, JSONPointer, JSONPointerList, MeasurementEvents, MeasurementSettings, OneOrMore, SignalsHandlerConfiguration, SignalsInterventionConfiguration, TrackerId };
|