@combeenation/custom-code-sdk 0.0.1-alpha6 → 0.0.1-alpha7

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.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { z } from 'zod';
2
2
 
3
+ declare type AppLanguage = 'en' | 'de';
4
+
3
5
  export declare class Button {
4
6
  #private;
5
7
  readonly id: CtrlId;
@@ -14,13 +16,20 @@ declare type CallbackUnsubscribeOption = {
14
16
  unsubscribe: () => void;
15
17
  };
16
18
 
17
- declare type CfgrClient = NonNullable<typeof client>;
18
-
19
- declare interface CfgrClientApi_v1 {
20
- finishConfiguration: (input?: string) => Promise<FinishResult>;
21
- onAnyCmpValueChanged<TInput extends ValueComponent_2>(listener: CmpValuesChangedListener<TInput['name']>, components: TInput[], lazy?: boolean): Promise<void>;
22
- getCmpValue<T extends CmpValue_2>(cmpName: CmpName_2): Promise<T | undefined>;
23
- onCmpValueChanged<TValue extends CmpValue_2>(cmpName: CmpName_2, listener: CmpValueChangedListener_2<TValue>, condition?: CmpValueChangedCondition_2<TValue>, callImmediately?: boolean): Promise<void>;
19
+ export declare namespace CbnSdk {
20
+ export {
21
+ configuratorIsInIFrame,
22
+ finishConfiguration,
23
+ fireAnalyticsEvent,
24
+ getParentPageUrl,
25
+ navigateToLogin,
26
+ onAnyCmpValueChanged,
27
+ redirectParentPage,
28
+ sendCustomMsgToParentPage,
29
+ setConfiguratorIFrameSize,
30
+ shareConfiguration,
31
+ version
32
+ }
24
33
  }
25
34
 
26
35
  export declare class Checkbox {
@@ -31,52 +40,27 @@ export declare class Checkbox {
31
40
  setVisible(visible: boolean): Promise<void>;
32
41
  }
33
42
 
34
- export declare type CheckoutProductCustomFields = {
35
- /**
36
- * Unique identifier
37
- */
38
- id: string;
39
- /**
40
- * Label which the user will also see in the cart (if it is visible)
41
- */
42
- label: string;
43
- /**
44
- * Value of the custom field
45
- */
46
- value: string;
47
- /**
48
- * Position in the cart
49
- */
50
- position: number;
51
- /**
52
- * If it should be visible in the cart
53
- */
54
- isVisible: boolean;
55
- };
56
-
57
- declare const client: CfgrClientApi_v1 | undefined;
58
-
59
43
  declare type CmpName = string;
60
44
 
61
- declare type CmpName_2 = string;
62
-
45
+ /**
46
+ * All possible typings for component values.
47
+ *
48
+ * Rule of thumb with this type: Limit usages to the bare minimum only when actually needed.
49
+ * Ideally, this type should not be used in the consuming app (cfgr editor etc.) at all but only in the API layer which
50
+ * does all the parsing & conversion of cmp values to raw wire format and vice versa.
51
+ *
52
+ * Why?
53
+ * This is practically an `unknown` ATM (see comment above {@link ZCmpValue}) and dealing with `unknown` in code is very
54
+ * cumbersome and leads to hard to maintain code.
55
+ */
63
56
  declare type CmpValue = z.infer<typeof ZCmpValue>;
64
57
 
65
- declare type CmpValue_2 = z.infer<typeof ZCmpValue_2>;
66
-
67
- declare interface CmpValueChangedCondition<T extends CmpValue = CmpValue> {
58
+ /** Interface for value changed condition function */
59
+ export declare interface CmpValueChangedCondition<T extends CmpValue = CmpValue> {
68
60
  (param: T | undefined): Promise<boolean>;
69
61
  }
70
62
 
71
- declare interface CmpValueChangedCondition_2<T extends CmpValue_2 = CmpValue_2> {
72
- (param: T | undefined): Promise<boolean>;
73
- }
74
-
75
- declare interface CmpValueChangedListener<T extends CmpValue = CmpValue> {
76
- (param: T | undefined): void;
77
- }
78
-
79
- declare interface CmpValueChangedListener_2<T extends CmpValue_2 = CmpValue_2> {
63
+ export declare interface CmpValueChangedListener<T extends CmpValue = CmpValue> {
80
64
  (param: T | undefined): void;
81
65
  }
82
66
 
@@ -84,7 +68,11 @@ declare type CmpValueChangedMap<TName extends string = string> = {
84
68
  [K in TName]: boolean;
85
69
  };
86
70
 
87
- declare interface CmpValuesChangedListener<TName extends string = string> {
71
+ export declare interface CmpValuesChangedListener<TName extends string = string> {
72
+ /**
73
+ * Returns an object where each key represents the given components, and the corresponding boolean value
74
+ * indicates whether that component has changed or not
75
+ */
88
76
  (changedCmps: CmpValueChangedMap<TName>): void;
89
77
  }
90
78
 
@@ -96,6 +84,11 @@ export declare class Collapsible {
96
84
  setVisible(visible: boolean): Promise<void>;
97
85
  }
98
86
 
87
+ /**
88
+ * Checks if the configurator is embedded inside an IFrame.
89
+ */
90
+ export declare const configuratorIsInIFrame: () => boolean;
91
+
99
92
  declare type CtrlId = z.infer<typeof ZCtrlId>;
100
93
 
101
94
  export declare class CustomControl {
@@ -104,9 +97,9 @@ export declare class CustomControl {
104
97
  constructor(id: CtrlId);
105
98
  /**
106
99
  * Things to mention when writing docs:
107
- * - Given `el` is only disconnected when ctrl is hidden
108
- * -> Event listener on that element shall only be installed once in custom code
109
- * Explicitly mention that this is only the case for `customCtrl.renderFn` and not for `otherCtrls.onRendered`.
100
+ * - The `renderFn` is always meant to actively render/set the content/innerHTML of the given `element`.
101
+ * ATM, system does sometimes pass a "pre-rendered" `element` but that will change in the future when introducing
102
+ * some dedicated ctrl property like "Custom control controlled/custom control rendered/...".
110
103
  * - Assigning a new fn does not trigger a re-render
111
104
  * - Explain, when this fn is being called (automatically on show, manually on `.render()`)
112
105
  * - Explain, why this should be used instead of a pattern like the following:
@@ -137,26 +130,78 @@ export declare class Dataview {
137
130
  setVisible(visible: boolean): Promise<void>;
138
131
  }
139
132
 
140
- export declare type DiyShopCheckoutJson = Shopware6CheckoutJson;
133
+ /**
134
+ * Creates a finish of the current configuration by running all the Configurator's finish actions and optionally passes
135
+ * the resulting data to the parent page.
136
+ */
137
+ export declare const finishConfiguration: (options: (FinishConfigurationBaseOptions & {
138
+ sendDataToParentPage: false;
139
+ }) | (FinishConfigurationBaseOptions & {
140
+ /**
141
+ * If `true`, the data returned by `transformParentPageData` will be passed to the function
142
+ * `window.Combeenation.onConfigurationFinished(data)` on the parent page (or one of its older aliases like
143
+ * `Combeenation.onCheckout` etc.).
144
+ */
145
+ sendDataToParentPage: true;
146
+ /**
147
+ * Allows transformation of the data that is passed to the parent page after the configuration is finished.
148
+ *
149
+ * @example
150
+ * ```ts
151
+ * const checkoutData: Shopware6CheckoutJson = { ... };
152
+ *
153
+ * finishConfiguration({
154
+ * transformParentPageData: () => {
155
+ * return {
156
+ * id: cfgnId, // E.g. from Hive's `configuration.id`
157
+ * authentication: authToken, // E.g. from Hive's `configuration.authToken`
158
+ * checkoutParameters: JSON.stringify(checkoutData),
159
+ * queryParameters: Object.fromEntries(new URLSearchParams(window.location.search)),
160
+ * checkoutParametersHash: '123', // Not actually used ATM, will be provided by the server in the future
161
+ * } satisfies ParentPageCheckoutData;
162
+ * },
163
+ * });
164
+ * ```
165
+ *
166
+ * FYI, this is mandatory ATM and does not get any input values which means that the consumer is required to
167
+ * build the return value himself. In the future we'll change this to be optional and provide the data generated
168
+ * on the server as input to the transformation function.
169
+ */
170
+ transformParentPageData: () => ParentPageCheckoutData & {
171
+ [key: string]: SerializableJsonValue;
172
+ };
173
+ })) => Promise<void>;
141
174
 
142
- export declare const finishConfiguration: CfgrClient['finishConfiguration'];
175
+ declare type FinishConfigurationBaseOptions = {
176
+ input?: string;
177
+ };
143
178
 
144
179
  /**
145
- * Why we need this?
180
+ * Pushes the given data into the Google Tag Manager data layer on the parent page.
146
181
  *
147
- * Our custom code SDK is using the `ConfiguratorClient` as its main gateway to communicate with cmps. It comes with the
148
- * `ConfiguratorClient` built in and only knows about the API of the version is was built with.
182
+ * If the Configurator is not embedded in an IFrame, the event is pushed directly into the data layer of the current
183
+ * window.
149
184
  *
150
- * Therefore, we'll always have to support older versions of the public API for custom code as well at "system runtime".
185
+ * If embedded in an IFrame, this requires the Configurator plugin to be installed correctly on the parent page.\
186
+ * See embedding instructions for details.
151
187
  *
152
- * Custom code shall always access the `ConfiguratorClient` via some well defined "gateway fn" like
153
- * `window.Cbn.getCustomCodeSdkBridge().createCfgrClient` which is responsible for returning the correct versioned API
154
- * e.g. by "hotpatching" the returned runtime object based on the requested version.
188
+ * @param event Key for event identification
155
189
  */
156
- declare type FinishResult = {
157
- newEditCfgnUrl: string;
158
- actionResults: {};
159
- };
190
+ export declare const fireAnalyticsEvent: (event: string, eventData?: object | string) => Promise<ParentPageComResult<void>>;
191
+
192
+ export declare type FlexShopFinishJson = Shopware6FinishJson;
193
+
194
+ /**
195
+ * Retrieve the parent page's URI.
196
+ *
197
+ * Requires the Configurator plugin to be installed correctly on the parent page.\
198
+ * See embedding instructions for details.
199
+ *
200
+ * @returns `undefined` if we're not inside an IFrame or the parent page does not respond to our request.
201
+ */
202
+ export declare const getParentPageUrl: () => Promise<ParentPageComResult<{
203
+ url: string;
204
+ }>>;
160
205
 
161
206
  export declare class Input {
162
207
  #private;
@@ -166,7 +211,59 @@ export declare class Input {
166
211
  setVisible(visible: boolean): Promise<void>;
167
212
  }
168
213
 
169
- export declare const onAnyCmpValueChanged: CfgrClient['onAnyCmpValueChanged'];
214
+ declare type JsonArray = Array<SerializableJsonValue>;
215
+
216
+ declare type JsonObject = {
217
+ [key: string]: SerializableJsonValue;
218
+ };
219
+
220
+ declare type JsonPrimitive = string | number | boolean | null;
221
+
222
+ /**
223
+ * Navigates to the login page of the Configurator.
224
+ *
225
+ * @param options.hideBackNavigation Defaults to `false`.\
226
+ * E.g. can be used if the Configurator immediately redirects to the login and
227
+ * shouldn't be accessible without a successful login.
228
+ * @param options.language Defaults to the browser language.
229
+ */
230
+ export declare const navigateToLogin: (options?: {
231
+ hideBackNavigation?: boolean;
232
+ language?: AppLanguage;
233
+ }) => void;
234
+
235
+ /**
236
+ * @param listener Called whenever the value of at least 1 component has changed.\
237
+ * Returns an object that indicates which components have actually changed.
238
+ * @param components Only call the listener if one of the given cmps have changed
239
+ * @param lazy `false` [default]: Immediately fetch the values of all changed components.\
240
+ * `true`: Trigger the listener but don't fetch values until specifically requested.
241
+ * This could reduce data traffic when only some components are required in the listener, due to
242
+ * conditions or similar.
243
+ *
244
+ * @example
245
+ * [SCENARIO 1] where `lazy: true` could be benefical
246
+ * ```typescript
247
+ * CmpUtils.onAnyCmpValueChanged(() => {
248
+ * const useBigData = CmpSimpleBool.getValue();
249
+ * if(useBigData) {
250
+ * // only now the data will be retrieved from the server
251
+ * const bigData = await CmpBigData.getValue();
252
+ * }
253
+ *
254
+ * }, [CmpBigData, CmpSimpleBool, CmpSimpleText], true);
255
+ * ```
256
+ *
257
+ * [SCENARIO 2] where `lazy: false` could be benefical
258
+ * ```typescript
259
+ * CmpUtils.onAnyCmpValueChanged(() => {
260
+ * // The data for both values has been fetched in the background, so no further server request is necessary
261
+ * const bigData1 = await CmpBigData1.getValue();
262
+ * const bigData2 = await CmpBigData2.getValue();
263
+ * }, [CmpBigData1, CmpBigData2]);
264
+ * ```
265
+ */
266
+ export declare const onAnyCmpValueChanged: <TInput extends ValueComponent>(listener: CmpValuesChangedListener<TInput["name"]>, components: TInput[], lazy?: boolean) => Promise<void>;
170
267
 
171
268
  declare type OnClickCallback = () => void;
172
269
 
@@ -180,7 +277,144 @@ export declare class Panel {
180
277
  setVisible(visible: boolean): Promise<void>;
181
278
  }
182
279
 
183
- export declare type ShopifyCheckoutJson = {
280
+ export declare type ParentPageCheckoutData = {
281
+ /** Cfgn id */
282
+ id: string;
283
+ /** Contains the value of the `data` passed to Hive's `OnFinish.CheckoutLegacy(data, key)` as stringified JSON */
284
+ checkoutParameters: string;
285
+ /** SHA256 hash of `checkoutParameters` built with the secret `key` passed to `OnFinish.CheckoutLegacy(data, key)` */
286
+ checkoutParametersHash: string;
287
+ /** Contains all query parameters which are added to the current cfgr URL */
288
+ queryParameters: {
289
+ [key: string]: string;
290
+ };
291
+ /** Cfgn auth token */
292
+ authentication: string;
293
+ };
294
+
295
+ declare type ParentPageComErrorPayload<T> = [T] extends [void] ? {} : {
296
+ [K in keyof T]: undefined;
297
+ };
298
+
299
+ /**
300
+ * Given `T` must be an object and all its properties are directly spread into the resulting object.
301
+ *
302
+ * @example
303
+ * ```ts
304
+ * ParentPageComResult<void>
305
+ * // -> { success: true; } | { success: false; error: Error };
306
+ *
307
+ * ParentPageComResult<{ url: string }>
308
+ * // -> { success: true; url: string; } | { success: false; error: Error; url: undefined; };
309
+ *
310
+ * // Not allowed:
311
+ * ParentPageComResult<number> // `number` is not an object
312
+ * ParentPageComResult<string[]> // `string[]` is not an object
313
+ * ParentPageComResult<{ success: string }> // Property `success` is not allowed
314
+ * ParentPageComResult<{ error: string, name: string }> // Property `error` is not allowed
315
+ * ```
316
+ */
317
+ declare type ParentPageComResult<T extends Record<string, unknown> | void> = ({
318
+ success: true;
319
+ error: undefined;
320
+ } & ([T] extends [void] ? {} : T)) | ({
321
+ success: false;
322
+ error: Error;
323
+ } & ParentPageComErrorPayload<T>);
324
+
325
+ export declare type ProductCustomFields = {
326
+ /**
327
+ * Unique identifier
328
+ */
329
+ id: string;
330
+ /**
331
+ * Label which the user will also see in the cart (if it is visible)
332
+ */
333
+ label: string;
334
+ /**
335
+ * Value of the custom field
336
+ */
337
+ value: string;
338
+ /**
339
+ * Position in the cart
340
+ */
341
+ position: number;
342
+ /**
343
+ * If it should be visible in the cart
344
+ */
345
+ isVisible: boolean;
346
+ };
347
+
348
+ /**
349
+ * Sets `window.location.href` to the given `url` on the parent page.
350
+ *
351
+ * Requires the Configurator plugin to be installed correctly on the parent page.\
352
+ * See embedding instructions for details.
353
+ */
354
+ export declare const redirectParentPage: (url: string) => Promise<ParentPageComResult<void>>;
355
+
356
+ /**
357
+ * Send a custom message to the parent page via the "CustomMessage".\
358
+ * The parent page can handle those messages by implementing the function `Combeenation.on{msgName}`.
359
+ *
360
+ * Requires the Configurator plugin to be installed correctly on the parent page.\
361
+ * See embedding instructions for details.
362
+ */
363
+ export declare const sendCustomMsgToParentPage: (msgName: string, data?: object) => Promise<ParentPageComResult<void>>;
364
+
365
+ /** A JSON-serializable value safe to use as a `postMessage` payload etc. */
366
+ declare type SerializableJsonValue = JsonPrimitive | JsonObject | JsonArray;
367
+
368
+ /**
369
+ * Changes the width and/or height of the IFrame and/or scroll position of the parent page window.
370
+ *
371
+ * Requires the Configurator plugin to be installed correctly on the parent page.\
372
+ * See embedding instructions for details.
373
+ *
374
+ * @param width If not given or 0, the width is not changed
375
+ * @param height If not given or 0, the height is not changed
376
+ * @param scrollToX New horizontal scroll position of the parent page window
377
+ * @param scrollToY New vertical scroll position of the parent page window
378
+ */
379
+ export declare const setConfiguratorIFrameSize: (data: {
380
+ width?: string;
381
+ height?: string;
382
+ scrollToX?: number;
383
+ scrollToY?: number;
384
+ }) => Promise<ParentPageComResult<void>>;
385
+
386
+ /**
387
+ * Creates a copy of the current configuration and opens a share window for the given platform with the resulting share
388
+ * URL
389
+ */
390
+ export declare const shareConfiguration: (data: {
391
+ /** If `Custom`, no share window will be opened */
392
+ platform: "Facebook" | "Pinterest" | "Twitter" | "LinkedIn" | "WhatsApp" | "Custom" | "NativeShare";
393
+ ogTitle?: string;
394
+ ogAuthor?: string;
395
+ ogDescription?: string;
396
+ /**
397
+ * URL to an image which will be used as share preview image when supported by the platform.
398
+ *
399
+ * It's recommended to use the URL of a file uploaded via upload tooling of the configurator.
400
+ */
401
+ imageUrl?: string;
402
+ /**
403
+ * URL of the parent page where the configurator is embedded.
404
+ *
405
+ * Will be integrated into the resulting share URL, so that the share redirects to the parent page, not the standalone
406
+ * configurator.
407
+ */
408
+ embedUrl?: string;
409
+ }) => Promise<{
410
+ /**
411
+ * Url which is enhanced for sharing on social media by providing required "Open Graph" tags.
412
+ */
413
+ shareUrl: string;
414
+ shareConfigurationId: string;
415
+ }>;
416
+
417
+ export declare type ShopifyFinishJson = {
184
418
  products: {
185
419
  main: {
186
420
  /**
@@ -204,7 +438,7 @@ export declare type ShopifyCheckoutJson = {
204
438
  * New description of your product
205
439
  */
206
440
  productText?: string;
207
- customFields?: CheckoutProductCustomFields[];
441
+ customFields?: ProductCustomFields[];
208
442
  /**
209
443
  * Weight of the main product
210
444
  */
@@ -229,7 +463,7 @@ export declare type ShopifyCheckoutJson = {
229
463
  }[];
230
464
  };
231
465
 
232
- export declare type Shopware6CheckoutJson = {
466
+ export declare type Shopware6FinishJson = {
233
467
  products: {
234
468
  main: {
235
469
  /**
@@ -253,7 +487,7 @@ export declare type Shopware6CheckoutJson = {
253
487
  * New description of your product
254
488
  */
255
489
  productText?: string;
256
- customFields?: CheckoutProductCustomFields[];
490
+ customFields?: ProductCustomFields[];
257
491
  };
258
492
  /**
259
493
  * Additional predefined Shopware products which will be added to the cart (no custom price/image/title)
@@ -306,39 +540,10 @@ export declare class ValueComponent<TName extends CmpName = CmpName, TValue exte
306
540
  onValueChanged(listener: CmpValueChangedListener<TValue>, callImmediately?: boolean, condition?: CmpValueChangedCondition<TValue>): void;
307
541
  }
308
542
 
309
- /**
310
- * Represents a component of type `Value`
311
- */
312
- declare class ValueComponent_2<TName extends CmpName_2 = CmpName_2, TValue extends CmpValue_2 = CmpValue_2, TInput extends CmpValue_2 = TValue> {
313
- readonly name: TName;
314
- readonly zodType: z.ZodType<CmpValue_2>;
315
- constructor(name: TName, zodType: z.ZodType<CmpValue_2>);
316
- /**
317
- * Function for receiving the value of a component.
318
- */
319
- getValue(): Promise<TValue | undefined>;
320
- /**
321
- * Sends the ChangeConfigurationValue request to the server
322
- */
323
- setInput(value: TInput | undefined): Promise<void>;
324
- /**
325
- * @param listener Called whenever the value of the given cmp has changed
326
- * @param callImmediately `True:` The listener is immediately called with the current value of the cmp at the
327
- * time, the listener is added\
328
- * `False:` The listener will be called for the first time when the value of the cmp
329
- * actually changes
330
- * @param condition A predicate function which is given the new cmp value.\
331
- * The function can decide on whether the listener is called or not by returning true or false.
332
- */
333
- onValueChanged(listener: CmpValueChangedListener_2<TValue>, callImmediately?: boolean, condition?: CmpValueChangedCondition_2<TValue>): void;
334
- }
335
-
336
- export declare const version = "@VERSION@";
543
+ export declare const version: string;
337
544
 
338
545
  declare const ZCmpValue: z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>, z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>, "many">, z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>, z.ZodUnknown]>;
339
546
 
340
- declare const ZCmpValue_2: z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>, z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>, "many">, z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>, z.ZodUnknown]>;
341
-
342
547
  declare const ZCtrlId: z.ZodString;
343
548
 
344
549
  export { }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@combeenation/custom-code-sdk",
3
- "version": "0.0.1-alpha6",
3
+ "version": "0.0.1-alpha7",
4
4
  "description": "Combeenation custom code SDK package",
5
5
  "keywords": [],
6
6
  "homepage": "",
@@ -13,10 +13,9 @@
13
13
  "dist"
14
14
  ],
15
15
  "scripts": {
16
- "build": "npm run build:be-lib-types && npm run lint && vite build",
17
- "build:be-lib-types": "npm run build:types --workspace=@repo/be-lib",
16
+ "build": "npm run build:dependency-types && npm run lint && vite build",
18
17
  "build:clean": "npm install && rimraf dist && npm run build",
19
- "dev": "vite build --watch",
18
+ "build:dependency-types": "npm run build:types --workspace=@repo/std-lib && npm run build:types --workspace=@repo/be-lib && npm run build:types --workspace=@combeenation/configurator-client",
20
19
  "lint": "eslint src/**/*.ts*",
21
20
  "pack": "npm run build:clean && npm pack",
22
21
  "pub:alpha": "npm run build:clean && npm publish --tag alpha",