@compilacion/colleciones-clientos 1.0.11 → 2.0.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/dist/index.cjs CHANGED
@@ -1,56 +1,27 @@
1
1
  'use strict';
2
2
 
3
3
  // helper 'private' functions
4
- const underscoreToCamelCase = function (str) {
5
- str = str.replace(/[^\x00-\x7F_]/g, '');
6
- return str
7
- .split('_')
8
- .map((word, index) => {
9
- if (index === 0) {
10
- return word;
11
- }
12
- return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
13
- })
14
- .join('');
15
- };
16
-
17
- const formatAdjectives = function (adjectiveParameter) {
18
- let errorMsg = new Error('Adjective must be a string, an array of strings, or undefined');
19
- if (typeof adjectiveParameter === 'undefined') {
20
- return undefined;
21
- }
22
- if (typeof adjectiveParameter === 'string') {
23
- return [underscoreToCamelCase(adjectiveParameter)];
24
- }
25
- if (Array.isArray(adjectiveParameter) && adjectiveParameter.every(item => typeof item === 'string')) {
26
- let returnValue = [];
27
- adjectiveParameter.forEach((adjectiveParameter) => {
28
- if (!typeof item === 'string') {
29
- throw errorMsg;
30
- }
31
- returnValue.push(underscoreToCamelCase(adjectiveParameter));
32
- });
33
- return returnValue;
34
- }
35
- throw errorMsg;
36
- };
37
4
 
38
- const stringifyAdjectives = function (adjective) {
39
- if (!Array.isArray(adjective) || adjective.length === 0) {
40
- return undefined;
41
- }
42
- const uniqueSorted = [...new Set(adjective)].sort();
43
- return '.' + uniqueSorted.join('.');
44
- };
45
5
 
