@compilacion/colleciones-clientos 1.0.12 → 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,58 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  // helper 'private' functions
4
- /**
5
- * Converts a snake_case string to camelCase.
6
- * Removes non-ASCII characters.
7
- * @param {string} str
8
- * @returns {string}
9
- */
10
- const underscoreToCamelCase = function (str) {
11
- str = str.replace(/[^\x00-\x7F_]/g, '');
12
- return str
13
- .split('_')
14
- .map((word, index) => {
15
- if (index === 0) {
16
- return word;
17
- }
18
- return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
19
- })
20
- .join('');
21
- };
22
4
 
23
- /**
24
- * Formats adjectives by converting them to camelCase strings.
25
- * Accepts a single string or an array of strings.
26
- * @param {string|string[]|undefined} adjectiveParameter
27
- * @returns {string[]|undefined}
28
- */
29
- const formatAdjectives = function (adjectiveParameter) {
30
- const errorMsg = new Error('Adjective must be a string, an array of strings, or undefined');
31
- if (typeof adjectiveParameter === 'undefined') {
32
- return undefined;
33
- }
34
- if (typeof adjectiveParameter === 'string') {
35
- return [underscoreToCamelCase(adjectiveParameter)];
36
- }
37
- if (Array.isArray(adjectiveParameter) && adjectiveParameter.every(item => typeof item === 'string')) {
38
- return adjectiveParameter.map(adjective => underscoreToCamelCase(adjective));
39
- }
40
- throw errorMsg;
41
- };
42
-
43
- /**
44
- * Converts an array of adjective strings to a dot-prefixed, dot-separated string.
45
- * Removes duplicates and sorts alphabetically.
46
- * @param {string[]} adjective
47
- * @returns {string|undefined}
48
- */
49
- const stringifyAdjectives = function (adjective) {
50
- if (!Array.isArray(adjective) || adjective.length === 0) {
51
- return undefined;
52
- }
53
- const uniqueSorted = [...new Set(adjective)].sort();
54
- return '.' + uniqueSorted.join('.');
55
- };
56
5
 
57
6
  /**
58
7
  * Encodes a string to Base64.
@@ -94,171 +43,264 @@ const getBrowserContext = function() {
94
43
 
95
44
  /**
96
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.
97
47
  */
