@blotout/qinto-cli 0.1.31 → 0.1.32

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.
@@ -21577,7 +21577,7 @@ var userGeoSchema = external_exports.object({
21577
21577
 
21578
21578
  // ../../libs/app-envelope/src/envelope.ts
21579
21579
  var ENVELOPE_VERSION = 3;
21580
- var ENVELOPE_ERROR_CODES = ["invalid_arguments"];
21580
+ var ENVELOPE_ERROR_CODES = ["invalid_arguments", "result_too_large", "callee_timeout", "rpc_error"];
21581
21581
  var MAX_INSTALLS_PER_APP = 15;
21582
21582
  var MAX_APPS_PER_DOMAIN = 50;
21583
21583
  var MAX_EMITS_PER_INSTALL = 10;
@@ -21593,6 +21593,7 @@ var MAX_SHARED_CONTEXT_ENTRY_BYTES = 4 * 1024;
21593
21593
  var MAX_PUSH_BYTES = 16 * 1024;
21594
21594
  var MAX_RESPONSE_BYTES = 1024 * 1024;
21595
21595
  var MAX_RPC_BYTES = 128 * 1024;
21596
+ var TRAFFIC_CLASSES = ["hot", "cold"];
21596
21597
  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();
21597
21598
  var installRuleSchema = external_exports.object({
21598
21599
  mode: external_exports.enum(["except", "only"]),
@@ -21677,7 +21678,15 @@ var envelopeRequestSchema = external_exports.object({
21677
21678
  context: external_exports.object({ private: contextEntrySchema.optional(), shared: external_exports.record(external_exports.string().min(1).max(30), contextEntrySchema).optional() }).strict().optional(),
21678
21679
  // RPC depth is capped at 3 by the broker; hook depth at 2 by the emit path.
21679
21680
  depth: external_exports.number().int().min(0).max(3),
21680
- rpc: external_exports.object({ caller: external_exports.string().min(1).max(30).nullable(), fn: external_exports.string().min(1).max(64), args: external_exports.unknown() }).strict().refine((rpc) => {
21681
+ rpc: external_exports.object({
21682
+ caller: external_exports.string().min(1).max(30).nullable(),
21683
+ fn: external_exports.string().min(1).max(64),
21684
+ args: external_exports.unknown(),
21685
+ // Optional on the wire: a site worker predating traffic classes sends none, which means hot.
21686
+ traffic: external_exports.enum(TRAFFIC_CLASSES).optional(),
21687
+ // Cold calls only: the broker mints it so the callee can query its own catalog.
21688
+ queryTicket: external_exports.string().min(1).max(2048).optional()
21689
+ }).strict().refine((rpc) => {
21681
21690
  return new TextEncoder().encode(JSON.stringify(rpc.args ?? null)).length <= MAX_RPC_BYTES;
21682
21691
  }, "RPC args exceed the size cap").optional(),
21683
21692
  action: external_exports.object({
@@ -26569,6 +26578,207 @@ var constantTimeEqual = /* @__PURE__ */ __name((expected, presented) => {
26569
26578
  return expectedBytes.length === presentedBytes.length && timingSafeEqual(expectedBytes, presentedBytes);
26570
26579
  }, "constantTimeEqual");
26571
26580
 
26581
+ // src/helpers/durable.ts
26582
+ var ownGraphEnv = /* @__PURE__ */ __name((ctx, env) => {
26583
+ const exports = ctx.exports;
26584
+ return {
26585
+ ...env,
26586
+ get ANON_DO() {
26587
+ return exports.AnonDO;
26588
+ },
26589
+ get GLOBAL_DO() {
26590
+ return exports.GlobalDO;
26591
+ },
26592
+ get ALIAS_DO() {
26593
+ return exports.AliasDO;
26594
+ }
26595
+ };
26596
+ }, "ownGraphEnv");
26597
+ var JURISDICTIONS = /* @__PURE__ */ new Set(["eu", "fedramp", "fedramp-high", "us"]);
26598
+ var LOCATION_HINTS = /* @__PURE__ */ new Set([
26599
+ "wnam",
26600
+ "enam",
26601
+ "sam",
26602
+ "weur",
26603
+ "eeur",
26604
+ "apac",
26605
+ "apac-ne",
26606
+ "apac-se",
26607
+ "oc",
26608
+ "afr",
26609
+ "me"
26610
+ ]);
26611
+ var residencyStub = /* @__PURE__ */ __name((namespace, env, name) => {
26612
+ const residency = env;
26613
+ const jurisdiction = residency.DO_JURISDICTION;
26614
+ const scoped = jurisdiction !== void 0 && JURISDICTIONS.has(jurisdiction) ? namespace.jurisdiction(jurisdiction) : namespace;
26615
+ const locationHint = residency.LOCATION_HINT;
26616
+ const options = locationHint !== void 0 && LOCATION_HINTS.has(locationHint) ? { locationHint } : void 0;
26617
+ return scoped.get(scoped.idFromName(name), options);
26618
+ }, "residencyStub");
26619
+
26620
+ // src/id-graph/anon/client.ts
26621
+ var anonStub = /* @__PURE__ */ __name((env, anonId) => {
26622
+ return residencyStub(env.ANON_DO, env, anonId);
26623
+ }, "anonStub");
26624
+
26625
+ // src/id-graph/consent.ts
26626
+ var CONSENT_CATEGORIES2 = ["necessary", "functional", "analytics", "marketing", "salesOfData"];
26627
+ var CONSENT_CATEGORY_PREFIX = "consent.category.";
26628
+ var CONSENT_APP_PREFIX = "consent.app.";
26629
+ var consentEntries = /* @__PURE__ */ __name((payload, observedAt) => {
26630
+ const entries = [];
26631
+ for (const category of CONSENT_CATEGORIES2) {
26632
+ const granted = payload.categories[category];
26633
+ if (granted === void 0) {
26634
+ continue;
26635
+ }
26636
+ entries.push({ key: `${CONSENT_CATEGORY_PREFIX}${category}`, value: String(granted), observedAt });
26637
+ }
26638
+ for (const [appId, granted] of Object.entries(payload.apps)) {
26639
+ entries.push({ key: `${CONSENT_APP_PREFIX}${appId}`, value: String(granted), observedAt });
26640
+ }
26641
+ return entries;
26642
+ }, "consentEntries");
26643
+
26644
+ // src/id-graph/projections.ts
26645
+ var PII_PREFIX = "pii.";
26646
+ var CUSTOM_PREFIX = "custom.";
26647
+ var GEO_PREFIX = "geo.";
26648
+ var PROJECTION_KINDS = ["pii", "custom", "consent_category", "consent_app", "geo"];
26649
+ var PROJECTION_PREFIX = {
26650
+ pii: PII_PREFIX,
26651
+ custom: CUSTOM_PREFIX,
26652
+ consent_category: CONSENT_CATEGORY_PREFIX,
26653
+ consent_app: CONSENT_APP_PREFIX,
26654
+ geo: GEO_PREFIX
26655
+ };
26656
+ var FANOUT_KINDS = ["pii", "custom", "consent_category", "consent_app"];
26657
+ var projectionFact = /* @__PURE__ */ __name((projectionKey) => {
26658
+ for (const kind2 of PROJECTION_KINDS) {
26659
+ const prefix = PROJECTION_PREFIX[kind2];
26660
+ if (projectionKey.startsWith(prefix)) {
26661
+ return { kind: kind2, scope: "", key: projectionKey.slice(prefix.length) };
26662
+ }
26663
+ }
26664
+ throw new Error(`Unknown projection key: ${projectionKey}`);
26665
+ }, "projectionFact");
26666
+
26667
+ // src/id-graph/anon/facts.ts
26668
+ var FACT_KINDS = [
26669
+ ...PROJECTION_KINDS,
26670
+ "capture",
26671
+ "identifier",
26672
+ "conversion",
26673
+ "context_private_kv",
26674
+ "context_private_text",
26675
+ "context_shared_kv",
26676
+ "context_shared_text"
26677
+ ];
26678
+ var APP_FACT_KINDS = ["custom", "capture", "identifier", "conversion", "pii", "consent_category", "consent_app", "geo"];
26679
+ var MAX_APP_FACTS_PER_PAGE = 100;
26680
+ var MAX_APP_FACT_PAGE_BYTES = 1024 * 1024;
26681
+ var COLUMNS = "kind, scope, key, value, source, type, amount, currency, event_id, data_json, first_at, observed_at, synced_at, expires_at";
26682
+ var rowOf = /* @__PURE__ */ __name((row) => {
26683
+ return {
26684
+ kind: row.kind,
26685
+ scope: row.scope,
26686
+ key: row.key,
26687
+ value: row.value,
26688
+ source: row.source,
26689
+ type: row.type,
26690
+ amount: row.amount,
26691
+ currency: row.currency,
26692
+ eventId: row.event_id,
26693
+ dataJson: row.data_json,
26694
+ firstAt: row.first_at,
26695
+ observedAt: row.observed_at,
26696
+ syncedAt: row.synced_at,
26697
+ expiresAt: row.expires_at
26698
+ };
26699
+ }, "rowOf");
26700
+ var appFactOf = /* @__PURE__ */ __name((row) => {
26701
+ const { syncedAt: _syncedAt, expiresAt: _expiresAt, ...fact } = rowOf(row);
26702
+ return { ...fact, kind: fact.kind };
26703
+ }, "appFactOf");
26704
+ var listAppFacts = /* @__PURE__ */ __name((sql, query, now) => {
26705
+ const maxRowId = query.maxRowId ?? sql.exec("SELECT MAX(rowid) AS maxRowId FROM facts").one().maxRowId;
26706
+ if (maxRowId === null) {
26707
+ return { items: [], next: null };
26708
+ }
26709
+ const where = ["rowid > ?", "rowid <= ?", "(expires_at IS NULL OR expires_at > ?)"];
26710
+ const params = [query.afterRowId, maxRowId, now];
26711
+ if (query.kinds.length > 0) {
26712
+ where.push(`kind IN (${query.kinds.map(() => "?").join(", ")})`);
26713
+ params.push(...query.kinds);
26714
+ }
26715
+ if (query.observedAtGte !== null) {
26716
+ where.push("observed_at >= ?");
26717
+ params.push(query.observedAtGte);
26718
+ }
26719
+ if (query.observedAtLt !== null) {
26720
+ where.push("observed_at < ?");
26721
+ params.push(query.observedAtLt);
26722
+ }
26723
+ const rows = sql.exec(`SELECT rowid, ${COLUMNS} FROM facts WHERE ${where.join(" AND ")} ORDER BY rowid LIMIT ?`, ...params, query.limit + 1).toArray();
26724
+ const items = [];
26725
+ let lastRowId = query.afterRowId;
26726
+ for (const row of rows.slice(0, query.limit)) {
26727
+ const fact = appFactOf(row);
26728
+ const candidate = [...items, fact];
26729
+ if (new TextEncoder().encode(JSON.stringify(candidate)).byteLength > MAX_APP_FACT_PAGE_BYTES) {
26730
+ if (items.length === 0) {
26731
+ throw new Error("fact_too_large");
26732
+ }
26733
+ break;
26734
+ }
26735
+ items.push(fact);
26736
+ lastRowId = row.rowid;
26737
+ }
26738
+ const hasMore = rows.length > items.length;
26739
+ return { items, next: hasMore ? { afterRowId: lastRowId, maxRowId } : null };
26740
+ }, "listAppFacts");
26741
+ var insertFact = /* @__PURE__ */ __name((sql, fact) => {
26742
+ sql.exec(
26743
+ `INSERT INTO facts (${COLUMNS}) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?)`,
26744
+ fact.kind,
26745
+ fact.scope,
26746
+ fact.key,
26747
+ fact.value ?? null,
26748
+ fact.source ?? null,
26749
+ fact.type ?? null,
26750
+ fact.amount ?? null,
26751
+ fact.currency ?? null,
26752
+ fact.eventId ?? null,
26753
+ fact.dataJson ?? null,
26754
+ fact.firstAt ?? null,
26755
+ fact.observedAt,
26756
+ fact.expiresAt ?? null
26757
+ );
26758
+ }, "insertFact");
26759
+ var latestFact = /* @__PURE__ */ __name((sql, coords) => {
26760
+ const row = sql.exec(
26761
+ `SELECT ${COLUMNS} FROM facts WHERE kind = ? AND scope = ? AND key = ? ORDER BY observed_at DESC, rowid DESC LIMIT 1`,
26762
+ coords.kind,
26763
+ coords.scope,
26764
+ coords.key
26765
+ ).toArray().at(0);
26766
+ return row === void 0 ? void 0 : rowOf(row);
26767
+ }, "latestFact");
26768
+ var latestFacts = /* @__PURE__ */ __name((sql, kind2) => {
26769
+ const rows = sql.exec(`SELECT ${COLUMNS} FROM facts WHERE kind = ? ORDER BY scope, key, observed_at, rowid`, kind2).toArray();
26770
+ const latest = [];
26771
+ for (const row of rows) {
26772
+ const previous = latest.at(-1);
26773
+ if (previous !== void 0 && previous.scope === row.scope && previous.key === row.key) {
26774
+ latest[latest.length - 1] = rowOf(row);
26775
+ continue;
26776
+ }
26777
+ latest.push(rowOf(row));
26778
+ }
26779
+ return latest;
26780
+ }, "latestFacts");
26781
+
26572
26782
  // src/apps/consent-gate.ts
26573
26783
  var parseEnforced = /* @__PURE__ */ __name((raw2) => {
26574
26784
  let parsed;
@@ -26651,6 +26861,9 @@ var appSchema = external_exports.object({
26651
26861
  // Absent from an old embedded registry; the default never equals a real claim, so the ui proxy
26652
26862
  // refuses stale registries with token_stale instead of turning the app off.
26653
26863
  versionId: external_exports.string().min(1).default(""),
26864
+ // Absent from a registry deployed before cold rpc calls carried a query ticket; without it the
26865
+ // broker sends the callee none.
26866
+ appId: external_exports.string().min(1).optional(),
26654
26867
  consent: external_exports.object({ category: external_exports.string() }),
26655
26868
  // Plain strings, not the bucket enum: an unknown bucket from a newer registry must not turn apps off.
26656
26869
  data: external_exports.array(external_exports.string()).default([]),
@@ -26737,559 +26950,50 @@ var siteRefOf = /* @__PURE__ */ __name(({ domainId, fingerprint }) => {
26737
26950
  return { domainId, fingerprint };
26738
26951
  }, "siteRefOf");
26739
26952
 
26740
- // ../../libs/cf-data/src/cf-data.ts
26741
- var CF_DATA_HEADER = "x-cf-data";
26742
- var cfDataFrom = /* @__PURE__ */ __name((cf) => {
26743
- return {
26744
- country: cf?.country,
26745
- city: cf?.city,
26746
- region: cf?.region,
26747
- regionCode: cf?.regionCode,
26748
- timezone: cf?.timezone,
26749
- postalCode: cf?.postalCode,
26750
- continent: cf?.continent,
26751
- longitude: cf?.longitude,
26752
- latitude: cf?.latitude,
26753
- isEUCountry: cf?.isEUCountry,
26754
- botManagement: {
26755
- ja4: cf?.botManagement?.ja4,
26756
- ja3Hash: cf?.botManagement?.ja3Hash,
26757
- score: cf?.botManagement?.score,
26758
- verifiedBot: cf?.botManagement?.verifiedBot
26759
- }
26760
- };
26761
- }, "cfDataFrom");
26762
- var parseCfData = /* @__PURE__ */ __name((raw2) => {
26763
- if (raw2 === null) {
26764
- return void 0;
26765
- }
26766
- let parsed;
26767
- try {
26768
- parsed = JSON.parse(raw2);
26769
- } catch {
26770
- return void 0;
26771
- }
26772
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
26773
- return void 0;
26774
- }
26775
- return parsed;
26776
- }, "parseCfData");
26777
-
26778
- // src/helpers/geo.ts
26779
- var UNDETERMINED_COUNTRIES = /* @__PURE__ */ new Set(["XX", "T1"]);
26780
- var detectedCountry = /* @__PURE__ */ __name((cf) => {
26781
- const country = cf?.country;
26782
- return country && !UNDETERMINED_COUNTRIES.has(country) ? country : void 0;
26783
- }, "detectedCountry");
26784
- var euCountry = /* @__PURE__ */ __name((cf, country) => {
26785
- if (cf?.isEUCountry === "1") {
26786
- return "yes";
26787
- }
26788
- return country ? "no" : "unknown";
26789
- }, "euCountry");
26790
- var withForwardedCf = /* @__PURE__ */ __name((request) => {
26791
- if (request.cf !== void 0) {
26792
- return request;
26793
- }
26794
- const cf = parseCfData(request.headers.get(CF_DATA_HEADER));
26795
- return cf === void 0 ? request : new Request(request, { cf });
26796
- }, "withForwardedCf");
26797
- var loggableGeo = /* @__PURE__ */ __name((geo) => {
26798
- const fields = {};
26799
- for (const [key, value] of Object.entries(geo)) {
26800
- if (value !== void 0) {
26801
- fields[key] = String(value);
26802
- }
26803
- }
26804
- return fields;
26805
- }, "loggableGeo");
26806
- var hostFromRequest = /* @__PURE__ */ __name((request) => {
26807
- return {
26808
- ip: request.headers.get("cf-connecting-ip") ?? void 0,
26809
- userAgent: request.headers.get("user-agent") ?? void 0,
26810
- locale: request.headers.get("accept-language")?.split(",")[0]?.trim() || void 0
26811
- };
26812
- }, "hostFromRequest");
26813
- var geoFromCf = /* @__PURE__ */ __name((cf) => {
26814
- const bot = cf?.botManagement;
26815
- const country = detectedCountry(cf);
26816
- return {
26817
- timezone: cf?.timezone ?? void 0,
26818
- city: cf?.city ?? void 0,
26819
- postalCode: cf?.postalCode ?? void 0,
26820
- region: cf?.region ?? void 0,
26821
- regionCode: cf?.regionCode ?? void 0,
26822
- country,
26823
- continent: cf?.continent ?? void 0,
26824
- isEUCountry: euCountry(cf, country),
26825
- latitude: cf?.latitude ?? void 0,
26826
- longitude: cf?.longitude ?? void 0,
26827
- ja4: bot?.ja4,
26828
- ja3: bot?.ja3Hash,
26829
- botScore: bot?.score
26830
- };
26831
- }, "geoFromCf");
26832
- var geoFromRequest = /* @__PURE__ */ __name((request) => {
26833
- return {
26834
- ...hostFromRequest(request),
26835
- ...geoFromCf(request.cf)
26836
- };
26837
- }, "geoFromRequest");
26838
-
26839
- // src/helpers/durable.ts
26840
- var ownGraphEnv = /* @__PURE__ */ __name((ctx, env) => {
26841
- const exports = ctx.exports;
26842
- return {
26843
- ...env,
26844
- get ANON_DO() {
26845
- return exports.AnonDO;
26846
- },
26847
- get GLOBAL_DO() {
26848
- return exports.GlobalDO;
26849
- },
26850
- get ALIAS_DO() {
26851
- return exports.AliasDO;
26852
- }
26853
- };
26854
- }, "ownGraphEnv");
26855
- var JURISDICTIONS = /* @__PURE__ */ new Set(["eu", "fedramp", "fedramp-high", "us"]);
26856
- var LOCATION_HINTS = /* @__PURE__ */ new Set([
26857
- "wnam",
26858
- "enam",
26859
- "sam",
26860
- "weur",
26861
- "eeur",
26862
- "apac",
26863
- "apac-ne",
26864
- "apac-se",
26865
- "oc",
26866
- "afr",
26867
- "me"
26868
- ]);
26869
- var residencyStub = /* @__PURE__ */ __name((namespace, env, name) => {
26870
- const residency = env;
26871
- const jurisdiction = residency.DO_JURISDICTION;
26872
- const scoped = jurisdiction !== void 0 && JURISDICTIONS.has(jurisdiction) ? namespace.jurisdiction(jurisdiction) : namespace;
26873
- const locationHint = residency.LOCATION_HINT;
26874
- const options = locationHint !== void 0 && LOCATION_HINTS.has(locationHint) ? { locationHint } : void 0;
26875
- return scoped.get(scoped.idFromName(name), options);
26876
- }, "residencyStub");
26877
-
26878
- // src/id-graph/anon/client.ts
26879
- var anonStub = /* @__PURE__ */ __name((env, anonId) => {
26880
- return residencyStub(env.ANON_DO, env, anonId);
26881
- }, "anonStub");
26882
-
26883
- // src/id-graph/consent.ts
26884
- var CONSENT_CATEGORIES2 = ["necessary", "functional", "analytics", "marketing", "salesOfData"];
26885
- var CONSENT_CATEGORY_PREFIX = "consent.category.";
26886
- var CONSENT_APP_PREFIX = "consent.app.";
26887
- var consentEntries = /* @__PURE__ */ __name((payload, observedAt) => {
26888
- const entries = [];
26889
- for (const category of CONSENT_CATEGORIES2) {
26890
- const granted = payload.categories[category];
26891
- if (granted === void 0) {
26892
- continue;
26893
- }
26894
- entries.push({ key: `${CONSENT_CATEGORY_PREFIX}${category}`, value: String(granted), observedAt });
26895
- }
26896
- for (const [appId, granted] of Object.entries(payload.apps)) {
26897
- entries.push({ key: `${CONSENT_APP_PREFIX}${appId}`, value: String(granted), observedAt });
26898
- }
26899
- return entries;
26900
- }, "consentEntries");
26901
-
26902
- // src/id-graph/traits.ts
26903
- var PII_KEYS = ["first_name", "last_name", "email", "phone", "country", "state", "city", "postal_code"];
26904
- var snakeCase = /* @__PURE__ */ __name((key) => {
26905
- return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
26906
- }, "snakeCase");
26907
- var stringifyTrait = /* @__PURE__ */ __name((value) => {
26908
- return typeof value === "string" ? value : JSON.stringify(value);
26909
- }, "stringifyTrait");
26910
- var piiTrait = /* @__PURE__ */ __name((key, rawValue) => {
26911
- if (key !== "email" && key !== "phone") {
26912
- return stringifyTrait(rawValue);
26913
- }
26914
- if (typeof rawValue !== "string") {
26915
- return void 0;
26916
- }
26917
- return (key === "email" ? emailIdentifier(rawValue) : phoneIdentifier(rawValue))?.value;
26918
- }, "piiTrait");
26919
- var resolvePiiTrait = /* @__PURE__ */ __name((key, rawValue, unset) => {
26920
- return unset ? null : piiTrait(key, rawValue);
26921
- }, "resolvePiiTrait");
26922
- var classifyTraits = /* @__PURE__ */ __name((traits, observedAt) => {
26923
- const classified = { pii: {}, custom: {}, latest: [], dropped: [] };
26924
- for (const [rawKey, rawValue] of Object.entries(traits)) {
26925
- const key = snakeCase(rawKey);
26926
- const unset = rawValue === null || rawValue === void 0;
26927
- if (PII_KEYS.includes(key)) {
26928
- const value2 = resolvePiiTrait(key, rawValue, unset);
26929
- if (value2 === void 0) {
26930
- classified.dropped.push(key);
26931
- continue;
26932
- }
26933
- classified.pii[key] = value2;
26934
- classified.latest.push({ key: `pii.${key}`, value: value2, observedAt });
26935
- continue;
26936
- }
26937
- const value = unset ? null : stringifyTrait(rawValue);
26938
- classified.custom[key] = value;
26939
- classified.latest.push({ key: `custom.${key}`, value, observedAt });
26940
- }
26941
- return classified;
26942
- }, "classifyTraits");
26943
- var conversionFromTrack = /* @__PURE__ */ __name((payload) => {
26944
- const amount = payload.properties["value"];
26945
- if (typeof amount !== "number" || !Number.isFinite(amount)) {
26946
- return void 0;
26947
- }
26948
- const orderId = payload.properties["orderId"];
26949
- if (typeof orderId !== "string" || orderId === "") {
26950
- return void 0;
26951
- }
26952
- const currency = payload.properties["currency"];
26953
- const contents = payload.properties["contents"];
26954
- return {
26955
- eventName: payload.event,
26956
- eventId: payload.eventId,
26957
- orderId,
26958
- amount,
26959
- currency: typeof currency === "string" ? currency : null,
26960
- contents: contents === void 0 ? null : JSON.stringify(contents)
26961
- };
26962
- }, "conversionFromTrack");
26963
-
26964
- // src/id-graph/alias/client.ts
26965
- var sha256Hex = /* @__PURE__ */ __name(async (value) => {
26966
- const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
26967
- return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
26968
- }, "sha256Hex");
26969
- var aliasKey = /* @__PURE__ */ __name(async (identifier) => {
26970
- return `alias:${identifier.type}:${await sha256Hex(identifier.value)}`;
26971
- }, "aliasKey");
26972
- var fallbackKey = /* @__PURE__ */ __name(async (cookie) => {
26973
- return `fallback:cookie:${await sha256Hex(`${cookie.name}=${cookie.value}`)}`;
26974
- }, "fallbackKey");
26975
- var aliasStub = /* @__PURE__ */ __name((env, key) => {
26976
- return residencyStub(env.ALIAS_DO, env, key);
26977
- }, "aliasStub");
26978
- var getAssignment = /* @__PURE__ */ __name(async (env, identifier) => {
26979
- return traced("rpc alias.get", { attrs: { type: identifier.type } }, async () => {
26980
- return aliasStub(env, await aliasKey(identifier)).get(currentTraceContext());
26981
- });
26982
- }, "getAssignment");
26983
- var claimAnon = /* @__PURE__ */ __name(async (env, identifier, anonId) => {
26984
- return traced("rpc alias.claim_anon", { attrs: { type: identifier.type } }, async () => {
26985
- return aliasStub(env, await aliasKey(identifier)).claimAnon(anonId, currentTraceContext());
26986
- });
26987
- }, "claimAnon");
26988
- var claimFallbackAnon = /* @__PURE__ */ __name(async (env, cookie, anonId) => {
26989
- return traced("rpc alias.claim_anon", { attrs: { type: "fallback" } }, async () => {
26990
- return aliasStub(env, await fallbackKey(cookie)).claimAnon(anonId, currentTraceContext());
26991
- });
26992
- }, "claimFallbackAnon");
26993
- var claimPair = /* @__PURE__ */ __name(async (env, identifier, globalId, anonId) => {
26994
- return traced("rpc alias.claim_pair", { attrs: { type: identifier.type } }, async () => {
26995
- return aliasStub(env, await aliasKey(identifier)).claimPair(globalId, anonId, currentTraceContext());
26996
- });
26997
- }, "claimPair");
26998
-
26999
- // src/id-graph/user.ts
27000
- var EDGETAG_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}-[0-9]{13}$/;
27001
- var isEdgeTagId = /* @__PURE__ */ __name((id) => {
27002
- return EDGETAG_ID.test(id);
27003
- }, "isEdgeTagId");
27004
- var isCanonicalId = /* @__PURE__ */ __name((id) => {
27005
- return id.startsWith("anon_") || isEdgeTagId(id);
27006
- }, "isCanonicalId");
27007
- var generateUserId = /* @__PURE__ */ __name(() => {
27008
- return `anon_${crypto.randomUUID()}`;
27009
- }, "generateUserId");
27010
- var restoreUser = /* @__PURE__ */ __name(async (env, cookie, candidate) => {
27011
- if (cookie === void 0) {
27012
- return candidate;
27013
- }
27014
- const assignment = await claimFallbackAnon(env, cookie, candidate);
27015
- setSpanAttributes({ "qinto.fallback_restored": assignment.anonId !== candidate });
27016
- return assignment.anonId;
27017
- }, "restoreUser");
27018
- var resolveUser = /* @__PURE__ */ __name(async (env, id) => {
27019
- if (isCanonicalId(id)) {
27020
- return { id };
27021
- }
27022
- const identifier = classifyIdentifier(id);
27023
- const assignment = await claimAnon(env, identifier, generateUserId());
27024
- return { id: assignment.anonId, identifier };
27025
- }, "resolveUser");
27026
- var resolveExistingUser = /* @__PURE__ */ __name(async (env, id) => {
27027
- if (isCanonicalId(id)) {
27028
- return { id };
27029
- }
27030
- const identifier = classifyIdentifier(id);
27031
- const anonId = (await getAssignment(env, identifier))?.anonId ?? null;
27032
- return anonId === null ? null : { id: anonId, identifier };
27033
- }, "resolveExistingUser");
27034
- var lookupUser = /* @__PURE__ */ __name(async (env, id) => {
27035
- if (isCanonicalId(id)) {
27036
- const globalId = await traced("rpc anon.get_global_id", {}, () => {
27037
- return anonStub(env, id).getGlobalId(currentTraceContext());
27038
- });
27039
- return { anonId: id, globalId };
27040
- }
27041
- const assignment = await getAssignment(env, classifyIdentifier(id));
27042
- return { anonId: assignment?.anonId ?? null, globalId: assignment?.globalId ?? null };
27043
- }, "lookupUser");
27044
-
27045
- // src/id-graph/noop.ts
27046
- var isNoopConsent = /* @__PURE__ */ __name((payload) => {
27047
- return consentEntries(payload, 0).length === 0;
27048
- }, "isNoopConsent");
27049
- var isNoopIdentify = /* @__PURE__ */ __name((traits) => {
27050
- return Object.keys(traits).length === 0;
27051
- }, "isNoopIdentify");
27052
- var isNoopSubmission = /* @__PURE__ */ __name((userId, args) => {
27053
- if (args.type === "consent") {
27054
- return isNoopConsent(args.payload);
27055
- }
27056
- if (args.type === "identify") {
27057
- return isCanonicalId(userId) && isNoopIdentify(args.payload.traits);
27058
- }
27059
- return false;
27060
- }, "isNoopSubmission");
27061
- var isNoopAction = /* @__PURE__ */ __name((action) => {
27062
- if (action.identifier !== void 0) {
27063
- return false;
27064
- }
27065
- return action.type === "consent" && isNoopConsent(action.payload);
27066
- }, "isNoopAction");
27067
- var isDeliveryOnlyAction = /* @__PURE__ */ __name((action) => {
27068
- if (action.identifier !== void 0 || action.type === "consent") {
27069
- return false;
27070
- }
27071
- return action.type === "track" ? conversionFromTrack(action.payload) === void 0 : isNoopIdentify(action.payload.traits);
27072
- }, "isDeliveryOnlyAction");
27073
-
27074
- // src/id-graph/action.ts
27075
- var UnknownUserError = class extends Error {
27076
- static {
27077
- __name(this, "UnknownUserError");
27078
- }
27079
- constructor() {
27080
- super("the identifier resolves to no user");
27081
- this.name = "UnknownUserError";
27082
- }
27083
- };
27084
- var mintActionId = /* @__PURE__ */ __name(() => {
27085
- return `act_${ulid3()}`;
27086
- }, "mintActionId");
27087
- var buildAction = /* @__PURE__ */ __name((args) => {
27088
- const receivedAt = args.receivedAt ?? Date.now();
27089
- return {
27090
- ...args,
27091
- actionId: mintActionId(),
27092
- receivedAt
27093
- };
27094
- }, "buildAction");
27095
- var ingest = /* @__PURE__ */ __name(async (env, action, site = ownSite(env)) => {
27096
- await traced("rpc anon.ingest", {}, () => {
27097
- return anonStub(env, action.userId).ingest(action, site, currentTraceContext());
27098
- });
27099
- }, "ingest");
27100
- var serverActionContext = /* @__PURE__ */ __name((input2, receivedAt) => {
27101
- const network = input2?.network;
27102
- return {
27103
- source: "server",
27104
- occurredAt: input2?.occurredAt ?? receivedAt,
27105
- ...input2?.page === void 0 ? {} : { page: input2.page },
27106
- ...network === void 0 || network.ip === void 0 && network.userAgent === void 0 && network.locale === void 0 ? {} : { network: { ...network, provenance: "caller" } },
27107
- ...input2?.session === void 0 ? {} : { session: input2.session },
27108
- offline: input2?.offline ?? false,
27109
- replay: input2?.replay ?? false
27110
- };
27111
- }, "serverActionContext");
27112
- var submitAction = /* @__PURE__ */ __name(async (env, userId, args, request) => {
27113
- const attrs = {
27114
- "action.type": args.type,
27115
- "action.payload": JSON.stringify(args.payload),
27116
- "action.identifier": userId,
27117
- ...args.type === "track" ? { "action.event": args.payload.event } : {}
27118
- };
27119
- return traced(`action ${args.type}`, { attrs }, async () => {
27120
- if (isNoopSubmission(userId, args)) {
27121
- setSpanAttributes({ "action.noop": true, ...isCanonicalId(userId) ? { "action.user_id": userId } : {} });
27122
- return mintActionId();
27123
- }
27124
- const resolved = await traced("resolve_user", {}, () => {
27125
- return args.type === "track" ? resolveExistingUser(env, userId) : resolveUser(env, userId);
27126
- });
27127
- if (resolved === null) {
27128
- throw new UnknownUserError();
27129
- }
27130
- const receivedAt = Date.now();
27131
- const action = buildAction({
27132
- ...args,
27133
- userId: resolved.id,
27134
- identifier: resolved.identifier,
27135
- receivedAt,
27136
- context: serverActionContext(args.context, receivedAt),
27137
- geo: request?.cf,
27138
- host: request === void 0 ? void 0 : hostFromRequest(request)
27139
- });
27140
- setSpanAttributes({ "action.user_id": resolved.id, "action.id": action.actionId });
27141
- await ingest(env, action);
27142
- return action.actionId;
27143
- });
27144
- }, "submitAction");
27145
-
27146
- // src/id-graph/projections.ts
27147
- var PII_PREFIX = "pii.";
27148
- var CUSTOM_PREFIX = "custom.";
27149
- var GEO_PREFIX = "geo.";
27150
- var PROJECTION_KINDS = ["pii", "custom", "consent_category", "consent_app", "geo"];
27151
- var PROJECTION_PREFIX = {
27152
- pii: PII_PREFIX,
27153
- custom: CUSTOM_PREFIX,
27154
- consent_category: CONSENT_CATEGORY_PREFIX,
27155
- consent_app: CONSENT_APP_PREFIX,
27156
- geo: GEO_PREFIX
27157
- };
27158
- var FANOUT_KINDS = ["pii", "custom", "consent_category", "consent_app"];
27159
- var projectionFact = /* @__PURE__ */ __name((projectionKey) => {
27160
- for (const kind2 of PROJECTION_KINDS) {
27161
- const prefix = PROJECTION_PREFIX[kind2];
27162
- if (projectionKey.startsWith(prefix)) {
27163
- return { kind: kind2, scope: "", key: projectionKey.slice(prefix.length) };
27164
- }
27165
- }
27166
- throw new Error(`Unknown projection key: ${projectionKey}`);
27167
- }, "projectionFact");
27168
-
27169
- // src/id-graph/anon/facts.ts
27170
- var FACT_KINDS = [
27171
- ...PROJECTION_KINDS,
27172
- "capture",
27173
- "identifier",
27174
- "conversion",
27175
- "context_private_kv",
27176
- "context_private_text",
27177
- "context_shared_kv",
27178
- "context_shared_text"
27179
- ];
27180
- var APP_FACT_KINDS = ["custom", "capture", "identifier", "conversion", "pii", "consent_category", "consent_app", "geo"];
27181
- var MAX_APP_FACTS_PER_PAGE = 100;
27182
- var MAX_APP_FACT_PAGE_BYTES = 1024 * 1024;
27183
- var COLUMNS = "kind, scope, key, value, source, type, amount, currency, event_id, data_json, first_at, observed_at, synced_at, expires_at";
27184
- var rowOf = /* @__PURE__ */ __name((row) => {
27185
- return {
27186
- kind: row.kind,
27187
- scope: row.scope,
27188
- key: row.key,
27189
- value: row.value,
27190
- source: row.source,
27191
- type: row.type,
27192
- amount: row.amount,
27193
- currency: row.currency,
27194
- eventId: row.event_id,
27195
- dataJson: row.data_json,
27196
- firstAt: row.first_at,
27197
- observedAt: row.observed_at,
27198
- syncedAt: row.synced_at,
27199
- expiresAt: row.expires_at
27200
- };
27201
- }, "rowOf");
27202
- var appFactOf = /* @__PURE__ */ __name((row) => {
27203
- const { syncedAt: _syncedAt, expiresAt: _expiresAt, ...fact } = rowOf(row);
27204
- return { ...fact, kind: fact.kind };
27205
- }, "appFactOf");
27206
- var listAppFacts = /* @__PURE__ */ __name((sql, query, now) => {
27207
- const maxRowId = query.maxRowId ?? sql.exec("SELECT MAX(rowid) AS maxRowId FROM facts").one().maxRowId;
27208
- if (maxRowId === null) {
27209
- return { items: [], next: null };
27210
- }
27211
- const where = ["rowid > ?", "rowid <= ?", "(expires_at IS NULL OR expires_at > ?)"];
27212
- const params = [query.afterRowId, maxRowId, now];
27213
- if (query.kinds.length > 0) {
27214
- where.push(`kind IN (${query.kinds.map(() => "?").join(", ")})`);
27215
- params.push(...query.kinds);
27216
- }
27217
- if (query.observedAtGte !== null) {
27218
- where.push("observed_at >= ?");
27219
- params.push(query.observedAtGte);
27220
- }
27221
- if (query.observedAtLt !== null) {
27222
- where.push("observed_at < ?");
27223
- params.push(query.observedAtLt);
27224
- }
27225
- const rows = sql.exec(`SELECT rowid, ${COLUMNS} FROM facts WHERE ${where.join(" AND ")} ORDER BY rowid LIMIT ?`, ...params, query.limit + 1).toArray();
27226
- const items = [];
27227
- let lastRowId = query.afterRowId;
27228
- for (const row of rows.slice(0, query.limit)) {
27229
- const fact = appFactOf(row);
27230
- const candidate = [...items, fact];
27231
- if (new TextEncoder().encode(JSON.stringify(candidate)).byteLength > MAX_APP_FACT_PAGE_BYTES) {
27232
- if (items.length === 0) {
27233
- throw new Error("fact_too_large");
27234
- }
27235
- break;
27236
- }
27237
- items.push(fact);
27238
- lastRowId = row.rowid;
27239
- }
27240
- const hasMore = rows.length > items.length;
27241
- return { items, next: hasMore ? { afterRowId: lastRowId, maxRowId } : null };
27242
- }, "listAppFacts");
27243
- var insertFact = /* @__PURE__ */ __name((sql, fact) => {
27244
- sql.exec(
27245
- `INSERT INTO facts (${COLUMNS}) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?)`,
27246
- fact.kind,
27247
- fact.scope,
27248
- fact.key,
27249
- fact.value ?? null,
27250
- fact.source ?? null,
27251
- fact.type ?? null,
27252
- fact.amount ?? null,
27253
- fact.currency ?? null,
27254
- fact.eventId ?? null,
27255
- fact.dataJson ?? null,
27256
- fact.firstAt ?? null,
27257
- fact.observedAt,
27258
- fact.expiresAt ?? null
27259
- );
27260
- }, "insertFact");
27261
- var latestFact = /* @__PURE__ */ __name((sql, coords) => {
27262
- const row = sql.exec(
27263
- `SELECT ${COLUMNS} FROM facts WHERE kind = ? AND scope = ? AND key = ? ORDER BY observed_at DESC, rowid DESC LIMIT 1`,
27264
- coords.kind,
27265
- coords.scope,
27266
- coords.key
27267
- ).toArray().at(0);
27268
- return row === void 0 ? void 0 : rowOf(row);
27269
- }, "latestFact");
27270
- var latestFacts = /* @__PURE__ */ __name((sql, kind2) => {
27271
- const rows = sql.exec(`SELECT ${COLUMNS} FROM facts WHERE kind = ? ORDER BY scope, key, observed_at, rowid`, kind2).toArray();
27272
- const latest = [];
27273
- for (const row of rows) {
27274
- const previous = latest.at(-1);
27275
- if (previous !== void 0 && previous.scope === row.scope && previous.key === row.key) {
27276
- latest[latest.length - 1] = rowOf(row);
27277
- continue;
27278
- }
27279
- latest.push(rowOf(row));
27280
- }
27281
- return latest;
27282
- }, "latestFacts");
27283
-
27284
- // src/id-graph/global/client.ts
27285
- var globalStub = /* @__PURE__ */ __name((env, globalId) => {
27286
- return residencyStub(env.GLOBAL_DO, env, globalId);
27287
- }, "globalStub");
27288
-
27289
- // src/id-graph/global/facts.ts
27290
- var FACT_KINDS2 = [...PROJECTION_KINDS, "identifier", "conversion", "anon"];
27291
- var FACT_COLUMNS = "kind, scope, key, value, source, amount, currency, event_id, data_json, first_at, observed_at";
27292
- var rowOf2 = /* @__PURE__ */ __name((row) => {
26953
+ // src/id-graph/alias/client.ts
26954
+ var sha256Hex = /* @__PURE__ */ __name(async (value) => {
26955
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
26956
+ return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
26957
+ }, "sha256Hex");
26958
+ var aliasKey = /* @__PURE__ */ __name(async (identifier) => {
26959
+ return `alias:${identifier.type}:${await sha256Hex(identifier.value)}`;
26960
+ }, "aliasKey");
26961
+ var fallbackKey = /* @__PURE__ */ __name(async (cookie) => {
26962
+ return `fallback:cookie:${await sha256Hex(`${cookie.name}=${cookie.value}`)}`;
26963
+ }, "fallbackKey");
26964
+ var aliasStub = /* @__PURE__ */ __name((env, key) => {
26965
+ return residencyStub(env.ALIAS_DO, env, key);
26966
+ }, "aliasStub");
26967
+ var getAssignment = /* @__PURE__ */ __name(async (env, identifier) => {
26968
+ return traced("rpc alias.get", { attrs: { type: identifier.type } }, async () => {
26969
+ return aliasStub(env, await aliasKey(identifier)).get(currentTraceContext());
26970
+ });
26971
+ }, "getAssignment");
26972
+ var claimAnon = /* @__PURE__ */ __name(async (env, identifier, anonId) => {
26973
+ return traced("rpc alias.claim_anon", { attrs: { type: identifier.type } }, async () => {
26974
+ return aliasStub(env, await aliasKey(identifier)).claimAnon(anonId, currentTraceContext());
26975
+ });
26976
+ }, "claimAnon");
26977
+ var claimFallbackAnon = /* @__PURE__ */ __name(async (env, cookie, anonId) => {
26978
+ return traced("rpc alias.claim_anon", { attrs: { type: "fallback" } }, async () => {
26979
+ return aliasStub(env, await fallbackKey(cookie)).claimAnon(anonId, currentTraceContext());
26980
+ });
26981
+ }, "claimFallbackAnon");
26982
+ var claimPair = /* @__PURE__ */ __name(async (env, identifier, globalId, anonId) => {
26983
+ return traced("rpc alias.claim_pair", { attrs: { type: identifier.type } }, async () => {
26984
+ return aliasStub(env, await aliasKey(identifier)).claimPair(globalId, anonId, currentTraceContext());
26985
+ });
26986
+ }, "claimPair");
26987
+
26988
+ // src/id-graph/global/client.ts
26989
+ var globalStub = /* @__PURE__ */ __name((env, globalId) => {
26990
+ return residencyStub(env.GLOBAL_DO, env, globalId);
26991
+ }, "globalStub");
26992
+
26993
+ // src/id-graph/global/facts.ts
26994
+ var FACT_KINDS2 = [...PROJECTION_KINDS, "identifier", "conversion", "anon"];
26995
+ var FACT_COLUMNS = "kind, scope, key, value, source, amount, currency, event_id, data_json, first_at, observed_at";
26996
+ var rowOf2 = /* @__PURE__ */ __name((row) => {
27293
26997
  return {
27294
26998
  kind: row.kind,
27295
26999
  scope: row.scope,
@@ -27358,6 +27062,52 @@ var allLinkedAnons = /* @__PURE__ */ __name((sql) => {
27358
27062
  return sql.exec("SELECT key FROM facts WHERE kind = 'anon' ORDER BY rowid").toArray().map((row) => row.key);
27359
27063
  }, "allLinkedAnons");
27360
27064
 
27065
+ // src/id-graph/user.ts
27066
+ var EDGETAG_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}-[0-9]{13}$/;
27067
+ var isEdgeTagId = /* @__PURE__ */ __name((id) => {
27068
+ return EDGETAG_ID.test(id);
27069
+ }, "isEdgeTagId");
27070
+ var isCanonicalId = /* @__PURE__ */ __name((id) => {
27071
+ return id.startsWith("anon_") || isEdgeTagId(id);
27072
+ }, "isCanonicalId");
27073
+ var generateUserId = /* @__PURE__ */ __name(() => {
27074
+ return `anon_${crypto.randomUUID()}`;
27075
+ }, "generateUserId");
27076
+ var restoreUser = /* @__PURE__ */ __name(async (env, cookie, candidate) => {
27077
+ if (cookie === void 0) {
27078
+ return candidate;
27079
+ }
27080
+ const assignment = await claimFallbackAnon(env, cookie, candidate);
27081
+ setSpanAttributes({ "qinto.fallback_restored": assignment.anonId !== candidate });
27082
+ return assignment.anonId;
27083
+ }, "restoreUser");
27084
+ var resolveUser = /* @__PURE__ */ __name(async (env, id) => {
27085
+ if (isCanonicalId(id)) {
27086
+ return { id };
27087
+ }
27088
+ const identifier = classifyIdentifier(id);
27089
+ const assignment = await claimAnon(env, identifier, generateUserId());
27090
+ return { id: assignment.anonId, identifier };
27091
+ }, "resolveUser");
27092
+ var resolveExistingUser = /* @__PURE__ */ __name(async (env, id) => {
27093
+ if (isCanonicalId(id)) {
27094
+ return { id };
27095
+ }
27096
+ const identifier = classifyIdentifier(id);
27097
+ const anonId = (await getAssignment(env, identifier))?.anonId ?? null;
27098
+ return anonId === null ? null : { id: anonId, identifier };
27099
+ }, "resolveExistingUser");
27100
+ var lookupUser = /* @__PURE__ */ __name(async (env, id) => {
27101
+ if (isCanonicalId(id)) {
27102
+ const globalId = await traced("rpc anon.get_global_id", {}, () => {
27103
+ return anonStub(env, id).getGlobalId(currentTraceContext());
27104
+ });
27105
+ return { anonId: id, globalId };
27106
+ }
27107
+ const assignment = await getAssignment(env, classifyIdentifier(id));
27108
+ return { anonId: assignment?.anonId ?? null, globalId: assignment?.globalId ?? null };
27109
+ }, "lookupUser");
27110
+
27361
27111
  // src/id-graph/person.ts
27362
27112
  var IDENTITY_CAPABILITY = "identity";
27363
27113
  var personLink = /* @__PURE__ */ __name(async (env, anonId) => {
@@ -27517,40 +27267,302 @@ var refreshCurrencyRates = /* @__PURE__ */ __name(async () => {
27517
27267
  currencyMemo = { current: current2, nextAttemptAt: now + RETRY_AFTER_FAILURE_MS };
27518
27268
  return current2;
27519
27269
  }
27520
- const current = { rates, fetchedAt: now };
27521
- currencyMemo = { current, nextAttemptAt: now + RATES_TTL_MS };
27522
- return current;
27523
- }, "refreshCurrencyRates");
27524
- var currentCurrencyRates = /* @__PURE__ */ __name(async (ctx) => {
27525
- const now = Date.now();
27526
- if (currencyMemo !== void 0 && now < currencyMemo.nextAttemptAt) {
27527
- return currencyMemo.current;
27270
+ const current = { rates, fetchedAt: now };
27271
+ currencyMemo = { current, nextAttemptAt: now + RATES_TTL_MS };
27272
+ return current;
27273
+ }, "refreshCurrencyRates");
27274
+ var currentCurrencyRates = /* @__PURE__ */ __name(async (ctx) => {
27275
+ const now = Date.now();
27276
+ if (currencyMemo !== void 0 && now < currencyMemo.nextAttemptAt) {
27277
+ return currencyMemo.current;
27278
+ }
27279
+ const stale = currencyMemo?.current ?? null;
27280
+ if (stale === null) {
27281
+ return refreshCurrencyRates();
27282
+ }
27283
+ currencyMemo = { current: stale, nextAttemptAt: now + RETRY_AFTER_FAILURE_MS };
27284
+ ctx.waitUntil(
27285
+ runInvocation({ name: "currency.refresh", trace: currentTraceContext() }, () => {
27286
+ return refreshCurrencyRates();
27287
+ })
27288
+ );
27289
+ return stale;
27290
+ }, "currentCurrencyRates");
27291
+
27292
+ // src/apps/broker-currency.ts
27293
+ var currencyRatesBody = external_exports.object({
27294
+ ...identityFields,
27295
+ kind: external_exports.literal("currencyRates")
27296
+ }).strict();
27297
+ var handleCurrencyRates = /* @__PURE__ */ __name(async (ctx) => {
27298
+ const current = await currentCurrencyRates(ctx);
27299
+ if (current === null) {
27300
+ return Response.json({ error: "currency_rates_unavailable" }, { status: 503 });
27301
+ }
27302
+ return Response.json(current);
27303
+ }, "handleCurrencyRates");
27304
+
27305
+ // ../../libs/cf-data/src/cf-data.ts
27306
+ var CF_DATA_HEADER = "x-cf-data";
27307
+ var cfDataFrom = /* @__PURE__ */ __name((cf) => {
27308
+ return {
27309
+ country: cf?.country,
27310
+ city: cf?.city,
27311
+ region: cf?.region,
27312
+ regionCode: cf?.regionCode,
27313
+ timezone: cf?.timezone,
27314
+ postalCode: cf?.postalCode,
27315
+ continent: cf?.continent,
27316
+ longitude: cf?.longitude,
27317
+ latitude: cf?.latitude,
27318
+ isEUCountry: cf?.isEUCountry,
27319
+ botManagement: {
27320
+ ja4: cf?.botManagement?.ja4,
27321
+ ja3Hash: cf?.botManagement?.ja3Hash,
27322
+ score: cf?.botManagement?.score,
27323
+ verifiedBot: cf?.botManagement?.verifiedBot
27324
+ }
27325
+ };
27326
+ }, "cfDataFrom");
27327
+ var parseCfData = /* @__PURE__ */ __name((raw2) => {
27328
+ if (raw2 === null) {
27329
+ return void 0;
27330
+ }
27331
+ let parsed;
27332
+ try {
27333
+ parsed = JSON.parse(raw2);
27334
+ } catch {
27335
+ return void 0;
27336
+ }
27337
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
27338
+ return void 0;
27339
+ }
27340
+ return parsed;
27341
+ }, "parseCfData");
27342
+
27343
+ // src/helpers/geo.ts
27344
+ var UNDETERMINED_COUNTRIES = /* @__PURE__ */ new Set(["XX", "T1"]);
27345
+ var detectedCountry = /* @__PURE__ */ __name((cf) => {
27346
+ const country = cf?.country;
27347
+ return country && !UNDETERMINED_COUNTRIES.has(country) ? country : void 0;
27348
+ }, "detectedCountry");
27349
+ var euCountry = /* @__PURE__ */ __name((cf, country) => {
27350
+ if (cf?.isEUCountry === "1") {
27351
+ return "yes";
27352
+ }
27353
+ return country ? "no" : "unknown";
27354
+ }, "euCountry");
27355
+ var withForwardedCf = /* @__PURE__ */ __name((request) => {
27356
+ if (request.cf !== void 0) {
27357
+ return request;
27358
+ }
27359
+ const cf = parseCfData(request.headers.get(CF_DATA_HEADER));
27360
+ return cf === void 0 ? request : new Request(request, { cf });
27361
+ }, "withForwardedCf");
27362
+ var loggableGeo = /* @__PURE__ */ __name((geo) => {
27363
+ const fields = {};
27364
+ for (const [key, value] of Object.entries(geo)) {
27365
+ if (value !== void 0) {
27366
+ fields[key] = String(value);
27367
+ }
27368
+ }
27369
+ return fields;
27370
+ }, "loggableGeo");
27371
+ var hostFromRequest = /* @__PURE__ */ __name((request) => {
27372
+ return {
27373
+ ip: request.headers.get("cf-connecting-ip") ?? void 0,
27374
+ userAgent: request.headers.get("user-agent") ?? void 0,
27375
+ locale: request.headers.get("accept-language")?.split(",")[0]?.trim() || void 0
27376
+ };
27377
+ }, "hostFromRequest");
27378
+ var geoFromCf = /* @__PURE__ */ __name((cf) => {
27379
+ const bot = cf?.botManagement;
27380
+ const country = detectedCountry(cf);
27381
+ return {
27382
+ timezone: cf?.timezone ?? void 0,
27383
+ city: cf?.city ?? void 0,
27384
+ postalCode: cf?.postalCode ?? void 0,
27385
+ region: cf?.region ?? void 0,
27386
+ regionCode: cf?.regionCode ?? void 0,
27387
+ country,
27388
+ continent: cf?.continent ?? void 0,
27389
+ isEUCountry: euCountry(cf, country),
27390
+ latitude: cf?.latitude ?? void 0,
27391
+ longitude: cf?.longitude ?? void 0,
27392
+ ja4: bot?.ja4,
27393
+ ja3: bot?.ja3Hash,
27394
+ botScore: bot?.score
27395
+ };
27396
+ }, "geoFromCf");
27397
+ var geoFromRequest = /* @__PURE__ */ __name((request) => {
27398
+ return {
27399
+ ...hostFromRequest(request),
27400
+ ...geoFromCf(request.cf)
27401
+ };
27402
+ }, "geoFromRequest");
27403
+
27404
+ // src/id-graph/traits.ts
27405
+ var PII_KEYS = ["first_name", "last_name", "email", "phone", "country", "state", "city", "postal_code"];
27406
+ var snakeCase = /* @__PURE__ */ __name((key) => {
27407
+ return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
27408
+ }, "snakeCase");
27409
+ var stringifyTrait = /* @__PURE__ */ __name((value) => {
27410
+ return typeof value === "string" ? value : JSON.stringify(value);
27411
+ }, "stringifyTrait");
27412
+ var piiTrait = /* @__PURE__ */ __name((key, rawValue) => {
27413
+ if (key !== "email" && key !== "phone") {
27414
+ return stringifyTrait(rawValue);
27415
+ }
27416
+ if (typeof rawValue !== "string") {
27417
+ return void 0;
27418
+ }
27419
+ return (key === "email" ? emailIdentifier(rawValue) : phoneIdentifier(rawValue))?.value;
27420
+ }, "piiTrait");
27421
+ var resolvePiiTrait = /* @__PURE__ */ __name((key, rawValue, unset) => {
27422
+ return unset ? null : piiTrait(key, rawValue);
27423
+ }, "resolvePiiTrait");
27424
+ var classifyTraits = /* @__PURE__ */ __name((traits, observedAt) => {
27425
+ const classified = { pii: {}, custom: {}, latest: [], dropped: [] };
27426
+ for (const [rawKey, rawValue] of Object.entries(traits)) {
27427
+ const key = snakeCase(rawKey);
27428
+ const unset = rawValue === null || rawValue === void 0;
27429
+ if (PII_KEYS.includes(key)) {
27430
+ const value2 = resolvePiiTrait(key, rawValue, unset);
27431
+ if (value2 === void 0) {
27432
+ classified.dropped.push(key);
27433
+ continue;
27434
+ }
27435
+ classified.pii[key] = value2;
27436
+ classified.latest.push({ key: `pii.${key}`, value: value2, observedAt });
27437
+ continue;
27438
+ }
27439
+ const value = unset ? null : stringifyTrait(rawValue);
27440
+ classified.custom[key] = value;
27441
+ classified.latest.push({ key: `custom.${key}`, value, observedAt });
27442
+ }
27443
+ return classified;
27444
+ }, "classifyTraits");
27445
+ var conversionFromTrack = /* @__PURE__ */ __name((payload) => {
27446
+ const amount = payload.properties["value"];
27447
+ if (typeof amount !== "number" || !Number.isFinite(amount)) {
27448
+ return void 0;
27449
+ }
27450
+ const orderId = payload.properties["orderId"];
27451
+ if (typeof orderId !== "string" || orderId === "") {
27452
+ return void 0;
27453
+ }
27454
+ const currency = payload.properties["currency"];
27455
+ const contents = payload.properties["contents"];
27456
+ return {
27457
+ eventName: payload.event,
27458
+ eventId: payload.eventId,
27459
+ orderId,
27460
+ amount,
27461
+ currency: typeof currency === "string" ? currency : null,
27462
+ contents: contents === void 0 ? null : JSON.stringify(contents)
27463
+ };
27464
+ }, "conversionFromTrack");
27465
+
27466
+ // src/id-graph/noop.ts
27467
+ var isNoopConsent = /* @__PURE__ */ __name((payload) => {
27468
+ return consentEntries(payload, 0).length === 0;
27469
+ }, "isNoopConsent");
27470
+ var isNoopIdentify = /* @__PURE__ */ __name((traits) => {
27471
+ return Object.keys(traits).length === 0;
27472
+ }, "isNoopIdentify");
27473
+ var isNoopSubmission = /* @__PURE__ */ __name((userId, args) => {
27474
+ if (args.type === "consent") {
27475
+ return isNoopConsent(args.payload);
27476
+ }
27477
+ if (args.type === "identify") {
27478
+ return isCanonicalId(userId) && isNoopIdentify(args.payload.traits);
27528
27479
  }
27529
- const stale = currencyMemo?.current ?? null;
27530
- if (stale === null) {
27531
- return refreshCurrencyRates();
27480
+ return false;
27481
+ }, "isNoopSubmission");
27482
+ var isNoopAction = /* @__PURE__ */ __name((action) => {
27483
+ if (action.identifier !== void 0) {
27484
+ return false;
27532
27485
  }
27533
- currencyMemo = { current: stale, nextAttemptAt: now + RETRY_AFTER_FAILURE_MS };
27534
- ctx.waitUntil(
27535
- runInvocation({ name: "currency.refresh", trace: currentTraceContext() }, () => {
27536
- return refreshCurrencyRates();
27537
- })
27538
- );
27539
- return stale;
27540
- }, "currentCurrencyRates");
27486
+ return action.type === "consent" && isNoopConsent(action.payload);
27487
+ }, "isNoopAction");
27488
+ var isDeliveryOnlyAction = /* @__PURE__ */ __name((action) => {
27489
+ if (action.identifier !== void 0 || action.type === "consent") {
27490
+ return false;
27491
+ }
27492
+ return action.type === "track" ? conversionFromTrack(action.payload) === void 0 : isNoopIdentify(action.payload.traits);
27493
+ }, "isDeliveryOnlyAction");
27541
27494
 
27542
- // src/apps/broker-currency.ts
27543
- var currencyRatesBody = external_exports.object({
27544
- ...identityFields,
27545
- kind: external_exports.literal("currencyRates")
27546
- }).strict();
27547
- var handleCurrencyRates = /* @__PURE__ */ __name(async (ctx) => {
27548
- const current = await currentCurrencyRates(ctx);
27549
- if (current === null) {
27550
- return Response.json({ error: "currency_rates_unavailable" }, { status: 503 });
27495
+ // src/id-graph/action.ts
27496
+ var UnknownUserError = class extends Error {
27497
+ static {
27498
+ __name(this, "UnknownUserError");
27551
27499
  }
27552
- return Response.json(current);
27553
- }, "handleCurrencyRates");
27500
+ constructor() {
27501
+ super("the identifier resolves to no user");
27502
+ this.name = "UnknownUserError";
27503
+ }
27504
+ };
27505
+ var mintActionId = /* @__PURE__ */ __name(() => {
27506
+ return `act_${ulid3()}`;
27507
+ }, "mintActionId");
27508
+ var buildAction = /* @__PURE__ */ __name((args) => {
27509
+ const receivedAt = args.receivedAt ?? Date.now();
27510
+ return {
27511
+ ...args,
27512
+ actionId: mintActionId(),
27513
+ receivedAt
27514
+ };
27515
+ }, "buildAction");
27516
+ var ingest = /* @__PURE__ */ __name(async (env, action, site = ownSite(env)) => {
27517
+ await traced("rpc anon.ingest", {}, () => {
27518
+ return anonStub(env, action.userId).ingest(action, site, currentTraceContext());
27519
+ });
27520
+ }, "ingest");
27521
+ var serverActionContext = /* @__PURE__ */ __name((input2, receivedAt) => {
27522
+ const network = input2?.network;
27523
+ return {
27524
+ source: "server",
27525
+ occurredAt: input2?.occurredAt ?? receivedAt,
27526
+ ...input2?.page === void 0 ? {} : { page: input2.page },
27527
+ ...network === void 0 || network.ip === void 0 && network.userAgent === void 0 && network.locale === void 0 ? {} : { network: { ...network, provenance: "caller" } },
27528
+ ...input2?.session === void 0 ? {} : { session: input2.session },
27529
+ offline: input2?.offline ?? false,
27530
+ replay: input2?.replay ?? false
27531
+ };
27532
+ }, "serverActionContext");
27533
+ var submitAction = /* @__PURE__ */ __name(async (env, userId, args, request) => {
27534
+ const attrs = {
27535
+ "action.type": args.type,
27536
+ "action.payload": JSON.stringify(args.payload),
27537
+ "action.identifier": userId,
27538
+ ...args.type === "track" ? { "action.event": args.payload.event } : {}
27539
+ };
27540
+ return traced(`action ${args.type}`, { attrs }, async () => {
27541
+ if (isNoopSubmission(userId, args)) {
27542
+ setSpanAttributes({ "action.noop": true, ...isCanonicalId(userId) ? { "action.user_id": userId } : {} });
27543
+ return mintActionId();
27544
+ }
27545
+ const resolved = await traced("resolve_user", {}, () => {
27546
+ return args.type === "track" ? resolveExistingUser(env, userId) : resolveUser(env, userId);
27547
+ });
27548
+ if (resolved === null) {
27549
+ throw new UnknownUserError();
27550
+ }
27551
+ const receivedAt = Date.now();
27552
+ const action = buildAction({
27553
+ ...args,
27554
+ userId: resolved.id,
27555
+ identifier: resolved.identifier,
27556
+ receivedAt,
27557
+ context: serverActionContext(args.context, receivedAt),
27558
+ geo: request?.cf,
27559
+ host: request === void 0 ? void 0 : hostFromRequest(request)
27560
+ });
27561
+ setSpanAttributes({ "action.user_id": resolved.id, "action.id": action.actionId });
27562
+ await ingest(env, action);
27563
+ return action.actionId;
27564
+ });
27565
+ }, "submitAction");
27554
27566
 
27555
27567
  // src/id-graph/upsert.ts
27556
27568
  var identifierValue = external_exports.string().min(1).max(256).optional();
@@ -27638,35 +27650,249 @@ var rateLimited = /* @__PURE__ */ __name(async (env, key, binding = "BROKER_RATE
27638
27650
  }
27639
27651
  return false;
27640
27652
  }
27641
- const outcome = await limiter.limit({ key });
27642
- return !outcome.success;
27643
- }, "rateLimited");
27653
+ const outcome = await limiter.limit({ key });
27654
+ return !outcome.success;
27655
+ }, "rateLimited");
27656
+
27657
+ // src/apps/broker-identity.ts
27658
+ var identityUpsertBody = external_exports.object({
27659
+ ...identityFields,
27660
+ kind: external_exports.literal("identityUpsert"),
27661
+ person: personUpsertSchema
27662
+ }).strict();
27663
+ var identityGranted = /* @__PURE__ */ __name((slug) => {
27664
+ return siteRegistry().registry.apps[slug]?.data.includes(IDENTITY_CAPABILITY) === true;
27665
+ }, "identityGranted");
27666
+ var identityPermissionDenied = /* @__PURE__ */ __name(() => {
27667
+ return Response.json({ error: "identity_permission_denied" }, { status: 403 });
27668
+ }, "identityPermissionDenied");
27669
+ var handleIdentityUpsert = /* @__PURE__ */ __name(async (env, body) => {
27670
+ if (!identityGranted(body.slug)) {
27671
+ return identityPermissionDenied();
27672
+ }
27673
+ if (await rateLimited(env, `${body.slug}::identity-upsert`)) {
27674
+ return Response.json({ error: "rate_limited" }, { status: 429 });
27675
+ }
27676
+ const upserted = await upsertPerson(env, body.person);
27677
+ if (upserted === null) {
27678
+ return Response.json({ error: "invalid_identifier" }, { status: 400 });
27679
+ }
27680
+ return Response.json(upserted);
27681
+ }, "handleIdentityUpsert");
27682
+
27683
+ // ../../libs/app-ui-token/src/base64url.ts
27684
+ var base64UrlEncode = /* @__PURE__ */ __name((bytes) => {
27685
+ let binary = "";
27686
+ for (const byte of bytes) {
27687
+ binary += String.fromCharCode(byte);
27688
+ }
27689
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
27690
+ }, "base64UrlEncode");
27691
+ var base64UrlDecode = /* @__PURE__ */ __name((text) => {
27692
+ const padded = text.replaceAll("-", "+").replaceAll("_", "/").padEnd(text.length + (4 - text.length % 4) % 4, "=");
27693
+ let binary;
27694
+ try {
27695
+ binary = atob(padded);
27696
+ } catch {
27697
+ return null;
27698
+ }
27699
+ const bytes = new Uint8Array(binary.length);
27700
+ for (let index = 0; index < binary.length; index += 1) {
27701
+ bytes[index] = binary.charCodeAt(index);
27702
+ }
27703
+ return bytes;
27704
+ }, "base64UrlDecode");
27705
+
27706
+ // ../../libs/app-ui-token/src/env.ts
27707
+ var envSchema = external_exports.object({
27708
+ v: external_exports.literal(1),
27709
+ keys: external_exports.record(external_exports.string().min(1).max(16), external_exports.string().min(1))
27710
+ }).strict();
27711
+ var parseAppUiKeyEnv = /* @__PURE__ */ __name((raw2) => {
27712
+ let json2;
27713
+ try {
27714
+ json2 = JSON.parse(raw2);
27715
+ } catch {
27716
+ return null;
27717
+ }
27718
+ const parsed = envSchema.safeParse(json2);
27719
+ if (!parsed.success) {
27720
+ return null;
27721
+ }
27722
+ const keys = {};
27723
+ for (const [kid, encoded] of Object.entries(parsed.data.keys)) {
27724
+ const bytes = base64UrlDecode(encoded);
27725
+ if (bytes === null) {
27726
+ return null;
27727
+ }
27728
+ keys[kid] = bytes;
27729
+ }
27730
+ return keys;
27731
+ }, "parseAppUiKeyEnv");
27732
+
27733
+ // ../../libs/app-ui-token/src/jwt.ts
27734
+ var headerSchema = external_exports.object({
27735
+ alg: external_exports.literal("HS256"),
27736
+ typ: external_exports.literal("JWT"),
27737
+ kid: external_exports.string().min(1).max(16)
27738
+ }).strict();
27739
+ var encodeJsonPart = /* @__PURE__ */ __name((value) => {
27740
+ return base64UrlEncode(new TextEncoder().encode(JSON.stringify(value)));
27741
+ }, "encodeJsonPart");
27742
+ var parseJsonPart = /* @__PURE__ */ __name((part) => {
27743
+ const bytes = base64UrlDecode(part);
27744
+ if (bytes === null) {
27745
+ return null;
27746
+ }
27747
+ try {
27748
+ return JSON.parse(new TextDecoder().decode(bytes));
27749
+ } catch {
27750
+ return null;
27751
+ }
27752
+ }, "parseJsonPart");
27753
+ var hmacKey = /* @__PURE__ */ __name((key, usage) => {
27754
+ return crypto.subtle.importKey("raw", key, { name: "HMAC", hash: "SHA-256" }, false, [usage]);
27755
+ }, "hmacKey");
27756
+ var signCompact = /* @__PURE__ */ __name(async (kid, key, claims) => {
27757
+ const signingInput = `${encodeJsonPart({ alg: "HS256", typ: "JWT", kid })}.${encodeJsonPart(claims)}`;
27758
+ const signature = await crypto.subtle.sign("HMAC", await hmacKey(key, "sign"), new TextEncoder().encode(signingInput));
27759
+ return `${signingInput}.${base64UrlEncode(new Uint8Array(signature))}`;
27760
+ }, "signCompact");
27761
+ var verifyCompactSignature = /* @__PURE__ */ __name(async (token, keys) => {
27762
+ const [headerPart, claimsPart, signaturePart, extra] = token.split(".");
27763
+ if (headerPart === void 0 || claimsPart === void 0 || signaturePart === void 0 || extra !== void 0) {
27764
+ return { ok: false, reason: "malformed" };
27765
+ }
27766
+ const header = headerSchema.safeParse(parseJsonPart(headerPart));
27767
+ if (!header.success) {
27768
+ return { ok: false, reason: "malformed" };
27769
+ }
27770
+ const key = keys[header.data.kid];
27771
+ if (key === void 0) {
27772
+ return { ok: false, reason: "unknown_kid" };
27773
+ }
27774
+ const signature = base64UrlDecode(signaturePart);
27775
+ if (signature === null) {
27776
+ return { ok: false, reason: "malformed" };
27777
+ }
27778
+ const signed = await crypto.subtle.verify(
27779
+ "HMAC",
27780
+ await hmacKey(key, "verify"),
27781
+ signature,
27782
+ new TextEncoder().encode(`${headerPart}.${claimsPart}`)
27783
+ );
27784
+ if (!signed) {
27785
+ return { ok: false, reason: "bad_signature" };
27786
+ }
27787
+ return { ok: true, claims: parseJsonPart(claimsPart), kid: header.data.kid, key };
27788
+ }, "verifyCompactSignature");
27644
27789
 
27645
- // src/apps/broker-identity.ts
27646
- var identityUpsertBody = external_exports.object({
27647
- ...identityFields,
27648
- kind: external_exports.literal("identityUpsert"),
27649
- person: personUpsertSchema
27790
+ // ../../libs/app-ui-token/src/token.ts
27791
+ var APP_UI_TOKEN_SKEW_SECONDS = 60;
27792
+ var APP_UI_TOKEN_ISSUER = "qinto-portal";
27793
+ var claimsSchema = external_exports.object({
27794
+ iss: external_exports.literal(APP_UI_TOKEN_ISSUER),
27795
+ aud: external_exports.string().min(1),
27796
+ sub: external_exports.string().min(1),
27797
+ userId: external_exports.string().min(1),
27798
+ iat: external_exports.number().int(),
27799
+ exp: external_exports.number().int(),
27800
+ domainId: external_exports.string().min(1),
27801
+ appId: external_exports.string().min(1),
27802
+ appInstallId: external_exports.string().min(1),
27803
+ appVersionId: external_exports.string().min(1),
27804
+ access: external_exports.enum(["read", "write"]),
27805
+ // Absent means `full`; see the mint below.
27806
+ appRole: external_exports.enum(APP_ROLES).optional()
27650
27807
  }).strict();
27651
- var identityGranted = /* @__PURE__ */ __name((slug) => {
27652
- return siteRegistry().registry.apps[slug]?.data.includes(IDENTITY_CAPABILITY) === true;
27653
- }, "identityGranted");
27654
- var identityPermissionDenied = /* @__PURE__ */ __name(() => {
27655
- return Response.json({ error: "identity_permission_denied" }, { status: 403 });
27656
- }, "identityPermissionDenied");
27657
- var handleIdentityUpsert = /* @__PURE__ */ __name(async (env, body) => {
27658
- if (!identityGranted(body.slug)) {
27659
- return identityPermissionDenied();
27808
+ var appUiAudience = /* @__PURE__ */ __name((slug) => {
27809
+ return `app-ui:${slug}`;
27810
+ }, "appUiAudience");
27811
+ var verifyAppUiToken = /* @__PURE__ */ __name(async (input2) => {
27812
+ const signature = await verifyCompactSignature(input2.token, input2.keys);
27813
+ if (!signature.ok) {
27814
+ return signature;
27660
27815
  }
27661
- if (await rateLimited(env, `${body.slug}::identity-upsert`)) {
27662
- return Response.json({ error: "rate_limited" }, { status: 429 });
27816
+ const claims = claimsSchema.safeParse(signature.claims);
27817
+ if (!claims.success) {
27818
+ return { ok: false, reason: "bad_claims" };
27663
27819
  }
27664
- const upserted = await upsertPerson(env, body.person);
27665
- if (upserted === null) {
27666
- return Response.json({ error: "invalid_identifier" }, { status: 400 });
27820
+ if (claims.data.aud !== appUiAudience(input2.slug)) {
27821
+ return { ok: false, reason: "wrong_app" };
27667
27822
  }
27668
- return Response.json(upserted);
27669
- }, "handleIdentityUpsert");
27823
+ const now = Math.floor(input2.now.getTime() / 1e3);
27824
+ if (claims.data.iat > now + (input2.skewSeconds ?? APP_UI_TOKEN_SKEW_SECONDS)) {
27825
+ return { ok: false, reason: "future_iat" };
27826
+ }
27827
+ if (claims.data.exp <= now) {
27828
+ return { ok: false, reason: "expired" };
27829
+ }
27830
+ return { ok: true, claims: claims.data, kid: signature.kid, key: signature.key };
27831
+ }, "verifyAppUiToken");
27832
+
27833
+ // ../../libs/app-ui-token/src/runtime-query-ticket.ts
27834
+ var APP_RUNTIME_QUERY_TICKET_TTL_SECONDS = 600;
27835
+ var APP_RUNTIME_QUERY_TICKET_ISSUER = "qinto-portal";
27836
+ var claimsSchema2 = external_exports.object({
27837
+ iss: external_exports.literal(APP_RUNTIME_QUERY_TICKET_ISSUER),
27838
+ aud: external_exports.string().min(1),
27839
+ sub: external_exports.string().min(1),
27840
+ iat: external_exports.number().int(),
27841
+ exp: external_exports.number().int(),
27842
+ domainId: external_exports.string().min(1),
27843
+ appId: external_exports.string().min(1),
27844
+ appInstallId: external_exports.string().min(1),
27845
+ appVersionId: external_exports.string().min(1)
27846
+ }).strict();
27847
+ var appRuntimeQueryAudience = /* @__PURE__ */ __name((slug) => {
27848
+ return `app-runtime-query:${slug}`;
27849
+ }, "appRuntimeQueryAudience");
27850
+ var mintAppRuntimeQueryTicket = /* @__PURE__ */ __name(async (input2) => {
27851
+ const iat = Math.floor(input2.now.getTime() / 1e3);
27852
+ const claims = {
27853
+ iss: APP_RUNTIME_QUERY_TICKET_ISSUER,
27854
+ aud: appRuntimeQueryAudience(input2.slug),
27855
+ sub: input2.appInstallId,
27856
+ iat,
27857
+ exp: iat + (input2.ttlSeconds ?? APP_RUNTIME_QUERY_TICKET_TTL_SECONDS),
27858
+ domainId: input2.domainId,
27859
+ appId: input2.appId,
27860
+ appInstallId: input2.appInstallId,
27861
+ appVersionId: input2.appVersionId
27862
+ };
27863
+ return signCompact(input2.kid, input2.key, claims);
27864
+ }, "mintAppRuntimeQueryTicket");
27865
+
27866
+ // ../../libs/app-ui-token/src/write-ticket.ts
27867
+ var APP_UI_WRITE_TICKET_TTL_SECONDS = 60;
27868
+ var APP_UI_WRITE_TICKET_ISSUER = "qinto-site";
27869
+ var claimsSchema3 = external_exports.object({
27870
+ iss: external_exports.literal(APP_UI_WRITE_TICKET_ISSUER),
27871
+ aud: external_exports.string().min(1),
27872
+ sub: external_exports.string().min(1),
27873
+ iat: external_exports.number().int(),
27874
+ exp: external_exports.number().int(),
27875
+ domainId: external_exports.string().min(1),
27876
+ appId: external_exports.string().min(1),
27877
+ appVersionId: external_exports.string().min(1)
27878
+ }).strict();
27879
+ var appUiWriteAudience = /* @__PURE__ */ __name((slug) => {
27880
+ return `app-ui-write:${slug}`;
27881
+ }, "appUiWriteAudience");
27882
+ var mintAppUiWriteTicket = /* @__PURE__ */ __name(async (input2) => {
27883
+ const iat = Math.floor(input2.now.getTime() / 1e3);
27884
+ const claims = {
27885
+ iss: APP_UI_WRITE_TICKET_ISSUER,
27886
+ aud: appUiWriteAudience(input2.slug),
27887
+ sub: input2.userId,
27888
+ iat,
27889
+ exp: iat + (input2.ttlSeconds ?? APP_UI_WRITE_TICKET_TTL_SECONDS),
27890
+ domainId: input2.domainId,
27891
+ appId: input2.appId,
27892
+ appVersionId: input2.appVersionId
27893
+ };
27894
+ return signCompact(input2.kid, input2.key, claims);
27895
+ }, "mintAppUiWriteTicket");
27670
27896
 
27671
27897
  // src/apps/emit-payload.ts
27672
27898
  var emitPayloadSchema = external_exports.object({
@@ -27685,51 +27911,6 @@ var emittedEventId = /* @__PURE__ */ __name((eventId, properties2) => {
27685
27911
  return `evt_${ulid3()}`;
27686
27912
  }, "emittedEventId");
27687
27913
 
27688
- // src/apps/broker-track.ts
27689
- var trackBody = external_exports.object({
27690
- ...identityFields,
27691
- kind: external_exports.literal("track"),
27692
- source: external_exports.enum(APP_HANDLER_SOURCES),
27693
- userId: external_exports.string().min(1).max(64),
27694
- installId: external_exports.string().min(1).max(64),
27695
- installs: installRuleSchema.optional(),
27696
- event: emitSchema.omit({ installs: true })
27697
- }).strict();
27698
- var handleTrack = /* @__PURE__ */ __name(async (env, body) => {
27699
- const app2 = siteRegistry().registry.apps[body.slug];
27700
- if (app2 === void 0) {
27701
- return Response.json({ error: "forbidden" }, { status: 403 });
27702
- }
27703
- if (!app2.installs.some((install) => install.active && install.id === body.installId)) {
27704
- return Response.json({ error: "invalid_install" }, { status: 400 });
27705
- }
27706
- const parsed = emitPayloadSchema.safeParse(body.event.payload);
27707
- if (!parsed.success) {
27708
- return Response.json({ error: "invalid_event" }, { status: 400 });
27709
- }
27710
- if (!isCanonicalId(body.userId)) {
27711
- return Response.json({ error: "invalid_user" }, { status: 400 });
27712
- }
27713
- if (await rateLimited(env, `${body.slug}:${body.installId}:track`)) {
27714
- return Response.json({ error: "rate_limited" }, { status: 429 });
27715
- }
27716
- const site = ownSite(env);
27717
- if (!await anonStub(env, body.userId).appAllowed(body.slug, site, currentTraceContext())) {
27718
- return Response.json({ error: "forbidden" }, { status: 403 });
27719
- }
27720
- const { event, eventId, properties: properties2 } = parsed.data;
27721
- const action = buildAction({
27722
- type: "track",
27723
- userId: body.userId,
27724
- source: body.source,
27725
- payload: { event, eventId: emittedEventId(eventId, properties2), properties: properties2 ?? {} },
27726
- context: { source: "app", occurredAt: body.event.occurredAt, offline: false, replay: false },
27727
- ...body.installs === void 0 ? {} : { installs: body.installs }
27728
- });
27729
- await ingest(env, action, site);
27730
- return Response.json({ accepted: true }, { status: 202 });
27731
- }, "handleTrack");
27732
-
27733
27914
  // src/id-graph/anon/context.ts
27734
27915
  var LEVEL_KINDS = {
27735
27916
  private: { kv: "context_private_kv", text: "context_private_text" },
@@ -28591,7 +28772,8 @@ var adoptAppSpans = /* @__PURE__ */ __name((response) => {
28591
28772
  }, "adoptAppSpans");
28592
28773
 
28593
28774
  // src/apps/invoke.ts
28594
- var APP_INVOCATION_TIMEOUT_MS = 1e4;
28775
+ var RPC_HOT_TIMEOUT_MS = 1e4;
28776
+ var RPC_COLD_TIMEOUT_MS = 4e4;
28595
28777
  var APP_HOOK_TIMEOUT_MS = 25e3;
28596
28778
  var MAX_EMIT_DEPTH = 2;
28597
28779
  var HOOK_URL = "https://app/__qinto/hook";
@@ -28882,18 +29064,8 @@ var invokeApp = /* @__PURE__ */ __name(async (env, input2) => {
28882
29064
  );
28883
29065
  }, "invokeApp");
28884
29066
 
28885
- // src/apps/broker.ts
29067
+ // src/apps/broker-rpc.ts
28886
29068
  var MAX_RPC_DEPTH = 3;
28887
- var BROKER_PATHS = ["/__qinto/push", "/__qinto/rpc"];
28888
- var pushBody = external_exports.object({
28889
- ...identityFields,
28890
- kind: external_exports.literal("push"),
28891
- userId: external_exports.string().min(1).max(64),
28892
- installId: external_exports.string().min(1).max(64).optional(),
28893
- broadcast: external_exports.enum(PUSH_BROADCASTS).optional(),
28894
- topic: external_exports.string().min(1).max(64),
28895
- data: external_exports.unknown().optional()
28896
- }).strict();
28897
29069
  var rpcBody = external_exports.object({
28898
29070
  ...identityFields,
28899
29071
  kind: external_exports.literal("rpc"),
@@ -28903,150 +29075,17 @@ var rpcBody = external_exports.object({
28903
29075
  fn: external_exports.string().min(1).max(64),
28904
29076
  args: external_exports.unknown().optional(),
28905
29077
  installId: external_exports.string().min(1).max(64).optional(),
28906
- depth: external_exports.number().int().min(0)
28907
- }).strict();
28908
- var installsBody = external_exports.object({
28909
- ...identityFields,
28910
- kind: external_exports.literal("installs"),
28911
- callee: external_exports.string().min(1).max(30)
28912
- }).strict();
28913
- var activeBody = external_exports.object({
28914
- ...identityFields,
28915
- kind: external_exports.literal("active"),
28916
- ord: external_exports.number().int().min(1),
28917
- userId: external_exports.string().min(1).max(64).optional()
28918
- }).strict();
28919
- var contextReadBody = external_exports.object({
28920
- ...identityFields,
28921
- kind: external_exports.literal("contextRead"),
28922
- userId: external_exports.string().min(1).max(64)
28923
- }).strict();
28924
- var contextWriteBody = external_exports.object({
28925
- ...identityFields,
28926
- kind: external_exports.literal("contextWrite"),
28927
- userId: external_exports.string().min(1).max(64),
28928
- writes: external_exports.array(contextWriteSchema).min(1).max(MAX_CONTEXT_WRITES_PER_INSTALL)
28929
- }).strict();
28930
- var factsQuery = external_exports.object({
28931
- kinds: external_exports.array(external_exports.enum(APP_FACT_KINDS)).min(1).max(APP_FACT_KINDS.length).optional(),
28932
- observedAtGte: external_exports.number().int().nonnegative().safe().optional(),
28933
- observedAtLt: external_exports.number().int().nonnegative().safe().optional(),
28934
- limit: external_exports.number().int().min(1).max(MAX_APP_FACTS_PER_PAGE).optional()
28935
- }).strict().refine((query) => query.observedAtGte === void 0 || query.observedAtLt === void 0 || query.observedAtGte < query.observedAtLt);
28936
- var factsReadBody = external_exports.object({
28937
- ...identityFields,
28938
- kind: external_exports.literal("factsRead"),
28939
- userId: external_exports.string().min(1).max(64),
28940
- query: factsQuery.optional(),
28941
- cursor: external_exports.string().min(1).max(4096).optional()
28942
- }).strict().refine((body) => body.query === void 0 !== (body.cursor === void 0));
28943
- var identityReadBody = external_exports.object({
28944
- ...identityFields,
28945
- kind: external_exports.literal("identityRead"),
28946
- identifier: identifierField2,
28947
- cursor: external_exports.string().regex(/^\d+$/).optional()
28948
- }).strict();
28949
- var brokerBody = external_exports.discriminatedUnion("kind", [
28950
- pushBody,
28951
- rpcBody,
28952
- installsBody,
28953
- activeBody,
28954
- contextReadBody,
28955
- contextWriteBody,
28956
- factsReadBody,
28957
- identityReadBody,
28958
- identityUpsertBody,
28959
- currencyRatesBody,
28960
- trackBody
28961
- ]);
28962
- var BODY_ENVELOPE_ALLOWANCE_BYTES = 2 * 1024;
28963
- var MAX_BODY_BYTES = MAX_RPC_BYTES + BODY_ENVELOPE_ALLOWANCE_BYTES;
28964
- var parseJson = /* @__PURE__ */ __name((raw2) => {
28965
- try {
28966
- return JSON.parse(raw2);
28967
- } catch {
28968
- return null;
28969
- }
28970
- }, "parseJson");
28971
- var factsCursor = external_exports.object({
28972
- userId: external_exports.string().min(1).max(64),
28973
- kinds: external_exports.array(external_exports.enum(APP_FACT_KINDS)).min(1).max(APP_FACT_KINDS.length),
28974
- observedAtGte: external_exports.number().int().nonnegative().safe().nullable(),
28975
- observedAtLt: external_exports.number().int().nonnegative().safe().nullable(),
28976
- limit: external_exports.number().int().min(1).max(MAX_APP_FACTS_PER_PAGE),
28977
- afterRowId: external_exports.number().int().nonnegative().safe(),
28978
- maxRowId: external_exports.number().int().positive().safe().nullable()
29078
+ depth: external_exports.number().int().min(0),
29079
+ // Optional on the wire: a runtime predating traffic classes sends none, which means hot.
29080
+ traffic: external_exports.enum(TRAFFIC_CLASSES).optional()
28979
29081
  }).strict();
28980
- var cursorKey = /* @__PURE__ */ __name(async (hex3) => {
28981
- const bytes = Uint8Array.from(hex3.matchAll(/.{2}/g), ([pair]) => Number.parseInt(pair, 16));
28982
- return crypto.subtle.importKey("raw", bytes, "AES-GCM", false, ["encrypt", "decrypt"]);
28983
- }, "cursorKey");
28984
- var encodeBase64Url = /* @__PURE__ */ __name((bytes) => {
28985
- let binary = "";
28986
- for (const byte of bytes) {
28987
- binary += String.fromCharCode(byte);
28988
- }
28989
- return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
28990
- }, "encodeBase64Url");
28991
- var decodeBase64Url = /* @__PURE__ */ __name((value) => {
28992
- const base643 = value.replaceAll("-", "+").replaceAll("_", "/");
28993
- const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
28994
- const binary = atob(padded);
28995
- return Uint8Array.from(binary, (character) => character.charCodeAt(0));
28996
- }, "decodeBase64Url");
28997
- var encryptFactsCursor = /* @__PURE__ */ __name(async (key, cursor) => {
28998
- const iv = crypto.getRandomValues(new Uint8Array(12));
28999
- const plaintext = new TextEncoder().encode(JSON.stringify(cursor));
29000
- const ciphertext = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv }, await cursorKey(key), plaintext));
29001
- const packed = new Uint8Array(iv.byteLength + ciphertext.byteLength);
29002
- packed.set(iv);
29003
- packed.set(ciphertext, iv.byteLength);
29004
- return encodeBase64Url(packed);
29005
- }, "encryptFactsCursor");
29006
- var decryptFactsCursor = /* @__PURE__ */ __name(async (key, encoded) => {
29082
+ var parseJson = /* @__PURE__ */ __name((raw2) => {
29007
29083
  try {
29008
- const packed = decodeBase64Url(encoded);
29009
- if (packed.byteLength <= 12) {
29010
- return null;
29011
- }
29012
- const plaintext = await crypto.subtle.decrypt({ name: "AES-GCM", iv: packed.slice(0, 12) }, await cursorKey(key), packed.slice(12));
29013
- return JSON.parse(new TextDecoder().decode(plaintext));
29084
+ return JSON.parse(raw2);
29014
29085
  } catch {
29015
29086
  return null;
29016
29087
  }
29017
- }, "decryptFactsCursor");
29018
- var invalidBody = /* @__PURE__ */ __name(() => {
29019
- return Response.json({ error: "invalid_body" }, { status: 400 });
29020
- }, "invalidBody");
29021
- var forbidden = /* @__PURE__ */ __name(() => {
29022
- return Response.json({ error: "forbidden" }, { status: 403 });
29023
- }, "forbidden");
29024
- var factsPermissionDenied = /* @__PURE__ */ __name(() => {
29025
- return Response.json({ error: "facts_permission_denied" }, { status: 403 });
29026
- }, "factsPermissionDenied");
29027
- var handlePush = /* @__PURE__ */ __name(async (env, body) => {
29028
- if (new TextEncoder().encode(JSON.stringify(body.data ?? null)).length > MAX_PUSH_BYTES) {
29029
- return invalidBody();
29030
- }
29031
- const broadcast = body.broadcast ?? "install";
29032
- if (broadcast === "install" && body.installId === void 0) {
29033
- return invalidBody();
29034
- }
29035
- const installId = broadcast === "install" ? body.installId : null;
29036
- if (await rateLimited(env, `${body.slug}:${installId ?? ""}:push`)) {
29037
- return Response.json({ error: "rate_limited" }, { status: 429 });
29038
- }
29039
- const app2 = siteRegistry().registry.apps[body.slug];
29040
- if (broadcast === "site" && (app2 === void 0 || !app2.events.publishes.includes(body.topic) || !app2.data.includes(SHARED_CONTEXT_CAPABILITY))) {
29041
- return Response.json({ error: "topic_not_public" }, { status: 400 });
29042
- }
29043
- await anonStub(env, body.userId).appPush(
29044
- { slug: body.slug, installId, topic: body.topic, data: body.data, scope: broadcast === "site" ? "site" : "app" },
29045
- ownSite(env),
29046
- currentTraceContext()
29047
- );
29048
- return Response.json({ accepted: true }, { status: 202 });
29049
- }, "handlePush");
29088
+ }, "parseJson");
29050
29089
  var resolveInstall = /* @__PURE__ */ __name((callee, installId) => {
29051
29090
  const active = callee.installs.filter((install) => install.active);
29052
29091
  if (installId !== void 0) {
@@ -29060,6 +29099,14 @@ var calleeFailed = /* @__PURE__ */ __name((callee, reason) => {
29060
29099
  addSpanEvent("rpc callee failed", { level: "warn", attrs: { app: callee, reason } });
29061
29100
  return Response.json({ error: "callee_failed" }, { status: 502 });
29062
29101
  }, "calleeFailed");
29102
+ var calleeError = /* @__PURE__ */ __name((callee, error61, message) => {
29103
+ addSpanEvent("rpc callee failed", { level: "warn", attrs: { app: callee, reason: message, code: error61 } });
29104
+ return Response.json({ error: error61, message }, { status: 502 });
29105
+ }, "calleeError");
29106
+ var resultTooLarge = /* @__PURE__ */ __name((candidate) => {
29107
+ const result = candidate?.rpc?.result;
29108
+ return new TextEncoder().encode(JSON.stringify(result ?? null)).length > MAX_RPC_BYTES;
29109
+ }, "resultTooLarge");
29063
29110
  var deliverRpcEffects = /* @__PURE__ */ __name(async (env, { body, userId, effects, install }) => {
29064
29111
  for (const ord of effects.rejectedOrds) {
29065
29112
  addSpanEvent("app effects rejected over the per-install caps", { level: "warn", attrs: { app: body.callee, ord } });
@@ -29085,10 +29132,32 @@ var deliverRpcEffects = /* @__PURE__ */ __name(async (env, { body, userId, effec
29085
29132
  }, "ingest")
29086
29133
  });
29087
29134
  }, "deliverRpcEffects");
29088
- var runRelayRpc = /* @__PURE__ */ __name(async (env, { context, body, callee, install }) => {
29089
- let raw2;
29135
+ var calleeQueryTicket = /* @__PURE__ */ __name(async (env, { context, body, callee, install }) => {
29136
+ const keyEnv = env.APP_UI_KEY;
29137
+ const [signing] = Object.entries((keyEnv === void 0 ? null : parseAppUiKeyEnv(keyEnv)) ?? {});
29138
+ if (callee.appId === void 0 || signing === void 0) {
29139
+ return void 0;
29140
+ }
29141
+ const [kid, key] = signing;
29142
+ return mintAppRuntimeQueryTicket({
29143
+ kid,
29144
+ key,
29145
+ now: /* @__PURE__ */ new Date(),
29146
+ slug: body.callee,
29147
+ domainId: context.domainId,
29148
+ appId: callee.appId,
29149
+ appInstallId: install.id,
29150
+ // The portal authorizes a ticket only for the version the site serves, which is the registry's.
29151
+ appVersionId: callee.versionId
29152
+ });
29153
+ }, "calleeQueryTicket");
29154
+ var postToCallee = /* @__PURE__ */ __name(async (env, input2) => {
29155
+ const { context, body, callee, install } = input2;
29156
+ const traffic = body.traffic ?? "hot";
29157
+ const timeoutMs = traffic === "cold" ? RPC_COLD_TIMEOUT_MS : RPC_HOT_TIMEOUT_MS;
29090
29158
  try {
29091
29159
  const key = await deriveAppInternalKey(context.master, context.domainId, body.callee);
29160
+ const queryTicket = traffic === "cold" ? await calleeQueryTicket(env, input2) : void 0;
29092
29161
  const response = await postHookEnvelope(env, {
29093
29162
  binding: callee.binding,
29094
29163
  key,
@@ -29102,9 +29171,9 @@ var runRelayRpc = /* @__PURE__ */ __name(async (env, { context, body, callee, in
29102
29171
  ...body.userId === void 0 ? {} : { user: { anonId: body.userId, globalId: null, properties: {} } },
29103
29172
  depth: body.depth,
29104
29173
  // JSON.stringify drops an undefined key, and the envelope requires `args` to be present.
29105
- rpc: { caller: body.slug, fn: body.fn, args: body.args ?? null }
29174
+ rpc: { caller: body.slug, fn: body.fn, args: body.args ?? null, traffic, ...queryTicket === void 0 ? {} : { queryTicket } }
29106
29175
  },
29107
- timeoutMs: APP_INVOCATION_TIMEOUT_MS
29176
+ timeoutMs
29108
29177
  });
29109
29178
  if (response === void 0) {
29110
29179
  return calleeFailed(body.callee, "The callee service binding is missing.");
@@ -29120,13 +29189,27 @@ var runRelayRpc = /* @__PURE__ */ __name(async (env, { context, body, callee, in
29120
29189
  }
29121
29190
  const bytes = await readBoundedBody(response, MAX_RESPONSE_BYTES);
29122
29191
  if (bytes === null) {
29123
- return calleeFailed(body.callee, "The response exceeds the size cap.");
29192
+ return calleeError(body.callee, "result_too_large", `The callee response exceeds ${MAX_RESPONSE_BYTES / 1024 / 1024} MB.`);
29124
29193
  }
29125
- raw2 = new TextDecoder().decode(bytes);
29194
+ return new TextDecoder().decode(bytes);
29126
29195
  } catch (error61) {
29196
+ if (error61 instanceof Error && error61.name === "TimeoutError") {
29197
+ return calleeError(body.callee, "callee_timeout", `The callee did not answer within ${timeoutMs / 1e3} s.`);
29198
+ }
29127
29199
  return calleeFailed(body.callee, String(error61));
29128
29200
  }
29129
- const verdict = validateEnvelopeResponse(parseJson(raw2), 1);
29201
+ }, "postToCallee");
29202
+ var runRelayRpc = /* @__PURE__ */ __name(async (env, input2) => {
29203
+ const { body, install } = input2;
29204
+ const raw2 = await postToCallee(env, input2);
29205
+ if (raw2 instanceof Response) {
29206
+ return raw2;
29207
+ }
29208
+ const candidate = parseJson(raw2);
29209
+ if (resultTooLarge(candidate)) {
29210
+ return calleeError(body.callee, "result_too_large", `The rpc result exceeds ${MAX_RPC_BYTES / 1024} KB.`);
29211
+ }
29212
+ const verdict = validateEnvelopeResponse(candidate, 1);
29130
29213
  if (!verdict.ok) {
29131
29214
  return calleeFailed(body.callee, verdict.reason);
29132
29215
  }
@@ -29135,6 +29218,9 @@ var runRelayRpc = /* @__PURE__ */ __name(async (env, { context, body, callee, in
29135
29218
  if (verdict.errorCode === "invalid_arguments") {
29136
29219
  return Response.json({ error: "invalid_arguments", message: reason }, { status: 400 });
29137
29220
  }
29221
+ if (verdict.errorCode === "rpc_error") {
29222
+ return calleeError(body.callee, "rpc_error", reason);
29223
+ }
29138
29224
  return calleeFailed(body.callee, reason);
29139
29225
  }
29140
29226
  if (verdict.rpc === null) {
@@ -29163,38 +29249,238 @@ var relayRpc = /* @__PURE__ */ __name(async (env, input2) => {
29163
29249
  "app.install_ord": install.ord,
29164
29250
  "app.install_label": install.label,
29165
29251
  "app.rpc_caller": body.slug,
29166
- "app.rpc_depth": body.depth
29252
+ "app.rpc_depth": body.depth,
29253
+ "app.rpc_traffic": body.traffic ?? "hot"
29167
29254
  }
29168
29255
  },
29169
29256
  () => {
29170
29257
  return runRelayRpc(env, input2);
29171
29258
  }
29172
- );
29173
- }, "relayRpc");
29174
- var handleRpc = /* @__PURE__ */ __name(async (env, context, body) => {
29175
- if (body.depth > MAX_RPC_DEPTH) {
29176
- return Response.json({ error: "depth_exceeded" }, { status: 400 });
29177
- }
29178
- const callee = siteRegistry().registry.apps[body.callee];
29179
- if (callee === void 0) {
29180
- return forbidden();
29181
- }
29182
- const visibility = callee.rpc.exposes[body.fn];
29183
- if (visibility !== "public" && !(visibility === "private" && (callee.rpc.grants[body.slug] ?? []).includes(body.fn))) {
29184
- return forbidden();
29259
+ );
29260
+ }, "relayRpc");
29261
+ var handleRpc = /* @__PURE__ */ __name(async (env, context, body) => {
29262
+ if (body.depth > MAX_RPC_DEPTH) {
29263
+ return Response.json({ error: "depth_exceeded" }, { status: 400 });
29264
+ }
29265
+ const callee = siteRegistry().registry.apps[body.callee];
29266
+ if (callee === void 0) {
29267
+ return Response.json({ error: "forbidden" }, { status: 403 });
29268
+ }
29269
+ const visibility = callee.rpc.exposes[body.fn];
29270
+ if (visibility !== "public" && !(visibility === "private" && (callee.rpc.grants[body.slug] ?? []).includes(body.fn))) {
29271
+ return Response.json({ error: "forbidden" }, { status: 403 });
29272
+ }
29273
+ const install = resolveInstall(callee, body.installId);
29274
+ if (install === "invalid_install" || install === "install_required") {
29275
+ return Response.json({ error: install }, { status: 400 });
29276
+ }
29277
+ if (new TextEncoder().encode(JSON.stringify(body.args ?? null)).length > MAX_RPC_BYTES) {
29278
+ return Response.json({ error: "too_large" }, { status: 413 });
29279
+ }
29280
+ if (await rateLimited(env, `${body.slug}:${install.id}:rpc`)) {
29281
+ return Response.json({ error: "rate_limited" }, { status: 429 });
29282
+ }
29283
+ return relayRpc(env, { context, body, callee, install });
29284
+ }, "handleRpc");
29285
+
29286
+ // src/apps/broker-track.ts
29287
+ var trackBody = external_exports.object({
29288
+ ...identityFields,
29289
+ kind: external_exports.literal("track"),
29290
+ source: external_exports.enum(APP_HANDLER_SOURCES),
29291
+ userId: external_exports.string().min(1).max(64),
29292
+ installId: external_exports.string().min(1).max(64),
29293
+ installs: installRuleSchema.optional(),
29294
+ event: emitSchema.omit({ installs: true })
29295
+ }).strict();
29296
+ var handleTrack = /* @__PURE__ */ __name(async (env, body) => {
29297
+ const app2 = siteRegistry().registry.apps[body.slug];
29298
+ if (app2 === void 0) {
29299
+ return Response.json({ error: "forbidden" }, { status: 403 });
29300
+ }
29301
+ if (!app2.installs.some((install) => install.active && install.id === body.installId)) {
29302
+ return Response.json({ error: "invalid_install" }, { status: 400 });
29303
+ }
29304
+ const parsed = emitPayloadSchema.safeParse(body.event.payload);
29305
+ if (!parsed.success) {
29306
+ return Response.json({ error: "invalid_event" }, { status: 400 });
29307
+ }
29308
+ if (!isCanonicalId(body.userId)) {
29309
+ return Response.json({ error: "invalid_user" }, { status: 400 });
29310
+ }
29311
+ if (await rateLimited(env, `${body.slug}:${body.installId}:track`)) {
29312
+ return Response.json({ error: "rate_limited" }, { status: 429 });
29313
+ }
29314
+ const site = ownSite(env);
29315
+ if (!await anonStub(env, body.userId).appAllowed(body.slug, site, currentTraceContext())) {
29316
+ return Response.json({ error: "forbidden" }, { status: 403 });
29317
+ }
29318
+ const { event, eventId, properties: properties2 } = parsed.data;
29319
+ const action = buildAction({
29320
+ type: "track",
29321
+ userId: body.userId,
29322
+ source: body.source,
29323
+ payload: { event, eventId: emittedEventId(eventId, properties2), properties: properties2 ?? {} },
29324
+ context: { source: "app", occurredAt: body.event.occurredAt, offline: false, replay: false },
29325
+ ...body.installs === void 0 ? {} : { installs: body.installs }
29326
+ });
29327
+ await ingest(env, action, site);
29328
+ return Response.json({ accepted: true }, { status: 202 });
29329
+ }, "handleTrack");
29330
+
29331
+ // src/apps/broker.ts
29332
+ var BROKER_PATHS = ["/__qinto/push", "/__qinto/rpc"];
29333
+ var pushBody = external_exports.object({
29334
+ ...identityFields,
29335
+ kind: external_exports.literal("push"),
29336
+ userId: external_exports.string().min(1).max(64),
29337
+ installId: external_exports.string().min(1).max(64).optional(),
29338
+ broadcast: external_exports.enum(PUSH_BROADCASTS).optional(),
29339
+ topic: external_exports.string().min(1).max(64),
29340
+ data: external_exports.unknown().optional()
29341
+ }).strict();
29342
+ var installsBody = external_exports.object({
29343
+ ...identityFields,
29344
+ kind: external_exports.literal("installs"),
29345
+ callee: external_exports.string().min(1).max(30)
29346
+ }).strict();
29347
+ var activeBody = external_exports.object({
29348
+ ...identityFields,
29349
+ kind: external_exports.literal("active"),
29350
+ ord: external_exports.number().int().min(1),
29351
+ userId: external_exports.string().min(1).max(64).optional()
29352
+ }).strict();
29353
+ var contextReadBody = external_exports.object({
29354
+ ...identityFields,
29355
+ kind: external_exports.literal("contextRead"),
29356
+ userId: external_exports.string().min(1).max(64)
29357
+ }).strict();
29358
+ var contextWriteBody = external_exports.object({
29359
+ ...identityFields,
29360
+ kind: external_exports.literal("contextWrite"),
29361
+ userId: external_exports.string().min(1).max(64),
29362
+ writes: external_exports.array(contextWriteSchema).min(1).max(MAX_CONTEXT_WRITES_PER_INSTALL)
29363
+ }).strict();
29364
+ var factsQuery = external_exports.object({
29365
+ kinds: external_exports.array(external_exports.enum(APP_FACT_KINDS)).min(1).max(APP_FACT_KINDS.length).optional(),
29366
+ observedAtGte: external_exports.number().int().nonnegative().safe().optional(),
29367
+ observedAtLt: external_exports.number().int().nonnegative().safe().optional(),
29368
+ limit: external_exports.number().int().min(1).max(MAX_APP_FACTS_PER_PAGE).optional()
29369
+ }).strict().refine((query) => query.observedAtGte === void 0 || query.observedAtLt === void 0 || query.observedAtGte < query.observedAtLt);
29370
+ var factsReadBody = external_exports.object({
29371
+ ...identityFields,
29372
+ kind: external_exports.literal("factsRead"),
29373
+ userId: external_exports.string().min(1).max(64),
29374
+ query: factsQuery.optional(),
29375
+ cursor: external_exports.string().min(1).max(4096).optional()
29376
+ }).strict().refine((body) => body.query === void 0 !== (body.cursor === void 0));
29377
+ var identityReadBody = external_exports.object({
29378
+ ...identityFields,
29379
+ kind: external_exports.literal("identityRead"),
29380
+ identifier: identifierField2,
29381
+ cursor: external_exports.string().regex(/^\d+$/).optional()
29382
+ }).strict();
29383
+ var brokerBody = external_exports.discriminatedUnion("kind", [
29384
+ pushBody,
29385
+ rpcBody,
29386
+ installsBody,
29387
+ activeBody,
29388
+ contextReadBody,
29389
+ contextWriteBody,
29390
+ factsReadBody,
29391
+ identityReadBody,
29392
+ identityUpsertBody,
29393
+ currencyRatesBody,
29394
+ trackBody
29395
+ ]);
29396
+ var BODY_ENVELOPE_ALLOWANCE_BYTES = 2 * 1024;
29397
+ var MAX_BODY_BYTES = MAX_RPC_BYTES + BODY_ENVELOPE_ALLOWANCE_BYTES;
29398
+ var parseJson2 = /* @__PURE__ */ __name((raw2) => {
29399
+ try {
29400
+ return JSON.parse(raw2);
29401
+ } catch {
29402
+ return null;
29403
+ }
29404
+ }, "parseJson");
29405
+ var factsCursor = external_exports.object({
29406
+ userId: external_exports.string().min(1).max(64),
29407
+ kinds: external_exports.array(external_exports.enum(APP_FACT_KINDS)).min(1).max(APP_FACT_KINDS.length),
29408
+ observedAtGte: external_exports.number().int().nonnegative().safe().nullable(),
29409
+ observedAtLt: external_exports.number().int().nonnegative().safe().nullable(),
29410
+ limit: external_exports.number().int().min(1).max(MAX_APP_FACTS_PER_PAGE),
29411
+ afterRowId: external_exports.number().int().nonnegative().safe(),
29412
+ maxRowId: external_exports.number().int().positive().safe().nullable()
29413
+ }).strict();
29414
+ var cursorKey = /* @__PURE__ */ __name(async (hex3) => {
29415
+ const bytes = Uint8Array.from(hex3.matchAll(/.{2}/g), ([pair]) => Number.parseInt(pair, 16));
29416
+ return crypto.subtle.importKey("raw", bytes, "AES-GCM", false, ["encrypt", "decrypt"]);
29417
+ }, "cursorKey");
29418
+ var encodeBase64Url = /* @__PURE__ */ __name((bytes) => {
29419
+ let binary = "";
29420
+ for (const byte of bytes) {
29421
+ binary += String.fromCharCode(byte);
29422
+ }
29423
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
29424
+ }, "encodeBase64Url");
29425
+ var decodeBase64Url = /* @__PURE__ */ __name((value) => {
29426
+ const base643 = value.replaceAll("-", "+").replaceAll("_", "/");
29427
+ const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
29428
+ const binary = atob(padded);
29429
+ return Uint8Array.from(binary, (character) => character.charCodeAt(0));
29430
+ }, "decodeBase64Url");
29431
+ var encryptFactsCursor = /* @__PURE__ */ __name(async (key, cursor) => {
29432
+ const iv = crypto.getRandomValues(new Uint8Array(12));
29433
+ const plaintext = new TextEncoder().encode(JSON.stringify(cursor));
29434
+ const ciphertext = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv }, await cursorKey(key), plaintext));
29435
+ const packed = new Uint8Array(iv.byteLength + ciphertext.byteLength);
29436
+ packed.set(iv);
29437
+ packed.set(ciphertext, iv.byteLength);
29438
+ return encodeBase64Url(packed);
29439
+ }, "encryptFactsCursor");
29440
+ var decryptFactsCursor = /* @__PURE__ */ __name(async (key, encoded) => {
29441
+ try {
29442
+ const packed = decodeBase64Url(encoded);
29443
+ if (packed.byteLength <= 12) {
29444
+ return null;
29445
+ }
29446
+ const plaintext = await crypto.subtle.decrypt({ name: "AES-GCM", iv: packed.slice(0, 12) }, await cursorKey(key), packed.slice(12));
29447
+ return JSON.parse(new TextDecoder().decode(plaintext));
29448
+ } catch {
29449
+ return null;
29185
29450
  }
29186
- const install = resolveInstall(callee, body.installId);
29187
- if (install === "invalid_install" || install === "install_required") {
29188
- return Response.json({ error: install }, { status: 400 });
29451
+ }, "decryptFactsCursor");
29452
+ var invalidBody = /* @__PURE__ */ __name(() => {
29453
+ return Response.json({ error: "invalid_body" }, { status: 400 });
29454
+ }, "invalidBody");
29455
+ var forbidden = /* @__PURE__ */ __name(() => {
29456
+ return Response.json({ error: "forbidden" }, { status: 403 });
29457
+ }, "forbidden");
29458
+ var factsPermissionDenied = /* @__PURE__ */ __name(() => {
29459
+ return Response.json({ error: "facts_permission_denied" }, { status: 403 });
29460
+ }, "factsPermissionDenied");
29461
+ var handlePush = /* @__PURE__ */ __name(async (env, body) => {
29462
+ if (new TextEncoder().encode(JSON.stringify(body.data ?? null)).length > MAX_PUSH_BYTES) {
29463
+ return invalidBody();
29189
29464
  }
29190
- if (new TextEncoder().encode(JSON.stringify(body.args ?? null)).length > MAX_RPC_BYTES) {
29191
- return Response.json({ error: "too_large" }, { status: 413 });
29465
+ const broadcast = body.broadcast ?? "install";
29466
+ if (broadcast === "install" && body.installId === void 0) {
29467
+ return invalidBody();
29192
29468
  }
29193
- if (await rateLimited(env, `${body.slug}:${install.id}:rpc`)) {
29469
+ const installId = broadcast === "install" ? body.installId : null;
29470
+ if (await rateLimited(env, `${body.slug}:${installId ?? ""}:push`)) {
29194
29471
  return Response.json({ error: "rate_limited" }, { status: 429 });
29195
29472
  }
29196
- return relayRpc(env, { context, body, callee, install });
29197
- }, "handleRpc");
29473
+ const app2 = siteRegistry().registry.apps[body.slug];
29474
+ if (broadcast === "site" && (app2 === void 0 || !app2.events.publishes.includes(body.topic) || !app2.data.includes(SHARED_CONTEXT_CAPABILITY))) {
29475
+ return Response.json({ error: "topic_not_public" }, { status: 400 });
29476
+ }
29477
+ await anonStub(env, body.userId).appPush(
29478
+ { slug: body.slug, installId, topic: body.topic, data: body.data, scope: broadcast === "site" ? "site" : "app" },
29479
+ ownSite(env),
29480
+ currentTraceContext()
29481
+ );
29482
+ return Response.json({ accepted: true }, { status: 202 });
29483
+ }, "handlePush");
29198
29484
  var handleInstalls = /* @__PURE__ */ __name(async (env, body) => {
29199
29485
  const callee = siteRegistry().registry.apps[body.callee];
29200
29486
  if (callee === void 0 || !(Object.values(callee.rpc.exposes).includes("public") || (callee.rpc.grants[body.slug] ?? []).length > 0)) {
@@ -29293,7 +29579,7 @@ var handleBroker = /* @__PURE__ */ __name(async (request, env, ctx) => {
29293
29579
  if (bytes === null) {
29294
29580
  return Response.json({ error: "too_large" }, { status: 413 });
29295
29581
  }
29296
- const candidate = parseJson(new TextDecoder().decode(bytes));
29582
+ const candidate = parseJson2(new TextDecoder().decode(bytes));
29297
29583
  const parsed = brokerBody.safeParse(candidate);
29298
29584
  if (!parsed.success) {
29299
29585
  if (typeof candidate === "object" && candidate !== null && "kind" in candidate && candidate.kind === "factsRead") {
@@ -29472,7 +29758,7 @@ var textBody = /* @__PURE__ */ __name(async (request) => {
29472
29758
  const bytes = await readBoundedBody(request, MAX_CONTROL_BYTES);
29473
29759
  return bytes === null ? null : new TextDecoder().decode(bytes);
29474
29760
  }, "textBody");
29475
- var parseJson2 = /* @__PURE__ */ __name((value) => {
29761
+ var parseJson3 = /* @__PURE__ */ __name((value) => {
29476
29762
  try {
29477
29763
  return JSON.parse(value);
29478
29764
  } catch {
@@ -29501,7 +29787,7 @@ var handleControl = /* @__PURE__ */ __name(async (request, env) => {
29501
29787
  if (authentication === null) {
29502
29788
  return Response.json({ error: "unauthorized" }, { status: 401 });
29503
29789
  }
29504
- const raw2 = parseJson2(body);
29790
+ const raw2 = parseJson3(body);
29505
29791
  if (raw2 === void 0) {
29506
29792
  return Response.json({ error: "invalid_body" }, { status: 400 });
29507
29793
  }
@@ -29539,7 +29825,7 @@ var handleControl = /* @__PURE__ */ __name(async (request, env) => {
29539
29825
  if (responseBytes === null) {
29540
29826
  return Response.json({ error: "invalid_response" }, { status: 502 });
29541
29827
  }
29542
- const responseBody = parseJson2(new TextDecoder().decode(responseBytes));
29828
+ const responseBody = parseJson3(new TextDecoder().decode(responseBytes));
29543
29829
  if (responseBody === void 0) {
29544
29830
  return Response.json({ error: "invalid_response" }, { status: 502 });
29545
29831
  }
@@ -30115,7 +30401,7 @@ var passThroughResponse = /* @__PURE__ */ __name((upstream) => {
30115
30401
  });
30116
30402
  return new Response(body, { status: upstream.status, headers });
30117
30403
  }, "passThroughResponse");
30118
- var parseJson3 = /* @__PURE__ */ __name((text) => {
30404
+ var parseJson4 = /* @__PURE__ */ __name((text) => {
30119
30405
  try {
30120
30406
  return JSON.parse(text);
30121
30407
  } catch {
@@ -30130,7 +30416,7 @@ var webhookAck = /* @__PURE__ */ __name(async (slug, upstream) => {
30130
30416
  if (bytes === null) {
30131
30417
  return upstreamFailed(slug, "The endpoint outcomes exceed the size cap.");
30132
30418
  }
30133
- const parsed = endpointOutcomesSchema.safeParse(parseJson3(new TextDecoder().decode(bytes)));
30419
+ const parsed = endpointOutcomesSchema.safeParse(parseJson4(new TextDecoder().decode(bytes)));
30134
30420
  if (!parsed.success) {
30135
30421
  return upstreamFailed(slug, "The endpoint outcomes are malformed.");
30136
30422
  }
@@ -30274,201 +30560,6 @@ appEndpointRoutes.all("/app/:slug/*", (c) => {
30274
30560
  return handleAppEndpoint(c, c.req.param("slug"));
30275
30561
  });
30276
30562
 
30277
- // ../../libs/app-ui-token/src/base64url.ts
30278
- var base64UrlEncode = /* @__PURE__ */ __name((bytes) => {
30279
- let binary = "";
30280
- for (const byte of bytes) {
30281
- binary += String.fromCharCode(byte);
30282
- }
30283
- return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
30284
- }, "base64UrlEncode");
30285
- var base64UrlDecode = /* @__PURE__ */ __name((text) => {
30286
- const padded = text.replaceAll("-", "+").replaceAll("_", "/").padEnd(text.length + (4 - text.length % 4) % 4, "=");
30287
- let binary;
30288
- try {
30289
- binary = atob(padded);
30290
- } catch {
30291
- return null;
30292
- }
30293
- const bytes = new Uint8Array(binary.length);
30294
- for (let index = 0; index < binary.length; index += 1) {
30295
- bytes[index] = binary.charCodeAt(index);
30296
- }
30297
- return bytes;
30298
- }, "base64UrlDecode");
30299
-
30300
- // ../../libs/app-ui-token/src/env.ts
30301
- var envSchema = external_exports.object({
30302
- v: external_exports.literal(1),
30303
- keys: external_exports.record(external_exports.string().min(1).max(16), external_exports.string().min(1))
30304
- }).strict();
30305
- var parseAppUiKeyEnv = /* @__PURE__ */ __name((raw2) => {
30306
- let json2;
30307
- try {
30308
- json2 = JSON.parse(raw2);
30309
- } catch {
30310
- return null;
30311
- }
30312
- const parsed = envSchema.safeParse(json2);
30313
- if (!parsed.success) {
30314
- return null;
30315
- }
30316
- const keys = {};
30317
- for (const [kid, encoded] of Object.entries(parsed.data.keys)) {
30318
- const bytes = base64UrlDecode(encoded);
30319
- if (bytes === null) {
30320
- return null;
30321
- }
30322
- keys[kid] = bytes;
30323
- }
30324
- return keys;
30325
- }, "parseAppUiKeyEnv");
30326
-
30327
- // ../../libs/app-ui-token/src/jwt.ts
30328
- var headerSchema = external_exports.object({
30329
- alg: external_exports.literal("HS256"),
30330
- typ: external_exports.literal("JWT"),
30331
- kid: external_exports.string().min(1).max(16)
30332
- }).strict();
30333
- var encodeJsonPart = /* @__PURE__ */ __name((value) => {
30334
- return base64UrlEncode(new TextEncoder().encode(JSON.stringify(value)));
30335
- }, "encodeJsonPart");
30336
- var parseJsonPart = /* @__PURE__ */ __name((part) => {
30337
- const bytes = base64UrlDecode(part);
30338
- if (bytes === null) {
30339
- return null;
30340
- }
30341
- try {
30342
- return JSON.parse(new TextDecoder().decode(bytes));
30343
- } catch {
30344
- return null;
30345
- }
30346
- }, "parseJsonPart");
30347
- var hmacKey = /* @__PURE__ */ __name((key, usage) => {
30348
- return crypto.subtle.importKey("raw", key, { name: "HMAC", hash: "SHA-256" }, false, [usage]);
30349
- }, "hmacKey");
30350
- var signCompact = /* @__PURE__ */ __name(async (kid, key, claims) => {
30351
- const signingInput = `${encodeJsonPart({ alg: "HS256", typ: "JWT", kid })}.${encodeJsonPart(claims)}`;
30352
- const signature = await crypto.subtle.sign("HMAC", await hmacKey(key, "sign"), new TextEncoder().encode(signingInput));
30353
- return `${signingInput}.${base64UrlEncode(new Uint8Array(signature))}`;
30354
- }, "signCompact");
30355
- var verifyCompactSignature = /* @__PURE__ */ __name(async (token, keys) => {
30356
- const [headerPart, claimsPart, signaturePart, extra] = token.split(".");
30357
- if (headerPart === void 0 || claimsPart === void 0 || signaturePart === void 0 || extra !== void 0) {
30358
- return { ok: false, reason: "malformed" };
30359
- }
30360
- const header = headerSchema.safeParse(parseJsonPart(headerPart));
30361
- if (!header.success) {
30362
- return { ok: false, reason: "malformed" };
30363
- }
30364
- const key = keys[header.data.kid];
30365
- if (key === void 0) {
30366
- return { ok: false, reason: "unknown_kid" };
30367
- }
30368
- const signature = base64UrlDecode(signaturePart);
30369
- if (signature === null) {
30370
- return { ok: false, reason: "malformed" };
30371
- }
30372
- const signed = await crypto.subtle.verify(
30373
- "HMAC",
30374
- await hmacKey(key, "verify"),
30375
- signature,
30376
- new TextEncoder().encode(`${headerPart}.${claimsPart}`)
30377
- );
30378
- if (!signed) {
30379
- return { ok: false, reason: "bad_signature" };
30380
- }
30381
- return { ok: true, claims: parseJsonPart(claimsPart), kid: header.data.kid, key };
30382
- }, "verifyCompactSignature");
30383
-
30384
- // ../../libs/app-ui-token/src/token.ts
30385
- var APP_UI_TOKEN_SKEW_SECONDS = 60;
30386
- var APP_UI_TOKEN_ISSUER = "qinto-portal";
30387
- var claimsSchema = external_exports.object({
30388
- iss: external_exports.literal(APP_UI_TOKEN_ISSUER),
30389
- aud: external_exports.string().min(1),
30390
- sub: external_exports.string().min(1),
30391
- userId: external_exports.string().min(1),
30392
- iat: external_exports.number().int(),
30393
- exp: external_exports.number().int(),
30394
- domainId: external_exports.string().min(1),
30395
- appId: external_exports.string().min(1),
30396
- appInstallId: external_exports.string().min(1),
30397
- appVersionId: external_exports.string().min(1),
30398
- access: external_exports.enum(["read", "write"]),
30399
- // Absent means `full`; see the mint below.
30400
- appRole: external_exports.enum(APP_ROLES).optional()
30401
- }).strict();
30402
- var appUiAudience = /* @__PURE__ */ __name((slug) => {
30403
- return `app-ui:${slug}`;
30404
- }, "appUiAudience");
30405
- var verifyAppUiToken = /* @__PURE__ */ __name(async (input2) => {
30406
- const signature = await verifyCompactSignature(input2.token, input2.keys);
30407
- if (!signature.ok) {
30408
- return signature;
30409
- }
30410
- const claims = claimsSchema.safeParse(signature.claims);
30411
- if (!claims.success) {
30412
- return { ok: false, reason: "bad_claims" };
30413
- }
30414
- if (claims.data.aud !== appUiAudience(input2.slug)) {
30415
- return { ok: false, reason: "wrong_app" };
30416
- }
30417
- const now = Math.floor(input2.now.getTime() / 1e3);
30418
- if (claims.data.iat > now + (input2.skewSeconds ?? APP_UI_TOKEN_SKEW_SECONDS)) {
30419
- return { ok: false, reason: "future_iat" };
30420
- }
30421
- if (claims.data.exp <= now) {
30422
- return { ok: false, reason: "expired" };
30423
- }
30424
- return { ok: true, claims: claims.data, kid: signature.kid, key: signature.key };
30425
- }, "verifyAppUiToken");
30426
-
30427
- // ../../libs/app-ui-token/src/runtime-query-ticket.ts
30428
- var APP_RUNTIME_QUERY_TICKET_ISSUER = "qinto-portal";
30429
- var claimsSchema2 = external_exports.object({
30430
- iss: external_exports.literal(APP_RUNTIME_QUERY_TICKET_ISSUER),
30431
- aud: external_exports.string().min(1),
30432
- sub: external_exports.string().min(1),
30433
- iat: external_exports.number().int(),
30434
- exp: external_exports.number().int(),
30435
- domainId: external_exports.string().min(1),
30436
- appId: external_exports.string().min(1),
30437
- appInstallId: external_exports.string().min(1),
30438
- appVersionId: external_exports.string().min(1)
30439
- }).strict();
30440
-
30441
- // ../../libs/app-ui-token/src/write-ticket.ts
30442
- var APP_UI_WRITE_TICKET_TTL_SECONDS = 60;
30443
- var APP_UI_WRITE_TICKET_ISSUER = "qinto-site";
30444
- var claimsSchema3 = external_exports.object({
30445
- iss: external_exports.literal(APP_UI_WRITE_TICKET_ISSUER),
30446
- aud: external_exports.string().min(1),
30447
- sub: external_exports.string().min(1),
30448
- iat: external_exports.number().int(),
30449
- exp: external_exports.number().int(),
30450
- domainId: external_exports.string().min(1),
30451
- appId: external_exports.string().min(1),
30452
- appVersionId: external_exports.string().min(1)
30453
- }).strict();
30454
- var appUiWriteAudience = /* @__PURE__ */ __name((slug) => {
30455
- return `app-ui-write:${slug}`;
30456
- }, "appUiWriteAudience");
30457
- var mintAppUiWriteTicket = /* @__PURE__ */ __name(async (input2) => {
30458
- const iat = Math.floor(input2.now.getTime() / 1e3);
30459
- const claims = {
30460
- iss: APP_UI_WRITE_TICKET_ISSUER,
30461
- aud: appUiWriteAudience(input2.slug),
30462
- sub: input2.userId,
30463
- iat,
30464
- exp: iat + (input2.ttlSeconds ?? APP_UI_WRITE_TICKET_TTL_SECONDS),
30465
- domainId: input2.domainId,
30466
- appId: input2.appId,
30467
- appVersionId: input2.appVersionId
30468
- };
30469
- return signCompact(input2.kid, input2.key, claims);
30470
- }, "mintAppUiWriteTicket");
30471
-
30472
30563
  // src/apps/ui-proxy.ts
30473
30564
  var APP_UI_TIMEOUT_MS = 6e4;
30474
30565
  var refuse3 = /* @__PURE__ */ __name((origin, status, error61) => {
@@ -31404,14 +31495,14 @@ var open2 = /* @__PURE__ */ __name(async (c) => {
31404
31495
 
31405
31496
  // browser-artifact/meta.json
31406
31497
  var meta_default = {
31407
- version: "0.1.14",
31408
- gitSha: "38d2892377935b8b457db896715c24891fc3b1ae",
31409
- builtAt: "2026-10-02T07:54:26.292Z",
31410
- hash: "50484908a3b28aa31a614fda30b1b3d803fe5922c8a485079f12e6bbf24cd9c1"
31498
+ version: "0.1.15",
31499
+ gitSha: "b90e20a6f236a81312f9525a2b089d2019d0c027",
31500
+ builtAt: "2026-10-09T06:11:09.581Z",
31501
+ hash: "a0cb067dc6246faae53d7842489effb3c46aa848ef529484ab6ee3868fd86762"
31411
31502
  };
31412
31503
 
31413
31504
  // src/paths/q-js.ts
31414
- import qScript from "./8809017061697bf9b90fa4d72f7eb2e0f0e00ad4-q.js.txt";
31505
+ import qScript from "./73ef5f028ec35836560c0489d1abdeea83eceede-q.js.txt";
31415
31506
 
31416
31507
  // src/apps-q.ts
31417
31508
  import appsQScript from "./apps-q.json";