6
+ /**
7
+ * Encodes a string to Base64.
8
+ * Uses browser or Node.js method depending on environment.
9
+ * @param {string} str
10
+ * @returns {string}
11
+ */
46
12
  const toBase64 = function (str) {
47
- if (typeof window !== 'undefined' && window.btoa) {
13
+ if (typeof window !== 'undefined' && typeof window.btoa === 'function') {
48
14
  return window.btoa(unescape(encodeURIComponent(str)));
49
15
  } else {
50
16
  return Buffer.from(str, 'utf-8').toString('base64');
51
17
  }
52
18
  };
53
19
 
20
+ /**
21
+ * Collects browser-related context values like screen size, language, etc.
22
+ * Returns an empty object if not in browser environment.
23
+ * @returns {Object}
24
+ */
54
25
  const getBrowserContext = function() {
55
26
  if (typeof window === 'undefined' || typeof navigator === 'undefined') {
56
27
  return {};
@@ -70,108 +41,275 @@ const getBrowserContext = function() {
70
41
  };
71
42
  };
72
43
 
73
- class CollecionesBaseEvent {
44
+ /**
45
+ * Base class representing a structured event with timestamp, identifiers, and data fields.
46
+ * This class is used to model events in a semantic and structured format for tracking purposes.
47
+ */
48
+ class CollecionesEvent {
74
49
 
50
+ /**
51
+ * Constructs a new event with default metadata and timestamps.
52
+ */
75
53
  constructor() {
76
- this.eventName = '';
77
- this.data = {};
78
- this.data.meta = {
79
- eventFormat: 'CollecionesBaseEvent',
54
+ // initialize event properties
55
+ this.entity = '';
56
+ this.adjevtives = [];
57
+ this.identifiers = {};
58
+ this.action = '';
59
+ this.actor = {
60
+ name:'',
61
+ identifiers: []
62
+ };
63
+ this.context = {};
64
+ this.references = {};
65
+ // set default values
66
+ this.meta = {
67
+ eventFormat: 'CollecionesEvent',
80
68
  eventFormatVersion: '1'
81
69
  };
82
- this.data.timestamps = {};
83
- this.data.timestamps.clientDatetimeUtc = new Date().toISOString();
70
+ this.meta.tracker = '';
71
+ this.meta.app = '';
72
+ this.meta.timestamps = {};
73
+ this.meta.timestamps.clientDatetimeUtc = new Date().toISOString();
84
74
  if (typeof window !== 'undefined' && typeof navigator !== 'undefined' && navigator.language) {
85
- this.data.timestamps.clientDatetimeLocal = new Date(Date.now() - new Date().getTimezoneOffset() * 60000).toISOString();
86
- this.data.timestamps.timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
87
- this.data.timestamps.timeZoneOffset = new Date().getTimezoneOffset();
75
+ this.meta.timestamps.clientDatetimeLocal = new Date(Date.now() - new Date().getTimezoneOffset() * 60000).toISOString();
76
+ this.meta.timestamps.timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
77
+ this.meta.timestamps.timeZoneOffset = new Date().getTimezoneOffset();
88
78
  } else {
89
- this.data.timestamps.clientDatetimeLocal = new Date().toISOString();
90
- this.data.timestamps.timeZone = 'UTC';
79
+ this.meta.timestamps.clientDatetimeLocal = new Date().toISOString();
80
+ this.meta.timestamps.timeZone = 'UTC';
91
81
  }
92
82
  }
93
83
 
94
- setEventName(name) {
95
- this.eventName = name;
84
+ /**
85
+ * Returns the declared event format.
86
+ * @returns {string} The format name (e.g. 'CollecionesEvent').
87
+ */
88
+ getEventFormat() {
89
+ let v = this.meta?.eventFormat;
90
+ return (typeof v !== 'undefined') ? v : '1';
96
91
  }
97
92
 
98
- getEventName() {
99
- return this.eventName;
93
+ /**
94
+ * Returns the version of the event format.
95
+ * @returns {string} The format version string.
96
+ */
97
+ getEventFormatVersion() {
98
+ let v = this?.meta?.eventFormatVersion;
99
+ return (typeof v !== 'undefined') ? v : 'CollecionesEvent';
100
100
  }
101
101
 
102
- getEventFormat() {
103
- let v = this.data?.meta?.eventFormat;
104
- return (typeof v !== 'undefined') ? v : '1';
102
+ /**
103
+ * Overrides or supplements the event's timestamp fields with custom values.
104
+ * @param {object} dateTimeObject - Key-value pairs to merge into the existing timestamp object.
105
+ */
106
+ overrideDatetime(dateTimeObject = {}) {
107
+ for (const [key, value] of Object.entries(dateTimeObject)) {
108
+ this.meta.timestamps[key] = value;
109
+ }
105
110
  }
106
111
 
107
- getEventFormatVersion() {
108
- let v = this.data?.meta?.eventFormatVersion;
109
- return (typeof v !== 'undefined') ? v : 'CollecionesBaseEvent';
112
+ /**
113
+ * Sets the name of the tracker responsible for generating this event.
114
+ * @param {string} name - Tracker name.
115
+ */
116
+ setTracker(name) {
117
+ this.meta.tracker = name;
110
118
  }
111
119
 
112
- setData(data) {
113
- this.data = data;
120
+ /**
121
+ * Sets the name of the application that generated the event.
122
+ * @param {string} name - Application name.
123
+ */
124
+ setAppName(name) {
125
+ this.meta.appName = name;
114
126
  }
115
127
 
116
- addAttribute(name, value) {
117
- return this.addField(name, value);
128
+ /**
129
+ * Sets the expected schema name for this event.
130
+ * @param {string} schema - The name of the schema.
131
+ */
132
+ setSchema(schema) {
133
+ if (typeof schema !== 'string') {
134
+ throw new Error('Schema must be a string');
135
+ }
136
+ this.meta.schema = schema;
118
137
  }
119
138
 
120
- addField(name, value) {
121
- if (typeof this.data.fields !== 'object' || this.data.fields === null) {
122
- this.data.fields = {};
139
+ /**
140
+ * Sets the entity (subject) of the event.
141
+ * @param {string} entity - The entity name.
142
+ */
143
+ setEntity = function(entity) {
144
+ this.entity = entity;
145
+ }
146
+
147
+ /**
148
+ * Defines the main action of the event (e.g., 'clicked').
149
+ * @param {string} action - The action string.
150
+ */
151
+ setAction = function(action) {
152
+ this.action = action;
153
+ }
154
+
155
+ /**
156
+ * Adds an adjective that describes the entity in more detail.
157
+ * @param {string} adjective - An adjective string.
158
+ */
159
+ addAdjective = function(adjective) {
160
+ if (typeof adjective !== 'string') {
161
+ throw new Error('Adjective must be a string');
123
162
  }
124
- this.data.fields[name] = value;
163
+ this.adjevtives.push(adjective);
125
164
  }
126
165
 
127
- setTracker(name) {
128
- this.data.tracker = name;
166
+ /**
167
+ * Adds or updates an identifier for the primary entity.
168
+ * @param {string} name - The identifier key.
169
+ * @param {*} identifier - The identifier value.
170
+ */
171
+ setIdentifier = function(name, identifier) {
172
+ if (typeof name !== 'string') {
173
+ throw new Error('Identifier name must be a string');
174
+ }
175
+ this.identifiers[name] = identifier;
129
176
  }
130
177
 
131
- setAppName(name) {
132
- this.data.appName = name;
178
+ /**
179
+ * Defines the name of the actor (who or what performed the action).
180
+ * @param {string} name - Actor name (e.g., 'user').
181
+ */
182
+ setActor = function(name) {
183
+ if (typeof name !== 'string') {
184
+ throw new Error('Actor name must be a string');
185
+ }
186
+ this.actor.name = name;
133
187
  }
134
188
 
135
- convertParamIdentifiers(param) {
136
- if (typeof param === 'object' && param !== null && !Array.isArray(param)) {
137
- for (const [key, value] of Object.entries(param)) {
138
- this.addIdentifier(key, value);
139
- }
189
+ /**
190
+ * Adds or updates an identifier for the actor.
191
+ * @param {string} name - Identifier name.
192
+ * @param {*} identifier - Identifier value.
193
+ */
194
+ setActorIdentifier = function(name, identifier) {
195
+ if (typeof name !== 'string') {
196
+ throw new Error('Actor Identifier name must be a string');
140
197
  }
198
+ this.actor.identifiers[name] = identifier;
141
199
  }
142
200
 
143
- addIdentifier(name, value) {
144
- if (typeof this.data.identifiers !== 'object' || this.data.identifiers === null) {
145
- this.data.identifiers = {};
201
+ /**
202
+ * Adds contextual information to the event.
203
+ * @param {string} context - The key of the context field.
204
+ * @param {*} value - The value of the context field.
205
+ */
206
+ setContext = function(context, value) {
207
+ if (typeof context !== 'string') {
208
+ throw new Error('Context must be a string');
146
209
  }
147
- this.data.identifiers[name] = value;
210
+ this.context[context] = value;
148
211
  }
149
212
 
150
- getPostObject() {
151
- this.data.timestamps.sendDatetimeUtc = new Date().toISOString();
152
- this.data.timestamps.sendDatetimeLocal = new Date(Date.now() - new Date().getTimezoneOffset() * 60000).toISOString();
153
- return {
154
- eventname: this.getEventName(),
155
- eventFormat: this.getEventFormat(),
156
- eventFormatVersion: this.getEventFormatVersion(),
157
- payload: toBase64(this.getPayload())
158
- };
213
+ /**
214
+ * Declares an entity referenced by this event.
215
+ * @param {string} entity - The referenced entity name.
216
+ */
217
+ setRefence = function(entity) {
218
+ if (typeof entity !== 'string') {
219
+ throw new Error('Referenced entity must be a string');
220
+ }
221
+ if(this.references[entity] === undefined) {
222
+ this.references[entity] = {identifiers: {}};
223
+ }
159
224
  }
160
225
 
161
- overrideDatetime(dateTimeObject = {}) {
162
- for (const [key, value] of Object.entries(dateTimeObject)) {
163
- this.data.timestamps[key] = value;
226
+ /**
227
+ * Adds or updates an identifier for a referenced entity.
228
+ * @param {string} entity - The referenced entity name.
229
+ * @param {string} name - The identifier key.
230
+ * @param {*} identifier - The identifier value.
231
+ */
232
+ setRefenceIdentifier = function(entity, name, identifier) {
233
+ if (typeof entity !== 'string') {
234
+ throw new Error('Referenced entity name must be a string');
164
235
  }
236
+ if (typeof name !== 'string') {
237
+ throw new Error('Actor Identifier name must be a string');
238
+ }
239
+ this.setRefence(entity);
240
+ this.references[entity].identifiers[name] = identifier;
165
241
  }
166
242
 
167
- getPayload() {
168
- return JSON.stringify(this.data);
243
+ /**
244
+ * Serializes the event to a plain object suitable for JSON.stringify().
245
+ * @returns {object}
246
+ */
247
+ toJSON() {
248
+ return {
249
+ class: 'CollecionesEvent',
250
+ entity: this.entity,
251
+ adjectives: this.adjevtives,
252
+ identifiers: this.identifiers,
253
+ action: this.action,
254
+ actor: this.actor,
255
+ context: this.context,
256
+ references: this.references,
257
+ meta: this.meta
258
+ };
169
259
  }
170
260
 
261
+ /**
262
+ * Recreates an instance of CollecionesEvent from a plain object.
263
+ * @param {object} obj
264
+ * @returns {CollecionesEvent}
265
+ */
266
+ static fromJSON(obj) {
267
+ if (!obj || obj.class !== 'CollecionesEvent') {
268
+ throw new Error('Invalid or missing event class type');
269
+ }
270
+ const instance = new CollecionesEvent();
271
+ instance.entity = obj.entity;
272
+ instance.adjevtives = obj.adjectives || [];
273
+ instance.identifiers = obj.identifiers || {};
274
+ instance.action = obj.action;
275
+ instance.actor = obj.actor || { name: '', identifiers: {} };
276
+ instance.context = obj.context || {};
277
+ instance.references = obj.references || {};
278
+ instance.meta = obj.meta || {};
279
+ return instance;
280
+ }
281
+
171
282
  }
172
283
 
284
+ /**
285
+ * CollecionesEmitter
286
+ * -------------------
287
+ * This class collects and sends event objects to a remote endpoint (e.g., an event collector API).
288
+ * It is used in both client- and server-side tracking scenarios, typically in combination with
289
+ * CollecionesEvent or subclasses like CollecionesBaseEvent.
290
+ *
291
+ * Behavior:
292
+ * - Events are buffered via `.track()` or `.trackAsync()`.
293
+ * - If the number of buffered events reaches `flushSize`, the buffer is automatically flushed.
294
+ * - If `flushInterval` is provided, the buffer is flushed at a fixed interval.
295
+ * - Flushing serializes each event using `.toJSON()`, encodes it with base64, and posts
296
+ * the resulting array to the configured endpoint.
297
+ *
298
+ * Example usage:
299
+ * const emitter = new CollecionesEmitter('/track', 5, 10000);
300
+ * emitter.track(new CollecionesEvent());
301
+ *
302
+ * Note:
303
+ * This class is stateful. To stop periodic flushing, call `.stopTimer()` when the emitter is no longer in use.
304
+ */
173
305
  class CollecionesEmitter {
174
306
 
307
+ /**
308
+ * Initializes the emitter with buffering settings.
309
+ * @param {string} [endpoint='/collect'] - The URL to send events to.
310
+ * @param {number} [flushSize=10] - Number of events to buffer before flushing.
311
+ * @param {number|boolean} [flushInterval=false] - Time in ms to flush events periodically.
312
+ */
175
313
  constructor(endpoint = '/collect', flushSize = 10, flushInterval = false) {
176
314
  this.endpoint = endpoint;
177
315
  this.flushInterval = flushInterval;
@@ -180,6 +318,10 @@ class CollecionesEmitter {
180
318
  this.timer = null;
181
319
  }
182
320
 
321
+ /**
322
+ * Starts the flush timer if a valid interval is set.
323
+ * @returns {void}
324
+ */
183
325
  startTimer() {
184
326
  this.stopTimer();
185
327
  if (typeof this.flushInterval == 'number' && this.flushInterval > 0) {
@@ -187,12 +329,20 @@ class CollecionesEmitter {
187
329
  }
188
330
  }
189
331
 
332
+ /**
333
+ * Starts the flush timer only if not already running.
334
+ * @returns {void}
335
+ */
190
336
  startTimerIfStopped() {
191
337
  if (!this.timer) {
192
338
  this.startTimer();
193
339
  }
194
340
  }
195
341
 
342
+ /**
343
+ * Stops the active flush timer.
344
+ * @returns {void}
345
+ */
196
346
  stopTimer() {
197
347
  if (this.timer) {
198
348
  clearInterval(this.timer);
@@ -200,29 +350,50 @@ class CollecionesEmitter {
200
350
  this.timer = null;
201
351
  }
202
352
 
353
+ /**
354
+ * Adds an event to the buffer and flushes if threshold is reached.
355
+ * Validates that the event is an instance of CollecionesEvent to ensure correct event type.
356
+ * @param {CollecionesEvent} event - Event instance to be tracked.
357
+ * @throws {Error} Throws if event is not a CollecionesEvent instance.
358
+ * @returns {void}
359
+ */
203
360
  track(event) {
204
- if (!(event instanceof CollecionesBaseEvent)) {
205
- throw new Error('Event must be an instance of CollecionesBaseEvent');
361
+ if (!(event instanceof CollecionesEvent)) {
362
+ throw new Error('Event must be an instance of CollecionesEvent');
206
363
  }
207
364
  this.trackAsync(event);
208
365
  }
209
366
 
367
+ /**
368
+ * Asynchronously adds an event and flushes if the buffer size is exceeded.
369
+ * Validates that the event is an instance of CollecionesEvent to ensure correct event type.
370
+ * @param {CollecionesEvent} event - Event instance to be tracked asynchronously.
371
+ * @throws {Error} Throws if event is not a CollecionesEvent instance.
372
+ * @returns {Promise<void>} Resolves when event is added and flush triggered if needed.
373
+ */
210
374
  async trackAsync(event) {
211
- if (!(event instanceof CollecionesBaseEvent)) {
212
- throw new Error('Event must be an instance of CollecionesBaseEvent');
375
+ if (!(event instanceof CollecionesEvent)) {
376
+ throw new Error('Event must be an instance of CollecionesEvent');
213
377
  }
214
378
  this.startTimerIfStopped();
215
379
  this.buffer.push(event);
216
380
  return (this.buffer.length >= this.flushSize) ? this.flush() : Promise.resolve();
217
381
  }
218
382
 
383
+ /**
384
+ * Sends all buffered events in a single POST request to the server.
385
+ * Each event is serialized via `.toJSON()` and encoded as a base64 string.
386
+ * Response status is checked for HTTP success; errors are logged but not thrown.
387
+ *
388
+ * @returns {Promise<boolean|undefined>} Resolves true if flush was triggered, or undefined if buffer was empty.
389
+ */
219
390
  async flush() {
220
391
  if (this.buffer.length === 0) return;
221
392
  const eventsToSend = [...this.buffer];
222
393
  this.buffer = [];
223
394
  let postPayload = [];
224
395
  eventsToSend.forEach((e) => {
225
- postPayload.push( e.getPostObject() );
396
+ postPayload.push( toBase64( JSON.stringify(e.toJSON())) );
226
397
  });
227
398
  this.stopTimer();
228
399
  try {
@@ -244,8 +415,17 @@ class CollecionesEmitter {
244
415
  }
245
416
  }
246
417
 
418
+ /**
419
+ * Tracks events by enriching them with shared identifiers and routing through configured emitters.
420
+ */
247
421
  class CollecionesTracker {
248
-
422
+
423
+ /**
424
+ * Constructs a new tracker instance.
425
+ * @param {Array} emitters - Array of emitter instances responsible for sending events.
426
+ * @param {string} trackerName - Name identifying this tracker.
427
+ * @param {string} appName - Name of the application generating events.
428
+ */
249
429
  constructor(emitters, trackerName, appName) {
250
430
  this.emitters = emitters;
251
431
  this.trackerName = trackerName;
@@ -253,12 +433,13 @@ class CollecionesTracker {
253
433
  this.identifiers = {};
254
434
  }
255
435
 
256
- addIdentifier(name, value) {
257
- this.identifiers[name] = value;
258
- }
259
-
436
+ /**
437
+ * Sends an event to all emitters after enriching it with identifiers and metadata.
438
+ * @param {CollecionesEvent} collecionesEvent - The event to be sent.
439
+ * @throws {Error} If the input is not an instance of CollecionesEvent.
440
+ */
260
441
  track(collecionesEvent) {
261
- if (!(collecionesEvent instanceof CollecionesBaseEvent)) {
442
+ if (!(collecionesEvent instanceof CollecionesEvent)) {
262
443
  throw new Error('Event must be of type CollecionesEvent');
263
444
  }
264
445
  for (const [key, value] of Object.entries(this.identifiers)) {
@@ -269,172 +450,273 @@ class CollecionesTracker {
269
450
  this.emitters.forEach(element => {
270
451
  element.track(collecionesEvent, this.trackerName, this.appName);
271
452
  });
272
-
273
453
  }
274
454
  }
275
455
 
456
+ /**
457
+ * Web-specific tracker that enriches events with browser context before sending them.
458
+ * Extends the base CollecionesTracker.
459
+ */
276
460
  class CollecionesWebTracker extends CollecionesTracker {
277
-
461
+ /**
462
+ * Creates a new instance of CollecionesWebTracker.
463
+ * @param {Array} emitters - A list of emitter instances used to send the event.
464
+ * @param {string} trackerName - The name of the tracker.
465
+ * @param {string} appName - The name of the application generating events.
466
+ */
278
467
  constructor(emitters, trackerName, appName) {
279
468
  super(emitters, trackerName, appName);
280
469
  }
281
470
 
471
+ /**
472
+ * Tracks an event, enriching it with browser context information.
473
+ * @param {CollecionesEvent} collecionesEvent - The event object to track.
474
+ * @throws {Error} If the event is not an instance of CollecionesEvent.
475
+ */
282
476
  track(collecionesEvent) {
283
- if (!(collecionesEvent instanceof CollecionesBaseEvent)) {
477
+ if (!(collecionesEvent instanceof CollecionesEvent)) {
284
478
  throw new Error('Event must be of type CollecionesEvent');
285
479
  }
286
- collecionesEvent.addField('browserContext', getBrowserContext());
480
+ collecionesEvent.setContext('browserContext', getBrowserContext());
287
481
  super.track(collecionesEvent);
288
482
  }
289
483
  }
290
484
 
291
- class CollecionesEvent extends CollecionesBaseEvent {
292
-
293
- constructor(name, data, identifiers) {
294
- super();
295
- this.setEventName(name);
296
- Object.assign(this.data, data);
297
- this.convertParamIdentifiers(identifiers);
298
- }
485
+ /**
486
+ * Colleciones DSL
487
+ * ---------------
488
+ * This module provides a fluent, human-readable DSL (domain-specific language) for constructing
489
+ * structured tracking events based on CollecionesBaseEvent. Each step in the chain represents
490
+ * a semantically meaningful piece of the event: the entity, the action, the actor, references, etc.
491
+ *
492
+ * Entry Point:
493
+ * collecionesDsl.the('dark')
494
+ *
495
+ * Chaining:
496
+ * - .and('...') : add additional adjectives
497
+ * - ._('entity') : specify the entity being acted on
498
+ * - .identified.by('field') : declare primary identifier for the subject
499
+ * - .has.been('action') : declare what happened
500
+ * - .by('actor') : describe the actor performing the action
501
+ * - .identified.by('id') : add identifiers for the actor
502
+ * - .with('key').set.to('val') : add contextual data fields
503
+ * - .referring.to('entity') : describe referenced/related entities
504
+ * - .identified.by('refId') : add identifiers for the reference
505
+ * - .conform.to('SchemaName') : attach schema metadata
506
+ * - .then.track.with(emitter) : finalize and emit the event
507
+ *
508
+ * Each function in the chain passes forward a scoped version of the CollecionesBaseEvent instance,
509
+ * and enforces semantic constraints (e.g. `.as()` is required after `.by()`).
510
+ *
511
+ * Internal:
512
+ * - Uses setRefence / setRefenceIdentifier for references
513
+ * - Uses helpers.getEvent() for test access
514
+ * - Uses instanceof CollecionesEmitter for validation
515
+ *
516
+ * This file is designed for internal use by developers building with the Colleciones tracking model.
517
+ */
518
+
519
+
520
+ let init = (entity) => {
521
+ return ((entity)=>{
522
+ let eventInstance = new CollecionesEvent(); // Core event object
523
+ eventInstance.setEntity(entity);
524
+
525
+ let helpers = {
526
+ getEvent: () => {
527
+ return eventInstance;
528
+ },
529
+ };
299
530
 
300
- }
531
+ // DSL function groups
532
+ let andEntity = () => {}; // .and(...) chaining after the()
533
+ let setEntityAfterAnd = () => {}; // ._('entity') after .and
534
+ let setEntityIdentifiers = () => {}; // .identified.by(...) for main subject
535
+ let setAction = () => {}; // .has.been(...) for action
536
+ let setActor = () => {}; // .by('actor')
537
+ let setActorIdentifier = () => {}; // .identified.by(...) inside .by(...)
538
+ let addContext = () => {}; // .with(...).set.to(...)
539
+ let addReference = () => {}; // .referring.to(...)
540
+ let getAddReference = () => {}; // .identified.by().as() inside .referring
541
+ let addReferenceIdentifier = () => {}; // .and(...) after reference
542
+ let conformingTo = () => {}; // .conform.to('SchemaName')
543
+ let track = () => {}; // .then.track.with(emitter)
544
+
545
+ // Adjective chaining: .and(...)._('entity')
546
+ setEntityAfterAnd = (entity) => {
547
+ eventInstance.addAdjective(eventInstance.entity);
548
+ eventInstance.setEntity(entity);
549
+ return {
550
+ as: () => {
551
+ return { helpers }
552
+ },
553
+ identified: {
554
+ by: setEntityIdentifiers
555
+ },
556
+ has: { been: setAction },
557
+ helpers
558
+ };
559
+ };
301
560
 
302
- const byteToHex = [];
303
- for (let i = 0; i < 256; ++i) {
304
- byteToHex.push((i + 0x100).toString(16).slice(1));
305
- }
306
- function unsafeStringify(arr, offset = 0) {
307
- return (byteToHex[arr[offset + 0]] +
308
- byteToHex[arr[offset + 1]] +
309
- byteToHex[arr[offset + 2]] +
310
- byteToHex[arr[offset + 3]] +
311
- '-' +
312
- byteToHex[arr[offset + 4]] +
313
- byteToHex[arr[offset + 5]] +
314
- '-' +
315
- byteToHex[arr[offset + 6]] +
316
- byteToHex[arr[offset + 7]] +
317
- '-' +
318
- byteToHex[arr[offset + 8]] +
319
- byteToHex[arr[offset + 9]] +
320
- '-' +
321
- byteToHex[arr[offset + 10]] +
322
- byteToHex[arr[offset + 11]] +
323
- byteToHex[arr[offset + 12]] +
324
- byteToHex[arr[offset + 13]] +
325
- byteToHex[arr[offset + 14]] +
326
- byteToHex[arr[offset + 15]]).toLowerCase();
327
- }
561
+ // Identifier setup: .identified.by().as()
562
+ setEntityIdentifiers = (name) => {
563
+ eventInstance.setIdentifier(name, null);
564
+ return {
565
+ as: (value) => {
566
+ eventInstance.setIdentifier(name, value);
567
+ return {
568
+ helpers,
569
+ and: {
570
+ by: setEntityIdentifiers
571
+ },
572
+ has: { been: setAction },
573
+ }
574
+ },
575
+ helpers
576
+ };
577
+ };
328
578
 
329
- let getRandomValues;
330
- const rnds8 = new Uint8Array(16);
331
- function rng() {
332
- if (!getRandomValues) {
333
- if (typeof crypto === 'undefined' || !crypto.getRandomValues) {
334
- throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
335
- }
336
- getRandomValues = crypto.getRandomValues.bind(crypto);
337
- }
338
- return getRandomValues(rnds8);
339
- }
579
+ // Additional adjectives: .and('...')._()
580
+ andEntity = (entity) => {
581
+ eventInstance.addAdjective(eventInstance.entity);
582
+ eventInstance.setEntity(entity);
583
+ return {
584
+ and: andEntity,
585
+ _ : setEntityAfterAnd,
586
+ helpers
587
+ }
588
+ };
340
589
 
341
- const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);
342
- var native = { randomUUID };
590
+ // Action: .has.been('...')
591
+ setAction = (action) => {
592
+ eventInstance.setAction(action);
593
+ return {
594
+ by: setActor,
595
+ referring: { to: addReference },
596
+ with: addContext,
597
+ conform: {to: conformingTo},
598
+ then: {track: {with: track}},
599
+ helpers
600
+ }
601
+ };
343
602
 
344
- function v4(options, buf, offset) {
345
- if (native.randomUUID && true && !options) {
346
- return native.randomUUID();
347
- }
348
- options = options || {};
349
- const rnds = options.random ?? options.rng?.() ?? rng();
350
- if (rnds.length < 16) {
351
- throw new Error('Random bytes length must be >= 16');
352
- }
353
- rnds[6] = (rnds[6] & 0x0f) | 0x40;
354
- rnds[8] = (rnds[8] & 0x3f) | 0x80;
355
- return unsafeStringify(rnds);
356
- }
603
+ // Actor: .by('user')
604
+ setActor = (name) => {
605
+ eventInstance.setActor(name);
606
+ return {
607
+ identified: {
608
+ by: setActorIdentifier
609
+ },
610
+ with: addContext,
611
+ helpers
612
+ }
613
+ };
357
614
 
358
- class CollecionesSemanticEvent extends CollecionesBaseEvent {
359
-
360
- constructor(entity, action, adjective, identifiers) {
361
- super();
362
- this.entity = underscoreToCamelCase(entity);
363
- this.action = underscoreToCamelCase(action);
364
- this.adjective = formatAdjectives(adjective);
365
- let adjectiveString = stringifyAdjectives(this.adjective);
366
- this.eventName = `${this.entity}${(adjectiveString !== undefined) ? adjectiveString : ''}__${this.action}`;
367
- this.convertParamIdentifiers(identifiers);
368
- this.data.entityIdentifiers = {};
369
- this.data.attributes = {};
370
- this.data.clientEventId = v4();
371
- this.data.meta = {
372
- eventFormat: 'CollecionesSemanticEvent',
373
- eventFormatVersion: '1'
615
+ // Actor identifier: .identified.by().as()
616
+ setActorIdentifier = (name) => {
617
+ return {
618
+ as: (value) => {
619
+ eventInstance.setActorIdentifier(name, value);
620
+ return {
621
+ helpers,
622
+ and: setActorIdentifier,
623
+ with: addContext,
624
+ referring: { to: addReference },
625
+ }
626
+ },
627
+ helpers
628
+ }
374
629
  };
375
- }
376
630
 
377
- setData() {
378
- throw new Error('setData deprecated in semantic events');
379
- }
631
+ // Contextual field: .with('key').set.to('value')
632
+ addContext = (context) => {
633
+ return {
634
+ helpers,
635
+ set: {
636
+ to: (value) => {
637
+ eventInstance.setContext(context, value);
638
+ return {
639
+ helpers,
640
+ and: addContext,
641
+ referring: { to: addReference },
642
+ }
643
+ }
644
+ }
645
+ }
646
+ };
380
647
 
381
- addEntityIdentifier(key, value) {
382
- if (typeof key !== 'string') {
383
- throw new Error('Entity identifier key must be a string');
384
- }
385
- if (typeof value !== 'string' && typeof value !== 'number') {
386
- throw new Error('Entity identifier value must be a string or number');
387
- }
388
- this.data.entityIdentifiers[key] = value;
389
- }
648
+ // Reference: .referring.to('...')
649
+ addReference = (entity) => {
650
+ eventInstance.setRefence(entity);
651
+ return {
652
+ identified: {
653
+ by: getAddReference(entity)
654
+ },
655
+ conform: {to: conformingTo},
656
+ then: {track: {with: track}},
657
+ helpers
658
+ }
659
+ };
390
660
 
391
- }
661
+ // Reference identifier setup: .identified.by().as()
662
+ getAddReference = (entity) => {
663
+ return (name) => {
664
+ return {
665
+ as: (value) => {
666
+ eventInstance.setRefenceIdentifier(entity, name, value);
667
+ return {
668
+ helpers,
669
+ and: addReferenceIdentifier,
670
+ conform: {to: conformingTo},
671
+ then: {track: {with: track}},
672
+ }
673
+ },
674
+ helpers,
675
+ };
676
+ };
677
+ };
392
678
 
393
- class CollecionesSemanticCollectionEvent extends CollecionesSemanticEvent {
679
+ // Schema declaration: .conform.to('...')
680
+ conformingTo = (name) => {
681
+ eventInstance.setSchema(name);
682
+ return {
683
+ then: {track: {with: track}},
684
+ helpers
685
+ }
686
+ };
394
687
 
395
- constructor(itemEntity, action, adjective, identifiers, collectionEntity) {
396
- if(typeof collectionEntity == 'undefined') {
397
- collectionEntity = `${itemEntity}Collection`;
398
- }
399
- super(collectionEntity, action, undefined, identifiers);
400
- this.data.meta = {
401
- eventFormat: 'CollecionesSemanticCollectionEvent',
402
- eventFormatVersion: '1'
688
+ // Final dispatch: .then.track.with(emitter)
689
+ track = (emitter) => {
690
+ if(emitter instanceof CollecionesEmitter){
691
+ emitter.track(eventInstance);
692
+ }
693
+ return {
694
+ and: track,
695
+ helpers,
696
+ }
403
697
  };
404
- this.adjective = formatAdjectives(adjective);
405
- let adjectiveString = stringifyAdjectives(this.adjective);
406
- itemEntity = underscoreToCamelCase(itemEntity);
407
- this.data.itemEntity = itemEntity;
408
- this.data.itemEventName = `${itemEntity}${(adjectiveString !== undefined) ? adjectiveString : ''}__${this.action}`;
409
- this.data.entityItemIdentifiers = {};
410
- }
411
698
 
412
- addEntityItemIdentifier(key, value) {
413
- if (typeof key !== 'string') {
414
- throw new Error('Entity identifier key must be a string');
415
- }
416
- if (typeof value !== 'string' && typeof value !== 'number' && !Array.isArray(value)) {
417
- throw new Error('Entity identifier value must be a string or number');
418
- }
419
- if(typeof this.data.entityItemIdentifiers[key] == 'undefined') {
420
- this.data.entityItemIdentifiers[key] = [];
421
- }
422
- if(Array.isArray(value)) {
423
- value.forEach((v)=> {
424
- this.data.entityItemIdentifiers[key].push(v);
425
- });
426
- } else {
427
- this.data.entityItemIdentifiers[key].push(value);
699
+ return {
700
+ and: andEntity,
701
+ _: setEntityAfterAnd,
702
+ identified: {
703
+ by: setEntityIdentifiers
704
+ },
705
+ has: { been: setAction},
706
+ node: '_base',
707
+ helpers
428
708
  }
429
- }
430
709
 
431
-
432
- }
710
+ })(entity);
711
+ };
712
+
713
+ let collecionesDsl = {
714
+ the: init
715
+ };
433
716
 
434
717
  exports.CollecionesEmitter = CollecionesEmitter;
435
718
  exports.CollecionesEvent = CollecionesEvent;
436
- exports.CollecionesSemanticCollectionEvent = CollecionesSemanticCollectionEvent;
437
- exports.CollecionesSemanticEvent = CollecionesSemanticEvent;
438
719
  exports.CollecionesTracker = CollecionesTracker;
439
720
  exports.CollecionesWebTracker = CollecionesWebTracker;
721
+ exports.collecionesDsl = collecionesDsl;
440
722
  //# sourceMappingURL=index.cjs.map