@blotout/qinto-cli 0.1.24 → 0.1.26

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.
@@ -19140,7 +19140,7 @@ var endpointPathParams = (route) => {
19140
19140
  };
19141
19141
 
19142
19142
  // ../../../libs/app-manifest/src/tools.ts
19143
- var MAX_APP_TOOLS = 8;
19143
+ var MAX_APP_TOOLS = 20;
19144
19144
  var MAX_APP_TOOL_TITLE_LENGTH = 60;
19145
19145
  var MIN_APP_TOOL_DESCRIPTION = 20;
19146
19146
  var MAX_APP_TOOL_DESCRIPTION = 16 * 1024;
@@ -19148,7 +19148,7 @@ var MAX_APP_TOOL_PROPERTY_DESCRIPTION = 200;
19148
19148
  var MAX_APP_TOOL_PROPERTIES = 24;
19149
19149
  var MAX_APP_TOOL_SCHEMA_DEPTH = 4;
19150
19150
  var MAX_APP_TOOL_ENUM_VALUES = 32;
19151
- var MAX_MANIFEST_TOOLS_BYTES = 150 * 1024;
19151
+ var MAX_MANIFEST_TOOLS_BYTES = 375 * 1024;
19152
19152
  var TOOL_PROPERTY_NAME = /^[a-zA-Z][a-zA-Z0-9_]*$/;
19153
19153
  var RESERVED_TOOL_ARGUMENTS = ["teamId", "siteId", "installId"];
19154
19154
  var TOOL_STRING_FORMATS = ["uuid", "date", "date-time", "email", "uri"];
@@ -19354,6 +19354,7 @@ var APP_FLOWS = ["transform", "destination"];
19354
19354
  var TRANSFORM_ACTION_TYPES = ["track", "identify"];
19355
19355
  var EVENT_ACTION_TYPES = ["track", "identify", "consent"];
19356
19356
  var BROWSER_RESULT_ACTION_TYPES = ["track", "identify"];
19357
+ var BROWSER_HOOKS = ["transform"];
19357
19358
  var APP_LIFECYCLE_TYPES = ["installed", "configurationChanged", "enabled", "disabled", "versionChanged", "uninstalled"];
19358
19359
  var API_CAPABILITIES = ["track", "identify", "alias", "consentWrite", "consentRead", "propertiesRead", "sessionRead"];