98
- class CollecionesBaseEvent {
48
+ class CollecionesEvent {
99
49
 
100
50
  /**
101
51
  * Constructs a new event with default metadata and timestamps.
102
52
  */
103
53
  constructor() {
104
- this.eventName = '';
105
- this.data = {};
106
- this.data.meta = {
107
- 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',
108
68
  eventFormatVersion: '1'
109
69
  };
110
- this.data.timestamps = {};
111
- 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();
112
74
  if (typeof window !== 'undefined' && typeof navigator !== 'undefined' && navigator.language) {
113
- this.data.timestamps.clientDatetimeLocal = new Date(Date.now() - new Date().getTimezoneOffset() * 60000).toISOString();
114
- this.data.timestamps.timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
115
- 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();
116
78
  } else {
117
- this.data.timestamps.clientDatetimeLocal = new Date().toISOString();
118
- this.data.timestamps.timeZone = 'UTC';
79
+ this.meta.timestamps.clientDatetimeLocal = new Date().toISOString();
80
+ this.meta.timestamps.timeZone = 'UTC';
119
81
  }
120
82
  }
121
83
 
122
84
  /**
123
- * Sets the event name.
124
- * @param {string} name
85
+ * Returns the declared event format.
86
+ * @returns {string} The format name (e.g. 'CollecionesEvent').
125
87
  */
126
- setEventName(name) {
127
- this.eventName = name;
88
+ getEventFormat() {
89
+ let v = this.meta?.eventFormat;
90
+ return (typeof v !== 'undefined') ? v : '1';
128
91
  }
129
92
 
130
93
  /**
131
- * Returns the event name.
132
- * @returns {string}
94
+ * Returns the version of the event format.
95
+ * @returns {string} The format version string.
133
96
  */
134
- getEventName() {
135
- return this.eventName;
97
+ getEventFormatVersion() {
98
+ let v = this?.meta?.eventFormatVersion;
99
+ return (typeof v !== 'undefined') ? v : 'CollecionesEvent';
136
100
  }
137
101
 
138
102
  /**
139
- * Gets the format of the event.
140
- * @returns {string}
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.
141
105
  */
142
- getEventFormat() {
143
- let v = this.data?.meta?.eventFormat;
144
- return (typeof v !== 'undefined') ? v : '1';
106
+ overrideDatetime(dateTimeObject = {}) {
107
+ for (const [key, value] of Object.entries(dateTimeObject)) {
108
+ this.meta.timestamps[key] = value;
109
+ }
145
110
  }
146
111
 
147
112
  /**
148
- * Gets the version of the event format.
149
- * @returns {string}
113
+ * Sets the name of the tracker responsible for generating this event.
114
+ * @param {string} name - Tracker name.
150
115
  */
151
- getEventFormatVersion() {
152
- let v = this.data?.meta?.eventFormatVersion;
153
- return (typeof v !== 'undefined') ? v : 'CollecionesBaseEvent';
116
+ setTracker(name) {
117
+ this.meta.tracker = name;
154
118
  }
155
119
 
156
120
  /**
157
- * Replaces the entire data object.
158
- * @param {object} data
121
+ * Sets the name of the application that generated the event.
122
+ * @param {string} name - Application name.
159
123
  */
160
- setData(data) {
161
- this.data = data;
124
+ setAppName(name) {
125
+ this.meta.appName = name;
162
126
  }
163
127
 
164
128
  /**
165
- * Adds a field to the event's custom fields section.
166
- * @param {string} name
167
- * @param {*} value
129
+ * Sets the expected schema name for this event.
130
+ * @param {string} schema - The name of the schema.
168
131
  */
169
- addAttribute(name, value) {
170
- return this.addField(name, value);
132
+ setSchema(schema) {
133
+ if (typeof schema !== 'string') {
134
+ throw new Error('Schema must be a string');
135
+ }
136
+ this.meta.schema = schema;
171
137
  }
172
138
 
173
139
  /**
174
- * Adds a key-value pair to the custom fields.
175
- * @param {string} name
176
- * @param {*} value
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.
177
150
  */
178
- addField(name, value) {
179
- if (typeof this.data.fields !== 'object' || this.data.fields === null) {
180
- this.data.fields = {};
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');
181
162
  }
182
- this.data.fields[name] = value;
163
+ this.adjevtives.push(adjective);
183
164
  }
184
165
 
185
166
  /**
186
- * Sets the name of the tracker used to generate the event.
187
- * @param {string} name
167
+ * Adds or updates an identifier for the primary entity.
168
+ * @param {string} name - The identifier key.
169
+ * @param {*} identifier - The identifier value.
188
170
  */
189
- setTracker(name) {
190
- this.data.tracker = name;
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;
191
176
  }
192
177
 
193
178
  /**
194
- * Sets the name of the application that created the event.
195
- * @param {string} name
179
+ * Defines the name of the actor (who or what performed the action).
180
+ * @param {string} name - Actor name (e.g., 'user').
196
181
  */
197
- setAppName(name) {
198
- this.data.appName = name;
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;
199
187
  }
200
188
 
201
189
  /**
202
- * Adds multiple identifiers from an object.
203
- * @param {object} param
190
+ * Adds or updates an identifier for the actor.
191
+ * @param {string} name - Identifier name.
192
+ * @param {*} identifier - Identifier value.
204
193
  */
205
- convertParamIdentifiers(param) {
206
- if (typeof param === 'object' && param !== null && !Array.isArray(param)) {
207
- for (const [key, value] of Object.entries(param)) {
208
- this.addIdentifier(key, value);
209
- }
194
+ setActorIdentifier = function(name, identifier) {
195
+ if (typeof name !== 'string') {
196
+ throw new Error('Actor Identifier name must be a string');
210
197
  }
198
+ this.actor.identifiers[name] = identifier;
211
199
  }
212
200
 
213
201
  /**
214
- * Adds a single identifier to the event.
215
- * @param {string} name
216
- * @param {*} value
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.
217
205
  */
218
- addIdentifier(name, value) {
219
- if (typeof this.data.identifiers !== 'object' || this.data.identifiers === null) {
220
- this.data.identifiers = {};
206
+ setContext = function(context, value) {
207
+ if (typeof context !== 'string') {
208
+ throw new Error('Context must be a string');
221
209
  }
222
- this.data.identifiers[name] = value;
210
+ this.context[context] = value;
223
211
  }
224
212
 
225
213
  /**
226
- * Constructs the postable event object with metadata and encoded payload.
227
- * @returns {object}
214
+ * Declares an entity referenced by this event.
215
+ * @param {string} entity - The referenced entity name.
228
216
  */
229
- getPostObject() {
230
- this.data.timestamps.sendDatetimeUtc = new Date().toISOString();
231
- this.data.timestamps.sendDatetimeLocal = new Date(Date.now() - new Date().getTimezoneOffset() * 60000).toISOString();
232
- return {
233
- eventname: this.getEventName(),
234
- eventFormat: this.getEventFormat(),
235
- eventFormatVersion: this.getEventFormatVersion(),
236
- payload: toBase64(this.getPayload())
237
- };
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
+ }
238
224
  }
239
225
 
240
226
  /**
241
- * Overrides or extends the timestamp fields of the event.
242
- * @param {object} dateTimeObject
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.
243
231
  */
244
- overrideDatetime(dateTimeObject = {}) {
245
- for (const [key, value] of Object.entries(dateTimeObject)) {
246
- this.data.timestamps[key] = value;
232
+ setRefenceIdentifier = function(entity, name, identifier) {
233
+ if (typeof entity !== 'string') {
234
+ throw new Error('Referenced entity name must be a string');
235
+ }
236
+ if (typeof name !== 'string') {
237
+ throw new Error('Actor Identifier name must be a string');
247
238
  }
239
+ this.setRefence(entity);
240
+ this.references[entity].identifiers[name] = identifier;
248
241
  }
249
242
 
250
243
  /**
251
- * Serializes the event data to a JSON string.
252
- * @returns {string}
244
+ * Serializes the event to a plain object suitable for JSON.stringify().
245
+ * @returns {object}
253
246
  */
254
- getPayload() {
255
- return JSON.stringify(this.data);
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
+ };
256
259
  }
257
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
+
258
282
  }
259
283
 
260
284
  /**
261
- * Emitter class responsible for batching and sending events to a configured endpoint.
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.
262
304
  */
263
305
  class CollecionesEmitter {
264
306
 
@@ -278,6 +320,7 @@ class CollecionesEmitter {
278
320
 
279
321
  /**
280
322
  * Starts the flush timer if a valid interval is set.
323
+ * @returns {void}
281
324
  */
282
325
  startTimer() {
283
326
  this.stopTimer();
@@ -288,6 +331,7 @@ class CollecionesEmitter {
288
331
 
289
332
  /**
290
333
  * Starts the flush timer only if not already running.
334
+ * @returns {void}
291
335
  */
292
336
  startTimerIfStopped() {
293
337
  if (!this.timer) {
@@ -297,6 +341,7 @@ class CollecionesEmitter {
297
341
 
298
342
  /**
299
343
  * Stops the active flush timer.
344
+ * @returns {void}
300
345
  */
301
346
  stopTimer() {
302
347
  if (this.timer) {
@@ -307,23 +352,28 @@ class CollecionesEmitter {
307
352
 
308
353
  /**
309
354
  * Adds an event to the buffer and flushes if threshold is reached.
310
- * @param {CollecionesBaseEvent} event
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}
311
359
  */
312
360
  track(event) {
313
- if (!(event instanceof CollecionesBaseEvent)) {
314
- 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');
315
363
  }
316
364
  this.trackAsync(event);
317
365
  }
318
366
 
319
367
  /**
320
368
  * Asynchronously adds an event and flushes if the buffer size is exceeded.
321
- * @param {CollecionesBaseEvent} event
322
- * @returns {Promise<void>}
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.
323
373
  */
324
374
  async trackAsync(event) {
325
- if (!(event instanceof CollecionesBaseEvent)) {
326
- 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');
327
377
  }
328
378
  this.startTimerIfStopped();
329
379
  this.buffer.push(event);
@@ -331,8 +381,11 @@ class CollecionesEmitter {
331
381
  }
332
382
 
333
383
  /**
334
- * Sends the buffered events to the server and clears the buffer.
335
- * @returns {Promise<boolean|undefined>}
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.
336
389
  */
337
390
  async flush() {
338
391
  if (this.buffer.length === 0) return;
@@ -340,7 +393,7 @@ class CollecionesEmitter {
340
393
  this.buffer = [];
341
394
  let postPayload = [];
342
395
  eventsToSend.forEach((e) => {
343
- postPayload.push( e.getPostObject() );
396
+ postPayload.push( toBase64( JSON.stringify(e.toJSON())) );
344
397
  });
345
398
  this.stopTimer();
346
399
  try {
@@ -380,22 +433,13 @@ class CollecionesTracker {
380
433
  this.identifiers = {};
381
434
  }
382
435
 
383
- /**
384
- * Adds a global identifier to be included with every event.
385
- * @param {string} name - Identifier key.
386
- * @param {*} value - Identifier value.
387
- */
388
- addIdentifier(name, value) {
389
- this.identifiers[name] = value;
390
- }
391
-
392
436
  /**
393
437
  * Sends an event to all emitters after enriching it with identifiers and metadata.
394
- * @param {CollecionesBaseEvent} collecionesEvent - The event to be sent.
395
- * @throws {Error} If the input is not an instance of CollecionesBaseEvent.
438
+ * @param {CollecionesEvent} collecionesEvent - The event to be sent.
439
+ * @throws {Error} If the input is not an instance of CollecionesEvent.
396
440
  */
397
441
  track(collecionesEvent) {
398
- if (!(collecionesEvent instanceof CollecionesBaseEvent)) {
442
+ if (!(collecionesEvent instanceof CollecionesEvent)) {
399
443
  throw new Error('Event must be of type CollecionesEvent');
400
444
  }
401
445
  for (const [key, value] of Object.entries(this.identifiers)) {
@@ -426,214 +470,253 @@ class CollecionesWebTracker extends CollecionesTracker {
426
470
 
427
471
  /**
428
472
  * Tracks an event, enriching it with browser context information.
429
- * @param {CollecionesBaseEvent} collecionesEvent - The event object to track.
430
- * @throws {Error} If the event is not an instance of CollecionesBaseEvent.
473
+ * @param {CollecionesEvent} collecionesEvent - The event object to track.
474
+ * @throws {Error} If the event is not an instance of CollecionesEvent.
431
475
  */
432
476
  track(collecionesEvent) {
433
- if (!(collecionesEvent instanceof CollecionesBaseEvent)) {
477
+ if (!(collecionesEvent instanceof CollecionesEvent)) {
434
478
  throw new Error('Event must be of type CollecionesEvent');
435
479
  }
436
- collecionesEvent.addField('browserContext', getBrowserContext());
480
+ collecionesEvent.setContext('browserContext', getBrowserContext());
437
481
  super.track(collecionesEvent);
438
482
  }
439
483
  }
440
484
 
441
485
  /**
442
- * Represents a semantic event with a name, data payload, and identifiers.
443
- * Extends CollecionesBaseEvent.
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.
444
517
  */
445
- class CollecionesEvent extends CollecionesBaseEvent {
446
518
 
447
- /**
448
- * Constructs a new CollecionesEvent instance.
449
- * @param {string} name - The name of the event.
450
- * @param {object} data - The main data payload of the event.
451
- * @param {object} identifiers - A set of identifiers to associate with the event.
452
- */
453
- constructor(name, data, identifiers) {
454
- super();
455
- this.setEventName(name);
456
- Object.assign(this.data, data);
457
- this.convertParamIdentifiers(identifiers);
458
- }
459
519
 
460
- }
520
+ let init = (entity) => {
521
+ return ((entity)=>{
522
+ let eventInstance = new CollecionesEvent(); // Core event object
523
+ eventInstance.setEntity(entity);
461
524
 
462
- const byteToHex = [];
463
- for (let i = 0; i < 256; ++i) {
464
- byteToHex.push((i + 0x100).toString(16).slice(1));
465
- }
466
- function unsafeStringify(arr, offset = 0) {
467
- return (byteToHex[arr[offset + 0]] +
468
- byteToHex[arr[offset + 1]] +
469
- byteToHex[arr[offset + 2]] +
470
- byteToHex[arr[offset + 3]] +
471
- '-' +
472
- byteToHex[arr[offset + 4]] +
473
- byteToHex[arr[offset + 5]] +
474
- '-' +
475
- byteToHex[arr[offset + 6]] +
476
- byteToHex[arr[offset + 7]] +
477
- '-' +
478
- byteToHex[arr[offset + 8]] +
479
- byteToHex[arr[offset + 9]] +
480
- '-' +
481
- byteToHex[arr[offset + 10]] +
482
- byteToHex[arr[offset + 11]] +
483
- byteToHex[arr[offset + 12]] +
484
- byteToHex[arr[offset + 13]] +
485
- byteToHex[arr[offset + 14]] +
486
- byteToHex[arr[offset + 15]]).toLowerCase();
487
- }
525
+ let helpers = {
526
+ getEvent: () => {
527
+ return eventInstance;
528
+ },
529
+ };
488
530
 
489
- let getRandomValues;
490
- const rnds8 = new Uint8Array(16);
491
- function rng() {
492
- if (!getRandomValues) {
493
- if (typeof crypto === 'undefined' || !crypto.getRandomValues) {
494
- throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
495
- }
496
- getRandomValues = crypto.getRandomValues.bind(crypto);
497
- }
498
- return getRandomValues(rnds8);
499
- }
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
+ };
500
560
 
501
- const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);
502
- var native = { randomUUID };
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
+ };
503
578
 
504
- function v4(options, buf, offset) {
505
- if (native.randomUUID && true && !options) {
506
- return native.randomUUID();
507
- }
508
- options = options || {};
509
- const rnds = options.random ?? options.rng?.() ?? rng();
510
- if (rnds.length < 16) {
511
- throw new Error('Random bytes length must be >= 16');
512
- }
513
- rnds[6] = (rnds[6] & 0x0f) | 0x40;
514
- rnds[8] = (rnds[8] & 0x3f) | 0x80;
515
- return unsafeStringify(rnds);
516
- }
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
+ };
517
589
 
518
- /**
519
- * Represents a structured semantic event with entity, action, and optional adjective.
520
- * Includes automatic naming and identifier mapping.
521
- * Extends CollecionesBaseEvent.
522
- */
523
- class CollecionesSemanticEvent extends CollecionesBaseEvent {
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
+ };
524
602
 
525
- /**
526
- * Constructs a new semantic event.
527
- * @param {string} entity - The entity involved in the event.
528
- * @param {string} action - The action performed on the entity.
529
- * @param {string|string[]|undefined} adjective - Optional adjective(s) modifying the event.
530
- * @param {object} identifiers - Key-value pairs to be added as identifiers.
531
- */
532
- constructor(entity, action, adjective, identifiers) {
533
- super();
534
- this.entity = underscoreToCamelCase(entity);
535
- this.action = underscoreToCamelCase(action);
536
- this.adjective = formatAdjectives(adjective);
537
- let adjectiveString = stringifyAdjectives(this.adjective);
538
- this.eventName = `${this.entity}${(adjectiveString !== undefined) ? adjectiveString : ''}__${this.action}`;
539
- this.convertParamIdentifiers(identifiers);
540
- this.data.entityIdentifiers = {};
541
- this.data.attributes = {};
542
- this.data.clientEventId = v4();
543
- this.data.meta = {
544
- eventFormat: 'CollecionesSemanticEvent',
545
- eventFormatVersion: '1'
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
+ }
546
613
  };
547
- }
548
614
 
549
- /**
550
- * This method is deprecated in semantic events and will throw if called.
551
- * @throws {Error}
552
- */
553
- setData() {
554
- throw new Error('setData deprecated in semantic events');
555
- }
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
+ }
629
+ };
556
630
 
557
- /**
558
- * Adds a key-value pair as an identifier for the semantic entity.
559
- * @param {string} key - The identifier name.
560
- * @param {string|number} value - The identifier value.
561
- * @throws Will throw if key is not a string or value is not a string or number.
562
- */
563
- addEntityIdentifier(key, value) {
564
- if (typeof key !== 'string') {
565
- throw new Error('Entity identifier key must be a string');
566
- }
567
- if (typeof value !== 'string' && typeof value !== 'number') {
568
- throw new Error('Entity identifier value must be a string or number');
569
- }
570
- this.data.entityIdentifiers[key] = value;
571
- }
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
+ };
572
647
 
573
- }
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
+ };
574
660
 
575
- /**
576
- * Represents a semantic event related to a collection of entities.
577
- * Extends CollecionesSemanticEvent and adds item-level detail and identifiers.
578
- */
579
- class CollecionesSemanticCollectionEvent extends CollecionesSemanticEvent {
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
+ };
580
678
 
581
- /**
582
- * Constructs a new CollecionesSemanticCollectionEvent.
583
- * @param {string} itemEntity - The name of the item entity being acted on.
584
- * @param {string} action - The action performed.
585
- * @param {string|string[]|undefined} adjective - Optional adjective(s) describing the action.
586
- * @param {object} identifiers - Identifiers associated with the event.
587
- * @param {string} [collectionEntity] - Optional collection name, defaults to `${itemEntity}Collection`.
588
- */
589
- constructor(itemEntity, action, adjective, identifiers, collectionEntity) {
590
- if (typeof collectionEntity == 'undefined') {
591
- collectionEntity = `${itemEntity}Collection`;
592
- }
593
- super(collectionEntity, action, undefined, identifiers);
594
- this.data.meta = {
595
- eventFormat: 'CollecionesSemanticCollectionEvent',
596
- eventFormatVersion: '1'
679
+ // Schema declaration: .conform.to('...')
680
+ conformingTo = (name) => {
681
+ eventInstance.setSchema(name);
682
+ return {
683
+ then: {track: {with: track}},
684
+ helpers
685
+ }
597
686
  };
598
- this.adjective = formatAdjectives(adjective);
599
- let adjectiveString = stringifyAdjectives(this.adjective);
600
- itemEntity = underscoreToCamelCase(itemEntity);
601
- this.data.itemEntity = itemEntity;
602
- this.data.itemEventName = `${itemEntity}${(adjectiveString !== undefined) ? adjectiveString : ''}__${this.action}`;
603
- this.data.entityItemIdentifiers = {};
604
- }
605
687
 
606
- /**
607
- * Adds an identifier value (or values) for a specific entity item key.
608
- * @param {string} key - The identifier name.
609
- * @param {string|number|Array<string|number>} value - The identifier value(s).
610
- * @throws Will throw if key is not a string or value is of invalid type.
611
- */
612
- addEntityItemIdentifier(key, value) {
613
- if (typeof key !== 'string') {
614
- throw new Error('Entity identifier key must be a string');
615
- }
616
- if (typeof value !== 'string' && typeof value !== 'number' && !Array.isArray(value)) {
617
- throw new Error('Entity identifier value must be a string or number');
618
- }
619
- if (typeof this.data.entityItemIdentifiers[key] == 'undefined') {
620
- this.data.entityItemIdentifiers[key] = [];
621
- }
622
- if (Array.isArray(value)) {
623
- value.forEach((v) => {
624
- this.data.entityItemIdentifiers[key].push(v);
625
- });
626
- } else {
627
- this.data.entityItemIdentifiers[key].push(value);
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
+ }
697
+ };
698
+
699
+ return {
700
+ and: andEntity,
701
+ _: setEntityAfterAnd,
702
+ identified: {
703
+ by: setEntityIdentifiers
704
+ },
705
+ has: { been: setAction},
706
+ node: '_base',
707
+ helpers
628
708
  }
629
- }
630
709
 
631
- }
710
+ })(entity);
711
+ };
712
+
713
+ let collecionesDsl = {
714
+ the: init
715
+ };
632
716
 
633
717
  exports.CollecionesEmitter = CollecionesEmitter;
634
718
  exports.CollecionesEvent = CollecionesEvent;
635
- exports.CollecionesSemanticCollectionEvent = CollecionesSemanticCollectionEvent;
636
- exports.CollecionesSemanticEvent = CollecionesSemanticEvent;
637
719
  exports.CollecionesTracker = CollecionesTracker;
638
720
  exports.CollecionesWebTracker = CollecionesWebTracker;
721
+ exports.collecionesDsl = collecionesDsl;
639
722
  //# sourceMappingURL=index.cjs.map