@syntrologie/runtime-sdk 0.2.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.
Files changed (163) hide show
  1. package/README.md +185 -0
  2. package/dist/SmartCanvasApp.d.ts +29 -0
  3. package/dist/SmartCanvasApp.js +68 -0
  4. package/dist/SmartCanvasApp.js.map +1 -0
  5. package/dist/SmartCanvasElement.d.ts +29 -0
  6. package/dist/SmartCanvasElement.js +133 -0
  7. package/dist/SmartCanvasElement.js.map +1 -0
  8. package/dist/SmartCanvasPortal.d.ts +7 -0
  9. package/dist/SmartCanvasPortal.js +17 -0
  10. package/dist/SmartCanvasPortal.js.map +1 -0
  11. package/dist/antiFlicker.d.ts +10 -0
  12. package/dist/antiFlicker.js +39 -0
  13. package/dist/antiFlicker.js.map +1 -0
  14. package/dist/api.d.ts +60 -0
  15. package/dist/api.js +159 -0
  16. package/dist/api.js.map +1 -0
  17. package/dist/bootstrap.d.ts +62 -0
  18. package/dist/bootstrap.js +83 -0
  19. package/dist/bootstrap.js.map +1 -0
  20. package/dist/bundle-entry.d.ts +4 -0
  21. package/dist/bundle-entry.js +9 -0
  22. package/dist/bundle-entry.js.map +1 -0
  23. package/dist/components/RectangleCard.d.ts +15 -0
  24. package/dist/components/RectangleCard.js +226 -0
  25. package/dist/components/RectangleCard.js.map +1 -0
  26. package/dist/components/RectangleWheel.d.ts +8 -0
  27. package/dist/components/RectangleWheel.js +30 -0
  28. package/dist/components/RectangleWheel.js.map +1 -0
  29. package/dist/components/ShadowCanvasOverlay.d.ts +26 -0
  30. package/dist/components/ShadowCanvasOverlay.js +163 -0
  31. package/dist/components/ShadowCanvasOverlay.js.map +1 -0
  32. package/dist/configFetcher.d.ts +15 -0
  33. package/dist/configFetcher.js +90 -0
  34. package/dist/configFetcher.js.map +1 -0
  35. package/dist/controller.d.ts +15 -0
  36. package/dist/controller.js +34 -0
  37. package/dist/controller.js.map +1 -0
  38. package/dist/earlyPatcher.d.ts +23 -0
  39. package/dist/earlyPatcher.js +70 -0
  40. package/dist/earlyPatcher.js.map +1 -0
  41. package/dist/editorLoader.d.ts +17 -0
  42. package/dist/editorLoader.js +95 -0
  43. package/dist/editorLoader.js.map +1 -0
  44. package/dist/experiments/adapters/growthbook.d.ts +45 -0
  45. package/dist/experiments/adapters/growthbook.js +79 -0
  46. package/dist/experiments/adapters/growthbook.js.map +1 -0
  47. package/dist/experiments/index.d.ts +3 -0
  48. package/dist/experiments/index.js +4 -0
  49. package/dist/experiments/index.js.map +1 -0
  50. package/dist/experiments/registry.d.ts +13 -0
  51. package/dist/experiments/registry.js +30 -0
  52. package/dist/experiments/registry.js.map +1 -0
  53. package/dist/experiments/types.d.ts +25 -0
  54. package/dist/experiments/types.js +2 -0
  55. package/dist/experiments/types.js.map +1 -0
  56. package/dist/fetchers/cdnFetcher.d.ts +35 -0
  57. package/dist/fetchers/cdnFetcher.js +100 -0
  58. package/dist/fetchers/cdnFetcher.js.map +1 -0
  59. package/dist/fetchers/experimentsFetcher.d.ts +33 -0
  60. package/dist/fetchers/experimentsFetcher.js +42 -0
  61. package/dist/fetchers/experimentsFetcher.js.map +1 -0
  62. package/dist/fetchers/index.d.ts +3 -0
  63. package/dist/fetchers/index.js +5 -0
  64. package/dist/fetchers/index.js.map +1 -0
  65. package/dist/fetchers/registry.d.ts +14 -0
  66. package/dist/fetchers/registry.js +58 -0
  67. package/dist/fetchers/registry.js.map +1 -0
  68. package/dist/fetchers/types.d.ts +26 -0
  69. package/dist/fetchers/types.js +2 -0
  70. package/dist/fetchers/types.js.map +1 -0
  71. package/dist/hooks/useCanvasOverlays.d.ts +13 -0
  72. package/dist/hooks/useCanvasOverlays.js +59 -0
  73. package/dist/hooks/useCanvasOverlays.js.map +1 -0
  74. package/dist/hooks/useHostPatches.d.ts +9 -0
  75. package/dist/hooks/useHostPatches.js +40 -0
  76. package/dist/hooks/useHostPatches.js.map +1 -0
  77. package/dist/hooks/useShadowCanvasConfig.d.ts +20 -0
  78. package/dist/hooks/useShadowCanvasConfig.js +46 -0
  79. package/dist/hooks/useShadowCanvasConfig.js.map +1 -0
  80. package/dist/hostPatcher/core/patcher.d.ts +3 -0
  81. package/dist/hostPatcher/core/patcher.js +173 -0
  82. package/dist/hostPatcher/core/patcher.js.map +1 -0
  83. package/dist/hostPatcher/core/sanitizer.d.ts +1 -0
  84. package/dist/hostPatcher/core/sanitizer.js +45 -0
  85. package/dist/hostPatcher/core/sanitizer.js.map +1 -0
  86. package/dist/hostPatcher/core/types.d.ts +94 -0
  87. package/dist/hostPatcher/core/types.js +2 -0
  88. package/dist/hostPatcher/core/types.js.map +1 -0
  89. package/dist/hostPatcher/index.d.ts +6 -0
  90. package/dist/hostPatcher/index.js +7 -0
  91. package/dist/hostPatcher/index.js.map +1 -0
  92. package/dist/hostPatcher/policy/defaultPolicy.d.ts +2 -0
  93. package/dist/hostPatcher/policy/defaultPolicy.js +41 -0
  94. package/dist/hostPatcher/policy/defaultPolicy.js.map +1 -0
  95. package/dist/hostPatcher/utils/anchors.d.ts +13 -0
  96. package/dist/hostPatcher/utils/anchors.js +107 -0
  97. package/dist/hostPatcher/utils/anchors.js.map +1 -0
  98. package/dist/hostPatcher/utils/observer.d.ts +3 -0
  99. package/dist/hostPatcher/utils/observer.js +11 -0
  100. package/dist/hostPatcher/utils/observer.js.map +1 -0
  101. package/dist/index.d.ts +20 -0
  102. package/dist/index.js +20 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/overlays/fetcher.d.ts +4 -0
  105. package/dist/overlays/fetcher.js +17 -0
  106. package/dist/overlays/fetcher.js.map +1 -0
  107. package/dist/overlays/runtime/anchor/resolve.d.ts +4 -0
  108. package/dist/overlays/runtime/anchor/resolve.js +87 -0
  109. package/dist/overlays/runtime/anchor/resolve.js.map +1 -0
  110. package/dist/overlays/runtime/index.d.ts +6 -0
  111. package/dist/overlays/runtime/index.js +7 -0
  112. package/dist/overlays/runtime/index.js.map +1 -0
  113. package/dist/overlays/runtime/overlay/highlight.d.ts +10 -0
  114. package/dist/overlays/runtime/overlay/highlight.js +152 -0
  115. package/dist/overlays/runtime/overlay/highlight.js.map +1 -0
  116. package/dist/overlays/runtime/overlay/root.d.ts +4 -0
  117. package/dist/overlays/runtime/overlay/root.js +165 -0
  118. package/dist/overlays/runtime/overlay/root.js.map +1 -0
  119. package/dist/overlays/runtime/overlay/runner.d.ts +2 -0
  120. package/dist/overlays/runtime/overlay/runner.js +101 -0
  121. package/dist/overlays/runtime/overlay/runner.js.map +1 -0
  122. package/dist/overlays/runtime/overlay/tooltip.d.ts +14 -0
  123. package/dist/overlays/runtime/overlay/tooltip.js +174 -0
  124. package/dist/overlays/runtime/overlay/tooltip.js.map +1 -0
  125. package/dist/overlays/runtime/utils/dom.d.ts +2 -0
  126. package/dist/overlays/runtime/utils/dom.js +9 -0
  127. package/dist/overlays/runtime/utils/dom.js.map +1 -0
  128. package/dist/overlays/schema.d.ts +907 -0
  129. package/dist/overlays/schema.js +48 -0
  130. package/dist/overlays/schema.js.map +1 -0
  131. package/dist/overlays/types.d.ts +68 -0
  132. package/dist/overlays/types.js +2 -0
  133. package/dist/overlays/types.js.map +1 -0
  134. package/dist/react.d.ts +99 -0
  135. package/dist/react.js +119 -0
  136. package/dist/react.js.map +1 -0
  137. package/dist/smart-canvas.esm.js +202 -0
  138. package/dist/smart-canvas.esm.js.map +7 -0
  139. package/dist/smart-canvas.js +40406 -0
  140. package/dist/smart-canvas.js.map +7 -0
  141. package/dist/smart-canvas.min.js +202 -0
  142. package/dist/smart-canvas.min.js.map +7 -0
  143. package/dist/telemetry/adapters/posthog.d.ts +67 -0
  144. package/dist/telemetry/adapters/posthog.js +61 -0
  145. package/dist/telemetry/adapters/posthog.js.map +1 -0
  146. package/dist/telemetry/index.d.ts +3 -0
  147. package/dist/telemetry/index.js +3 -0
  148. package/dist/telemetry/index.js.map +1 -0
  149. package/dist/telemetry/registry.d.ts +13 -0
  150. package/dist/telemetry/registry.js +27 -0
  151. package/dist/telemetry/registry.js.map +1 -0
  152. package/dist/telemetry/types.d.ts +28 -0
  153. package/dist/telemetry/types.js +2 -0
  154. package/dist/telemetry/types.js.map +1 -0
  155. package/dist/token.d.ts +36 -0
  156. package/dist/token.js +47 -0
  157. package/dist/token.js.map +1 -0
  158. package/dist/types.d.ts +147 -0
  159. package/dist/types.js +5 -0
  160. package/dist/types.js.map +1 -0
  161. package/package.json +64 -0
  162. package/schema/canvas-config.schema.json +329 -0
  163. package/scripts/validate-config.mjs +80 -0
