@avsbhq/node 1.0.0 → 1.5.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.d.cts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { FlagDatafile, StickyBucketService, Logger, EvaluationSource, StickyAssignment, DecideOption, Flag, TrackPayload, DecisionLog, InitResult, EvalContext } from '@avsbhq/core';
2
- export { DecideOption, DecisionLog, DecisionLogEntry, EvalContext, EvaluationSource, ExposureEvent, Flag, FlagDatafile, FlagEvaluationDetails, InitResult, Logger, MetricEvent, MultiContext, RuleType, SingleContext, StickyAssignment, StickyBucketService, TrackPayload, consoleLogger, consoleTransport, createLogger, noopLogger } from '@avsbhq/core';
2
+ export { DatafileDataset, DatafileDatasetType, DecideOption, DecisionLog, DecisionLogEntry, EvalContext, EvaluationSource, ExposureEvent, Flag, FlagDatafile, FlagEvaluationDetails, InitResult, Logger, MetricEvent, MultiContext, PurchaseHistoryAttribute, RuleType, SingleContext, StickyAssignment, StickyBucketService, TrackPayload, consoleLogger, consoleTransport, createLogger, noopLogger } from '@avsbhq/core';
3
3
  import { AvsbUtils } from '@avsbhq/utils';
4
4
  export { AvsbUtils } from '@avsbhq/utils';
5
+ export { StreamingClient, StreamingOptions, createStreamingClient } from '@avsbhq/utils/streaming';
5
6
 