19359
19360
  var DATA_CAPABILITIES = [
@@ -19364,7 +19365,8 @@ var DATA_CAPABILITIES = [
19364
19365
  "eventContext",
19365
19366
  "sharedContext",
19366
19367
  "facts",
19367
- "identity"
19368
+ "identity",
19369
+ "siteInstalls"
19368
19370
  ];
19369
19371
  var MAX_APP_VARIABLES = 32;
19370
19372
  var MAX_APP_SCOPE_VARIABLES = 16;
@@ -19642,7 +19644,8 @@ var baseSchema = external_exports.object({
19642
19644
  browser: external_exports.object({
19643
19645
  entry: external_exports.string().min(1).max(255).optional(),
19644
19646
  capture: captureSchema.optional(),
19645
- eventResults: external_exports.array(external_exports.enum(BROWSER_RESULT_ACTION_TYPES)).max(BROWSER_RESULT_ACTION_TYPES.length).optional()
19647
+ eventResults: external_exports.array(external_exports.enum(BROWSER_RESULT_ACTION_TYPES)).max(BROWSER_RESULT_ACTION_TYPES.length).optional(),
19648
+ hooks: external_exports.array(external_exports.enum(BROWSER_HOOKS)).max(BROWSER_HOOKS.length).optional()
19646
19649
  }).strict().optional().meta({
19647
19650
  description: "The app's browser surface: an optional entry for the bundle that ships inside the site's q.js, and the query params and cookies it declares for capture."
19648
19651
  }),
@@ -19946,6 +19949,15 @@ var validateCapture = (manifest, ctx) => {
19946
19949
  }
19947
19950
  }
19948
19951
  };
19952
+ var validateBrowserHooks = (manifest, ctx) => {
19953
+ const hooks = manifest.browser?.hooks ?? [];
19954
+ if (hooks.length > 0 && manifest.browser?.entry === void 0) {
19955
+ ctx.addIssue({ code: "custom", path: ["browser", "hooks"], message: "hooks needs a browser entry" });
19956
+ }
19957
+ if (hooks.includes("transform") && !manifest.flows.includes("transform")) {
19958
+ ctx.addIssue({ code: "custom", path: ["browser", "hooks"], message: "The browser transform hook needs the transform flow" });
19959
+ }
19960
+ };
19949
19961
  var validateRpc = (manifest, ctx) => {
19950
19962
  const exposes = manifest.rpc?.exposes ?? [];
19951
19963
  uniqueOrIssue(
@@ -20006,6 +20018,7 @@ var appManifestSchema = baseSchema.superRefine((manifest, ctx) => {
20006
20018
  validatePipelines(manifest, ctx);
20007
20019
  validateEndpoints(manifest, ctx);
20008
20020
  validateCapture(manifest, ctx);
20021
+ validateBrowserHooks(manifest, ctx);
20009
20022
  validateRpc(manifest, ctx);
20010
20023
  validateEvents(manifest, ctx);
20011
20024
  validateOauth(manifest, ctx);
@@ -20030,6 +20043,7 @@ var appRpcContractSchema = external_exports.record(external_exports.string().reg
20030
20043
  var ENVELOPE_VERSION = 3;
20031
20044
  var ENVELOPE_ERROR_CODES = ["invalid_arguments"];
20032
20045
  var MAX_INSTALLS_PER_APP = 15;
20046
+ var MAX_APPS_PER_DOMAIN = 50;
20033
20047
  var MAX_EMITS_PER_INSTALL = 10;
20034
20048
  var MAX_PUSHES_PER_INSTALL = 10;
20035
20049
  var MAX_CAPTURE_WRITES_PER_INSTALL = 10;
@@ -20043,6 +20057,10 @@ var MAX_RESPONSE_BYTES = 1024 * 1024;
20043
20057
  var MAX_RPC_BYTES = 128 * 1024;
20044
20058
  var installSchema = external_exports.object({ id: external_exports.string().min(1).max(64), ord: external_exports.number().int().min(1), label: external_exports.string().max(100) }).strict();
20045
20059
  var emitSchema = external_exports.object({ type: external_exports.literal("track"), occurredAt: external_exports.number().int().nonnegative().safe(), payload: external_exports.record(external_exports.string(), external_exports.unknown()) }).strict();
20060
+ var installRuleSchema = external_exports.object({
20061
+ mode: external_exports.enum(["except", "only"]),
20062
+ installIds: external_exports.array(external_exports.string().min(1).max(64)).max(MAX_APPS_PER_DOMAIN * MAX_INSTALLS_PER_APP)
20063
+ }).strict();
20046
20064
  var pushSchema = external_exports.object({ topic: external_exports.string().min(1).max(64), data: external_exports.unknown(), broadcast: external_exports.enum(PUSH_BROADCASTS).optional() }).strict().refine((push) => {
20047
20065
  return new TextEncoder().encode(JSON.stringify(push.data ?? null)).length <= MAX_PUSH_BYTES;
20048
20066
  }, "Push data exceeds the per-message size cap");
@@ -20129,7 +20147,11 @@ var envelopeRequestSchema = external_exports.object({
20129
20147
  var envelopeResponseSchema = external_exports.object({
20130
20148
  v: external_exports.literal(ENVELOPE_VERSION),
20131
20149
  // Transform invocations only: pass the action through, drop it, or replace its payload (§5.4).
20132
- result: external_exports.union([external_exports.literal("pass"), external_exports.literal("drop"), external_exports.object({ payload: external_exports.record(external_exports.string(), external_exports.unknown()) }).strict()]).optional(),
20150
+ result: external_exports.union([
20151
+ external_exports.literal("pass"),
20152
+ external_exports.literal("drop"),
20153
+ external_exports.object({ payload: external_exports.record(external_exports.string(), external_exports.unknown()).optional(), installs: installRuleSchema.optional() }).strict()
20154
+ ]).optional(),
20133
20155
  effects: external_exports.array(effectGroupSchema).optional(),
20134
20156
  rpc: external_exports.object({ result: external_exports.unknown() }).strict().refine((rpc) => {
20135
20157
  return new TextEncoder().encode(JSON.stringify(rpc.result ?? null)).length <= MAX_RPC_BYTES;
@@ -20471,6 +20493,12 @@ var appUiAnalyticsQueryPath = (domainId, appSlug2, resourceIdentifier) => {
20471
20493
  return `/app-ui/sites/${domainId}/apps/${appSlug2}/analytics/${resourceIdentifier}/query`;
20472
20494
  };
20473
20495
  var uiInstallSchema = external_exports.object({ id: external_exports.string().min(1).max(64), ord: external_exports.number().int().min(1), label: external_exports.string().max(100), enabled: external_exports.boolean() }).strict();
20496
+ var siteInstallSchema = external_exports.object({
20497
+ id: external_exports.string().min(1).max(64),
20498
+ appSlug: external_exports.string().min(1).max(30),
20499
+ appName: external_exports.string().min(1).max(100),
20500
+ label: external_exports.string().max(100)
20501
+ }).strict();
20474
20502
  var uiContextSchema = external_exports.object({
20475
20503
  version: external_exports.string().min(1).max(32),
20476
20504
  viewer: external_exports.object({
@@ -20481,8 +20509,10 @@ var uiContextSchema = external_exports.object({
20481
20509
  }).strict(),
20482
20510
  install: uiInstallSchema,
20483
20511
  installs: external_exports.array(uiInstallSchema).min(1).max(MAX_INSTALLS_PER_APP),
20512
+ siteInstalls: external_exports.array(siteInstallSchema).max(MAX_APPS_PER_DOMAIN * MAX_INSTALLS_PER_APP).optional(),
20484
20513
  writeTicket: external_exports.string().min(1).max(2048).optional()
20485
20514
  }).strict();
20515
+ var MAX_UI_SITE_INSTALLS_BYTES = 64 * 1024;
20486
20516
  var parseUiContext = (raw) => {
20487
20517
  if (raw === null) {
20488
20518
  return null;
@@ -20946,6 +20976,18 @@ var addSpanEvent = (name, options = {}) => {
20946
20976
  span.events = [...span.events ?? [], event];
20947
20977
  };
20948
20978
 
20979
+ // src/emitted-event.ts
20980
+ var checkEmittedEvent = (event) => {
20981
+ if (event.type !== "track") {
20982
+ throw new Error("only track events may be emitted");
20983
+ }
20984
+ const occurredAt = event.occurredAt ?? Date.now();
20985
+ if (!Number.isSafeInteger(occurredAt) || occurredAt < 0) {
20986
+ throw new Error("an emitted event occurredAt must be non-negative Unix milliseconds");
20987
+ }
20988
+ return { ...event, occurredAt };
20989
+ };
20990
+
20949
20991
  // src/read-body.ts
20950
20992
  var MAX_ENVELOPE_BYTES = 1024 * 1024;
20951
20993
  var readBody = async (request, maxBytes = MAX_ENVELOPE_BYTES) => {
@@ -21038,17 +21080,21 @@ var brokerPush = async (env, input2) => {
21038
21080
  data: input2.data
21039
21081
  });
21040
21082
  };
21041
- var brokerTrack = async (env, input2) => {
21042
- await askBroker(env, `apps.track ${input2.event.payload["event"]}`, {
21043
- v: ENVELOPE_VERSION,
21044
- kind: "track",
21045
- slug: callerSlug(env),
21046
- key: env.QINTO_INTERNAL_KEY,
21047
- source: input2.source,
21048
- userId: input2.userId,
21049
- installId: input2.installId,
21050
- event: input2.event
21051
- });
21083
+ var buildTrack = (env, source, installId) => {
21084
+ return async (userId, event, options) => {
21085
+ const checked = checkEmittedEvent(event);
21086
+ await askBroker(env, `apps.track ${checked.payload["event"]}`, {
21087
+ v: ENVELOPE_VERSION,
21088
+ kind: "track",
21089
+ slug: callerSlug(env),
21090
+ key: env.QINTO_INTERNAL_KEY,
21091
+ source,
21092
+ userId,
21093
+ installId,
21094
+ installs: options?.installs,
21095
+ event: checked
21096
+ });
21097
+ };
21052
21098
  };
21053
21099
  var brokerContextRead = async (env, userId) => {
21054
21100
  const answer = await askBroker(env, "apps.context read", {
@@ -21113,6 +21159,16 @@ var buildIdentity = (env) => {
21113
21159
  return {
21114
21160
  resolve: (identifier, options) => {
21115
21161
  return brokerIdentityRead(env, identifier, options);
21162
+ },
21163
+ upsert: async (person) => {
21164
+ const answer = await askBroker(env, "apps.identity upsert", {
21165
+ v: ENVELOPE_VERSION,
21166
+ kind: "identityUpsert",
21167
+ slug: callerSlug(env),
21168
+ key: env.QINTO_INTERNAL_KEY,
21169
+ person
21170
+ });
21171
+ return { anonId: answer.anonId, created: answer.created };
21116
21172
  }
21117
21173
  };
21118
21174
  };
@@ -21173,18 +21229,6 @@ var buildAppsClient = (env, envelope) => {
21173
21229
  };
21174
21230
  };
21175
21231
 
21176
- // src/emitted-event.ts
21177
- var checkEmittedEvent = (event) => {
21178
- if (event.type !== "track") {
21179
- throw new Error("only track events may be emitted");
21180
- }
21181
- const occurredAt = event.occurredAt ?? Date.now();
21182
- if (!Number.isSafeInteger(occurredAt) || occurredAt < 0) {
21183
- throw new Error("an emitted event occurredAt must be non-negative Unix milliseconds");
21184
- }
21185
- return { ...event, occurredAt };
21186
- };
21187
-
21188
21232
  // src/oauth.ts
21189
21233
  var EXPIRY_FLOOR_MS = 1e3;
21190
21234
  var read = (env, id, ord, now) => {
@@ -21670,9 +21714,7 @@ var buildWorkflowContext = (env, stamp) => {
21670
21714
  broadcast: message.broadcast
21671
21715
  });
21672
21716
  },
21673
- track: async (userId, event) => {
21674
- await brokerTrack(env, { source: "workflow", userId, installId: install.id, event: checkEmittedEvent(event) });
21675
- },
21717
+ track: buildTrack(env, "workflow", install.id),
21676
21718
  apps
21677
21719
  };
21678
21720
  };
@@ -21957,9 +21999,7 @@ var dispatchSchedule = async (envelope, bundle, env) => {
21957
21999
  broadcast: message.broadcast
21958
22000
  });
21959
22001
  },
21960
- track: async (userId, event2) => {
21961
- await brokerTrack(env, { source: "scheduled", userId, installId: install.id, event: checkEmittedEvent(event2) });
21962
- },
22002
+ track: buildTrack(env, "scheduled", install.id),
21963
22003
  context: (userId) => {
21964
22004
  return asyncContext(env, () => {
21965
22005
  return userId;
@@ -22079,9 +22119,7 @@ var buildContext2 = (envelope, env) => {
22079
22119
  currency: buildCurrency(env),
22080
22120
  apps: buildAppsClient(env, { depth: 0 }),
22081
22121
  query: buildQuery({ env, ticket: envelope.tool.queryTicket, installId: install.id }),
22082
- track: async (userId, event) => {
22083
- await brokerTrack(env, { source: "tool", userId, installId: install.id, event: checkEmittedEvent(event) });
22084
- },
22122
+ track: buildTrack(env, "tool", install.id),
22085
22123
  fail: (message) => {
22086
22124
  return { kind: "tool_error", message: truncate(message) };
22087
22125
  }
@@ -22371,9 +22409,7 @@ var buildContext3 = ({
22371
22409
  broadcast: message.broadcast
22372
22410
  });
22373
22411
  },
22374
- track: async (userId, event) => {
22375
- await brokerTrack(env, { source: "webhook", userId, installId: install.id, event: checkEmittedEvent(event) });
22376
- },
22412
+ track: buildTrack(env, "webhook", install.id),
22377
22413
  context: (userId) => {
22378
22414
  return asyncContext(env, () => {
22379
22415
  return userId;
@@ -22829,6 +22865,7 @@ var dispatchUi = async ({ request, env, versions }) => {
22829
22865
  site,
22830
22866
  install: { id: context.install.id, label: context.install.label },
22831
22867
  installs: projectAllInstallValues(maps, variableKinds, context.installs),
22868
+ ...context.siteInstalls === void 0 ? {} : { siteInstalls: context.siteInstalls },
22832
22869
  // The install is named rather than inherited: one panel serves every install, and reading the
22833
22870
  // subject install's token while showing another account's UI would be silently wrong.
22834
22871
  oauth: buildUiOauth(env, context.installs),
@@ -22846,6 +22883,7 @@ var dispatchUi = async ({ request, env, versions }) => {
22846
22883
  viewer: { ...context.viewer, appRole: context.viewer.appRole ?? "full" },
22847
22884
  observability: buildObservability(context.install.ord),
22848
22885
  identity: buildIdentity(env),
22886
+ currency: buildCurrency(env),
22849
22887
  apps: buildAppsClient(env, { depth: 0 })
22850
22888
  };
22851
22889
  let response;
@@ -22946,14 +22984,17 @@ var toTransformResult = (value) => {
22946
22984
  if (typeof value !== "object" || value === null) {
22947
22985
  return null;
22948
22986
  }
22949
- const { kind } = value;
22950
- if (kind === "pass" || kind === "drop") {
22987
+ const { kind, installs } = value;
22988
+ if (kind === "drop") {
22951
22989
  return kind;
22952
22990
  }
22991
+ if (kind === "pass") {
22992
+ return installs === void 0 ? kind : { installs };
22993
+ }
22953
22994
  if (kind === "replace") {
22954
22995
  const { payload } = value;
22955
22996
  if (typeof payload === "object" && payload !== null && !Array.isArray(payload)) {
22956
- return { payload };
22997
+ return { payload, installs };
22957
22998
  }
22958
22999
  }
22959
23000
  return null;
@@ -22983,14 +23024,14 @@ var runTransform = async (envelope, env, action, handler) => {
22983
23024
  });
22984
23025
  const ctx = {
22985
23026
  ...withoutApps,
22986
- pass: () => {
22987
- return { kind: "pass" };
23027
+ pass: (options) => {
23028
+ return { kind: "pass", installs: options?.installs };
22988
23029
  },
22989
23030
  drop: () => {
22990
23031
  return { kind: "drop" };
22991
23032
  },
22992
- replace: (payload) => {
22993
- return { kind: "replace", payload };
23033
+ replace: (payload, options) => {
23034
+ return { kind: "replace", payload, installs: options?.installs };
22994
23035
  }
22995
23036
  };
22996
23037
  let value;
@@ -0,0 +1 @@
1
+ (function(){var e=()=>{},t=t=>{t.config?.autoCapture?.pageLoad===!0&&t.q.push([`track`,[`PageView`],e,e])},n=class extends Error{constructor(e){super(e),this.name=`QintoError`}},r=class extends n{constructor(e){super(e),this.name=`QintoTimeoutError`}},i=(e=Date.now())=>`evt_${globalThis.crypto.randomUUID()}_${e}`,a=(e,t)=>{if(e!==void 0)return e;let n=t?.orderId;return typeof n==`string`&&n!==``?n:i()},o=[`necessary`,`functional`,`analytics`,`marketing`,`salesOfData`],s=[`then`,`ready`,`config`],c=()=>{},l=(e,t)=>(...n)=>{let r=new Promise((r,i)=>{e.q.push([t,n,r,i])});return r.catch(c),r},u=e=>{let t=e;return t._q=1,t.q=[],new Proxy(t,{get:(e,n)=>typeof n!=`string`||s.includes(n)||n in t?Reflect.get(t,n):(t[n]=l(t,n),t[n])})},d=()=>{let e=document.currentScript?.dataset.qintoGlobal;return typeof e==`string`&&e!==``?e:`qinto`},f=e=>typeof e==`object`&&!!e&&e._q===1,p=(e=`qinto`)=>{let t=globalThis;if(e in t){let n=t[e];if(!f(n))return null;let r=Array.isArray(n.q)?n:u(n);return r!==n&&Object.defineProperty(t,e,{value:r,writable:!0,enumerable:!0,configurable:!0}),r}let n=u({});return Object.defineProperty(t,e,{value:n,writable:!0,enumerable:!0,configurable:!0}),n},m=(e,t)=>async(r,i)=>{let a=Reflect.get(e,r);if(typeof a!=`function`)throw new n(`[Qinto] ${t}.${r} is not a method of this tag.`);return a.apply(e,Array.from(i))},h=e=>()=>Promise.reject(e),g=(e,t)=>{let[n,r,i,a]=t;e(n,r).then(i,a)},_=e=>{let t=[];return t.push=(...t)=>{for(let n of t)g(e,n);return 0},t},v=(e,t,n=`window.qinto`)=>{let r=e.ready;if(r!==void 0)return r;let i=e,a=e=>{let t=i.q;i.q=_(e);for(let n of t)g(e,n)},o=t().then(e=>{a(m(e,n))},e=>{throw a(h(e)),e});return o.catch(c),i.ready=o,o},y=(e,t,n)=>n===void 0||!o.some(e=>e===n)?!1:n===`necessary`||e!==null&&e.categories[n]===!0&&e.apps[t]!==!1,b=(e,t,n)=>e.config?.consentConfiguration?.enabled!==!0||y(n,t,e.config?.apps?.[t]?.category),x=e=>Object.values(e.config?.apps??{}).some(e=>e.category!==`necessary`||e.capture!==void 0),ee=(e,t,n,r)=>b(e,t,n)?r===void 0||b(e,t,r):!1,te=e=>{let{categories:t,apps:n}=e;if(typeof t==`object`&&t&&typeof n==`object`&&n)return{categories:t,apps:n}},S=()=>{},C=(e,t)=>{console.error(`[Qinto] A handler of app "${e.slug}" (install "${e.installId}") failed.`,t)},w=(e,t,n)=>{for(let r of t)try{let t=r(n);t instanceof Promise&&t.catch(t=>{C(e,t)})}catch(t){C(e,t)}},T=(e,t,n,r)=>{e.activated.add(r.id);let i={slug:t,installId:r.id,eventHandlers:[],transformHooks:[],consentHandlers:[],pushHandlers:[],sharedContextHandlers:[]};e.instances.push(i);let a={variables:r.variables,install:{id:r.id,label:r.label},getSession:async()=>{let n=await e.client.getSession();return e.target.config?.apps?.[t]?.geo===!0?n:{...n,ip:null,geo:null}},track:(t,n)=>{e.client.track(t,n).catch(S)},onEvent:e=>{i.eventHandlers.push(e)},onTransform:e=>{if(r.transform!==!0){console.error(`[Qinto] App "${t}" registers a transform hook without declaring browser.hooks: ["transform"].`);return}i.transformHooks.push(e)},onConsent:e=>{i.consentHandlers.push(e)},onPush:e=>{i.pushHandlers.push(e)},fetch:async(n,i)=>{let a=new URL(`${e.client.destination}/app/${t}${n}`);if(!n.startsWith(`/`)||!a.pathname.startsWith(`/app/${t}/`))throw TypeError(`[Qinto] App "${t}" fetched "${n}"; the path must be absolute and stay inside the app.`);let o=new Headers(i?.headers);return o.set(`x-qinto-install`,r.id),fetch(a,{...i,headers:o,credentials:`include`})},onSharedContext:n=>{if(e.target.config?.apps?.[t]?.sharedContext!==!0){console.error(`[Qinto] App "${t}" reads shared context without declaring the sharedContext capability.`);return}i.sharedContextHandlers.push(n),e.sharedContext!==null&&ee(e.target,t,e.consent,e.sharedContextConsent)&&w(i,[n],e.sharedContext)}};try{n(a)}catch(e){console.error(`[Qinto] App "${t}" failed to activate install "${r.id}".`,e)}},E=100,D=1024,ne=32768,re=e=>{let t;try{t=JSON.stringify(e)}catch{return}if(!(t===void 0||new TextEncoder().encode(t).length>D))return JSON.parse(t)},ie=e=>{let t={};for(let n of e){if(n.settled!==n.total||n.values.length!==1)continue;let e=re(n.values[0]);if(e===void 0)continue;let r={...t[n.source.slug]??{},[n.source.installId]:e},i={...t,[n.source.slug]:r};new TextEncoder().encode(JSON.stringify(i)).length<=ne&&(t[n.source.slug]=r)}return Object.keys(t).length===0?void 0:t},ae=async(e,t,{declares:n,notify:r,report:i})=>{let a=[],o=[];for(let s of e){if(!n(s)){r(s);continue}let e={source:s,total:s.eventHandlers.length,settled:0,values:[]};a.push(e);for(let n of s.eventHandlers){let r;try{r=n(t)}catch(t){e.settled+=1,i(s,t);continue}o.push(Promise.resolve(r).then(t=>{e.settled+=1,t!==void 0&&e.values.push(t)},t=>{e.settled+=1,i(s,t)}))}}if(o.length>0){let e,t=new Promise(t=>{e=setTimeout(t,E)});await Promise.race([Promise.all(o),t]),clearTimeout(e)}return ie(a)},oe=(e,t)=>{if(e.mode===`except`&&t.mode===`except`)return{mode:`except`,installIds:[...new Set([...e.installIds,...t.installIds])]};let[n,r]=e.mode===`only`?[e,t]:[t,e],i=new Set(r.installIds);return{mode:`only`,installIds:n.installIds.filter(e=>i.has(e)===(r.mode===`only`))}},se=(e,t,n,r)=>{let i;try{i=t(n,r)}catch(t){C(e,t);return}if(i===void 0||i===!1)return i;let a=i?.installs;if((a?.mode===`except`||a?.mode===`only`)&&Array.isArray(a.installIds))return a;C(e,TypeError(`A transform hook returned neither nothing, false, nor { installs }.`))},ce=(e,t,n,r)=>{let i=r;for(let r of e)for(let e of r.transformHooks){let a=se(r,e,t,n);if(a===!1)return!1;a!==void 0&&(i=i===void 0?a:oe(i,a))}return i},O=(e,t)=>{let{app:n,install:r,topic:i,to:a}=e;return typeof n!=`string`||typeof i!=`string`||r!==void 0&&typeof r!=`string`||t&&!(Array.isArray(a)&&a.every(e=>typeof e==`string`))},k=(e,t,n,r)=>r===null?e.slug===t&&(n===void 0||n===e.installId):r.has(e.slug),A=e=>`_appInstalls`in e?e._appInstalls:void 0,j=(e,t,n)=>{if(!b(e.target,t,e.consent))return;let r=(A(e.target)?.[t]??[]).filter(t=>!e.activated.has(t.id)&&(t.geoFilter!==!0||e.geoAllowed.has(t.id)));if(r.length===0)return;let i=n.factory;if(i===void 0){try{i=n.loader()}catch(e){i=null,console.error(`[Qinto] App "${t}" failed to load.`,e)}e.apps.set(t,{...n,factory:i})}if(i!==null)for(let n of r)T(e,t,i,n)},M=(e,t)=>{let n=e;n.consent=t,n.sharedContextConsent=void 0;for(let n of e.instances)w(n,n.consentHandlers,t);e.onConsentSettled?.(t);for(let[t,n]of e.apps)j(e,t,n)},N=async e=>{try{M(e,await e.client.getConsent())}catch(e){console.error(`[Qinto] The apps consent read failed.`,e)}},P=async e=>{if(e.geoRequested||!Object.values(A(e.target)??{}).some(e=>e.some(e=>e.geoFilter===!0)))return;let t=e;t.geoRequested=!0;try{t.geoAllowed=new Set(await e.client.getGeoInstalls())}catch(e){console.error(`[Qinto] The geo filter read failed; geo-filtered installs stay off on this page.`,e);return}for(let[t,n]of e.apps)j(e,t,n)},F=async(e,t,n)=>{e.onPageEvent?.(e.consent);let r=new Set(n?.installIds);return ae(e.instances.filter(t=>b(e.target,t.slug,e.consent)&&(n===void 0||r.has(t.installId)===(n.mode===`only`))),t,{declares:n=>e.target.config?.apps?.[n.slug]?.eventResults?.includes(t.type)===!0,notify:e=>{w(e,e.eventHandlers,t)},report:C})},I=e=>{let{client:t}=e;return{track:async(n,r,i)=>{let o=a(i?.eventId,r),s=t.actionContext(),c={type:`track`,event:n,eventId:o,properties:r??{}},l=i?.installs,u=ce(e.instances,c,s.page.url,l);if(u===!1)return{eventId:o};let d=await F(e,c,u);return await t.submitTrack({event:n,eventId:o,properties:r,context:s,appResults:d,installs:l}),{eventId:o}},identify:async(n,r)=>{let i=t.actionContext(),a=await F(e,{type:`identify`,event:`identify`,properties:n??{}});return t.submitIdentify({traits:n,id:r,context:i,appResults:a})},alias:t.alias,consent:async n=>{if(await t.submitConsent(n,t.actionContext()),e.onConsentMutation?.(),x(e.target)){let t=e;t.consent=null,await N(e)}},getAnonId:t.getAnonId,getConsent:t.getConsent,getSession:t.getSession,close:t.close}},L=(e,t)=>{let n=new Map,r=null,i=null,a=e=>{let[t,i]=e;if(n.has(t))return;let a={loader:i};n.set(t,a),r?.(t,a)},o=e,s=`_apps`in o?o._apps:void 0,c=Array.isArray(s)?s:[];c.push=(...e)=>{for(let t of e)a(t);return 0},o._apps=c;for(let e of c.splice(0))a(e);return{sharedContext:e=>{let{context:t}=e;if(typeof t!=`object`||!t||Array.isArray(t)){console.error(`[Qinto] The server sent a malformed shared context.`,e);return}let n=i;if(n===null)return;n.sharedContext=t;let r=te(e),a=r??n.consent;n.sharedContextConsent=r;for(let e of n.instances)b(n.target,e.slug,a)&&w(e,e.sharedContextHandlers,n.sharedContext)},push:e=>{let{app:t,install:n,topic:r,scope:a,to:o}=e,s=a===`site`;if(O(e,s)){console.error(`[Qinto] The server sent a malformed app push.`,e);return}let c=i;if(c===null)return;let l=s?new Set(o):null,u={topic:r,data:e.data,from:t};for(let e of c.instances)k(e,t,n,l)&&b(c.target,e.slug,c.consent)&&w(e,e.pushHandlers,u)},connect:async a=>{let o={target:e,client:a,apps:n,instances:[],activated:new Set,consent:null,geoAllowed:new Set,geoRequested:!1,sharedContext:i?.sharedContext??null,sharedContextConsent:i?.sharedContextConsent,onConsentSettled:t?.onConsentSettled,onConsentMutation:t?.onConsentMutation,onPageEvent:t?.onPageEvent};i=o,r=(e,t)=>{j(o,e,t),o.consent===null&&o.target.config?.consentConfiguration?.enabled===!0&&o.target.config?.apps?.[e]?.category!==`necessary`&&N(o),P(o)};for(let[e,t]of n)j(o,e,t);let s=P(o);return e.config?.consentConfiguration?.enabled===!0&&x(e)?await N(o):o.onConsentSettled?.(o.consent),await s,I(o)}}},R=512,z=864e5,B=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[e,Object.fromEntries(Object.entries(t).map(([e,t])=>[e,t.value]))])),V=(e,t)=>`qinto:cap:${encodeURIComponent(e)}:${encodeURIComponent(t)}`,H=e=>{try{let t=window.sessionStorage.getItem(e);if(t===null)return null;let n=JSON.parse(t);return typeof n.at!=`number`||typeof n.anonId!=`string`||typeof n.apps!=`object`||n.apps===null||Date.now()-n.at>z?null:{at:n.at,anonId:n.anonId,apps:n.apps}}catch{return null}},U=(e,t)=>{try{window.sessionStorage.setItem(e,JSON.stringify(t))}catch{}},W=e=>{try{window.sessionStorage.removeItem(e)}catch{}},G=e=>{try{return decodeURIComponent(e)}catch{return e}},le=()=>{let e={};for(let t of document.cookie.split(`;`)){let n=t.indexOf(`=`);n>0&&(e[t.slice(0,n).trim()]=G(t.slice(n+1)))}return e},ue=(e,t)=>{let n={};for(let r of e.queryParams){let e=t.params.get(r);e!==null&&e.length<=R&&(n[r]={value:e,source:`query`})}for(let r of e.cookies){let e=t.cookies[r];e!==void 0&&e.length<=R&&(n[r]={value:e,source:`cookie`})}return n},de=(e,t)=>{let n={params:new URLSearchParams(window.location.search),cookies:le()},r={};for(let[i,a]of Object.entries(e.config?.apps??{})){if(a.capture===void 0||!y(t,i,a.category))continue;let e=ue(a.capture,n);Object.keys(e).length>0&&(r[i]=e)}return r},fe=(e,t)=>{let n={};for(let[r,i]of Object.entries(e)){let e=t[r]??{},a={};for(let[t,n]of Object.entries(i))(e[t]?.value!==n.value||e[t]?.source!==n.source)&&(a[t]=n);Object.keys(a).length>0&&(n[r]=a)}return n},pe=(e,t,n,r)=>{let i=V(r,n),a=H(i),o=a?.apps??{},s=a?.anonId??null,c=a===null,l={},u=0,d=(e,t)=>{s!==null&&s!==e.anonId&&(o={}),s=e.anonId;let n=new Set(Object.entries(e.accepted).flatMap(([e,t])=>t.map(t=>`${e}\u0000${t}`)));for(let[e,r]of Object.entries(t))for(let[t,i]of Object.entries(r))n.has(`${e}\u0000${t}`)&&(o[e]={...o[e],[t]:i});U(i,{at:Date.now(),anonId:s,apps:o})},f=null,p=()=>{u+=1,o={},l={},W(i)},m=n=>{if(f=n,!c)return;let r=fe(de(e,n),{...o,...l});if(Object.keys(r).length===0)return;let i=u;l={...l,...r},t(B(r)).then(e=>{i===u&&d(e,r)}).catch(()=>{}).finally(()=>{l={}})};return{settled:e=>{m(e)},needsAnon:()=>!c,observedAnon:e=>{(e===null||s!==null&&s!==e)&&p(),s=e,c=!0,m(f)},clear:p}},K=Symbol.for(`qinto.connectGate`),q=()=>{},me=e=>{let t=globalThis,n=(t[K]??Promise.resolve()).then(e);return t[K]=n.then(q,q),n},J=class extends n{constructor(e){super(e),this.name=`QintoProtocolError`}},he=e=>{if(typeof e!=`string`)return null;let t;try{t=JSON.parse(e)}catch{return null}if(typeof t!=`object`||!t)return null;let n=t;return n.t===`ack`||n.t===`error`||n.t===`consentState`||n.t===`session`||n.t===`captureAck`||n.t===`geoInstalls`||n.t===`appPush`||n.t===`sharedContext`?t:null},ge=e=>{if(e.t===`consentState`)return{categories:e.categories,apps:e.apps};if(e.t===`session`)return{anonId:e.anonId,globalId:e.globalId,ip:e.ip,geo:e.geo};if(e.t===`captureAck`)return{anonId:e.anonId,accepted:e.accepted};if(e.t===`geoInstalls`)return e.installs},_e=e=>{let t=new Map,n=e=>{let n=t.get(e);if(n!==void 0)return clearTimeout(n.timer),t.delete(e),n};return{submit:n=>new Promise((i,a)=>{let o={frame:n,sent:e.send(n),resolve:i,reject:a,timer:setTimeout(()=>{t.delete(n.ref),a(new r(`The Qinto request timed out.`))},e.requestTimeoutMs)};t.set(n.ref,o)}),flush:()=>{for(let n of t.values())n.sent||=e.send(n.frame)},deliver:e=>{let t=e.ref===void 0?void 0:n(e.ref);if(t!==void 0){if(e.t===`error`){t.reject(new J(e.message));return}t.resolve(ge(e))}},rejectAll:e=>{let n=[...t.values()];t.clear();for(let t of n)clearTimeout(t.timer),t.reject(e)}}},Y=()=>{let e=document.referrer;return{url:window.location.href,...e===``?{}:{referrer:e}}},ve=e=>new WebSocket(e),ye=500,be=3e4,X=4096,xe=8192,Se=(e,t)=>{if(t.url.length>X)return e;let n=new URLSearchParams({url:t.url});t.referrer!==void 0&&t.referrer.length<=X&&n.set(`referrer`,t.referrer);let r=`${e}?${n}`;return r.length<=xe?r:e},Ce=`session not initialized`,we=(e,t)=>{let n=Math.min(ye*2**e,be);return Math.round(n/2+n/2*t)},Te=(e,t)=>e.t===`appPush`?(t.onAppPush?.(e),!0):e.t===`sharedContext`&&(t.onSharedContext?.(e),!0),Ee=e=>{let t=`${e.destination.replace(/\/+$/,``)}/open`,n=null,r=null,i=0,a=null,o=_e({send:e=>n===null||n.readyState!==1?!1:(n.send(JSON.stringify(e)),!0),requestTimeoutMs:e.requestTimeoutMs}),s=t=>{e.onError?.(t)},c=()=>{if(r!==null&&(clearTimeout(r),r=null),n!==null){let e=n;n=null,e.close()}o.rejectAll(new J(`connection closed`))},l=()=>{let u=ve(Se(t,Y()));n=u,u.onopen=()=>{i=0;let e=a;a=null,o.flush(),e?.resolve()},u.onmessage=t=>{let n=he(t.data);if(n===null){s(new J(`invalid message`));return}Te(n,e)||(`anonId`in n&&typeof n.anonId==`string`&&e.onAnonId?.(n.anonId),o.deliver(n),n.t===`error`&&n.message===Ce&&u.close())},u.onerror=()=>{s(new J(`connection closed`))},u.onclose=()=>{if(n!==u)return;n=null;let e=a;if(e!==null){a=null,c(),e.reject(new J(`connection closed`));return}o.rejectAll(new J(`connection closed`)),r=setTimeout(()=>{r=null,l()},we(i,Math.random())),i+=1}};return{connect:()=>new Promise((e,t)=>{a={resolve:e,reject:t},l()}),submit:e=>o.submit(e),close:()=>{c()}}},De=1e4,Oe=()=>{let e=0;return()=>(e+=1,`q${e}`)},ke=(e,t,n)=>{let r=null,i=()=>({occurredAt:Date.now(),page:Y()}),o=async()=>{let n=await e.submit({t:`getSession`,ref:t()});return r=n.anonId,n};return{destination:n.replace(/\/+$/,``),actionContext:i,submitIdentify:async({traits:n,id:r,context:i,appResults:a})=>{await e.submit({t:`identify`,ref:t(),traits:n,id:r,context:i,appResults:a})},submitTrack:async({event:n,eventId:r,properties:i,context:a,appResults:o,installs:s})=>{await e.submit({t:`track`,ref:t(),event:n,eventId:r,properties:i,context:a,appResults:o,installs:s})},submitConsent:async(n,r)=>{await e.submit({t:`consent`,ref:t(),categories:n.categories,apps:n.apps,context:r})},track:async(n,r,o)=>{let s=a(o?.eventId,r);return await e.submit({t:`track`,ref:t(),event:n,eventId:s,properties:r,context:i(),installs:o?.installs}),{eventId:s}},alias:async n=>{await e.submit({t:`alias`,ref:t(),alias:n})},getConsent:async()=>await e.submit({t:`getConsent`,ref:t()}),getGeoInstalls:async()=>await e.submit({t:`getGeoInstalls`,ref:t()}),getSession:o,getAnonId:async()=>(r===null&&await o(),r),close:async()=>{e.close()}}},Ae=async e=>{let t=Ee({destination:e.destination,requestTimeoutMs:e.requestTimeoutMs??De,onError:e.onError,onAppPush:e.onAppPush,onSharedContext:e.onSharedContext,onAnonId:e.onAnonId});await me(()=>t.connect());let n=Oe();return{client:ke(t,n,e.destination),submitCapture:async e=>await t.submit({t:`capture`,ref:n(),apps:e})}},je=(e,t)=>{let n=null,r=L(e,{onConsentSettled:e=>{n?.settled(e)},onConsentMutation:()=>{n?.clear()},onPageEvent:e=>{n?.settled(e)}});return{connect:async i=>{let a=await Ae({...i,onAppPush:r.push,onSharedContext:r.sharedContext,onAnonId:e=>{n?.observedAnon(e)}});n=pe(e,a.submitCapture,i.destination,t);let o=await r.connect(a.client);return n.needsAnon()&&n.observedAnon((await a.client.getSession()).anonId),o}}},Z=d(),Q=p(Z),$=`window.${Z}`;if(Q!==null&&Q.ready===void 0){let e=je(Q,Z);t(Q),v(Q,async()=>{let t=Q.config?.destination;if(typeof t!=`string`||t===``)throw Error(`[Qinto] ${$}.config.destination is missing.`);return e.connect({destination:t})},$)}})();