@blotout/qinto-cli 0.1.8 → 0.1.9
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 +2307 -1749
- package/dist/index.js.map +1 -1
- package/dist/worker-artifact/app-runtime/index.js +334 -37
- package/dist/worker-artifact/main/9026260a7a674b710223f296c5d2e7a01930cfed-q.js.txt +1 -0
- package/dist/worker-artifact/main/index.js +444 -48
- package/dist/worker-artifact/version.json +6 -6
- package/package.json +1 -1
- package/templates/app/full/ui/src/pages/index.astro +0 -2
- package/templates/ui/src/pages/index.astro +1 -2
- package/dist/worker-artifact/main/9dcfd236748459af038da772477100c4bb0223b7-q.js.txt +0 -1
|
@@ -15966,12 +15966,21 @@ var ENDPOINT_CONTEXT_HEADER = "x-qinto-endpoint-context";
|
|
|
15966
15966
|
var ENDPOINT_OUTCOMES_HEADER = "x-qinto-endpoint-outcomes";
|
|
15967
15967
|
var MAX_ENDPOINT_BODY_BYTES = 1024 * 1024;
|
|
15968
15968
|
var MAX_ENDPOINT_OUTCOMES_BYTES = 64 * 1024;
|
|
15969
|
+
var MAX_ENDPOINT_PATH_LENGTH = 16 * 1024;
|
|
15969
15970
|
var installSchema3 = 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();
|
|
15970
15971
|
var endpointContextSchema = external_exports.object({
|
|
15971
|
-
path
|
|
15972
|
+
// The declared template, which keys the bundle's handler map; `path` is what the caller asked
|
|
15973
|
+
// for. Only `route` may key the rate limiter — a concrete path gives every parameter value its
|
|
15974
|
+
// own bucket, which is no limit at all.
|
|
15975
|
+
route: external_exports.string().min(1).max(255),
|
|
15976
|
+
path: external_exports.string().min(1).max(MAX_ENDPOINT_PATH_LENGTH),
|
|
15977
|
+
// A name is cut from `route`, so the route's own cap bounds it; anything tighter would reject a
|
|
15978
|
+
// parameter the manifest grammar accepts and the worker already matched.
|
|
15979
|
+
params: external_exports.record(external_exports.string().min(1).max(255), external_exports.string().max(MAX_ENDPOINT_PATH_LENGTH)).default({}),
|
|
15972
15980
|
method: external_exports.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
|
|
15973
15981
|
mode: external_exports.enum(["webhook", "api"]),
|
|
15974
15982
|
version: external_exports.string().min(1).max(32),
|
|
15983
|
+
site: external_exports.object({ origin: external_exports.string().min(1).max(255) }).strict(),
|
|
15975
15984
|
installs: external_exports.array(installSchema3).min(1).max(15)
|
|
15976
15985
|
}).strict().refine((context) => {
|
|
15977
15986
|
return context.mode === "webhook" || context.installs.length === 1;
|
|
@@ -15998,6 +16007,71 @@ var aggregateEndpointOutcomes = /* @__PURE__ */ __name((outcomes) => {
|
|
|
15998
16007
|
return { status: failed ? 502 : 200 };
|
|
15999
16008
|
}, "aggregateEndpointOutcomes");
|
|
16000
16009
|
|
|
16010
|
+
// ../../libs/app-envelope/src/observability.ts
|
|
16011
|
+
var APP_OBSERVABILITY_HEADER = "x-qinto-app-observability";
|
|
16012
|
+
var APP_OBSERVABILITY_VERSION = 1;
|
|
16013
|
+
var MAX_APP_OBSERVABILITY_EVENTS = 20;
|
|
16014
|
+
var MAX_APP_SAVED_ERRORS = 5;
|
|
16015
|
+
var MAX_APP_EVENT_NAME_BYTES = 128;
|
|
16016
|
+
var MAX_APP_ACTION_NAME_BYTES = 256;
|
|
16017
|
+
var MAX_APP_ERROR_DESCRIPTION_BYTES = 2048;
|
|
16018
|
+
var MAX_APP_ERROR_PAYLOAD_BYTES = 4096;
|
|
16019
|
+
var MAX_APP_DATA_POINT_BLOB_BYTES = 16 * 1024;
|
|
16020
|
+
var MAX_APP_OBSERVABILITY_BYTES = 32 * 1024;
|
|
16021
|
+
var APP_OBSERVABILITY_JSON_BUDGET = MAX_APP_OBSERVABILITY_BYTES / 4 * 3;
|
|
16022
|
+
var MAX_APP_DATA_POINTS_PER_INVOCATION = 250;
|
|
16023
|
+
var APP_EVENT_STATUSES = ["success", "error"];
|
|
16024
|
+
var APP_ERROR_CATEGORIES = ["authorization", "configuration", "validation", "rate_limit", "upstream", "internal"];
|
|
16025
|
+
var encoder3 = new TextEncoder();
|
|
16026
|
+
var decoder2 = new TextDecoder();
|
|
16027
|
+
var observabilityEventSchema = external_exports.object({ ord: external_exports.number().int().min(1), name: external_exports.string().min(1).max(MAX_APP_EVENT_NAME_BYTES), status: external_exports.enum(APP_EVENT_STATUSES) }).strict();
|
|
16028
|
+
var savedErrorSchema = external_exports.object({
|
|
16029
|
+
ord: external_exports.number().int().min(1),
|
|
16030
|
+
category: external_exports.enum(APP_ERROR_CATEGORIES),
|
|
16031
|
+
action: external_exports.string().min(1).max(MAX_APP_ACTION_NAME_BYTES),
|
|
16032
|
+
description: external_exports.string().min(1).max(MAX_APP_ERROR_DESCRIPTION_BYTES),
|
|
16033
|
+
payload: external_exports.string().max(MAX_APP_ERROR_PAYLOAD_BYTES).optional(),
|
|
16034
|
+
error: external_exports.string().max(MAX_APP_ERROR_PAYLOAD_BYTES).optional()
|
|
16035
|
+
}).strict();
|
|
16036
|
+
var appObservabilityRecordSchema = external_exports.object({
|
|
16037
|
+
v: external_exports.literal(APP_OBSERVABILITY_VERSION),
|
|
16038
|
+
truncated: external_exports.boolean().optional(),
|
|
16039
|
+
events: external_exports.array(observabilityEventSchema).max(MAX_APP_OBSERVABILITY_EVENTS),
|
|
16040
|
+
errors: external_exports.array(savedErrorSchema).max(MAX_APP_SAVED_ERRORS)
|
|
16041
|
+
}).strict();
|
|
16042
|
+
var utf8Length = /* @__PURE__ */ __name((value) => {
|
|
16043
|
+
return encoder3.encode(value).length;
|
|
16044
|
+
}, "utf8Length");
|
|
16045
|
+
var truncateUtf8 = /* @__PURE__ */ __name((value, maxBytes) => {
|
|
16046
|
+
if (utf8Length(value) <= maxBytes) {
|
|
16047
|
+
return value;
|
|
16048
|
+
}
|
|
16049
|
+
let kept = "";
|
|
16050
|
+
let used = 0;
|
|
16051
|
+
for (const character of value) {
|
|
16052
|
+
const size = utf8Length(character);
|
|
16053
|
+
if (used + size > maxBytes) {
|
|
16054
|
+
break;
|
|
16055
|
+
}
|
|
16056
|
+
kept += character;
|
|
16057
|
+
used += size;
|
|
16058
|
+
}
|
|
16059
|
+
return kept;
|
|
16060
|
+
}, "truncateUtf8");
|
|
16061
|
+
var parseAppObservability = /* @__PURE__ */ __name((header) => {
|
|
16062
|
+
if (header === null || header.length > MAX_APP_OBSERVABILITY_BYTES) {
|
|
16063
|
+
return null;
|
|
16064
|
+
}
|
|
16065
|
+
let parsed;
|
|
16066
|
+
try {
|
|
16067
|
+
parsed = JSON.parse(decoder2.decode(Uint8Array.from(atob(header), (character) => character.charCodeAt(0))));
|
|
16068
|
+
} catch {
|
|
16069
|
+
return null;
|
|
16070
|
+
}
|
|
16071
|
+
const result = appObservabilityRecordSchema.safeParse(parsed);
|
|
16072
|
+
return result.success ? result.data : null;
|
|
16073
|
+
}, "parseAppObservability");
|
|
16074
|
+
|
|
16001
16075
|
// ../../libs/app-envelope/src/ui.ts
|
|
16002
16076
|
var UI_CONTEXT_HEADER = "x-qinto-ui-context";
|
|
16003
16077
|
var MAX_UI_BODY_BYTES = 1024 * 1024;
|
|
@@ -16204,13 +16278,13 @@ var getPattern = /* @__PURE__ */ __name((label, next) => {
|
|
|
16204
16278
|
}
|
|
16205
16279
|
return null;
|
|
16206
16280
|
}, "getPattern");
|
|
16207
|
-
var tryDecode = /* @__PURE__ */ __name((str,
|
|
16281
|
+
var tryDecode = /* @__PURE__ */ __name((str, decoder3) => {
|
|
16208
16282
|
try {
|
|
16209
|
-
return
|
|
16283
|
+
return decoder3(str);
|
|
16210
16284
|
} catch {
|
|
16211
16285
|
return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match2) => {
|
|
16212
16286
|
try {
|
|
16213
|
-
return
|
|
16287
|
+
return decoder3(match2);
|
|
16214
16288
|
} catch {
|
|
16215
16289
|
return match2;
|
|
16216
16290
|
}
|
|
@@ -18977,6 +19051,82 @@ var readableContext = /* @__PURE__ */ __name((own, shared) => {
|
|
|
18977
19051
|
return { private: own === void 0 ? null : wireEntry(own), shared: sharedContextWire(shared) };
|
|
18978
19052
|
}, "readableContext");
|
|
18979
19053
|
|
|
19054
|
+
// src/apps/observability.ts
|
|
19055
|
+
var observabilityApp = /* @__PURE__ */ __name((slug, app2) => {
|
|
19056
|
+
return { slug, name: app2.name, version: app2.version };
|
|
19057
|
+
}, "observabilityApp");
|
|
19058
|
+
var createDataPointBudget = /* @__PURE__ */ __name(() => {
|
|
19059
|
+
let spent = 0;
|
|
19060
|
+
return {
|
|
19061
|
+
take: /* @__PURE__ */ __name(() => {
|
|
19062
|
+
if (spent >= MAX_APP_DATA_POINTS_PER_INVOCATION) {
|
|
19063
|
+
return false;
|
|
19064
|
+
}
|
|
19065
|
+
spent += 1;
|
|
19066
|
+
return true;
|
|
19067
|
+
}, "take")
|
|
19068
|
+
};
|
|
19069
|
+
}, "createDataPointBudget");
|
|
19070
|
+
var totalLength = /* @__PURE__ */ __name((blobs) => {
|
|
19071
|
+
return blobs.reduce((sum, blob) => {
|
|
19072
|
+
return sum + utf8Length(blob);
|
|
19073
|
+
}, 0);
|
|
19074
|
+
}, "totalLength");
|
|
19075
|
+
var errorBlobs = /* @__PURE__ */ __name((app2, install, record2, rowId) => {
|
|
19076
|
+
const fixed = [app2.slug, app2.name, install.id, install.label, app2.version, record2.category, record2.action, rowId];
|
|
19077
|
+
let remaining = MAX_APP_DATA_POINT_BLOB_BYTES - totalLength(fixed);
|
|
19078
|
+
const description = truncateUtf8(record2.description, Math.max(0, remaining));
|
|
19079
|
+
remaining -= utf8Length(description);
|
|
19080
|
+
const payload = truncateUtf8(record2.payload ?? "", Math.max(0, remaining));
|
|
19081
|
+
remaining -= utf8Length(payload);
|
|
19082
|
+
const error51 = truncateUtf8(record2.error ?? "", Math.max(0, remaining));
|
|
19083
|
+
return [app2.slug, app2.name, install.id, install.label, app2.version, record2.category, record2.action, description, payload, error51, rowId];
|
|
19084
|
+
}, "errorBlobs");
|
|
19085
|
+
var eventBlobs = /* @__PURE__ */ __name((app2, install, record2) => {
|
|
19086
|
+
return [app2.slug, app2.name, install.id, install.label, app2.version, record2.name, record2.status];
|
|
19087
|
+
}, "eventBlobs");
|
|
19088
|
+
var writeAppObservability = /* @__PURE__ */ __name((env, response, target) => {
|
|
19089
|
+
const record2 = parseAppObservability(response.headers.get(APP_OBSERVABILITY_HEADER));
|
|
19090
|
+
if (record2 === null) {
|
|
19091
|
+
return;
|
|
19092
|
+
}
|
|
19093
|
+
const byOrd = new Map(
|
|
19094
|
+
target.installs.map((install) => {
|
|
19095
|
+
return [install.ord, install];
|
|
19096
|
+
})
|
|
19097
|
+
);
|
|
19098
|
+
for (const event of record2.events) {
|
|
19099
|
+
const install = byOrd.get(event.ord);
|
|
19100
|
+
if (install === void 0) {
|
|
19101
|
+
addSpanEvent("app observability names an install the site did not send", { level: "warn", attrs: { app: target.app.slug } });
|
|
19102
|
+
continue;
|
|
19103
|
+
}
|
|
19104
|
+
if (!target.budget.take()) {
|
|
19105
|
+
addSpanEvent("app observability dropped at the data-point cap", { level: "warn", attrs: { app: target.app.slug } });
|
|
19106
|
+
return;
|
|
19107
|
+
}
|
|
19108
|
+
env.APP_EVENTS.writeDataPoint({ indexes: [`${install.id}:${event.status}`], blobs: eventBlobs(target.app, install, event) });
|
|
19109
|
+
}
|
|
19110
|
+
for (const saved of record2.errors) {
|
|
19111
|
+
const install = byOrd.get(saved.ord);
|
|
19112
|
+
if (install === void 0) {
|
|
19113
|
+
addSpanEvent("app observability names an install the site did not send", { level: "warn", attrs: { app: target.app.slug } });
|
|
19114
|
+
continue;
|
|
19115
|
+
}
|
|
19116
|
+
if (!target.budget.take()) {
|
|
19117
|
+
addSpanEvent("app observability dropped at the data-point cap", { level: "warn", attrs: { app: target.app.slug } });
|
|
19118
|
+
return;
|
|
19119
|
+
}
|
|
19120
|
+
env.APP_ERRORS.writeDataPoint({
|
|
19121
|
+
indexes: [`${install.id}:${saved.category}`],
|
|
19122
|
+
blobs: errorBlobs(target.app, install, saved, ulid3())
|
|
19123
|
+
});
|
|
19124
|
+
}
|
|
19125
|
+
if (record2.truncated === true) {
|
|
19126
|
+
addSpanEvent("the app recorded more observability than one invocation carries", { level: "warn", attrs: { app: target.app.slug } });
|
|
19127
|
+
}
|
|
19128
|
+
}, "writeAppObservability");
|
|
19129
|
+
|
|
18980
19130
|
// src/apps/read-bounded.ts
|
|
18981
19131
|
var readBoundedBody = /* @__PURE__ */ __name(async (message, maxBytes) => {
|
|
18982
19132
|
const reader = message.body?.getReader();
|
|
@@ -19027,7 +19177,7 @@ var adoptAppSpans = /* @__PURE__ */ __name((response) => {
|
|
|
19027
19177
|
}, "adoptAppSpans");
|
|
19028
19178
|
|
|
19029
19179
|
// src/apps/invoke.ts
|
|
19030
|
-
var
|
|
19180
|
+
var APP_INVOCATION_TIMEOUT_MS = 1e4;
|
|
19031
19181
|
var MAX_EMIT_DEPTH = 2;
|
|
19032
19182
|
var HOOK_URL = "https://app/__qinto/hook";
|
|
19033
19183
|
var invocationContext = /* @__PURE__ */ __name((env) => {
|
|
@@ -19233,19 +19383,24 @@ var hookResponseBody = /* @__PURE__ */ __name(async (response, slug) => {
|
|
|
19233
19383
|
}
|
|
19234
19384
|
return new TextDecoder().decode(bytes);
|
|
19235
19385
|
}, "hookResponseBody");
|
|
19236
|
-
var runInvokeApp = /* @__PURE__ */ __name(async (env, { target, trigger, snapshot, context, deliverPush, writeAttribution: writeAttribution2, writeContext: writeContext2 }) => {
|
|
19386
|
+
var runInvokeApp = /* @__PURE__ */ __name(async (env, { target, trigger, snapshot, context, deliverPush, writeAttribution: writeAttribution2, writeContext: writeContext2, budget }) => {
|
|
19237
19387
|
try {
|
|
19238
19388
|
const key = await deriveAppInternalKey(context.master, context.domainId, target.slug);
|
|
19239
19389
|
const response = await postHookEnvelope(env, {
|
|
19240
19390
|
binding: target.app.binding,
|
|
19241
19391
|
key,
|
|
19242
19392
|
envelope: buildEnvelope(target, trigger, snapshot, context),
|
|
19243
|
-
timeoutMs:
|
|
19393
|
+
timeoutMs: APP_INVOCATION_TIMEOUT_MS
|
|
19244
19394
|
});
|
|
19245
19395
|
if (response === void 0) {
|
|
19246
19396
|
addSpanEvent("app service binding is missing", { level: "warn", attrs: { app: target.slug, binding: target.app.binding } });
|
|
19247
19397
|
return;
|
|
19248
19398
|
}
|
|
19399
|
+
writeAppObservability(env, response, {
|
|
19400
|
+
app: observabilityApp(target.slug, target.app),
|
|
19401
|
+
installs: target.installs,
|
|
19402
|
+
budget
|
|
19403
|
+
});
|
|
19249
19404
|
setSpanAttributes({ "app.status": response.status });
|
|
19250
19405
|
const body = await hookResponseBody(response, target.slug);
|
|
19251
19406
|
if (body === void 0) {
|
|
@@ -19329,6 +19484,9 @@ var installSchema4 = external_exports.object({
|
|
|
19329
19484
|
});
|
|
19330
19485
|
var appSchema = external_exports.object({
|
|
19331
19486
|
binding: external_exports.string().min(1),
|
|
19487
|
+
// Required, with no default, for the same reason `events` is: the display name is stored on every
|
|
19488
|
+
// observability data point, and a default would be a compatibility path for an older deploy.
|
|
19489
|
+
name: external_exports.string().min(1).max(100),
|
|
19332
19490
|
version: external_exports.string().min(1),
|
|
19333
19491
|
// Absent from an old embedded registry; the default never equals a real claim, so the ui proxy
|
|
19334
19492
|
// refuses stale registries with token_stale instead of turning the app off.
|
|
@@ -19616,11 +19774,16 @@ var runRelayRpc = /* @__PURE__ */ __name(async (env, { context, body, callee, in
|
|
|
19616
19774
|
// JSON.stringify drops an undefined key, and the envelope requires `args` to be present.
|
|
19617
19775
|
rpc: { caller: body.slug, fn: body.fn, args: body.args ?? null }
|
|
19618
19776
|
},
|
|
19619
|
-
timeoutMs:
|
|
19777
|
+
timeoutMs: APP_INVOCATION_TIMEOUT_MS
|
|
19620
19778
|
});
|
|
19621
19779
|
if (response === void 0) {
|
|
19622
19780
|
return calleeFailed(body.callee, "The callee service binding is missing.");
|
|
19623
19781
|
}
|
|
19782
|
+
writeAppObservability(env, response, {
|
|
19783
|
+
app: observabilityApp(body.callee, callee),
|
|
19784
|
+
installs: [install],
|
|
19785
|
+
budget: createDataPointBudget()
|
|
19786
|
+
});
|
|
19624
19787
|
setSpanAttributes({ "app.status": response.status });
|
|
19625
19788
|
if (!response.ok) {
|
|
19626
19789
|
return calleeFailed(body.callee, `The callee answered status ${response.status}.`);
|
|
@@ -19888,6 +20051,18 @@ var controlTargets = /* @__PURE__ */ __name(() => {
|
|
|
19888
20051
|
// src/apps/control.ts
|
|
19889
20052
|
var CONTROL_PATH = "/__qinto/control";
|
|
19890
20053
|
var MAX_CLOCK_SKEW_MS = 5 * 60 * 1e3;
|
|
20054
|
+
var writeControlObservability = /* @__PURE__ */ __name((env, upstream, envelope) => {
|
|
20055
|
+
const installs = envelope.schedule?.installs ?? (envelope.install === void 0 ? [] : [envelope.install]);
|
|
20056
|
+
const app2 = siteRegistry().registry.apps[envelope.app.slug];
|
|
20057
|
+
if (installs.length === 0 || app2 === void 0) {
|
|
20058
|
+
return;
|
|
20059
|
+
}
|
|
20060
|
+
writeAppObservability(env, upstream, {
|
|
20061
|
+
app: observabilityApp(envelope.app.slug, { name: app2.name, version: envelope.app.version }),
|
|
20062
|
+
installs,
|
|
20063
|
+
budget: createDataPointBudget()
|
|
20064
|
+
});
|
|
20065
|
+
}, "writeControlObservability");
|
|
19891
20066
|
var textBody = /* @__PURE__ */ __name(async (request) => {
|
|
19892
20067
|
const bytes = await readBoundedBody(request, MAX_CONTROL_BYTES);
|
|
19893
20068
|
return bytes === null ? null : new TextDecoder().decode(bytes);
|
|
@@ -19956,6 +20131,7 @@ var handleControl = /* @__PURE__ */ __name(async (request, env) => {
|
|
|
19956
20131
|
signal: AbortSignal.timeout(1e4)
|
|
19957
20132
|
});
|
|
19958
20133
|
adoptAppSpans(upstream);
|
|
20134
|
+
writeControlObservability(env, upstream, envelope);
|
|
19959
20135
|
const responseBytes = await readBoundedBody(upstream, MAX_CONTROL_BYTES);
|
|
19960
20136
|
if (responseBytes === null) {
|
|
19961
20137
|
return Response.json({ error: "invalid_response" }, { status: 502 });
|
|
@@ -19974,6 +20150,73 @@ var appControlRoutes = new Hono2().post(CONTROL_PATH, (c) => {
|
|
|
19974
20150
|
return handleControl(c.req.raw, c.env);
|
|
19975
20151
|
});
|
|
19976
20152
|
|
|
20153
|
+
// ../../libs/app-manifest/src/route.ts
|
|
20154
|
+
var isParam = /* @__PURE__ */ __name((segment) => {
|
|
20155
|
+
return segment.startsWith(":");
|
|
20156
|
+
}, "isParam");
|
|
20157
|
+
var splitRoute = /* @__PURE__ */ __name((route) => {
|
|
20158
|
+
return route === "/" ? [] : route.slice(1).split("/");
|
|
20159
|
+
}, "splitRoute");
|
|
20160
|
+
var splitRequest = /* @__PURE__ */ __name((requestPath) => {
|
|
20161
|
+
if (requestPath === "/") {
|
|
20162
|
+
return [];
|
|
20163
|
+
}
|
|
20164
|
+
const decoded = [];
|
|
20165
|
+
for (const segment of requestPath.slice(1).split("/")) {
|
|
20166
|
+
try {
|
|
20167
|
+
decoded.push(decodeURIComponent(segment));
|
|
20168
|
+
} catch {
|
|
20169
|
+
return null;
|
|
20170
|
+
}
|
|
20171
|
+
}
|
|
20172
|
+
return decoded;
|
|
20173
|
+
}, "splitRequest");
|
|
20174
|
+
var matches = /* @__PURE__ */ __name((parts, segments) => {
|
|
20175
|
+
if (parts.length !== segments.length) {
|
|
20176
|
+
return false;
|
|
20177
|
+
}
|
|
20178
|
+
return parts.every((part, index) => {
|
|
20179
|
+
const segment = segments[index];
|
|
20180
|
+
return isParam(part) ? segment.length > 0 : part === segment;
|
|
20181
|
+
});
|
|
20182
|
+
}, "matches");
|
|
20183
|
+
var isMoreSpecific = /* @__PURE__ */ __name((candidate, current) => {
|
|
20184
|
+
for (const [index, part] of candidate.entries()) {
|
|
20185
|
+
const candidateParam = isParam(part);
|
|
20186
|
+
const currentParam = isParam(current[index]);
|
|
20187
|
+
if (candidateParam !== currentParam) {
|
|
20188
|
+
return !candidateParam;
|
|
20189
|
+
}
|
|
20190
|
+
}
|
|
20191
|
+
return false;
|
|
20192
|
+
}, "isMoreSpecific");
|
|
20193
|
+
var extract = /* @__PURE__ */ __name((parts, segments) => {
|
|
20194
|
+
const params = {};
|
|
20195
|
+
for (const [index, part] of parts.entries()) {
|
|
20196
|
+
if (isParam(part)) {
|
|
20197
|
+
params[part.slice(1)] = segments[index];
|
|
20198
|
+
}
|
|
20199
|
+
}
|
|
20200
|
+
return params;
|
|
20201
|
+
}, "extract");
|
|
20202
|
+
var matchEndpointPath = /* @__PURE__ */ __name((routes, requestPath) => {
|
|
20203
|
+
const segments = splitRequest(requestPath);
|
|
20204
|
+
if (segments === null) {
|
|
20205
|
+
return void 0;
|
|
20206
|
+
}
|
|
20207
|
+
let best;
|
|
20208
|
+
for (const route of routes) {
|
|
20209
|
+
const parts = splitRoute(route);
|
|
20210
|
+
if (matches(parts, segments) && (best === void 0 || isMoreSpecific(parts, best.parts))) {
|
|
20211
|
+
best = { route, parts };
|
|
20212
|
+
}
|
|
20213
|
+
}
|
|
20214
|
+
if (best === void 0) {
|
|
20215
|
+
return void 0;
|
|
20216
|
+
}
|
|
20217
|
+
return { route: best.route, params: extract(best.parts, segments) };
|
|
20218
|
+
}, "matchEndpointPath");
|
|
20219
|
+
|
|
19977
20220
|
// ../../libs/worker-access-token/src/endpoints.ts
|
|
19978
20221
|
var APP_ENDPOINT_PREFIX = "/app/";
|
|
19979
20222
|
var MAX_CUSTOM_ENDPOINT_LENGTH = 128;
|
|
@@ -20209,7 +20452,76 @@ var requireScope = /* @__PURE__ */ __name((bit) => {
|
|
|
20209
20452
|
};
|
|
20210
20453
|
}, "requireScope");
|
|
20211
20454
|
|
|
20455
|
+
// src/apps/stream-deadlines.ts
|
|
20456
|
+
var streamWithDeadlines = /* @__PURE__ */ __name((source, { idleMs, totalMs }) => {
|
|
20457
|
+
if (source === null) {
|
|
20458
|
+
return null;
|
|
20459
|
+
}
|
|
20460
|
+
const reader = source.getReader();
|
|
20461
|
+
let target;
|
|
20462
|
+
let totalTimer;
|
|
20463
|
+
let idleTimer = null;
|
|
20464
|
+
let stopped = false;
|
|
20465
|
+
const clearIdleTimer = /* @__PURE__ */ __name(() => {
|
|
20466
|
+
if (idleTimer !== null) {
|
|
20467
|
+
clearTimeout(idleTimer);
|
|
20468
|
+
idleTimer = null;
|
|
20469
|
+
}
|
|
20470
|
+
}, "clearIdleTimer");
|
|
20471
|
+
const clearTimers = /* @__PURE__ */ __name(() => {
|
|
20472
|
+
clearTimeout(totalTimer);
|
|
20473
|
+
clearIdleTimer();
|
|
20474
|
+
}, "clearTimers");
|
|
20475
|
+
const stop = /* @__PURE__ */ __name((message) => {
|
|
20476
|
+
stopped = true;
|
|
20477
|
+
clearTimers();
|
|
20478
|
+
const error51 = new DOMException(message, "TimeoutError");
|
|
20479
|
+
target.error(error51);
|
|
20480
|
+
void reader.cancel(error51).catch(() => void 0);
|
|
20481
|
+
}, "stop");
|
|
20482
|
+
return new ReadableStream({
|
|
20483
|
+
start: /* @__PURE__ */ __name((controller) => {
|
|
20484
|
+
target = controller;
|
|
20485
|
+
totalTimer = setTimeout(() => {
|
|
20486
|
+
stop("The app endpoint stream exceeded its maximum duration.");
|
|
20487
|
+
}, totalMs);
|
|
20488
|
+
}, "start"),
|
|
20489
|
+
pull: /* @__PURE__ */ __name(async (controller) => {
|
|
20490
|
+
idleTimer = setTimeout(() => {
|
|
20491
|
+
stop("The app endpoint stream stopped producing data.");
|
|
20492
|
+
}, idleMs);
|
|
20493
|
+
let result;
|
|
20494
|
+
try {
|
|
20495
|
+
result = await reader.read();
|
|
20496
|
+
} catch (error51) {
|
|
20497
|
+
stopped = true;
|
|
20498
|
+
clearTimers();
|
|
20499
|
+
throw error51;
|
|
20500
|
+
}
|
|
20501
|
+
clearIdleTimer();
|
|
20502
|
+
if (stopped) {
|
|
20503
|
+
return;
|
|
20504
|
+
}
|
|
20505
|
+
if (result.done) {
|
|
20506
|
+
stopped = true;
|
|
20507
|
+
clearTimers();
|
|
20508
|
+
controller.close();
|
|
20509
|
+
return;
|
|
20510
|
+
}
|
|
20511
|
+
controller.enqueue(result.value);
|
|
20512
|
+
}, "pull"),
|
|
20513
|
+
cancel: /* @__PURE__ */ __name(async (reason) => {
|
|
20514
|
+
stopped = true;
|
|
20515
|
+
clearTimers();
|
|
20516
|
+
await reader.cancel(reason);
|
|
20517
|
+
}, "cancel")
|
|
20518
|
+
});
|
|
20519
|
+
}, "streamWithDeadlines");
|
|
20520
|
+
|
|
20212
20521
|
// src/apps/endpoint-proxy.ts
|
|
20522
|
+
var API_ENDPOINT_START_TIMEOUT_MS = 1e4;
|
|
20523
|
+
var API_ENDPOINT_STREAM_IDLE_TIMEOUT_MS = 15e4;
|
|
20524
|
+
var API_ENDPOINT_STREAM_MAX_DURATION_MS = 3e5;
|
|
20213
20525
|
var DENIED_REQUEST_HEADERS = /* @__PURE__ */ new Set(["authorization", "cookie", "x-cf-data"]);
|
|
20214
20526
|
var refuse = /* @__PURE__ */ __name((status, error51) => {
|
|
20215
20527
|
return Response.json({ error: error51 }, { status });
|
|
@@ -20225,16 +20537,23 @@ var matchEndpoint = /* @__PURE__ */ __name((app2, path, method) => {
|
|
|
20225
20537
|
if (!isHttpMethod(method)) {
|
|
20226
20538
|
return void 0;
|
|
20227
20539
|
}
|
|
20228
|
-
const
|
|
20229
|
-
return endpoint.
|
|
20540
|
+
const serving = app2.endpoints.filter((endpoint) => {
|
|
20541
|
+
return endpoint.methods.includes(method);
|
|
20230
20542
|
});
|
|
20231
|
-
|
|
20543
|
+
const matched = matchEndpointPath(
|
|
20544
|
+
serving.map((endpoint) => endpoint.path),
|
|
20545
|
+
path
|
|
20546
|
+
);
|
|
20547
|
+
if (matched === void 0) {
|
|
20232
20548
|
return void 0;
|
|
20233
20549
|
}
|
|
20550
|
+
const declared = serving.find((endpoint) => {
|
|
20551
|
+
return endpoint.path === matched.route;
|
|
20552
|
+
});
|
|
20234
20553
|
if (declared.auth !== "public" && declared.auth !== "token" || declared.mode !== "webhook" && declared.mode !== "api") {
|
|
20235
20554
|
return void 0;
|
|
20236
20555
|
}
|
|
20237
|
-
return {
|
|
20556
|
+
return { route: declared.path, path, params: matched.params, method, auth: declared.auth, mode: declared.mode };
|
|
20238
20557
|
}, "matchEndpoint");
|
|
20239
20558
|
var authorizeEndpoint = /* @__PURE__ */ __name(async (c, slug, endpoint) => {
|
|
20240
20559
|
if (endpoint.auth === "public") {
|
|
@@ -20266,12 +20585,17 @@ var passThroughResponse = /* @__PURE__ */ __name((upstream) => {
|
|
|
20266
20585
|
const headers = new Headers(upstream.headers);
|
|
20267
20586
|
headers.delete("set-cookie");
|
|
20268
20587
|
headers.delete(APP_SPANS_HEADER);
|
|
20588
|
+
headers.delete(APP_OBSERVABILITY_HEADER);
|
|
20269
20589
|
for (const name of [...headers.keys()]) {
|
|
20270
20590
|
if (name.startsWith("access-control-")) {
|
|
20271
20591
|
headers.delete(name);
|
|
20272
20592
|
}
|
|
20273
20593
|
}
|
|
20274
|
-
|
|
20594
|
+
const body = streamWithDeadlines(upstream.body, {
|
|
20595
|
+
idleMs: API_ENDPOINT_STREAM_IDLE_TIMEOUT_MS,
|
|
20596
|
+
totalMs: API_ENDPOINT_STREAM_MAX_DURATION_MS
|
|
20597
|
+
});
|
|
20598
|
+
return new Response(body, { status: upstream.status, headers });
|
|
20275
20599
|
}, "passThroughResponse");
|
|
20276
20600
|
var parseJson3 = /* @__PURE__ */ __name((text) => {
|
|
20277
20601
|
try {
|
|
@@ -20301,6 +20625,17 @@ var webhookAck = /* @__PURE__ */ __name(async (slug, upstream) => {
|
|
|
20301
20625
|
}
|
|
20302
20626
|
return refuse(502, "upstream");
|
|
20303
20627
|
}, "webhookAck");
|
|
20628
|
+
var fetchApiResponse = /* @__PURE__ */ __name(async (service, url2, init) => {
|
|
20629
|
+
const controller = new AbortController();
|
|
20630
|
+
const timer = setTimeout(() => {
|
|
20631
|
+
controller.abort(new DOMException("The app endpoint did not start within its deadline.", "TimeoutError"));
|
|
20632
|
+
}, API_ENDPOINT_START_TIMEOUT_MS);
|
|
20633
|
+
try {
|
|
20634
|
+
return await service.fetch(url2, { ...init, signal: controller.signal });
|
|
20635
|
+
} finally {
|
|
20636
|
+
clearTimeout(timer);
|
|
20637
|
+
}
|
|
20638
|
+
}, "fetchApiResponse");
|
|
20304
20639
|
var runForwardToApp = /* @__PURE__ */ __name(async (c, input) => {
|
|
20305
20640
|
const { slug, app: app2, endpoint, installs, body, search } = input;
|
|
20306
20641
|
const context = invocationContext(c.env);
|
|
@@ -20320,25 +20655,30 @@ var runForwardToApp = /* @__PURE__ */ __name(async (c, input) => {
|
|
|
20320
20655
|
headers.set(
|
|
20321
20656
|
ENDPOINT_CONTEXT_HEADER,
|
|
20322
20657
|
JSON.stringify({
|
|
20658
|
+
route: endpoint.route,
|
|
20323
20659
|
path: endpoint.path,
|
|
20660
|
+
params: endpoint.params,
|
|
20324
20661
|
method: endpoint.method,
|
|
20325
20662
|
mode: endpoint.mode,
|
|
20326
20663
|
version: app2.version,
|
|
20664
|
+
site: { origin: context.origin },
|
|
20327
20665
|
installs: installs.map((install) => ({ id: install.id, ord: install.ord, label: install.label }))
|
|
20328
20666
|
})
|
|
20329
20667
|
);
|
|
20330
20668
|
let upstream;
|
|
20331
20669
|
try {
|
|
20332
|
-
|
|
20333
|
-
|
|
20334
|
-
|
|
20335
|
-
body,
|
|
20336
|
-
signal: AbortSignal.timeout(HOOK_TIMEOUT_MS)
|
|
20337
|
-
});
|
|
20670
|
+
const url2 = `https://app/__qinto/endpoint${endpoint.route}${search}`;
|
|
20671
|
+
const init = { method: endpoint.method, headers, body };
|
|
20672
|
+
upstream = endpoint.mode === "api" ? await fetchApiResponse(service, url2, init) : await service.fetch(url2, { ...init, signal: AbortSignal.timeout(APP_INVOCATION_TIMEOUT_MS) });
|
|
20338
20673
|
} catch (error51) {
|
|
20339
20674
|
return upstreamFailed(slug, String(error51));
|
|
20340
20675
|
}
|
|
20341
20676
|
adoptAppSpans(upstream);
|
|
20677
|
+
writeAppObservability(c.env, upstream, {
|
|
20678
|
+
app: observabilityApp(slug, app2),
|
|
20679
|
+
installs,
|
|
20680
|
+
budget: createDataPointBudget()
|
|
20681
|
+
});
|
|
20342
20682
|
setSpanAttributes({ "app.status": upstream.status });
|
|
20343
20683
|
return endpoint.mode === "api" ? passThroughResponse(upstream) : webhookAck(slug, upstream);
|
|
20344
20684
|
}, "runForwardToApp");
|
|
@@ -20351,7 +20691,7 @@ var forwardToApp = /* @__PURE__ */ __name(async (c, input) => {
|
|
|
20351
20691
|
"app.slug": slug,
|
|
20352
20692
|
"app.version": app2.version,
|
|
20353
20693
|
"app.binding": app2.binding,
|
|
20354
|
-
"app.hook": `endpoint.${endpoint.method} ${endpoint.
|
|
20694
|
+
"app.hook": `endpoint.${endpoint.method} ${endpoint.route}`,
|
|
20355
20695
|
"app.endpoint_mode": endpoint.mode,
|
|
20356
20696
|
"app.installs": installs.length
|
|
20357
20697
|
}
|
|
@@ -20367,7 +20707,11 @@ var handleAppEndpoint = /* @__PURE__ */ __name(async (c, slug) => {
|
|
|
20367
20707
|
return refuse(404, "not_found");
|
|
20368
20708
|
}
|
|
20369
20709
|
const url2 = new URL(c.req.url);
|
|
20370
|
-
const
|
|
20710
|
+
const prefix = `/app/${slug}`;
|
|
20711
|
+
if (url2.pathname !== prefix && !url2.pathname.startsWith(`${prefix}/`)) {
|
|
20712
|
+
return refuse(404, "not_found");
|
|
20713
|
+
}
|
|
20714
|
+
const endpoint = matchEndpoint(app2, url2.pathname.slice(prefix.length) || "/", c.req.method);
|
|
20371
20715
|
if (endpoint === void 0) {
|
|
20372
20716
|
return refuse(404, "not_found");
|
|
20373
20717
|
}
|
|
@@ -20380,7 +20724,7 @@ var handleAppEndpoint = /* @__PURE__ */ __name(async (c, slug) => {
|
|
|
20380
20724
|
if (first === void 0) {
|
|
20381
20725
|
return refuse(503, "inactive");
|
|
20382
20726
|
}
|
|
20383
|
-
const key = endpoint.mode === "api" ? `${slug}:${first.id}:endpoint` : `${slug}:${endpoint.
|
|
20727
|
+
const key = endpoint.mode === "api" ? `${slug}:${first.id}:endpoint` : `${slug}:${endpoint.route}:endpoint`;
|
|
20384
20728
|
if (await rateLimited(c.env, key)) {
|
|
20385
20729
|
return refuse(429, "rate_limited");
|
|
20386
20730
|
}
|
|
@@ -20650,16 +20994,22 @@ var runForwardToApp2 = /* @__PURE__ */ __name(async (c, input) => {
|
|
|
20650
20994
|
method: c.req.method,
|
|
20651
20995
|
headers,
|
|
20652
20996
|
body,
|
|
20653
|
-
signal: AbortSignal.timeout(
|
|
20997
|
+
signal: AbortSignal.timeout(APP_INVOCATION_TIMEOUT_MS)
|
|
20654
20998
|
});
|
|
20655
20999
|
} catch (error51) {
|
|
20656
21000
|
return upstreamFailed2(origin, slug, String(error51));
|
|
20657
21001
|
}
|
|
20658
21002
|
adoptAppSpans(upstream);
|
|
21003
|
+
writeAppObservability(c.env, upstream, {
|
|
21004
|
+
app: observabilityApp(slug, app2),
|
|
21005
|
+
installs: [{ id: install.id, ord: install.ord, label: install.label }],
|
|
21006
|
+
budget: createDataPointBudget()
|
|
21007
|
+
});
|
|
20659
21008
|
setSpanAttributes({ "app.status": upstream.status });
|
|
20660
21009
|
const responseHeaders = new Headers(upstream.headers);
|
|
20661
21010
|
responseHeaders.delete("set-cookie");
|
|
20662
21011
|
responseHeaders.delete(APP_SPANS_HEADER);
|
|
21012
|
+
responseHeaders.delete(APP_OBSERVABILITY_HEADER);
|
|
20663
21013
|
for (const name of [...responseHeaders.keys()]) {
|
|
20664
21014
|
if (name.startsWith("access-control-")) {
|
|
20665
21015
|
responseHeaders.delete(name);
|
|
@@ -23693,6 +24043,21 @@ var withoutQuery = /* @__PURE__ */ __name((url2) => {
|
|
|
23693
24043
|
parsed.search = "";
|
|
23694
24044
|
return parsed.toString();
|
|
23695
24045
|
}, "withoutQuery");
|
|
24046
|
+
var browserGeoFrom = /* @__PURE__ */ __name((geo) => {
|
|
24047
|
+
if (geo === void 0) {
|
|
24048
|
+
return void 0;
|
|
24049
|
+
}
|
|
24050
|
+
return {
|
|
24051
|
+
country: geo.country ?? null,
|
|
24052
|
+
// EdgeTag's geoRegion is Cloudflare's subdivision code.
|
|
24053
|
+
region: geo.regionCode ?? null,
|
|
24054
|
+
state: geo.region ?? null,
|
|
24055
|
+
isEU: geo.isEUCountry === "yes"
|
|
24056
|
+
};
|
|
24057
|
+
}, "browserGeoFrom");
|
|
24058
|
+
var attachmentFieldBytes = /* @__PURE__ */ __name((name, value) => {
|
|
24059
|
+
return value === void 0 ? 0 : new TextEncoder().encode(`,"${name}":${JSON.stringify(value)}`).length;
|
|
24060
|
+
}, "attachmentFieldBytes");
|
|
23696
24061
|
var connectionAttachment = /* @__PURE__ */ __name((request, geo) => {
|
|
23697
24062
|
const userAgent = request.headers.get("user-agent");
|
|
23698
24063
|
const attrs = {
|
|
@@ -23708,15 +24073,18 @@ var connectionAttachment = /* @__PURE__ */ __name((request, geo) => {
|
|
|
23708
24073
|
locale: raw2.locale !== void 0 && raw2.locale.length <= MAX_HOST_LOCALE_LENGTH ? raw2.locale : void 0
|
|
23709
24074
|
};
|
|
23710
24075
|
const host = bounded.ip === void 0 && bounded.userAgent === void 0 && bounded.locale === void 0 ? void 0 : bounded;
|
|
23711
|
-
const hostBytes =
|
|
24076
|
+
const hostBytes = attachmentFieldBytes("host", host);
|
|
24077
|
+
const browserGeo = browserGeoFrom(geo);
|
|
24078
|
+
const browserGeoBytes = attachmentFieldBytes("browserGeo", browserGeo);
|
|
23712
24079
|
const cf = forwardedCf(request);
|
|
23713
24080
|
const cfSuffix = cf === void 0 ? "" : `,"cf":${JSON.stringify(cf)}`;
|
|
23714
24081
|
const cfBytes = new TextEncoder().encode(cfSuffix).length;
|
|
23715
24082
|
const emptyAttrsBytes = new TextEncoder().encode(JSON.stringify({ attrs: {} })).length;
|
|
23716
|
-
const includedCf = cfBytes <= MAX_ATTACHMENT_BYTES - emptyAttrsBytes - hostBytes ? cf : void 0;
|
|
23717
|
-
const budgeted = budgetAttrs(attrs, MAX_ATTACHMENT_BYTES - hostBytes - (includedCf === void 0 ? 0 : cfBytes));
|
|
24083
|
+
const includedCf = cfBytes <= MAX_ATTACHMENT_BYTES - emptyAttrsBytes - hostBytes - browserGeoBytes ? cf : void 0;
|
|
24084
|
+
const budgeted = budgetAttrs(attrs, MAX_ATTACHMENT_BYTES - hostBytes - browserGeoBytes - (includedCf === void 0 ? 0 : cfBytes));
|
|
23718
24085
|
return {
|
|
23719
24086
|
...budgeted,
|
|
24087
|
+
...browserGeo === void 0 ? {} : { browserGeo },
|
|
23720
24088
|
...includedCf === void 0 ? {} : { cf: includedCf },
|
|
23721
24089
|
...host === void 0 ? {} : { host }
|
|
23722
24090
|
};
|
|
@@ -23803,14 +24171,14 @@ var open = /* @__PURE__ */ __name(async (c) => {
|
|
|
23803
24171
|
|
|
23804
24172
|
// browser-artifact/meta.json
|
|
23805
24173
|
var meta_default = {
|
|
23806
|
-
version: "0.1.
|
|
23807
|
-
gitSha: "
|
|
23808
|
-
builtAt: "2026-08-
|
|
23809
|
-
hash: "
|
|
24174
|
+
version: "0.1.3",
|
|
24175
|
+
gitSha: "66e1bc45acbe4891948cbb3851f3f43ce06abc84",
|
|
24176
|
+
builtAt: "2026-08-28T17:17:19.113Z",
|
|
24177
|
+
hash: "050bb7dd702ac407623ce130c324f3342f048b8a201e2975994d5ef54de7f19f"
|
|
23810
24178
|
};
|
|
23811
24179
|
|
|
23812
24180
|
// src/paths/q-js.ts
|
|
23813
|
-
import qScript from "./
|
|
24181
|
+
import qScript from "./9026260a7a674b710223f296c5d2e7a01930cfed-q.js.txt";
|
|
23814
24182
|
|
|
23815
24183
|
// src/apps-q.ts
|
|
23816
24184
|
import appsQScript from "./apps-q.json";
|
|
@@ -23867,6 +24235,7 @@ var appsMetadata = /* @__PURE__ */ __name(() => {
|
|
|
23867
24235
|
return Object.fromEntries(
|
|
23868
24236
|
Object.entries(registry3.apps).map(([slug, app2]) => {
|
|
23869
24237
|
const capture = declaredCapture(app2);
|
|
24238
|
+
const geo = app2.data.includes("geo") ? { geo: true } : {};
|
|
23870
24239
|
const sharedContext = app2.data.includes(SHARED_CONTEXT_CAPABILITY) ? { sharedContext: true } : {};
|
|
23871
24240
|
return [
|
|
23872
24241
|
slug,
|
|
@@ -23874,6 +24243,7 @@ var appsMetadata = /* @__PURE__ */ __name(() => {
|
|
|
23874
24243
|
category: app2.consent.category,
|
|
23875
24244
|
eventResults: app2.eventResults,
|
|
23876
24245
|
...capture === void 0 ? {} : { capture },
|
|
24246
|
+
...geo,
|
|
23877
24247
|
...sharedContext
|
|
23878
24248
|
}
|
|
23879
24249
|
];
|
|
@@ -24520,7 +24890,7 @@ var runPool = /* @__PURE__ */ __name(async (limit, tasks) => {
|
|
|
24520
24890
|
}
|
|
24521
24891
|
await Promise.all(running);
|
|
24522
24892
|
}, "runPool");
|
|
24523
|
-
var fanOutToApps = /* @__PURE__ */ __name(async (env, trigger, snapshot, { deliverPush, writeAttribution: writeAttribution2, writeContext: writeContext2, trace }) => {
|
|
24893
|
+
var fanOutToApps = /* @__PURE__ */ __name(async (env, trigger, snapshot, { deliverPush, writeAttribution: writeAttribution2, writeContext: writeContext2, budget, trace }) => {
|
|
24524
24894
|
const { registry: registry3, error: error51 } = siteRegistry();
|
|
24525
24895
|
const targets = eligibleApps(registry3, trigger, snapshot.consent, consentEnforced(env));
|
|
24526
24896
|
if (error51 === void 0 && targets.length === 0) {
|
|
@@ -24548,7 +24918,7 @@ var fanOutToApps = /* @__PURE__ */ __name(async (env, trigger, snapshot, { deliv
|
|
|
24548
24918
|
await runPool(
|
|
24549
24919
|
FAN_OUT_CONCURRENCY,
|
|
24550
24920
|
capped.map((target) => {
|
|
24551
|
-
return () => invokeApp(env, { target, trigger, snapshot, context, deliverPush, writeAttribution: writeAttribution2, writeContext: writeContext2 });
|
|
24921
|
+
return () => invokeApp(env, { target, trigger, snapshot, context, deliverPush, writeAttribution: writeAttribution2, writeContext: writeContext2, budget });
|
|
24552
24922
|
})
|
|
24553
24923
|
);
|
|
24554
24924
|
}
|
|
@@ -24605,7 +24975,7 @@ var withReplacedPayload = /* @__PURE__ */ __name((entry, action, payload) => {
|
|
|
24605
24975
|
}
|
|
24606
24976
|
return { ...action, payload: parsed.data };
|
|
24607
24977
|
}, "withReplacedPayload");
|
|
24608
|
-
var postTransform = /* @__PURE__ */ __name(async (env, entry, post) => {
|
|
24978
|
+
var postTransform = /* @__PURE__ */ __name(async (env, entry, post, dataPoints) => {
|
|
24609
24979
|
let response;
|
|
24610
24980
|
try {
|
|
24611
24981
|
response = await postHookEnvelope(env, { binding: entry.app.binding, ...post });
|
|
@@ -24615,6 +24985,11 @@ var postTransform = /* @__PURE__ */ __name(async (env, entry, post) => {
|
|
|
24615
24985
|
if (response === void 0) {
|
|
24616
24986
|
throw entryFailure(entry, `the ${entry.app.binding} service binding is missing`);
|
|
24617
24987
|
}
|
|
24988
|
+
writeAppObservability(env, response, {
|
|
24989
|
+
app: observabilityApp(entry.slug, entry.app),
|
|
24990
|
+
installs: [entry.install],
|
|
24991
|
+
budget: dataPoints
|
|
24992
|
+
});
|
|
24618
24993
|
setSpanAttributes({ "app.status": response.status });
|
|
24619
24994
|
if (!response.ok) {
|
|
24620
24995
|
throw entryFailure(entry, `the hook answered status ${response.status}`);
|
|
@@ -24629,14 +25004,14 @@ var postTransform = /* @__PURE__ */ __name(async (env, entry, post) => {
|
|
|
24629
25004
|
throw entryFailure(entry, String(error51));
|
|
24630
25005
|
}
|
|
24631
25006
|
}, "postTransform");
|
|
24632
|
-
var runTransformEntry = /* @__PURE__ */ __name(async (env, { entry, action, snapshot, context, timeoutMs }) => {
|
|
25007
|
+
var runTransformEntry = /* @__PURE__ */ __name(async (env, { entry, action, snapshot, context, timeoutMs, dataPoints }) => {
|
|
24633
25008
|
const target = { slug: entry.slug, app: entry.app, installs: [entry.install] };
|
|
24634
25009
|
const envelope = {
|
|
24635
25010
|
...buildEnvelope(target, { kind: "event", action }, snapshot, context),
|
|
24636
25011
|
kind: "transform"
|
|
24637
25012
|
};
|
|
24638
25013
|
const key = await deriveAppInternalKey(context.master, context.domainId, entry.slug);
|
|
24639
|
-
const verdict = validateEnvelopeResponse(await postTransform(env, entry, { key, envelope, timeoutMs }), 1);
|
|
25014
|
+
const verdict = validateEnvelopeResponse(await postTransform(env, entry, { key, envelope, timeoutMs }, dataPoints), 1);
|
|
24640
25015
|
if (!verdict.ok) {
|
|
24641
25016
|
throw entryFailure(entry, verdict.reason);
|
|
24642
25017
|
}
|
|
@@ -24704,7 +25079,7 @@ var buildRelease = /* @__PURE__ */ __name((env, { collected, action, deliverPush
|
|
|
24704
25079
|
}
|
|
24705
25080
|
};
|
|
24706
25081
|
}, "buildRelease");
|
|
24707
|
-
var runTransformChain = /* @__PURE__ */ __name(async (env, { action, snapshot, deliverPush, writeAttribution: writeAttribution2, writeContext: writeContext2 }) => {
|
|
25082
|
+
var runTransformChain = /* @__PURE__ */ __name(async (env, { action, snapshot, deliverPush, writeAttribution: writeAttribution2, writeContext: writeContext2, dataPoints }) => {
|
|
24708
25083
|
const { registry: registry3, error: error51 } = siteRegistry();
|
|
24709
25084
|
if (error51 !== void 0) {
|
|
24710
25085
|
throw new TransformChainError(`the apps registry is malformed: ${error51}`);
|
|
@@ -24724,7 +25099,14 @@ var runTransformChain = /* @__PURE__ */ __name(async (env, { action, snapshot, d
|
|
|
24724
25099
|
for (const entry of entries) {
|
|
24725
25100
|
const stepped = entryBudget(budget, entry, Date.now());
|
|
24726
25101
|
budget = stepped.budget;
|
|
24727
|
-
const verdict = await invokeTransformEntry(env, {
|
|
25102
|
+
const verdict = await invokeTransformEntry(env, {
|
|
25103
|
+
entry,
|
|
25104
|
+
action: current,
|
|
25105
|
+
snapshot,
|
|
25106
|
+
context,
|
|
25107
|
+
timeoutMs: stepped.timeoutMs,
|
|
25108
|
+
dataPoints
|
|
25109
|
+
});
|
|
24728
25110
|
if (verdict.effects.accepted.length > 0) {
|
|
24729
25111
|
collected.push({ slug: entry.slug, installs: [entry.install], groups: verdict.effects.accepted });
|
|
24730
25112
|
}
|
|
@@ -25705,7 +26087,11 @@ var AnonDO = class extends DurableObject2 {
|
|
|
25705
26087
|
const attachment = connectionAttachment(request, geo);
|
|
25706
26088
|
server.serializeAttachment(attachment);
|
|
25707
26089
|
this.deliverSharedContext(server);
|
|
25708
|
-
this.appFanOut(
|
|
26090
|
+
this.appFanOut(
|
|
26091
|
+
{ kind: "connect", ...attachment.cf === void 0 ? {} : { geo: attachment.cf }, host: attachment.host },
|
|
26092
|
+
userId,
|
|
26093
|
+
createDataPointBudget()
|
|
26094
|
+
);
|
|
25709
26095
|
return new Response(null, { status: 101, webSocket: client });
|
|
25710
26096
|
});
|
|
25711
26097
|
}
|
|
@@ -25760,7 +26146,14 @@ var AnonDO = class extends DurableObject2 {
|
|
|
25760
26146
|
return;
|
|
25761
26147
|
}
|
|
25762
26148
|
if (parsed.frame.t === "getSession") {
|
|
25763
|
-
this.respond(ws, {
|
|
26149
|
+
this.respond(ws, {
|
|
26150
|
+
t: "session",
|
|
26151
|
+
ref: parsed.ref,
|
|
26152
|
+
anonId: userId,
|
|
26153
|
+
globalId: linkedGlobalId(this.kv),
|
|
26154
|
+
ip: attachment?.host?.ip ?? null,
|
|
26155
|
+
geo: attachment?.browserGeo ?? null
|
|
26156
|
+
});
|
|
25764
26157
|
return;
|
|
25765
26158
|
}
|
|
25766
26159
|
if (parsed.frame.t === "capture") {
|
|
@@ -26046,12 +26439,13 @@ var AnonDO = class extends DurableObject2 {
|
|
|
26046
26439
|
if (isNoopAction(action)) {
|
|
26047
26440
|
return;
|
|
26048
26441
|
}
|
|
26049
|
-
const
|
|
26442
|
+
const dataPoints = createDataPointBudget();
|
|
26443
|
+
const transformed = await this.transformAction(action, dataPoints);
|
|
26050
26444
|
if (transformed === null) {
|
|
26051
26445
|
return;
|
|
26052
26446
|
}
|
|
26053
26447
|
recorded = transformed.action;
|
|
26054
|
-
await this.runAction(transformed.action, transformed.releaseEmissions);
|
|
26448
|
+
await this.runAction(transformed.action, transformed.releaseEmissions, dataPoints);
|
|
26055
26449
|
} finally {
|
|
26056
26450
|
this.recordActionBlocks(recorded);
|
|
26057
26451
|
}
|
|
@@ -26061,9 +26455,9 @@ var AnonDO = class extends DurableObject2 {
|
|
|
26061
26455
|
actionBlocks(action, this.appsSnapshot(action.userId), this.wiped ? [] : allIdentifiers(this.sql, this.identifiersMirror))
|
|
26062
26456
|
);
|
|
26063
26457
|
}
|
|
26064
|
-
async runAction(current, releaseEmissions) {
|
|
26458
|
+
async runAction(current, releaseEmissions, dataPoints) {
|
|
26065
26459
|
if (current.type !== "alias" && isDeliveryOnlyAction(current)) {
|
|
26066
|
-
this.appFanOut({ kind: "event", action: current }, current.userId);
|
|
26460
|
+
this.appFanOut({ kind: "event", action: current }, current.userId, dataPoints);
|
|
26067
26461
|
this.releaseTransformEmissions(releaseEmissions);
|
|
26068
26462
|
return;
|
|
26069
26463
|
}
|
|
@@ -26099,7 +26493,7 @@ var AnonDO = class extends DurableObject2 {
|
|
|
26099
26493
|
} else {
|
|
26100
26494
|
await this.ingestConsent(current);
|
|
26101
26495
|
}
|
|
26102
|
-
this.appFanOut({ kind: "event", action: current }, current.userId);
|
|
26496
|
+
this.appFanOut({ kind: "event", action: current }, current.userId, dataPoints);
|
|
26103
26497
|
this.releaseTransformEmissions(releaseEmissions);
|
|
26104
26498
|
} finally {
|
|
26105
26499
|
if (novelIdentifier) {
|
|
@@ -26108,7 +26502,7 @@ var AnonDO = class extends DurableObject2 {
|
|
|
26108
26502
|
}
|
|
26109
26503
|
}
|
|
26110
26504
|
// null means a transform dropped the action: the turn succeeds with nothing persisted (§5.4).
|
|
26111
|
-
async transformAction(action) {
|
|
26505
|
+
async transformAction(action, dataPoints) {
|
|
26112
26506
|
if (action.type !== "track" && action.type !== "identify") {
|
|
26113
26507
|
return { action, releaseEmissions: null };
|
|
26114
26508
|
}
|
|
@@ -26117,7 +26511,8 @@ var AnonDO = class extends DurableObject2 {
|
|
|
26117
26511
|
snapshot: this.appsSnapshot(action.userId),
|
|
26118
26512
|
deliverPush: this.pushDelivery,
|
|
26119
26513
|
writeAttribution: this.attributionDelivery,
|
|
26120
|
-
writeContext: this.contextDelivery
|
|
26514
|
+
writeContext: this.contextDelivery,
|
|
26515
|
+
dataPoints
|
|
26121
26516
|
});
|
|
26122
26517
|
if (outcome.dropped) {
|
|
26123
26518
|
this.releaseTransformEmissions(outcome.releaseEmissions);
|
|
@@ -26153,13 +26548,14 @@ var AnonDO = class extends DurableObject2 {
|
|
|
26153
26548
|
}
|
|
26154
26549
|
this.ctx.waitUntil(release().catch((error51) => console.warn("transform emission release failed", { error: error51 })));
|
|
26155
26550
|
}
|
|
26156
|
-
appFanOut(trigger, anonId) {
|
|
26551
|
+
appFanOut(trigger, anonId, dataPoints) {
|
|
26157
26552
|
const snapshot = this.appsSnapshot(anonId);
|
|
26158
26553
|
this.ctx.waitUntil(
|
|
26159
26554
|
fanOutToApps(this.env, trigger, snapshot, {
|
|
26160
26555
|
deliverPush: this.pushDelivery,
|
|
26161
26556
|
writeAttribution: this.attributionDelivery,
|
|
26162
26557
|
writeContext: this.contextDelivery,
|
|
26558
|
+
budget: dataPoints,
|
|
26163
26559
|
trace: currentTraceContext()
|
|
26164
26560
|
}).catch((error51) => console.warn("app fan-out failed", { error: error51 }))
|
|
26165
26561
|
);
|