@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.
- package/dist/index.js +2667 -2659
- package/dist/index.js.map +1 -1
- package/dist/worker-artifact/app-runtime/index.js +81 -23
- package/dist/worker-artifact/main/73ef5f028ec35836560c0489d1abdeea83eceede-q.js.txt +1 -0
- package/dist/worker-artifact/main/index.js +1131 -1040
- package/dist/worker-artifact/version.json +8 -8
- package/package.json +1 -1
- package/dist/worker-artifact/main/8809017061697bf9b90fa4d72f7eb2e0f0e00ad4-q.js.txt +0 -1
|
@@ -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({
|
|
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
|
-
//
|
|
26741
|
-
var
|
|
26742
|
-
|
|
26743
|
-
return
|
|
26744
|
-
|
|
26745
|
-
|
|
26746
|
-
|
|
26747
|
-
|
|
26748
|
-
|
|
26749
|
-
|
|
26750
|
-
|
|
26751
|
-
|
|
26752
|
-
|
|
26753
|
-
|
|
26754
|
-
|
|
26755
|
-
|
|
26756
|
-
|
|
26757
|
-
|
|
26758
|
-
|
|
26759
|
-
|
|
26760
|
-
}
|
|
26761
|
-
|
|
26762
|
-
|
|
26763
|
-
|
|
26764
|
-
|
|
26765
|
-
}
|
|
26766
|
-
|
|
26767
|
-
|
|
26768
|
-
|
|
26769
|
-
|
|
26770
|
-
|
|
26771
|
-
|
|
26772
|
-
|
|
26773
|
-
|
|
26774
|
-
|
|
26775
|
-
|
|
26776
|
-
|
|
26777
|
-
|
|
26778
|
-
|
|
26779
|
-
|
|
26780
|
-
|
|
26781
|
-
|
|
26782
|
-
|
|
26783
|
-
|
|
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
|
-
|
|
27530
|
-
|
|
27531
|
-
|
|
27480
|
+
return false;
|
|
27481
|
+
}, "isNoopSubmission");
|
|
27482
|
+
var isNoopAction = /* @__PURE__ */ __name((action) => {
|
|
27483
|
+
if (action.identifier !== void 0) {
|
|
27484
|
+
return false;
|
|
27532
27485
|
}
|
|
27533
|
-
|
|
27534
|
-
|
|
27535
|
-
|
|
27536
|
-
|
|
27537
|
-
|
|
27538
|
-
|
|
27539
|
-
return
|
|
27540
|
-
}, "
|
|
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/
|
|
27543
|
-
var
|
|
27544
|
-
|
|
27545
|
-
|
|
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
|
-
|
|
27553
|
-
|
|
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/
|
|
27646
|
-
var
|
|
27647
|
-
|
|
27648
|
-
|
|
27649
|
-
|
|
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
|
|
27652
|
-
return
|
|
27653
|
-
}, "
|
|
27654
|
-
var
|
|
27655
|
-
|
|
27656
|
-
|
|
27657
|
-
|
|
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
|
-
|
|
27662
|
-
|
|
27816
|
+
const claims = claimsSchema.safeParse(signature.claims);
|
|
27817
|
+
if (!claims.success) {
|
|
27818
|
+
return { ok: false, reason: "bad_claims" };
|
|
27663
27819
|
}
|
|
27664
|
-
|
|
27665
|
-
|
|
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
|
-
|
|
27669
|
-
|
|
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
|
|
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
|
-
|
|
28908
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
}, "
|
|
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
|
|
29089
|
-
|
|
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
|
|
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
|
|
29192
|
+
return calleeError(body.callee, "result_too_large", `The callee response exceeds ${MAX_RESPONSE_BYTES / 1024 / 1024} MB.`);
|
|
29124
29193
|
}
|
|
29125
|
-
|
|
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
|
-
|
|
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
|
-
|
|
29187
|
-
|
|
29188
|
-
|
|
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
|
-
|
|
29191
|
-
|
|
29465
|
+
const broadcast = body.broadcast ?? "install";
|
|
29466
|
+
if (broadcast === "install" && body.installId === void 0) {
|
|
29467
|
+
return invalidBody();
|
|
29192
29468
|
}
|
|
29193
|
-
|
|
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
|
-
|
|
29197
|
-
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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(
|
|
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.
|
|
31408
|
-
gitSha: "
|
|
31409
|
-
builtAt: "2026-10-
|
|
31410
|
-
hash: "
|
|
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 "./
|
|
31505
|
+
import qScript from "./73ef5f028ec35836560c0489d1abdeea83eceede-q.js.txt";
|
|
31415
31506
|
|
|
31416
31507
|
// src/apps-q.ts
|
|
31417
31508
|
import appsQScript from "./apps-q.json";
|