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