@@ -0,0 +1,45 @@
1
+ /**
2
+ * GrowthBook adapter for the ExperimentClient interface.
3
+ *
4
+ * This file is INTERNAL - consumers should only import from experiments/types.ts
5
+ * and use the ExperimentClient interface.
6
+ */
7
+ import { GrowthBook } from "@growthbook/growthbook-react";
8
+ import type { Context as GrowthBookInitOptions } from "@growthbook/growthbook";
9
+ import type { ExperimentClient } from "../types";
10
+ import type { RectangleConfig } from "../../types";
11
+ /**
12
+ * Default API host for GrowthBook experiments.
13
+ */
14
+ export declare const DEFAULT_EXPERIMENT_API_HOST = "https://experiment.syntrologie.com";
15
+ export interface GrowthBookAdapterOptions extends GrowthBookInitOptions {
16
+ /**
17
+ * Existing GrowthBook instance to wrap.
18
+ * If not provided, a new instance will be created.
19
+ */
20
+ client?: GrowthBook;
21
+ /**
22
+ * Auto-initialize with streaming enabled.
23
+ */
24
+ autoInit?: boolean;
25
+ }
26
+ /**
27
+ * Internal adapter that implements ExperimentClient using GrowthBook.
28
+ */
29
+ export declare class GrowthBookAdapter implements ExperimentClient {
30
+ private readonly gb;
31
+ constructor(options?: GrowthBookAdapterOptions);
32
+ /**
33
+ * Access to the underlying GrowthBook instance.
34
+ * Only use this internally - don't expose to consumers.
35
+ */
36
+ get _internal(): GrowthBook;
37
+ refreshFeatures(): Promise<void>;
38
+ setAttributes(attrs: Record<string, unknown>): void;
39
+ getFeatureValue<T>(key: string, fallback: T): T;
40
+ shouldRenderRectangle(rectangle: RectangleConfig): boolean;
41
+ }
42
+ /**
43
+ * Create an ExperimentClient backed by GrowthBook.
44
+ */
45
+ export declare function createGrowthBookClient(options?: GrowthBookAdapterOptions): ExperimentClient;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * GrowthBook adapter for the ExperimentClient interface.
3
+ *
4
+ * This file is INTERNAL - consumers should only import from experiments/types.ts
5
+ * and use the ExperimentClient interface.
6
+ */
7
+ import { GrowthBook } from "@growthbook/growthbook-react";
8
+ /**
9
+ * Default API host for GrowthBook experiments.
10
+ */
11
+ export const DEFAULT_EXPERIMENT_API_HOST = "https://experiment.syntrologie.com";
12
+ /**
13
+ * Internal adapter that implements ExperimentClient using GrowthBook.
14
+ */
15
+ export class GrowthBookAdapter {
16
+ constructor(options = {}) {
17
+ var _a;
18
+ if (options.client) {
19
+ this.gb = options.client;
20
+ }
21
+ else {
22
+ this.gb = new GrowthBook({
23
+ ...options,
24
+ apiHost: (_a = options.apiHost) !== null && _a !== void 0 ? _a : DEFAULT_EXPERIMENT_API_HOST,
25
+ });
26
+ if (options.autoInit) {
27
+ this.gb.init({ streaming: true });
28
+ }
29
+ }
30
+ }
31
+ /**
32
+ * Access to the underlying GrowthBook instance.
33
+ * Only use this internally - don't expose to consumers.
34
+ */
35
+ get _internal() {
36
+ return this.gb;
37
+ }
38
+ async refreshFeatures() {
39
+ await this.gb.loadFeatures();
40
+ }
41
+ setAttributes(attrs) {
42
+ this.gb.setAttributes(attrs);
43
+ }
44
+ getFeatureValue(key, fallback) {
45
+ return this.gb.getFeatureValue(key, fallback);
46
+ }
47
+ shouldRenderRectangle(rectangle) {
48
+ const experiment = rectangle.experiment;
49
+ if (!experiment)
50
+ return true;
51
+ if (!experiment.featureKey)
52
+ return true;
53
+ const value = this.gb.getFeatureValue(experiment.featureKey, null);
54
+ if (value === null || value === undefined)
55
+ return false;
56
+ if (typeof experiment.variationId === "number") {
57
+ return Number(value) === experiment.variationId;
58
+ }
59
+ if (typeof experiment.variationValue !== "undefined") {
60
+ return value === experiment.variationValue;
61
+ }
62
+ if (experiment.predicate) {
63
+ try {
64
+ return experiment.predicate(value);
65
+ }
66
+ catch {
67
+ return false;
68
+ }
69
+ }
70
+ return Boolean(value);
71
+ }
72
+ }
73
+ /**
74
+ * Create an ExperimentClient backed by GrowthBook.
75
+ */
76
+ export function createGrowthBookClient(options = {}) {
77
+ return new GrowthBookAdapter(options);
78
+ }
79
+ //# sourceMappingURL=growthbook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"growthbook.js","sourceRoot":"","sources":["../../../src/experiments/adapters/growthbook.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAK1D;;GAEG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,oCAAoC,CAAC;AAehF;;GAEG;AACH,MAAM,OAAO,iBAAiB;IAG5B,YAAY,UAAoC,EAAE;;QAChD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,EAAE,GAAG,IAAI,UAAU,CAAC;gBACvB,GAAG,OAAO;gBACV,OAAO,EAAE,MAAA,OAAO,CAAC,OAAO,mCAAI,2BAA2B;aACxD,CAAC,CAAC;YACH,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC;IAC/B,CAAC;IAED,aAAa,CAAC,KAA8B;QAC1C,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,eAAe,CAAI,GAAW,EAAE,QAAW;QACzC,OAAO,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE,QAAQ,CAAM,CAAC;IACrD,CAAC;IAED,qBAAqB,CAAC,SAA0B;QAC9C,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC;QACxC,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAExC,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACnE,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAExD,IAAI,OAAO,UAAU,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;YAC/C,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC,WAAW,CAAC;QAClD,CAAC;QACD,IAAI,OAAO,UAAU,CAAC,cAAc,KAAK,WAAW,EAAE,CAAC;YACrD,OAAO,KAAK,KAAK,UAAU,CAAC,cAAc,CAAC;QAC7C,CAAC;QACD,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,OAAO,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACrC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CACpC,UAAoC,EAAE;IAEtC,OAAO,IAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export type { ExperimentClient, SyntroExperimentClient } from "./types";
2
+ export { createGrowthBookClient } from "./adapters/growthbook";
3
+ export type { GrowthBookAdapterOptions } from "./adapters/growthbook";
@@ -0,0 +1,4 @@
1
+ // Adapter factory - consumers use this to create clients
2
+ // but don't need to know about the internal implementation
3
+ export { createGrowthBookClient } from "./adapters/growthbook";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/experiments/index.ts"],"names":[],"mappings":"AAGA,yDAAyD;AACzD,2DAA2D;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { ExperimentClient } from "./types";
2
+ /**
3
+ * Create an experiment client for the specified provider.
4
+ *
5
+ * @param provider - Provider name (e.g., "growthbook")
6
+ * @param config - Provider-specific configuration
7
+ * @returns An ExperimentClient instance
8
+ * @throws Error if the provider is not supported
9
+ */
10
+ export declare function createExperimentClient(provider: string, config: {
11
+ clientKey: string;
12
+ apiHost?: string;
13
+ }): ExperimentClient;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Experiment provider registry.
3
+ *
4
+ * Maps provider names to their adapter factories.
5
+ * This allows the bootstrap module to dynamically create
6
+ * experiment clients based on token configuration.
7
+ */
8
+ import { createGrowthBookClient } from "./adapters/growthbook";
9
+ const adapters = {
10
+ growthbook: (config) => createGrowthBookClient({
11
+ ...config,
12
+ autoInit: true,
13
+ }),
14
+ };
15
+ /**
16
+ * Create an experiment client for the specified provider.
17
+ *
18
+ * @param provider - Provider name (e.g., "growthbook")
19
+ * @param config - Provider-specific configuration
20
+ * @returns An ExperimentClient instance
21
+ * @throws Error if the provider is not supported
22
+ */
23
+ export function createExperimentClient(provider, config) {
24
+ const factory = adapters[provider];
25
+ if (!factory) {
26
+ throw new Error(`Unknown experiment provider: ${provider}. Supported: ${Object.keys(adapters).join(", ")}`);
27
+ }
28
+ return factory(config);
29
+ }
30
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/experiments/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,sBAAsB,EAA4B,MAAM,uBAAuB,CAAC;AAKzF,MAAM,QAAQ,GAAmC;IAC/C,UAAU,EAAE,CAAC,MAAgC,EAAE,EAAE,CAC/C,sBAAsB,CAAC;QACrB,GAAG,MAAM;QACT,QAAQ,EAAE,IAAI;KACf,CAAC;CACL,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAAgB,EAChB,MAA+C;IAE/C,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,gCAAgC,QAAQ,gBAAgB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC;AACzB,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { RectangleConfig } from "../types";
2
+ /**
3
+ * Clean interface for experiment/feature flag clients.
4
+ *
5
+ * This is the ONLY interface consumers should use. The underlying
6
+ * implementation (GrowthBook, LaunchDarkly, etc.) is an internal detail.
7
+ */
8
+ export interface ExperimentClient {
9
+ /**
10
+ * Check if a rectangle/tile should be rendered based on its experiment config.
11
+ */
12
+ shouldRenderRectangle(rectangle: RectangleConfig): boolean;
13
+ /**
14
+ * Get a feature flag value.
15
+ */
16
+ getFeatureValue?<T>(key: string, fallback: T): T;
17
+ /**
18
+ * Update user/device attributes for targeting.
19
+ */
20
+ setAttributes?(attrs: Record<string, unknown>): void;
21
+ }
22
+ /**
23
+ * @deprecated Use ExperimentClient instead
24
+ */
25
+ export type SyntroExperimentClient = ExperimentClient;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/experiments/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ import type { ConfigFetcher, FetchResult } from "./types";
2
+ export interface CdnFetcherOptions {
3
+ /**
4
+ * Base CDN URL (e.g., "https://cdn.syntrologie.com/configs")
5
+ */
6
+ baseUrl: string;
7
+ /**
8
+ * Unique config identifier (UUID).
9
+ * This should be unguessable to prevent unauthorized access.
10
+ */
11
+ configId: string;
12
+ /**
13
+ * Optional SRI hash for integrity verification.
14
+ */
15
+ integrity?: string;
16
+ }
17
+ /**
18
+ * Fetches config from CDN using UUID-based paths.
19
+ *
20
+ * Security: Config paths use UUIDs which are unguessable.
21
+ * Each client has a unique config path that cannot be enumerated.
22
+ *
23
+ * Performance: CDN-cached with long TTL for versioned configs.
24
+ */
25
+ export declare class CdnFetcher implements ConfigFetcher {
26
+ readonly name = "cdn";
27
+ private url;
28
+ private integrity?;
29
+ constructor(options: CdnFetcherOptions);
30
+ fetch(): Promise<FetchResult>;
31
+ }
32
+ /**
33
+ * Factory function for creating a CDN fetcher.
34
+ */
35
+ export declare function createCdnFetcher(options: CdnFetcherOptions): ConfigFetcher;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Allowed CDN hosts for config fetching.
3
+ */
4
+ const ALLOWED_CDN_HOSTS = [
5
+ 'cdn.syntrologie.com',
6
+ 'localhost',
7
+ '127.0.0.1'
8
+ ];
9
+ /**
10
+ * Validates that a CDN URL is from an allowed host.
11
+ */
12
+ function validateCdnUrl(url) {
13
+ try {
14
+ const parsed = new URL(url);
15
+ const isLocalhost = /^(localhost|127\.0\.0\.1)$/.test(parsed.hostname);
16
+ if (parsed.protocol !== 'https:' && !isLocalhost) {
17
+ console.warn('[SmartCanvas] CDN URL must use HTTPS:', url);
18
+ return false;
19
+ }
20
+ const isAllowed = ALLOWED_CDN_HOSTS.some(host => parsed.hostname === host);
21
+ if (!isAllowed) {
22
+ console.warn('[SmartCanvas] CDN host not in allowlist:', parsed.hostname);
23
+ return false;
24
+ }
25
+ return true;
26
+ }
27
+ catch {
28
+ console.warn('[SmartCanvas] Invalid CDN URL:', url);
29
+ return false;
30
+ }
31
+ }
32
+ /**
33
+ * Fetches config from CDN using UUID-based paths.
34
+ *
35
+ * Security: Config paths use UUIDs which are unguessable.
36
+ * Each client has a unique config path that cannot be enumerated.
37
+ *
38
+ * Performance: CDN-cached with long TTL for versioned configs.
39
+ */
40
+ export class CdnFetcher {
41
+ constructor(options) {
42
+ this.name = "cdn";
43
+ this.url = `${options.baseUrl}/${options.configId}.json`;
44
+ this.integrity = options.integrity;
45
+ if (!validateCdnUrl(this.url)) {
46
+ throw new Error(`[SmartCanvas] CDN URL not allowed: ${this.url}`);
47
+ }
48
+ }
49
+ async fetch() {
50
+ var _a;
51
+ const start = performance.now();
52
+ const response = await fetch(this.url, {
53
+ credentials: 'omit', // Never send cookies to CDN
54
+ cache: 'default',
55
+ });
56
+ if (!response.ok) {
57
+ throw new Error(`[SmartCanvas] Failed to fetch config from CDN (${response.status})`);
58
+ }
59
+ const text = await response.text();
60
+ // Verify integrity if provided
61
+ if (this.integrity) {
62
+ const hash = await computeSha384(text);
63
+ const expected = this.integrity.replace('sha384-', '');
64
+ if (hash !== expected) {
65
+ throw new Error(`[SmartCanvas] Config integrity check failed. Expected ${expected}, got ${hash}`);
66
+ }
67
+ }
68
+ const config = JSON.parse(text);
69
+ const fetchTimeMs = performance.now() - start;
70
+ // Check cache headers
71
+ const cacheControl = response.headers.get('cache-control');
72
+ const age = response.headers.get('age');
73
+ return {
74
+ config,
75
+ meta: {
76
+ source: "cdn",
77
+ fetchTimeMs,
78
+ cached: (_a = cacheControl === null || cacheControl === void 0 ? void 0 : cacheControl.includes('public')) !== null && _a !== void 0 ? _a : false,
79
+ cacheAge: age ? parseInt(age, 10) : undefined,
80
+ },
81
+ };
82
+ }
83
+ }
84
+ /**
85
+ * Compute SHA-384 hash in base64 format (for SRI).
86
+ */
87
+ async function computeSha384(content) {
88
+ const encoder = new TextEncoder();
89
+ const data = encoder.encode(content);
90
+ const hashBuffer = await crypto.subtle.digest('SHA-384', data);
91
+ const hashArray = new Uint8Array(hashBuffer);
92
+ return btoa(String.fromCharCode(...hashArray));
93
+ }
94
+ /**
95
+ * Factory function for creating a CDN fetcher.
96
+ */
97
+ export function createCdnFetcher(options) {
98
+ return new CdnFetcher(options);
99
+ }
100
+ //# sourceMappingURL=cdnFetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdnFetcher.js","sourceRoot":"","sources":["../../src/fetchers/cdnFetcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { ConfigFetcher, FetchResult } from "./types";
2
+ import type { ExperimentClient } from "../experiments/types";
3
+ export interface ExperimentsFetcherOptions {
4
+ /**
5
+ * Experiment client instance (e.g., from createGrowthBookClient).
6
+ */
7
+ client: ExperimentClient;
8
+ /**
9
+ * Feature key that contains the config object.
10
+ * @default "smart-canvas-config"
11
+ */
12
+ featureKey?: string;
13
+ }
14
+ /**
15
+ * Fetches config from an experiment/feature flag system.
16
+ *
17
+ * Security: Config is scoped to the experiment client's environment/SDK key.
18
+ * Each client only sees their own config.
19
+ *
20
+ * Performance: No network request needed if features are already cached.
21
+ * Config is delivered with the feature flag payload.
22
+ */
23
+ export declare class ExperimentsFetcher implements ConfigFetcher {
24
+ readonly name = "experiments";
25
+ private client;
26
+ private featureKey;
27
+ constructor(options: ExperimentsFetcherOptions);
28
+ fetch(): Promise<FetchResult>;
29
+ }
30
+ /**
31
+ * Factory function for creating an experiments-based fetcher.
32
+ */
33
+ export declare function createExperimentsFetcher(options: ExperimentsFetcherOptions): ConfigFetcher;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Fetches config from an experiment/feature flag system.
3
+ *
4
+ * Security: Config is scoped to the experiment client's environment/SDK key.
5
+ * Each client only sees their own config.
6
+ *
7
+ * Performance: No network request needed if features are already cached.
8
+ * Config is delivered with the feature flag payload.
9
+ */
10
+ export class ExperimentsFetcher {
11
+ constructor(options) {
12
+ var _a;
13
+ this.name = "experiments";
14
+ this.client = options.client;
15
+ this.featureKey = (_a = options.featureKey) !== null && _a !== void 0 ? _a : "smart-canvas-config";
16
+ }
17
+ async fetch() {
18
+ var _a, _b;
19
+ const start = performance.now();
20
+ const config = (_b = (_a = this.client).getFeatureValue) === null || _b === void 0 ? void 0 : _b.call(_a, this.featureKey, null);
21
+ if (!config || typeof config !== "object") {
22
+ throw new Error(`[SmartCanvas] Feature "${this.featureKey}" not found or invalid. ` +
23
+ `Ensure the feature is configured in your experiment platform.`);
24
+ }
25
+ const fetchTimeMs = performance.now() - start;
26
+ return {
27
+ config: config,
28
+ meta: {
29
+ source: "experiments",
30
+ fetchTimeMs,
31
+ cached: true,
32
+ },
33
+ };
34
+ }
35
+ }
36
+ /**
37
+ * Factory function for creating an experiments-based fetcher.
38
+ */
39
+ export function createExperimentsFetcher(options) {
40
+ return new ExperimentsFetcher(options);
41
+ }
42
+ //# sourceMappingURL=experimentsFetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"experimentsFetcher.js","sourceRoot":"","sources":["../../src/fetchers/experimentsFetcher.ts"],"names":[],"mappings":"AAiBA;;;;;;;;GAQG;AACH,MAAM,OAAO,kBAAkB;IAM7B,YAAY,OAAkC;;QALrC,SAAI,GAAG,aAAa,CAAC;QAM5B,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,MAAA,OAAO,CAAC,UAAU,mCAAI,qBAAqB,CAAC;IAChE,CAAC;IAED,KAAK,CAAC,KAAK;;QACT,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAEhC,MAAM,MAAM,GAAG,MAAA,MAAA,IAAI,CAAC,MAAM,EAAC,eAAe,mDAAG,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAEpE,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CACb,0BAA0B,IAAI,CAAC,UAAU,0BAA0B;gBACnE,+DAA+D,CAChE,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QAE9C,OAAO;YACL,MAAM,EAAE,MAAoC;YAC5C,IAAI,EAAE;gBACJ,MAAM,EAAE,aAAa;gBACrB,WAAW;gBACX,MAAM,EAAE,IAAI;aACb;SACF,CAAC;IACJ,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAAkC;IAElC,OAAO,IAAI,kBAAkB,CAAC,OAAO,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export type { ConfigFetcher, FetchResult } from "./types";
2
+ export { ExperimentsFetcher, createExperimentsFetcher, type ExperimentsFetcherOptions, } from "./experimentsFetcher";
3
+ export { CdnFetcher, createCdnFetcher, type CdnFetcherOptions, } from "./cdnFetcher";
@@ -0,0 +1,5 @@
1
+ // Experiments-based fetcher (GrowthBook, LaunchDarkly, etc.)
2
+ export { ExperimentsFetcher, createExperimentsFetcher, } from "./experimentsFetcher";
3
+ // CDN fetcher with UUID-based paths
4
+ export { CdnFetcher, createCdnFetcher, } from "./cdnFetcher";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fetchers/index.ts"],"names":[],"mappings":"AAGA,6DAA6D;AAC7D,OAAO,EACL,kBAAkB,EAClB,wBAAwB,GAEzB,MAAM,sBAAsB,CAAC;AAE9B,oCAAoC;AACpC,OAAO,EACL,UAAU,EACV,gBAAgB,GAEjB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { ConfigFetcher } from "./types";
2
+ /**
3
+ * Default CDN base URL for config fetching.
4
+ */
5
+ export declare const DEFAULT_CDN_BASE_URL = "https://cdn.syntrologie.com/configs";
6
+ /**
7
+ * Create a config fetcher for the specified type.
8
+ *
9
+ * @param type - Fetcher type (e.g., "cdn", "experiments")
10
+ * @param options - Fetcher-specific options
11
+ * @returns A ConfigFetcher instance
12
+ * @throws Error if the fetcher type is not supported
13
+ */
14
+ export declare function createConfigFetcher(type: string, options?: Record<string, string>): ConfigFetcher;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Config fetcher registry.
3
+ *
4
+ * Maps fetcher type names to their factory functions.
5
+ * This allows the bootstrap module to dynamically create
6
+ * fetchers based on token configuration.
7
+ */
8
+ import { createCdnFetcher } from "./cdnFetcher";
9
+ import { createExperimentsFetcher } from "./experimentsFetcher";
10
+ /**
11
+ * Default CDN base URL for config fetching.
12
+ */
13
+ export const DEFAULT_CDN_BASE_URL = "https://cdn.syntrologie.com/configs";
14
+ const fetchers = {
15
+ /**
16
+ * CDN fetcher - fetches config from Syntrologie CDN.
17
+ * Options: configId (required), integrity (optional)
18
+ */
19
+ cdn: (options) => {
20
+ var _a;
21
+ if (!options.configId) {
22
+ throw new Error("CDN fetcher requires 'configId' option");
23
+ }
24
+ return createCdnFetcher({
25
+ baseUrl: (_a = options.baseUrl) !== null && _a !== void 0 ? _a : DEFAULT_CDN_BASE_URL,
26
+ configId: options.configId,
27
+ integrity: options.integrity,
28
+ });
29
+ },
30
+ /**
31
+ * Experiments fetcher - fetches config based on experiment variations.
32
+ * Options: featureKey (required)
33
+ */
34
+ experiments: (options) => {
35
+ if (!options.featureKey) {
36
+ throw new Error("Experiments fetcher requires 'featureKey' option");
37
+ }
38
+ return createExperimentsFetcher({
39
+ featureKey: options.featureKey,
40
+ });
41
+ },
42
+ };
43
+ /**
44
+ * Create a config fetcher for the specified type.
45
+ *
46
+ * @param type - Fetcher type (e.g., "cdn", "experiments")
47
+ * @param options - Fetcher-specific options
48
+ * @returns A ConfigFetcher instance
49
+ * @throws Error if the fetcher type is not supported
50
+ */
51
+ export function createConfigFetcher(type, options = {}) {
52
+ const factory = fetchers[type];
53
+ if (!factory) {
54
+ throw new Error(`Unknown config fetcher type: ${type}. Supported: ${Object.keys(fetchers).join(", ")}`);
55
+ }
56
+ return factory(options);
57
+ }
58
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/fetchers/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,gBAAgB,EAAqB,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,wBAAwB,EAA6B,MAAM,sBAAsB,CAAC;AAG3F;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,qCAAqC,CAAC;AAI1E,MAAM,QAAQ,GAAmC;IAC/C;;;OAGG;IACH,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE;;QACf,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,gBAAgB,CAAC;YACtB,OAAO,EAAE,MAAA,OAAO,CAAC,OAAO,mCAAI,oBAAoB;YAChD,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,SAAS,EAAE,OAAO,CAAC,SAAS;SACR,CAAC,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACH,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE;QACvB,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtE,CAAC;QACD,OAAO,wBAAwB,CAAC;YAC9B,UAAU,EAAE,OAAO,CAAC,UAAU;SACF,CAAC,CAAC;IAClC,CAAC;CACF,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAY,EACZ,UAAkC,EAAE;IAEpC,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,gCAAgC,IAAI,gBAAgB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACvF,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { ShadowCanvasConfigResponse } from "../types";
2
+ /**
3
+ * Result from a config fetch, including timing metadata.
4
+ */
5
+ export interface FetchResult {
6
+ config: ShadowCanvasConfigResponse;
7
+ meta: {
8
+ source: 'experiments' | 'cdn' | 'cache';
9
+ fetchTimeMs: number;
10
+ cached?: boolean;
11
+ cacheAge?: number;
12
+ };
13
+ }
14
+ /**
15
+ * Base interface for all config fetchers.
16
+ */
17
+ export interface ConfigFetcher {
18
+ /**
19
+ * Fetch the config.
20
+ */
21
+ fetch(): Promise<FetchResult>;
22
+ /**
23
+ * Name of this fetcher for logging/debugging.
24
+ */
25
+ readonly name: string;
26
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/fetchers/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ import type { ExperimentClient } from "../experiments/types";
2
+ import type { TelemetryClient } from "../telemetry/types";
3
+ import { type OverlayRecipeFetcher } from "../overlays/fetcher";
4
+ export interface UseCanvasOverlaysOptions {
5
+ fetcher?: OverlayRecipeFetcher;
6
+ configUri?: string;
7
+ featureKey?: string;
8
+ credentials?: RequestCredentials;
9
+ experiments?: ExperimentClient;
10
+ telemetry?: TelemetryClient;
11
+ canvasHost?: HTMLElement | null;
12
+ }
13
+ export declare function useCanvasOverlays({ fetcher, configUri, featureKey, credentials, experiments, telemetry, canvasHost, }: UseCanvasOverlaysOptions): void;
@@ -0,0 +1,59 @@
1
+ import { useEffect, useMemo } from "react";
2
+ import { createOverlayRecipeFetcher } from "../overlays/fetcher";
3
+ import { CanvasRecipeZ } from "../overlays/schema";
4
+ export function useCanvasOverlays({ fetcher, configUri, featureKey, credentials, experiments, telemetry, canvasHost, }) {
5
+ const derivedFetcher = useMemo(() => {
6
+ // Priority 1: Use explicit fetcher if provided
7
+ if (fetcher)
8
+ return fetcher;
9
+ // Priority 2: Only create a fetcher if we have an explicit configUri
10
+ // (inline recipes are passed via the fetcher prop, not configUri)
11
+ if (configUri) {
12
+ return createOverlayRecipeFetcher({
13
+ configUri,
14
+ experiments,
15
+ featureKey,
16
+ credentials,
17
+ validator: CanvasRecipeZ,
18
+ });
19
+ }
20
+ // No fetcher and no configUri = no overlays (waiting for inline recipe or none exist)
21
+ return undefined;
22
+ }, [fetcher, configUri, experiments, featureKey, credentials]);
23
+ useEffect(() => {
24
+ if (!derivedFetcher)
25
+ return;
26
+ let cancelled = false;
27
+ let cleanup;
28
+ (async () => {
29
+ var _a;
30
+ try {
31
+ const recipe = await derivedFetcher();
32
+ if (!((_a = recipe === null || recipe === void 0 ? void 0 : recipe.steps) === null || _a === void 0 ? void 0 : _a.length) || cancelled)
33
+ return;
34
+ const mod = await import("../overlays/runtime");
35
+ const overlayRoot = mod.ensureOverlayRoot();
36
+ const resolve = mod.createAnchorResolver({ canvasHost });
37
+ cleanup = await mod.runOverlays(recipe, {
38
+ overlayRoot,
39
+ resolve,
40
+ canvasHost,
41
+ onEvent: (name, payload) => {
42
+ var _a, _b;
43
+ if (!telemetry)
44
+ return;
45
+ (_a = telemetry.trackAction) === null || _a === void 0 ? void 0 : _a.call(telemetry, name, (_b = payload === null || payload === void 0 ? void 0 : payload.stepId) !== null && _b !== void 0 ? _b : "", "overlay");
46
+ },
47
+ });
48
+ }
49
+ catch (err) {
50
+ console.warn("[SmartCanvas] overlays failed", err);
51
+ }
52
+ })();
53
+ return () => {
54
+ cancelled = true;
55
+ cleanup === null || cleanup === void 0 ? void 0 : cleanup();
56
+ };
57
+ }, [derivedFetcher, telemetry, canvasHost]);
58
+ }
59
+ //# sourceMappingURL=useCanvasOverlays.js.map