6
7
  interface AvsbServerOptions {
7
8
  /** SDK key for the flag environment (e.g., "env_abc123") */
@@ -62,6 +63,163 @@ interface MiddlewareConfig {
62
63
  attributesFrom?: (req: unknown) => Record<string, unknown>;
63
64
  }
64
65
 
66
+ /**
67
+ * Purchase order shape for server-side purchase tracking.
68
+ * Mirrors the client-side snippet PurchaseOrder interface.
69
+ * Decimal values are forwarded as-is — no server-side currency conversion.
70
+ */
71
+ interface PurchaseOrder {
72
+ /** Required. Unique order/transaction identifier. */
73
+ orderId: string;
74
+ /** Required. Order total as a decimal (e.g. 99.95). */
75
+ total: number;
76
+ /** ISO 4217 currency code. */
77
+ currency?: string;
78
+ subtotal?: number;
79
+ shipping?: number;
80
+ tax?: number;
81
+ discount?: number;
82
+ coupon?: string;
83
+ items?: Array<{
84
+ sku: string;
85
+ /**
86
+ * Canonical product-grain key (e-commerce suite overhaul, contract C1).
87
+ * Pass when known so order items join catalog/recommendation analytics
88
+ * without alias resolution; the ingestion worker derives it from `sku`
89
+ * otherwise.
90
+ */
91
+ productKey?: string;
92
+ name?: string;
93
+ price?: number;
94
+ quantity?: number;
95
+ category?: string;
96
+ }>;
97
+ }
98
+
99
+ /**
100
+ * Server-side datasets read client (e-commerce suite Phase 2).
101
+ *
102
+ * Resolves the live version of a dataset from the SDK's datafile
103
+ * (`datasets` field) and fetches a single key from the edge worker:
104
+ *
105
+ * GET {ingestionHost}/v1/ds/{sdkKey}/{slug}/{versionShortId}/{key}
106
+ *
107
+ * The ingestion host is derived from the datafile's `collectEndpoint`,
108
+ * exactly like the server tracker derives `/v1/collect/*`. The worker's
109
+ * key cache resolves SDK keys as well as snippet keys in the first path
110
+ * segment.
111
+ *
112
+ * Error posture matches flag evaluation: this client NEVER throws.
113
+ * Unknown slug, missing live version, SDK not ready, HTTP errors and
114
+ * network failures all degrade to `{ found: false }`.
115
+ */
116
+ interface DatasetGetResult {
117
+ found: boolean;
118
+ /** Parsed row for TABLE/FEED datasets; `true` for LIST membership hits. */
119
+ value?: unknown;
120
+ meta: {
121
+ slug: string;
122
+ /** Live version short id used for the lookup; null when unresolvable. */
123
+ version: number | null;
124
+ };
125
+ }
126
+ interface DatasetsClient {
127
+ /**
128
+ * Look up `key` in the live version of dataset `slug`.
129
+ * Resolves the version from the current datafile and never throws.
130
+ */
131
+ get(slug: string, key: string): Promise<DatasetGetResult>;
132
+ }
133
+
134
+ /**
135
+ * Server-side recommendations client (e-commerce suite overhaul, contract C3).
136
+ *
137
+ * Mirrors ./datasets.ts: resolves a recipe handle against the datafile's
138
+ * recipe registry (`datafile.recipes`, additive) and POSTs the standard
139
+ * resolve body to the edge worker:
140
+ *
141
+ * POST {ingestionHost}/v1/recs/resolve
142
+ *
143
+ * The ingestion host is derived from the datafile's `collectEndpoint`. The
144
+ * worker's key cache resolves SDK keys as well as snippet keys, so the body's
145
+ * key field simply carries the SDK key.
146
+ *
147
+ * Attribution is OPT-IN server-side: `get()` fires a `rec:impression` (via
148
+ * the server tracker) only when the caller passes `attribution` — a server
149
+ * has no ambient variation context the way a browser harness does.
150
+ *
151
+ * Error posture matches datasets/flag evaluation: this client NEVER throws.
152
+ * Unknown recipe, SDK not ready, HTTP errors, timeouts and network failures
153
+ * all degrade to `{ items: [], served: false }`.
154
+ */
155
+ interface RecProduct {
156
+ id: string;
157
+ title?: string;
158
+ image?: string;
159
+ href?: string;
160
+ category?: string;
161
+ /** MINOR units (ISO-4217). */
162
+ price?: number;
163
+ /** MINOR units. */
164
+ compareAtPrice?: number;
165
+ currency?: string;
166
+ availability?: 'in_stock' | 'out_of_stock' | 'removed';
167
+ }
168
+ interface RecsAttribution {
169
+ visitorId: string;
170
+ experimentId: string;
171
+ variationId: string;
172
+ }
173
+ interface RecsGetRequest {
174
+ recipe: string;
175
+ context?: {
176
+ /** Single seed product key (product page). */
177
+ seed?: string;
178
+ /** Up to 3 seed product keys (cart page). */
179
+ seeds?: string[];
180
+ };
181
+ maxItems?: number;
182
+ excludeOutOfStock?: boolean;
183
+ /** When present, a rec:impression is queued with these ids on success. */
184
+ attribution?: RecsAttribution;
185
+ }
186
+ interface RecsResult {
187
+ items: RecProduct[];
188
+ served: boolean;
189
+ recipe: string;
190
+ /** Slug of the chain step that served, null on a miss. */
191
+ source: string | null;
192
+ fallbackStep: number | null;
193
+ /** True when the resolve failed (timeout / network / HTTP / parse). */
194
+ degraded: boolean;
195
+ }
196
+ interface RecsClient {
197
+ /** Resolve items for a recipe. Never throws. */
198
+ get(req: RecsGetRequest): Promise<RecsResult>;
199
+ /**
200
+ * Queue a rec:click for a product the shopper clicked. Pass `recipe` when
201
+ * known — results group click-through by (variation, recipe).
202
+ */
203
+ trackClick(productId: string, opts: RecsAttribution & {
204
+ position?: number;
205
+ recipe?: string;
206
+ }): void;
207
+ }
208
+ /**
209
+ * One entry of the datafile recipe registry (contract C3). Additive on
210
+ * FlagDatafile — SDKs on older datafiles see it absent.
211
+ */
212
+ interface DatafileRecipe {
213
+ recipe: string;
214
+ chain: Array<{
215
+ slug: string;
216
+ version: number;
217
+ }>;
218
+ excludeOutOfStock: boolean;
219
+ sessionAffinity: boolean;
220
+ merch?: unknown[];
221
+ }
222
+
65
223
  /**
66
224
  * A per-request scoped client with a bound EvalContext.
67
225
  *
@@ -143,6 +301,23 @@ declare class AvsbServer {
143
301
  */
144
302
  private _utils;
145
303
  get utils(): AvsbUtils;
304
+ /**
305
+ * Server-side datasets read surface (e-commerce suite Phase 2).
306
+ * Constructed lazily on first access, mirroring the `utils` getter.
307
+ * `client.datasets.get(slug, key)` resolves the live version from the
308
+ * current datafile and never throws — see ./datasets.ts.
309
+ */
310
+ private _datasets;
311
+ get datasets(): DatasetsClient;
312
+ /**
313
+ * Server-side recommendations surface (e-commerce suite overhaul, C3).
314
+ * Constructed lazily on first access, mirroring the `datasets` getter.
315
+ * `client.recs.get({ recipe, … })` resolves the recipe registry from the
316
+ * current datafile and never throws; impressions/clicks ride the server
317
+ * tracker's queue and revenue attaches via the existing `trackPurchase`.
318
+ */
319
+ private _recs;
320
+ get recs(): RecsClient;
146
321
  constructor(options: AvsbServerOptions);
147
322
  onReady(): Promise<InitResult>;
148
323
  private initializeAndReady;
@@ -155,6 +330,7 @@ declare class AvsbServer {
155
330
  getNumberFlag(flagKey: string, defaultValue: NoInfer<number> | number, options?: GetFlagOptions): Flag<number>;
156
331
  getJsonFlag<T>(flagKey: string, defaultValue: NoInfer<T> | T, options?: GetFlagOptions): Flag<T>;
157
332
  getAllFlags(context: EvalContext, options?: GetAllFlagsOptions): Record<string, Flag>;
333
+ trackPurchase(visitorId: string, order: PurchaseOrder): Promise<void>;
158
334
  track(eventKey: string, payload: TrackPayload & {
159
335
  context: EvalContext;
160
336
  }): void;
@@ -230,22 +406,8 @@ declare class RedisStickyBucketService implements StickyBucketService {
230
406
  private evictIfNeeded;
231
407
  }
232
408
 
233
- interface StreamingClient {
234
- connect(): void;
235
- disconnect(): void;
236
- isConnected(): boolean;
237
- }
238
- interface StreamingOptions {
239
- endpoint: string;
240
- sdkKey: string;
241
- onDatafileUpdated: () => void;
242
- logger: Logger;
243
- reconnectDelay?: number;
244
- }
245
- declare function createStreamingClient(options: StreamingOptions): StreamingClient;
246
-
247
409
  declare function createDecisionLog(): DecisionLog;
248
410
 
249
- declare const SDK_VERSION = "0.3.0";
411
+ declare const SDK_VERSION = "0.4.0";
250
412
 
251
- export { AvsbServer, type AvsbServerOptions, type EventOptions, type GetAllFlagsOptions, type GetFlagOptions, InMemoryStickyBucketService, type MiddlewareConfig, type RedisLike, type RedisStickyBucketOptions, RedisStickyBucketService, SDK_VERSION, type StreamingClient, type StreamingOptions, type UserBoundClient, createDecisionLog, createStreamingClient, expressMiddleware, fastifyPlugin };
413
+ export { AvsbServer, type AvsbServerOptions, type DatafileRecipe, type DatasetGetResult, type DatasetsClient, type EventOptions, type GetAllFlagsOptions, type GetFlagOptions, InMemoryStickyBucketService, type MiddlewareConfig, type PurchaseOrder, type RecProduct, type RecsAttribution, type RecsClient, type RecsGetRequest, type RecsResult, type RedisLike, type RedisStickyBucketOptions, RedisStickyBucketService, SDK_VERSION, type UserBoundClient, createDecisionLog, expressMiddleware, fastifyPlugin };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { FlagDatafile, StickyBucketService, Logger, EvaluationSource, StickyAssignment, DecideOption, Flag, TrackPayload, DecisionLog, InitResult, EvalContext } from '@avsbhq/core';
2
- export { DecideOption, DecisionLog, DecisionLogEntry, EvalContext, EvaluationSource, ExposureEvent, Flag, FlagDatafile, FlagEvaluationDetails, InitResult, Logger, MetricEvent, MultiContext, RuleType, SingleContext, StickyAssignment, StickyBucketService, TrackPayload, consoleLogger, consoleTransport, createLogger, noopLogger } from '@avsbhq/core';
2
+ export { DatafileDataset, DatafileDatasetType, DecideOption, DecisionLog, DecisionLogEntry, EvalContext, EvaluationSource, ExposureEvent, Flag, FlagDatafile, FlagEvaluationDetails, InitResult, Logger, MetricEvent, MultiContext, PurchaseHistoryAttribute, RuleType, SingleContext, StickyAssignment, StickyBucketService, TrackPayload, consoleLogger, consoleTransport, createLogger, noopLogger } from '@avsbhq/core';
3
3
  import { AvsbUtils } from '@avsbhq/utils';
4
4
  export { AvsbUtils } from '@avsbhq/utils';
5
+ export { StreamingClient, StreamingOptions, createStreamingClient } from '@avsbhq/utils/streaming';
5
6
 
6
7
  interface AvsbServerOptions {
7
8
  /** SDK key for the flag environment (e.g., "env_abc123") */
@@ -62,6 +63,163 @@ interface MiddlewareConfig {
62
63
  attributesFrom?: (req: unknown) => Record<string, unknown>;
63
64
  }
64
65
 
66
+ /**
67
+ * Purchase order shape for server-side purchase tracking.
68
+ * Mirrors the client-side snippet PurchaseOrder interface.
69
+ * Decimal values are forwarded as-is — no server-side currency conversion.
70
+ */
71
+ interface PurchaseOrder {
72
+ /** Required. Unique order/transaction identifier. */
73
+ orderId: string;
74
+ /** Required. Order total as a decimal (e.g. 99.95). */
75
+ total: number;
76
+ /** ISO 4217 currency code. */
77
+ currency?: string;
78
+ subtotal?: number;
79
+ shipping?: number;
80
+ tax?: number;
81
+ discount?: number;
82
+ coupon?: string;
83
+ items?: Array<{
84
+ sku: string;
85
+ /**
86
+ * Canonical product-grain key (e-commerce suite overhaul, contract C1).
87
+ * Pass when known so order items join catalog/recommendation analytics
88
+ * without alias resolution; the ingestion worker derives it from `sku`
89
+ * otherwise.
90
+ */
91
+ productKey?: string;
92
+ name?: string;
93
+ price?: number;
94
+ quantity?: number;
95
+ category?: string;
96
+ }>;
97
+ }
98
+
99
+ /**
100
+ * Server-side datasets read client (e-commerce suite Phase 2).
101
+ *
102
+ * Resolves the live version of a dataset from the SDK's datafile
103
+ * (`datasets` field) and fetches a single key from the edge worker:
104
+ *
105
+ * GET {ingestionHost}/v1/ds/{sdkKey}/{slug}/{versionShortId}/{key}
106
+ *
107
+ * The ingestion host is derived from the datafile's `collectEndpoint`,
108
+ * exactly like the server tracker derives `/v1/collect/*`. The worker's
109
+ * key cache resolves SDK keys as well as snippet keys in the first path
110
+ * segment.
111
+ *
112
+ * Error posture matches flag evaluation: this client NEVER throws.
113
+ * Unknown slug, missing live version, SDK not ready, HTTP errors and
114
+ * network failures all degrade to `{ found: false }`.
115
+ */
116
+ interface DatasetGetResult {
117
+ found: boolean;
118
+ /** Parsed row for TABLE/FEED datasets; `true` for LIST membership hits. */
119
+ value?: unknown;
120
+ meta: {
121
+ slug: string;
122
+ /** Live version short id used for the lookup; null when unresolvable. */
123
+ version: number | null;
124
+ };
125
+ }
126
+ interface DatasetsClient {
127
+ /**
128
+ * Look up `key` in the live version of dataset `slug`.
129
+ * Resolves the version from the current datafile and never throws.
130
+ */
131
+ get(slug: string, key: string): Promise<DatasetGetResult>;
132
+ }
133
+
134
+ /**
135
+ * Server-side recommendations client (e-commerce suite overhaul, contract C3).
136
+ *
137
+ * Mirrors ./datasets.ts: resolves a recipe handle against the datafile's
138
+ * recipe registry (`datafile.recipes`, additive) and POSTs the standard
139
+ * resolve body to the edge worker:
140
+ *
141
+ * POST {ingestionHost}/v1/recs/resolve
142
+ *
143
+ * The ingestion host is derived from the datafile's `collectEndpoint`. The
144
+ * worker's key cache resolves SDK keys as well as snippet keys, so the body's
145
+ * key field simply carries the SDK key.
146
+ *
147
+ * Attribution is OPT-IN server-side: `get()` fires a `rec:impression` (via
148
+ * the server tracker) only when the caller passes `attribution` — a server
149
+ * has no ambient variation context the way a browser harness does.
150
+ *
151
+ * Error posture matches datasets/flag evaluation: this client NEVER throws.
152
+ * Unknown recipe, SDK not ready, HTTP errors, timeouts and network failures
153
+ * all degrade to `{ items: [], served: false }`.
154
+ */
155
+ interface RecProduct {
156
+ id: string;
157
+ title?: string;
158
+ image?: string;
159
+ href?: string;
160
+ category?: string;
161
+ /** MINOR units (ISO-4217). */
162
+ price?: number;
163
+ /** MINOR units. */
164
+ compareAtPrice?: number;
165
+ currency?: string;
166
+ availability?: 'in_stock' | 'out_of_stock' | 'removed';
167
+ }
168
+ interface RecsAttribution {
169
+ visitorId: string;
170
+ experimentId: string;
171
+ variationId: string;
172
+ }
173
+ interface RecsGetRequest {
174
+ recipe: string;
175
+ context?: {
176
+ /** Single seed product key (product page). */
177
+ seed?: string;
178
+ /** Up to 3 seed product keys (cart page). */
179
+ seeds?: string[];
180
+ };
181
+ maxItems?: number;
182
+ excludeOutOfStock?: boolean;
183
+ /** When present, a rec:impression is queued with these ids on success. */
184
+ attribution?: RecsAttribution;
185
+ }
186
+ interface RecsResult {
187
+ items: RecProduct[];
188
+ served: boolean;
189
+ recipe: string;
190
+ /** Slug of the chain step that served, null on a miss. */
191
+ source: string | null;
192
+ fallbackStep: number | null;
193
+ /** True when the resolve failed (timeout / network / HTTP / parse). */
194
+ degraded: boolean;
195
+ }
196
+ interface RecsClient {
197
+ /** Resolve items for a recipe. Never throws. */
198
+ get(req: RecsGetRequest): Promise<RecsResult>;
199
+ /**
200
+ * Queue a rec:click for a product the shopper clicked. Pass `recipe` when
201
+ * known — results group click-through by (variation, recipe).
202
+ */
203
+ trackClick(productId: string, opts: RecsAttribution & {
204
+ position?: number;
205
+ recipe?: string;
206
+ }): void;
207
+ }
208
+ /**
209
+ * One entry of the datafile recipe registry (contract C3). Additive on
210
+ * FlagDatafile — SDKs on older datafiles see it absent.
211
+ */
212
+ interface DatafileRecipe {
213
+ recipe: string;
214
+ chain: Array<{
215
+ slug: string;
216
+ version: number;
217
+ }>;
218
+ excludeOutOfStock: boolean;
219
+ sessionAffinity: boolean;
220
+ merch?: unknown[];
221
+ }
222
+
65
223
  /**
66
224
  * A per-request scoped client with a bound EvalContext.
67
225
  *
@@ -143,6 +301,23 @@ declare class AvsbServer {
143
301
  */
144
302
  private _utils;
145
303
  get utils(): AvsbUtils;
304
+ /**
305
+ * Server-side datasets read surface (e-commerce suite Phase 2).
306
+ * Constructed lazily on first access, mirroring the `utils` getter.
307
+ * `client.datasets.get(slug, key)` resolves the live version from the
308
+ * current datafile and never throws — see ./datasets.ts.
309
+ */
310
+ private _datasets;
311
+ get datasets(): DatasetsClient;
312
+ /**
313
+ * Server-side recommendations surface (e-commerce suite overhaul, C3).
314
+ * Constructed lazily on first access, mirroring the `datasets` getter.
315
+ * `client.recs.get({ recipe, … })` resolves the recipe registry from the
316
+ * current datafile and never throws; impressions/clicks ride the server
317
+ * tracker's queue and revenue attaches via the existing `trackPurchase`.
318
+ */
319
+ private _recs;
320
+ get recs(): RecsClient;
146
321
  constructor(options: AvsbServerOptions);
147
322
  onReady(): Promise<InitResult>;
148
323
  private initializeAndReady;
@@ -155,6 +330,7 @@ declare class AvsbServer {
155
330
  getNumberFlag(flagKey: string, defaultValue: NoInfer<number> | number, options?: GetFlagOptions): Flag<number>;
156
331
  getJsonFlag<T>(flagKey: string, defaultValue: NoInfer<T> | T, options?: GetFlagOptions): Flag<T>;
157
332
  getAllFlags(context: EvalContext, options?: GetAllFlagsOptions): Record<string, Flag>;
333
+ trackPurchase(visitorId: string, order: PurchaseOrder): Promise<void>;
158
334
  track(eventKey: string, payload: TrackPayload & {
159
335
  context: EvalContext;
160
336
  }): void;
@@ -230,22 +406,8 @@ declare class RedisStickyBucketService implements StickyBucketService {
230
406
  private evictIfNeeded;
231
407
  }
232
408
 
233
- interface StreamingClient {
234
- connect(): void;
235
- disconnect(): void;
236
- isConnected(): boolean;
237
- }
238
- interface StreamingOptions {
239
- endpoint: string;
240
- sdkKey: string;
241
- onDatafileUpdated: () => void;
242
- logger: Logger;
243
- reconnectDelay?: number;
244
- }
245
- declare function createStreamingClient(options: StreamingOptions): StreamingClient;
246
-
247
409
  declare function createDecisionLog(): DecisionLog;
248
410
 
249
- declare const SDK_VERSION = "0.3.0";
411
+ declare const SDK_VERSION = "0.4.0";
250
412
 
251
- export { AvsbServer, type AvsbServerOptions, type EventOptions, type GetAllFlagsOptions, type GetFlagOptions, InMemoryStickyBucketService, type MiddlewareConfig, type RedisLike, type RedisStickyBucketOptions, RedisStickyBucketService, SDK_VERSION, type StreamingClient, type StreamingOptions, type UserBoundClient, createDecisionLog, createStreamingClient, expressMiddleware, fastifyPlugin };
413
+ export { AvsbServer, type AvsbServerOptions, type DatafileRecipe, type DatasetGetResult, type DatasetsClient, type EventOptions, type GetAllFlagsOptions, type GetFlagOptions, InMemoryStickyBucketService, type MiddlewareConfig, type PurchaseOrder, type RecProduct, type RecsAttribution, type RecsClient, type RecsGetRequest, type RecsResult, type RedisLike, type RedisStickyBucketOptions, RedisStickyBucketService, SDK_VERSION, type UserBoundClient, createDecisionLog, expressMiddleware, fastifyPlugin };